diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..56fe7b7 --- /dev/null +++ b/.clang-format @@ -0,0 +1,30 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: Never +SpaceInEmptyParentheses: false +SpacesInCStyleCastParentheses: false +IndentWidth: 4 +TabWidth: 4 +UseTab: Never +AllowShortBlocksOnASingleLine: true +AllowShortIfStatementsOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortLoopsOnASingleLine: true +ColumnLimit: 0 +DerivePointerAlignment: true +PointerAlignment: Left +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: false + AfterStruct: false + AfterUnion: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false +... diff --git a/src/ccInstHelper.cpp b/src/ccInstHelper.cpp index 179b4f5..7cdc221 100644 --- a/src/ccInstHelper.cpp +++ b/src/ccInstHelper.cpp @@ -1,332 +1,331 @@ // uninstallHelper.cpp : Defines the entry point for the console application. // +#include +#include +#include #include #include -#include #include -#include -#include //#define __stdcall #ifndef KREPLACEMENTS_H // For compilation download the NSIS source package and modify the following // line to point to the exdll.h-file #include "C:/Programme/NSIS/Contrib/ExDll/exdll.h" #endif -struct ReplacementItem -{ const char* fileType; const char* operationType; }; +struct ReplacementItem { + const char* fileType; + const char* operationType; +}; ReplacementItem g_replacementTable[] = { - {"text_file_delta", "xcompare"}, - {"text_file_delta", "xmerge"}, - {"whole_copy", "xcompare"}, - {"whole_copy", "xmerge"}, - {"z_text_file_delta", "xcompare"}, - {"z_text_file_delta", "xmerge"}, - {"z_whole_copy", "xcompare"}, - {"z_whole_copy", "xmerge"}, - {"_xml", "xcompare"}, - {"_xml", "xmerge"}, - {"_xml2", "xcompare"}, - {"_xml2", "xmerge"}, - {"_rftdef", "xcompare"}, - {"_rftmap", "xcompare"}, - {"_rftvp", "xcompare"}, - {"_xtools", "xcompare"}, - {0,0} -}; + {"text_file_delta", "xcompare"}, + {"text_file_delta", "xmerge"}, + {"whole_copy", "xcompare"}, + {"whole_copy", "xmerge"}, + {"z_text_file_delta", "xcompare"}, + {"z_text_file_delta", "xmerge"}, + {"z_whole_copy", "xcompare"}, + {"z_whole_copy", "xmerge"}, + {"_xml", "xcompare"}, + {"_xml", "xmerge"}, + {"_xml2", "xcompare"}, + {"_xml2", "xmerge"}, + {"_rftdef", "xcompare"}, + {"_rftmap", "xcompare"}, + {"_rftvp", "xcompare"}, + {"_xtools", "xcompare"}, + {0, 0}}; -struct LineItem -{ - std::string fileType; - std::string opType; - std::string command; - std::string fileOpPart; +struct LineItem { + std::string fileType; + std::string opType; + std::string command; + std::string fileOpPart; }; // Return true if successful, else false -bool readAndParseMapFile( const std::string& filename, std::list& lineItemList ) +bool readAndParseMapFile(const std::string& filename, std::list& lineItemList) { - // Read file - FILE* pFile = fopen( filename.c_str(), "r" ); - if (pFile) - { - fseek(pFile,0,SEEK_END); - int size = ftell(pFile); - fseek(pFile,0,SEEK_SET); - std::vector buf( size ); - fread( &buf[0], 1, size, pFile ); - fclose( pFile ); + // Read file + FILE* pFile = fopen(filename.c_str(), "r"); + if(pFile) + { + fseek(pFile, 0, SEEK_END); + int size = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + std::vector buf(size); + fread(&buf[0], 1, size, pFile); + fclose(pFile); - // Replace strings - int lineStartPos=0; - int wordInLine = 0; - LineItem lineItem; - for( int i=0; i& lineItemList ) +bool writeMapFile(const std::string& filename, const std::list& lineItemList) { - FILE* pFile = fopen( filename.c_str(), "w" ); - if (pFile) - { - std::list::const_iterator i = lineItemList.begin(); - for( ; i!=lineItemList.end(); ++i ) - { - const LineItem& li = *i; - fprintf( pFile, "%s%s\n", li.fileOpPart.c_str(), li.command.c_str() ); - } - fclose( pFile ); - } - else - { - return false; - } - return true; + FILE* pFile = fopen(filename.c_str(), "w"); + if(pFile) + { + std::list::const_iterator i = lineItemList.begin(); + for(; i != lineItemList.end(); ++i) + { + const LineItem& li = *i; + fprintf(pFile, "%s%s\n", li.fileOpPart.c_str(), li.command.c_str()); + } + fclose(pFile); + } + else + { + return false; + } + return true; } -std::string toUpper( const std::string& s ) +std::string toUpper(const std::string& s) { - std::string s2 = s; + std::string s2 = s; - for( unsigned int i=0; i0 && len+1 0 && len + 1 < int(sizeof(buffer) / sizeof(buffer[0])) && pLastPart) + { + pLastPart[-1] = 0; + pLastPart = strrchr(buffer, '\\'); // cd up (because cleartool.exe is in bin subdir) + if(pLastPart) + pLastPart[1] = 0; - std::string path( buffer ); - path += "lib\\mgrs\\map"; - std::string bakName = path + ".preKDiff3Install"; - - if ( installCommand == "existsClearCase") - { - return 1; - } - else if ( installCommand == "install") - { - std::list lineItemList; - bool bSuccess = readAndParseMapFile( path, lineItemList ); - if ( !bSuccess ) - { - fprintf(stderr, "Error reading original map file.\n"); - return -1; - } + std::string path(buffer); + path += "lib\\mgrs\\map"; + std::string bakName = path + ".preKDiff3Install"; - // Create backup - if ( access( bakName.c_str(), 0 )!=0 ) // Create backup only if not exists yet - { - if ( rename( path.c_str(), bakName.c_str() ) ) + if(installCommand == "existsClearCase") + { + return 1; + } + else if(installCommand == "install") + { + std::list lineItemList; + bool bSuccess = readAndParseMapFile(path, lineItemList); + if(!bSuccess) { - fprintf(stderr, "Error renaming original map file.\n"); - return -1; + fprintf(stderr, "Error reading original map file.\n"); + return -1; } - } - std::list::iterator i = lineItemList.begin(); - for( ; i!=lineItemList.end(); ++i ) - { - LineItem& li = *i; - for (int j=0;;++j) + // Create backup + if(access(bakName.c_str(), 0) != 0) // Create backup only if not exists yet { - ReplacementItem& ri = g_replacementTable[j]; - if ( ri.fileType==0 || ri.operationType==0 ) - break; - if ( li.fileType == ri.fileType && li.opType == ri.operationType ) - { - li.command = kdiff3Command.c_str(); - break; - } + if(rename(path.c_str(), bakName.c_str())) + { + fprintf(stderr, "Error renaming original map file.\n"); + return -1; + } } - } - bSuccess = writeMapFile( path, lineItemList ); - if ( !bSuccess ) - { - if ( rename( bakName.c_str(), path.c_str() ) ) - fprintf(stderr, "Error writing new map file, restoring old file also failed.\n"); - else - fprintf(stderr, "Error writing new map file, old file restored.\n"); + std::list::iterator i = lineItemList.begin(); + for(; i != lineItemList.end(); ++i) + { + LineItem& li = *i; + for(int j = 0;; ++j) + { + ReplacementItem& ri = g_replacementTable[j]; + if(ri.fileType == 0 || ri.operationType == 0) + break; + if(li.fileType == ri.fileType && li.opType == ri.operationType) + { + li.command = kdiff3Command.c_str(); + break; + } + } + } - return -1; - } - } - else if ( installCommand == "uninstall" ) - { - std::list lineItemList; - bool bSuccess = readAndParseMapFile( path, lineItemList ); - if ( !bSuccess ) - { - fprintf(stderr, "Error reading original map file\n."); - return -1; - } + bSuccess = writeMapFile(path, lineItemList); + if(!bSuccess) + { + if(rename(bakName.c_str(), path.c_str())) + fprintf(stderr, "Error writing new map file, restoring old file also failed.\n"); + else + fprintf(stderr, "Error writing new map file, old file restored.\n"); - std::list lineItemListBak; - bSuccess = readAndParseMapFile( bakName, lineItemListBak ); - if ( !bSuccess ) - { - fprintf(stderr, "Error reading backup map file.\n"); - return -1; - } + return -1; + } + } + else if(installCommand == "uninstall") + { + std::list lineItemList; + bool bSuccess = readAndParseMapFile(path, lineItemList); + if(!bSuccess) + { + fprintf(stderr, "Error reading original map file\n."); + return -1; + } - std::list::iterator i = lineItemList.begin(); - for( ; i!=lineItemList.end(); ++i ) - { - LineItem& li = *i; - if ((int)toUpper(li.command).find("KDIFF3")>=0) + std::list lineItemListBak; + bSuccess = readAndParseMapFile(bakName, lineItemListBak); + if(!bSuccess) { - std::list::const_iterator j = lineItemListBak.begin(); - for (;j!=lineItemListBak.end();++j) - { - const LineItem& bi = *j; // backup iterator - if ( li.fileType == bi.fileType && li.opType == bi.opType ) - { - li.command = bi.command; - break; - } - } + fprintf(stderr, "Error reading backup map file.\n"); + return -1; } - } - bSuccess = writeMapFile( path, lineItemList ); - if ( !bSuccess ) - { - fprintf(stderr, "Error writing map file."); - return -1; - } - } - } - return 0; + std::list::iterator i = lineItemList.begin(); + for(; i != lineItemList.end(); ++i) + { + LineItem& li = *i; + if((int)toUpper(li.command).find("KDIFF3") >= 0) + { + std::list::const_iterator j = lineItemListBak.begin(); + for(; j != lineItemListBak.end(); ++j) + { + const LineItem& bi = *j; // backup iterator + if(li.fileType == bi.fileType && li.opType == bi.opType) + { + li.command = bi.command; + break; + } + } + } + } + + bSuccess = writeMapFile(path, lineItemList); + if(!bSuccess) + { + fprintf(stderr, "Error writing map file."); + return -1; + } + } + } + return 0; } #ifndef KREPLACEMENTS_H -extern "C" -void __declspec(dllexport) nsisPlugin(HWND hwndParent, int string_size, - char *variables, stack_t **stacktop, - extra_parameters *extra) +extern "C" void __declspec(dllexport) nsisPlugin(HWND hwndParent, int string_size, + char* variables, stack_t** stacktop, + extra_parameters* extra) { - //g_hwndParent=hwndParent; + //g_hwndParent=hwndParent; - EXDLL_INIT(); - { - std::string param1( g_stringsize, ' ' ); - int retVal = popstring( ¶m1[0] ); - if ( retVal == 0 ) - { - std::string param2( g_stringsize, ' ' ); - retVal = popstring( ¶m2[0] ); - if ( retVal == 0 ) - install( param1.c_str(), param2.c_str() ); - return; - } - fprintf(stderr, "Not enough parameters.\n"); - } + EXDLL_INIT(); + { + std::string param1(g_stringsize, ' '); + int retVal = popstring(¶m1[0]); + if(retVal == 0) + { + std::string param2(g_stringsize, ' '); + retVal = popstring(¶m2[0]); + if(retVal == 0) + install(param1.c_str(), param2.c_str()); + return; + } + fprintf(stderr, "Not enough parameters.\n"); + } } #endif /* int _tmain(int argc, _TCHAR* argv[]) { if ( argc<3 ) { std::cout << "This program is needed to install/uninstall KDiff3 for clearcase.\n" "It tries to patch the map file (clearcase-subdir\\lib\\mgrs\\map)\n" "Usage 1: ccInstHelper install pathToKdiff3.exe\n" "Usage 2: ccInstHelper uninstall pathToKdiff3.exe\n" "Backups of the original map files are created in the dir of the map file.\n"; } else { return install( argv[1], argv[2] ); } return 0; } */ diff --git a/src/common.cpp b/src/common.cpp index 0ec7169..f903900 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -1,366 +1,382 @@ /*************************************************************************** * Copyright (C) 2004-2007 by Joachim Eibl * * joachim.eibl at gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "common.h" -#include -#include #include #include -#include #include #include +#include +#include +#include ValueMap::ValueMap() { } ValueMap::~ValueMap() { } -void ValueMap::save( QTextStream& ts ) +void ValueMap::save(QTextStream& ts) { - std::map::iterator i; - for( i=m_map.begin(); i!=m_map.end(); ++i) - { - QString key = i->first; - QString val = i->second; - ts << key << "=" << val << "\n"; - } + std::map::iterator i; + for(i = m_map.begin(); i != m_map.end(); ++i) + { + QString key = i->first; + QString val = i->second; + ts << key << "=" << val << "\n"; + } } QString ValueMap::getAsString() { - QString result; - std::map::iterator i; - for( i=m_map.begin(); i!=m_map.end(); ++i) - { - QString key = i->first; - QString val = i->second; - result += key + "=" + val + "\n"; - } - return result; + QString result; + std::map::iterator i; + for(i = m_map.begin(); i != m_map.end(); ++i) + { + QString key = i->first; + QString val = i->second; + result += key + "=" + val + "\n"; + } + return result; } -void ValueMap::load( QTextStream& ts ) +void ValueMap::load(QTextStream& ts) { - while ( !ts.atEnd() ) - { // until end of file... - QString s = ts.readLine(); // line of text excluding '\n' - int pos = s.indexOf('='); - if( pos > 0 ) // seems not to have a tag - { - QString key = s.left(pos); - QString val = s.mid(pos+1); - m_map[key] = val; - } - } + while(!ts.atEnd()) + { // until end of file... + QString s = ts.readLine(); // line of text excluding '\n' + int pos = s.indexOf('='); + if(pos > 0) // seems not to have a tag + { + QString key = s.left(pos); + QString val = s.mid(pos + 1); + m_map[key] = val; + } + } } /* void ValueMap::load( const QString& s ) { int pos=0; while ( pos<(int)s.length() ) { // until end of file... int pos2 = s.find('=', pos); int pos3 = s.find('\n', pos2 ); if (pos3<0) pos3=s.length(); if( pos2 > 0 ) // seems not to have a tag { QString key = s.mid(pos, pos2-pos); QString val = s.mid(pos2+1, pos3-pos2-1); m_map[key] = val; } pos = pos3; } } */ // safeStringJoin and safeStringSplit allow to convert a stringlist into a string and back // safely, even if the individual strings in the list contain the separator character. -QString safeStringJoin(const QStringList& sl, char sepChar, char metaChar ) -{ - // Join the strings in the list, using the separator ',' - // If a string contains the separator character, it will be replaced with "\,". - // Any occurances of "\" (one backslash) will be replaced with "\\" (2 backslashes) - - assert(sepChar!=metaChar); - - QString sep; - sep += sepChar; - QString meta; - meta += metaChar; - - QString safeString; - - QStringList::const_iterator i; - for (i=sl.begin(); i!=sl.end(); ++i) - { - QString s = *i; - s.replace(meta, meta+meta); // "\" -> "\\" - s.replace(sep, meta+sep); // "," -> "\," - if ( i==sl.begin() ) - safeString = s; - else - safeString += sep + s; - } - return safeString; +QString safeStringJoin(const QStringList& sl, char sepChar, char metaChar) +{ + // Join the strings in the list, using the separator ',' + // If a string contains the separator character, it will be replaced with "\,". + // Any occurances of "\" (one backslash) will be replaced with "\\" (2 backslashes) + + assert(sepChar != metaChar); + + QString sep; + sep += sepChar; + QString meta; + meta += metaChar; + + QString safeString; + + QStringList::const_iterator i; + for(i = sl.begin(); i != sl.end(); ++i) + { + QString s = *i; + s.replace(meta, meta + meta); // "\" -> "\\" + s.replace(sep, meta + sep); // "," -> "\," + if(i == sl.begin()) + safeString = s; + else + safeString += sep + s; + } + return safeString; } // Split a string that was joined with safeStringJoin -QStringList safeStringSplit(const QString& s, char sepChar, char metaChar ) -{ - assert(sepChar!=metaChar); - QStringList sl; - // Miniparser - int i=0; - int len=s.length(); - QString b; - for(i=0;i0 ) - { - pos = s.indexOf( sep, pos ); - --idx; - if (pos<0) break; - ++pos; - } - if ( pos>=0 ) - { - int pos2 = s.indexOf( sep, pos ); - if ( pos2>0 ) - return s.mid(pos, pos2-pos); - else - return s.mid(pos); - } + int pos = 0; + while(idx > 0) + { + pos = s.indexOf(sep, pos); + --idx; + if(pos < 0) break; + ++pos; + } + if(pos >= 0) + { + int pos2 = s.indexOf(sep, pos); + if(pos2 > 0) + return s.mid(pos, pos2 - pos); + else + return s.mid(pos); + } - return ""; + return ""; } -static int num( QString& s, int idx ) +static int num(QString& s, int idx) { - return subSection( s, idx, ',').toInt(); + return subSection(s, idx, ',').toInt(); } -void ValueMap::writeEntry(const QString& k, const QFont& v ) +void ValueMap::writeEntry(const QString& k, const QFont& v) { - m_map[k] = v.family() + "," + QString::number(v.pointSize()) + "," + (v.bold() ? "bold" : "normal"); + m_map[k] = v.family() + "," + QString::number(v.pointSize()) + "," + (v.bold() ? "bold" : "normal"); } -void ValueMap::writeEntry(const QString& k, const QColor& v ) +void ValueMap::writeEntry(const QString& k, const QColor& v) { - m_map[k] = numStr(v.red()) + "," + numStr(v.green()) + "," + numStr(v.blue()); + m_map[k] = numStr(v.red()) + "," + numStr(v.green()) + "," + numStr(v.blue()); } -void ValueMap::writeEntry(const QString& k, const QSize& v ) +void ValueMap::writeEntry(const QString& k, const QSize& v) { - m_map[k] = numStr(v.width()) + "," + numStr(v.height()); + m_map[k] = numStr(v.width()) + "," + numStr(v.height()); } -void ValueMap::writeEntry(const QString& k, const QPoint& v ) +void ValueMap::writeEntry(const QString& k, const QPoint& v) { - m_map[k] = numStr(v.x()) + "," + numStr(v.y()); + m_map[k] = numStr(v.x()) + "," + numStr(v.y()); } -void ValueMap::writeEntry(const QString& k, int v ) +void ValueMap::writeEntry(const QString& k, int v) { - m_map[k] = numStr(v); + m_map[k] = numStr(v); } -void ValueMap::writeEntry(const QString& k, bool v ) +void ValueMap::writeEntry(const QString& k, bool v) { - m_map[k] = numStr(v); + m_map[k] = numStr(v); } -void ValueMap::writeEntry(const QString& k, const QString& v ) +void ValueMap::writeEntry(const QString& k, const QString& v) { - m_map[k] = v; + m_map[k] = v; } -void ValueMap::writeEntry(const QString& k, const char* v ) +void ValueMap::writeEntry(const QString& k, const char* v) { - m_map[k] = v; + m_map[k] = v; } -void ValueMap::writeEntry(const QString& k, const QStringList& v ) +void ValueMap::writeEntry(const QString& k, const QStringList& v) { m_map[k] = safeStringJoin(v); } - -QFont ValueMap::readFontEntry(const QString& k, const QFont* defaultVal ) +QFont ValueMap::readFontEntry(const QString& k, const 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.setBold( subSection( i->second, 2, ',' )=="bold" ); - } - return f; + 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.setBold(subSection(i->second, 2, ',') == "bold"); + } + return f; } -QColor ValueMap::readColorEntry(const QString& k, const QColor* defaultVal ) +QColor ValueMap::readColorEntry(const QString& k, const 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) ); - } + 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; + return c; } -QSize ValueMap::readSizeEntry(const QString& k, const QSize* defaultVal ) +QSize ValueMap::readSizeEntry(const QString& k, const QSize* defaultVal) { - QSize size = defaultVal ? *defaultVal : QSize(600,400); - std::map::iterator i = m_map.find( k ); - if ( i!=m_map.end() ) - { + QSize size = defaultVal ? *defaultVal : QSize(600, 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) ); - } + QString s = i->second; + size = QSize(num(s, 0), num(s, 1)); + } - return size; + return size; } QPoint ValueMap::readPointEntry(const QString& k, const QPoint* defaultVal) { - QPoint point = defaultVal ? *defaultVal : QPoint(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) ); - } + QPoint point = defaultVal ? *defaultVal : QPoint(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; + return point; } -bool ValueMap::readBoolEntry(const QString& k, bool bDefault ) +bool ValueMap::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); - } + 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; + return b; } -int ValueMap::readNumEntry(const QString& k, int iDefault ) +int ValueMap::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); - } + 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; + return ival; } -QString ValueMap::readStringEntry(const QString& k, const QString& sDefault ) +QString ValueMap::readStringEntry(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; - } + QString sval = sDefault; + std::map::iterator i = m_map.find(k); + if(i != m_map.end()) + { + sval = i->second; + } - return sval; + return sval; } QStringList ValueMap::readListEntry(const QString& k, const QStringList& defaultVal) { QStringList strList; - std::map::iterator i = m_map.find( k ); - if( i != m_map.end() ) { - strList = safeStringSplit( i->second ); + std::map::iterator i = m_map.find(k); + if(i != m_map.end()) { + strList = safeStringSplit(i->second); return strList; } else return defaultVal; } -QString ValueMap::readEntry( const QString& s, const QString& defaultVal ) { - return readStringEntry( s, defaultVal ); +QString ValueMap::readEntry(const QString& s, const QString& defaultVal) +{ + return readStringEntry(s, defaultVal); } -QString ValueMap::readEntry( const QString& s, const char* defaultVal ) { - return readStringEntry( s, QString::fromLatin1( defaultVal ) ); +QString ValueMap::readEntry(const QString& s, const char* defaultVal) +{ + return readStringEntry(s, QString::fromLatin1(defaultVal)); } -QFont ValueMap::readEntry( const QString& s, const QFont& defaultVal ) { - return readFontEntry( s, &defaultVal ); +QFont ValueMap::readEntry(const QString& s, const QFont& defaultVal) +{ + return readFontEntry(s, &defaultVal); } -QColor ValueMap::readEntry( const QString& s, const QColor defaultVal ) { - return readColorEntry( s, &defaultVal ); +QColor ValueMap::readEntry(const QString& s, const QColor defaultVal) +{ + return readColorEntry(s, &defaultVal); } -QSize ValueMap::readEntry( const QString& s, const QSize defaultVal ) { - return readSizeEntry( s, &defaultVal ); +QSize ValueMap::readEntry(const QString& s, const QSize defaultVal) +{ + return readSizeEntry(s, &defaultVal); } -QPoint ValueMap::readEntry( const QString& s, const QPoint defaultVal ) { - return readPointEntry( s, &defaultVal ); +QPoint ValueMap::readEntry(const QString& s, const QPoint defaultVal) +{ + return readPointEntry(s, &defaultVal); } -bool ValueMap::readEntry( const QString& s, bool bDefault ) { - return readBoolEntry( s, bDefault ); +bool ValueMap::readEntry(const QString& s, bool bDefault) +{ + return readBoolEntry(s, bDefault); } -int ValueMap::readEntry( const QString& s, int iDefault ) { - return readNumEntry( s, iDefault ); +int ValueMap::readEntry(const QString& s, int iDefault) +{ + return readNumEntry(s, iDefault); } -QStringList ValueMap::readEntry( const QString& s, const QStringList& defaultVal ) { - return readListEntry( s, defaultVal ); +QStringList ValueMap::readEntry(const QString& s, const QStringList& defaultVal) +{ + return readListEntry(s, defaultVal); } diff --git a/src/diff.cpp b/src/diff.cpp index f688b61..93f0045 100644 --- a/src/diff.cpp +++ b/src/diff.cpp @@ -1,2460 +1,2474 @@ /*************************************************************************** diff.cpp - description ------------------- begin : Mon Mar 18 2002 copyright : (C) 2002-2007 by Joachim Eibl email : joachim.eibl at gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef _WIN32 #include #endif #include #include "diff.h" #include "fileaccess.h" #include "gnudiff_diff.h" #include "options.h" #include "progress.h" -#include #include +#include -#include #include +#include +#include #include #include -#include -#include #include #include +#include //using namespace std; - int LineData::width(int tabSize) const { - int w=0; - int j=0; - for( int i=0; i=5 || l2.occurances>=5) ) - return false; + if(bStrict && g_bIgnoreTrivialMatches) //&& (l1.occurances>=5 || l2.occurances>=5) ) + return false; - // Ignore white space diff - const QChar* p1 = l1.pLine; - const QChar* p1End = p1 + l1.size; + // Ignore white space diff + const QChar* p1 = l1.pLine; + const QChar* p1End = p1 + l1.size; - const QChar* p2 = l2.pLine; - const QChar* p2End = p2 + l2.size; + const QChar* p2 = l2.pLine; + const QChar* p2End = p2 + l2.size; - if ( g_bIgnoreWhiteSpace ) - { - int nonWhite = 0; - for(;;) - { - while( isWhite( *p1 ) && p1!=p1End ) ++p1; - while( isWhite( *p2 ) && p2!=p2End ) ++p2; + if(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; + if(p1 == p1End && p2 == p2End) + { + if(bStrict && g_bIgnoreTrivialMatches) + { // Then equality is not enough + return nonWhite > 2; + } + else // equality is enough + return true; } - else // equality is enough - return true; - } - else if ( p1 == p1End || p2 == p2End ) + 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; - - if( *p1 != *p2 ) - return false; - ++p1; - ++p2; - ++nonWhite; - } - } - - else - { - if ( l1.size==l2.size && memcmp(p1, p2, l1.size)==0) - return true; - else - return false; - } + } } - -static bool isLineOrBufEnd( const QChar* p, int i, int size ) +static bool isLineOrBufEnd(const QChar* p, int i, int size) { - return - i>=size // End of file - || isEndOfLine(p[i]) // Normal end of line - - // No support for Mac-end of line yet, because incompatible with GNU-diff-routines. - // || ( p[i]=='\r' && (i>=size-1 || p[i+1]!='\n') - // && (i==0 || p[i-1]!='\n') ) // Special case: '\r' without '\n' - ; -} + return i >= size // End of file + || isEndOfLine(p[i]) // Normal end of line + // No support for Mac-end of line yet, because incompatible with GNU-diff-routines. + // || ( p[i]=='\r' && (i>=size-1 || p[i+1]!='\n') + // && (i==0 || p[i-1]!='\n') ) // Special case: '\r' without '\n' + ; +} /* Features of class SourceData: - Read a file (from the given URL) or accept data via a string. - Allocate and free buffers as necessary. - Run a preprocessor, when specified. - Run the line-matching preprocessor, when specified. - Run other preprocessing steps: Uppercase, ignore comments, remove carriage return, ignore numbers. Order of operation: 1. If data was given via a string then save it to a temp file. (see setData()) 2. If the specified file is nonlocal (URL) copy it to a temp file. 3. If a preprocessor was specified, run the input file through it. 4. Read the output of the preprocessor. 5. If Uppercase was specified: Turn the read data to uppercase. 6. Write the result to a temp file. 7. If a line-matching preprocessor was specified, run the temp file through it. 8. Read the output of the line-matching preprocessor. 9. If ignore numbers was specified, strip the LMPP-output of all numbers. 10. If ignore comments was specified, strip the LMPP-output of comments. Optimizations: Skip unneeded steps. */ SourceData::SourceData() { - m_pOptions = 0; - reset(); + m_pOptions = 0; + reset(); } SourceData::~SourceData() { - reset(); + reset(); } void SourceData::reset() { - m_pEncoding = 0; - m_fileAccess = FileAccess(); - m_normalData.reset(); - m_lmppData.reset(); - if ( !m_tempInputFileName.isEmpty() ) - { - FileAccess::removeFile( m_tempInputFileName ); - m_tempInputFileName = ""; - } + m_pEncoding = 0; + m_fileAccess = FileAccess(); + m_normalData.reset(); + m_lmppData.reset(); + if(!m_tempInputFileName.isEmpty()) + { + FileAccess::removeFile(m_tempInputFileName); + m_tempInputFileName = ""; + } } -void SourceData::setFilename( const QString& filename ) +void SourceData::setFilename(const QString& filename) { - if (filename.isEmpty()) - { - reset(); - } - else - { - FileAccess fa( filename ); - setFileAccess( fa ); - } + if(filename.isEmpty()) + { + reset(); + } + else + { + FileAccess fa(filename); + setFileAccess(fa); + } } -bool SourceData::isEmpty() -{ - return getFilename().isEmpty(); +bool SourceData::isEmpty() +{ + return getFilename().isEmpty(); } -bool SourceData::hasData() -{ - return m_normalData.m_pBuf != 0; +bool SourceData::hasData() +{ + return m_normalData.m_pBuf != 0; } bool SourceData::isValid() { - return isEmpty() || hasData(); + return isEmpty() || hasData(); } -void SourceData::setOptions( Options* pOptions ) +void SourceData::setOptions(Options* pOptions) { - m_pOptions = pOptions; + m_pOptions = pOptions; } QString SourceData::getFilename() { - return m_fileAccess.absoluteFilePath(); + return m_fileAccess.absoluteFilePath(); } QString SourceData::getAliasName() { - return m_aliasName.isEmpty() ? m_fileAccess.prettyAbsPath() : m_aliasName; + return m_aliasName.isEmpty() ? m_fileAccess.prettyAbsPath() : m_aliasName; } -void SourceData::setAliasName( const QString& name ) +void SourceData::setAliasName(const QString& name) { - m_aliasName = name; + m_aliasName = name; } -void SourceData::setFileAccess( const FileAccess& fileAccess ) +void SourceData::setFileAccess(const FileAccess& fileAccess) { - m_fileAccess = fileAccess; - m_aliasName = QString(); - if ( !m_tempInputFileName.isEmpty() ) - { - FileAccess::removeFile( m_tempInputFileName ); - m_tempInputFileName = ""; - } + m_fileAccess = fileAccess; + m_aliasName = QString(); + if(!m_tempInputFileName.isEmpty()) + { + FileAccess::removeFile(m_tempInputFileName); + m_tempInputFileName = ""; + } } void SourceData::setEncoding(QTextCodec* pEncoding) { m_pEncoding = pEncoding; } -QStringList SourceData::setData( const QString& data ) +QStringList SourceData::setData(const QString& data) { - QStringList errors; - - // Create a temp file for preprocessing: - if ( m_tempInputFileName.isEmpty() ) - { - m_tempInputFileName = FileAccess::tempFileName(); - } - - FileAccess f( m_tempInputFileName ); - QByteArray ba = QTextCodec::codecForName("UTF-8")->fromUnicode(data); - bool bSuccess = f.writeFile( ba.constData(), ba.length() ); - if ( !bSuccess ) - { - errors.append( i18n("Writing clipboard data to temp file failed.") ); - } - else - { - m_aliasName = i18n("From Clipboard"); - m_fileAccess = FileAccess(""); // Effect: m_fileAccess.isValid() is false - } - - return errors; + QStringList errors; + + // Create a temp file for preprocessing: + if(m_tempInputFileName.isEmpty()) + { + m_tempInputFileName = FileAccess::tempFileName(); + } + + FileAccess f(m_tempInputFileName); + QByteArray ba = QTextCodec::codecForName("UTF-8")->fromUnicode(data); + bool bSuccess = f.writeFile(ba.constData(), ba.length()); + if(!bSuccess) + { + errors.append(i18n("Writing clipboard data to temp file failed.")); + } + else + { + m_aliasName = i18n("From Clipboard"); + m_fileAccess = FileAccess(""); // Effect: m_fileAccess.isValid() is false + } + + return errors; } const LineData* SourceData::getLineDataForDiff() const { - if ( m_lmppData.m_pBuf==0 ) - return m_normalData.m_v.size()>0 ? &m_normalData.m_v[0] : 0; - else - return m_lmppData.m_v.size()>0 ? &m_lmppData.m_v[0] : 0; + if(m_lmppData.m_pBuf == 0) + return m_normalData.m_v.size() > 0 ? &m_normalData.m_v[0] : 0; + else + return m_lmppData.m_v.size() > 0 ? &m_lmppData.m_v[0] : 0; } const LineData* SourceData::getLineDataForDisplay() const { - return m_normalData.m_v.size()>0 ? &m_normalData.m_v[0] : 0; + return m_normalData.m_v.size() > 0 ? &m_normalData.m_v[0] : 0; } -int SourceData::getSizeLines() const +int SourceData::getSizeLines() const { - return m_normalData.m_vSize; + return m_normalData.m_vSize; } int SourceData::getSizeBytes() const { - return m_normalData.m_size; + return m_normalData.m_size; } const char* SourceData::getBuf() const { - return m_normalData.m_pBuf; + return m_normalData.m_pBuf; } const QString& SourceData::getText() const { - return m_normalData.m_unicodeBuf; + return m_normalData.m_unicodeBuf; } bool SourceData::isText() { - return m_normalData.m_bIsText; + return m_normalData.m_bIsText; } bool SourceData::isIncompleteConversion() { - return m_normalData.m_bIncompleteConversion; + return m_normalData.m_bIncompleteConversion; } bool SourceData::isFromBuffer() { - return !m_fileAccess.isValid(); + return !m_fileAccess.isValid(); } - -bool SourceData::isBinaryEqualWith( const SourceData& other ) const +bool SourceData::isBinaryEqualWith(const SourceData& other) const { - return m_fileAccess.exists() && other.m_fileAccess.exists() && - getSizeBytes() == other.getSizeBytes() && - ( getSizeBytes()==0 || memcmp( getBuf(), other.getBuf(), getSizeBytes() )==0 ); + return m_fileAccess.exists() && other.m_fileAccess.exists() && + getSizeBytes() == other.getSizeBytes() && + (getSizeBytes() == 0 || memcmp(getBuf(), other.getBuf(), getSizeBytes()) == 0); } void SourceData::FileData::reset() { - delete[] (char*)m_pBuf; - m_pBuf = 0; - m_v.clear(); - m_size = 0; - m_vSize = 0; - m_bIsText = true; - m_bIncompleteConversion = false; - m_eLineEndStyle = eLineEndStyleUndefined; + delete[](char*) m_pBuf; + m_pBuf = 0; + m_v.clear(); + m_size = 0; + m_vSize = 0; + m_bIsText = true; + m_bIncompleteConversion = false; + m_eLineEndStyle = eLineEndStyleUndefined; } -bool SourceData::FileData::readFile( const QString& filename ) +bool SourceData::FileData::readFile(const QString& filename) { - reset(); - if ( filename.isEmpty() ) { return true; } - - FileAccess fa( filename ); - m_size = fa.sizeForReading(); - char* pBuf; - m_pBuf = pBuf = new char[m_size+100]; // Alloc 100 byte extra: Savety hack, not nice but does no harm. - // Some extra bytes at the end of the buffer are needed by - // the diff algorithm. See also GnuDiff::diff_2_files(). - bool bSuccess = fa.readFile( pBuf, m_size ); - if ( !bSuccess ) - { - delete pBuf; - m_pBuf = 0; - m_size = 0; - } - return bSuccess; + reset(); + if(filename.isEmpty()) { + return true; + } + + FileAccess fa(filename); + m_size = fa.sizeForReading(); + char* pBuf; + m_pBuf = pBuf = new char[m_size + 100]; // Alloc 100 byte extra: Savety hack, not nice but does no harm. + // Some extra bytes at the end of the buffer are needed by + // the diff algorithm. See also GnuDiff::diff_2_files(). + bool bSuccess = fa.readFile(pBuf, m_size); + if(!bSuccess) + { + delete pBuf; + m_pBuf = 0; + m_size = 0; + } + return bSuccess; } -bool SourceData::saveNormalDataAs( const QString& fileName ) +bool SourceData::saveNormalDataAs(const QString& fileName) { - return m_normalData.writeFile( fileName ); + return m_normalData.writeFile(fileName); } -bool SourceData::FileData::writeFile( const QString& filename ) +bool SourceData::FileData::writeFile(const QString& filename) { - if ( filename.isEmpty() ) { return true; } + if(filename.isEmpty()) { + return true; + } - FileAccess fa( filename ); - bool bSuccess = fa.writeFile(m_pBuf, m_size); - return bSuccess; + FileAccess fa(filename); + bool bSuccess = fa.writeFile(m_pBuf, m_size); + return bSuccess; } -void SourceData::FileData::copyBufFrom( const FileData& src ) +void SourceData::FileData::copyBufFrom(const FileData& src) { - reset(); - char* pBuf; - m_size = src.m_size; - m_pBuf = pBuf = new char[m_size+100]; - memcpy( pBuf, src.m_pBuf, m_size ); + reset(); + char* pBuf; + m_size = src.m_size; + m_pBuf = pBuf = new char[m_size + 100]; + memcpy(pBuf, src.m_pBuf, m_size); } // Convert the input file from input encoding to output encoding and write it to the output file. -static bool convertFileEncoding( const QString& fileNameIn, QTextCodec* pCodecIn, - const QString& fileNameOut, QTextCodec* pCodecOut ) +static bool convertFileEncoding(const QString& fileNameIn, QTextCodec* pCodecIn, + const QString& fileNameOut, QTextCodec* pCodecOut) { - QFile in( fileNameIn ); - if ( ! in.open(QIODevice::ReadOnly ) ) - return false; - QTextStream inStream( &in ); - inStream.setCodec( pCodecIn ); - inStream.setAutoDetectUnicode( false ); - - QFile out( fileNameOut ); - if ( ! out.open( QIODevice::WriteOnly ) ) - return false; - QTextStream outStream( &out ); - outStream.setCodec( pCodecOut ); - - QString data = inStream.readAll(); - outStream << data; - - return true; + QFile in(fileNameIn); + if(!in.open(QIODevice::ReadOnly)) + return false; + QTextStream inStream(&in); + inStream.setCodec(pCodecIn); + inStream.setAutoDetectUnicode(false); + + QFile out(fileNameOut); + if(!out.open(QIODevice::WriteOnly)) + return false; + QTextStream outStream(&out); + outStream.setCodec(pCodecOut); + + QString data = inStream.readAll(); + outStream << data; + + return true; } -static QTextCodec* getEncodingFromTag( const QByteArray& s, const QByteArray& encodingTag ) -{ - int encodingPos = s.indexOf( encodingTag ); - if ( encodingPos>=0 ) - { - int apostrophPos = s.indexOf( '"', encodingPos + encodingTag.length() ); - int apostroph2Pos = s.indexOf( '\'', encodingPos + encodingTag.length() ); - char apostroph = '"'; - if ( apostroph2Pos>=0 && ( apostrophPos<0 || apostroph2Pos < apostrophPos) ) - { - apostroph = '\''; - apostrophPos = apostroph2Pos; - } - - int encodingEnd = s.indexOf( apostroph, apostrophPos+1 ); - if ( encodingEnd>=0 ) // e.g.: or - { - QByteArray encoding = s.mid( apostrophPos+1, encodingEnd - (apostrophPos + 1) ); - return QTextCodec::codecForName( encoding ); - } - else // e.g.: - { - QByteArray encoding = s.mid( encodingPos+encodingTag.length(), apostrophPos - ( encodingPos+encodingTag.length() ) ); - return QTextCodec::codecForName( encoding ); - } - } - return 0; +static QTextCodec* getEncodingFromTag(const QByteArray& s, const QByteArray& encodingTag) +{ + int encodingPos = s.indexOf(encodingTag); + if(encodingPos >= 0) + { + int apostrophPos = s.indexOf('"', encodingPos + encodingTag.length()); + int apostroph2Pos = s.indexOf('\'', encodingPos + encodingTag.length()); + char apostroph = '"'; + if(apostroph2Pos >= 0 && (apostrophPos < 0 || apostroph2Pos < apostrophPos)) + { + apostroph = '\''; + apostrophPos = apostroph2Pos; + } + + int encodingEnd = s.indexOf(apostroph, apostrophPos + 1); + if(encodingEnd >= 0) // e.g.: or + { + QByteArray encoding = s.mid(apostrophPos + 1, encodingEnd - (apostrophPos + 1)); + return QTextCodec::codecForName(encoding); + } + else // e.g.: + { + QByteArray encoding = s.mid(encodingPos + encodingTag.length(), apostrophPos - (encodingPos + encodingTag.length())); + return QTextCodec::codecForName(encoding); + } + } + return 0; } -static QTextCodec* detectEncoding( const char* buf, qint64 size, qint64& skipBytes ) +static QTextCodec* detectEncoding(const char* buf, qint64 size, qint64& skipBytes) { - if (size>=2) - { - if (buf[0]=='\xFF' && buf[1]=='\xFE' ) - { - skipBytes = 2; - return QTextCodec::codecForName( "UTF-16LE" ); - } - - if (buf[0]=='\xFE' && buf[1]=='\xFF' ) - { - skipBytes = 2; - return QTextCodec::codecForName( "UTF-16BE" ); - } - } - if (size>=3) - { - if (buf[0]=='\xEF' && buf[1]=='\xBB' && buf[2]=='\xBF' ) - { - skipBytes = 3; - return QTextCodec::codecForName( "UTF-8-BOM" ); - } - } - skipBytes = 0; - QByteArray s( buf, size ); - int xmlHeaderPos = s.indexOf( "= 0 ) - { - int xmlHeaderEnd = s.indexOf( "?>", xmlHeaderPos ); - if ( xmlHeaderEnd>=0 ) - { - QTextCodec* pCodec = getEncodingFromTag( s.mid( xmlHeaderPos, xmlHeaderEnd - xmlHeaderPos ), "encoding=" ); - if (pCodec) - return pCodec; - } - } - else // HTML - { - int metaHeaderPos = s.indexOf( "= 0) - { - int metaHeaderEnd = s.indexOf( ">", metaHeaderPos ); - if (metaHeaderEnd>=0) - { - QTextCodec* pCodec = getEncodingFromTag( s.mid( metaHeaderPos, metaHeaderEnd - metaHeaderPos ), "charset=" ); - if (pCodec) - return pCodec; + if(size >= 2) + { + if(buf[0] == '\xFF' && buf[1] == '\xFE') + { + skipBytes = 2; + return QTextCodec::codecForName("UTF-16LE"); + } + + if(buf[0] == '\xFE' && buf[1] == '\xFF') + { + skipBytes = 2; + return QTextCodec::codecForName("UTF-16BE"); + } + } + if(size >= 3) + { + if(buf[0] == '\xEF' && buf[1] == '\xBB' && buf[2] == '\xBF') + { + skipBytes = 3; + return QTextCodec::codecForName("UTF-8-BOM"); + } + } + skipBytes = 0; + QByteArray s(buf, size); + int xmlHeaderPos = s.indexOf("= 0) + { + int xmlHeaderEnd = s.indexOf("?>", xmlHeaderPos); + if(xmlHeaderEnd >= 0) + { + QTextCodec* pCodec = getEncodingFromTag(s.mid(xmlHeaderPos, xmlHeaderEnd - xmlHeaderPos), "encoding="); + if(pCodec) + return pCodec; + } + } + else // HTML + { + int metaHeaderPos = s.indexOf("= 0) + { + int metaHeaderEnd = s.indexOf(">", metaHeaderPos); + if(metaHeaderEnd >= 0) + { + QTextCodec* pCodec = getEncodingFromTag(s.mid(metaHeaderPos, metaHeaderEnd - metaHeaderPos), "charset="); + if(pCodec) + return pCodec; - metaHeaderPos = s.indexOf( ""1" "2"< => >1<, >2< * Eg. >'\'\\'< => >'\< backslash is a meta character between single quotes * Eg. > "\\" < => >\\< but not between double quotes * Eg. >"c:\sed" 's/a/\' /g'< => >c:\sed<, >s/a/' /g< */ -static QString getArguments( QString cmd, QString& program, QStringList& args ) +static QString getArguments(QString cmd, QString& program, QStringList& args) { - program = QString(); - args.clear(); - for ( int i=0; i 0 ) - { + m_fileAccess.copyFile(m_tempInputFileName); + fileNameIn1 = m_tempInputFileName; + } + if(bAutoDetectUnicode) + { + m_pEncoding = detectEncoding(fileNameIn1, pEncoding); + } + } + else // The input was set via setData(), probably from clipboard. + { + fileNameIn1 = m_tempInputFileName; + m_pEncoding = QTextCodec::codecForName("UTF-8"); + } + QTextCodec* pEncoding1 = m_pEncoding; + QTextCodec* pEncoding2 = m_pEncoding; + + m_normalData.reset(); + m_lmppData.reset(); + + FileAccess faIn(fileNameIn1); + int fileInSize = faIn.size(); + + if(faIn.exists()) // fileInSize > 0 ) + { #if defined(_WIN32) || defined(Q_OS_OS2) - QString catCmd = "type"; - fileNameIn1.replace( '/', "\\" ); + QString catCmd = "type"; + fileNameIn1.replace('/', "\\"); #else - QString catCmd = "cat"; + QString catCmd = "cat"; #endif - // Run the first preprocessor - if ( m_pOptions->m_PreProcessorCmd.isEmpty() ) - { - // No preprocessing: Read the file directly: - m_normalData.readFile( fileNameIn1 ); - } - else - { - QString fileNameInPP = fileNameIn1; - - if ( pEncoding1 != m_pOptions->m_pEncodingPP ) - { - // Before running the preprocessor convert to the format that the preprocessor expects. - fileNameInPP = FileAccess::tempFileName(); - pEncoding1 = m_pOptions->m_pEncodingPP; - convertFileEncoding( fileNameIn1, pEncoding, fileNameInPP, pEncoding1 ); - } - - QString ppCmd = m_pOptions->m_PreProcessorCmd; - fileNameOut1 = FileAccess::tempFileName(); - - QProcess ppProcess; - ppProcess.setStandardInputFile( fileNameInPP ); - ppProcess.setStandardOutputFile( fileNameOut1 ); - QString program; - QStringList args; - QString errorReason = getArguments(ppCmd, program, args); - if ( errorReason.isEmpty() ) - { - ppProcess.start( program, args ); - ppProcess.waitForFinished(-1); - } - else - errorReason = "\n("+errorReason+")"; - //QString cmd = catCmd + " \"" + fileNameInPP + "\" | " + ppCmd + " >\"" + fileNameOut1+"\""; - //::system( encodeString(cmd) ); - bool bSuccess = errorReason.isEmpty() && m_normalData.readFile( fileNameOut1 ); - if ( fileInSize >0 && ( !bSuccess || m_normalData.m_size==0 ) ) - { - - errors.append( - i18n("Preprocessing possibly failed. Check this command:\n\n %1" - "\n\nThe preprocessing command will be disabled now." - ).arg(ppCmd) + errorReason ); - m_pOptions->m_PreProcessorCmd = ""; - m_normalData.readFile( fileNameIn1 ); - pEncoding1 = m_pEncoding; - } - if (fileNameInPP != fileNameIn1) - { - FileAccess::removeTempFile( fileNameInPP ); - } - } - - // LineMatching Preprocessor - if ( ! m_pOptions->m_LineMatchingPreProcessorCmd.isEmpty() ) - { - fileNameIn2 = fileNameOut1.isEmpty() ? fileNameIn1 : fileNameOut1; - QString fileNameInPP = fileNameIn2; - pEncoding2 = pEncoding1; - if ( pEncoding2 != m_pOptions->m_pEncodingPP ) - { - // Before running the preprocessor convert to the format that the preprocessor expects. - fileNameInPP = FileAccess::tempFileName(); - pEncoding2 = m_pOptions->m_pEncodingPP; - convertFileEncoding( fileNameIn2, pEncoding1, fileNameInPP, pEncoding2 ); - } - - QString ppCmd = m_pOptions->m_LineMatchingPreProcessorCmd; - fileNameOut2 = FileAccess::tempFileName(); - QProcess ppProcess; - ppProcess.setStandardInputFile( fileNameInPP ); - ppProcess.setStandardOutputFile( fileNameOut2 ); - QString program; - QStringList args; - QString errorReason = getArguments(ppCmd, program, args); - if ( errorReason.isEmpty() ) - { - ppProcess.start( program, args ); - ppProcess.waitForFinished(-1); - } - else - errorReason = "\n("+errorReason+")"; - //QString cmd = catCmd + " \"" + fileNameInPP + "\" | " + ppCmd + " >\"" + fileNameOut2 + "\""; - //::system( encodeString(cmd) ); - bool bSuccess = errorReason.isEmpty() && m_lmppData.readFile( fileNameOut2 ); - if ( FileAccess(fileNameIn2).size()>0 && ( !bSuccess || m_lmppData.m_size==0 ) ) - { - errors.append( - i18n("The line-matching-preprocessing possibly failed. Check this command:\n\n %1" - "\n\nThe line-matching-preprocessing command will be disabled now." - ).arg(ppCmd) + errorReason ); - m_pOptions->m_LineMatchingPreProcessorCmd = ""; - m_lmppData.readFile( fileNameIn2 ); - } - FileAccess::removeTempFile( fileNameOut2 ); - if (fileNameInPP != fileNameIn2) - { - FileAccess::removeTempFile( fileNameInPP ); - } - } - else if ( m_pOptions->m_bIgnoreComments || m_pOptions->m_bIgnoreCase ) - { - // We need a copy of the normal data. - m_lmppData.copyBufFrom( m_normalData ); - } - else - { // We don't need any lmpp data at all. - m_lmppData.reset(); - } - } - - m_normalData.preprocess( m_pOptions->m_bPreserveCarriageReturn, pEncoding1 ); - m_lmppData.preprocess( false, pEncoding2 ); - - if ( m_lmppData.m_vSize < m_normalData.m_vSize ) - { - // This probably is the fault of the LMPP-Command, but not worth reporting. - m_lmppData.m_v.resize( m_normalData.m_vSize ); - for(int i=m_lmppData.m_vSize; im_bIgnoreCase ) - { - int i; - QChar* pBuf = const_cast(m_lmppData.m_unicodeBuf.unicode()); - int ucSize = m_lmppData.m_unicodeBuf.length(); - for(i=0; im_PreProcessorCmd.isEmpty()) + { + // No preprocessing: Read the file directly: + m_normalData.readFile(fileNameIn1); + } + else + { + QString fileNameInPP = fileNameIn1; + + if(pEncoding1 != m_pOptions->m_pEncodingPP) + { + // Before running the preprocessor convert to the format that the preprocessor expects. + fileNameInPP = FileAccess::tempFileName(); + pEncoding1 = m_pOptions->m_pEncodingPP; + convertFileEncoding(fileNameIn1, pEncoding, fileNameInPP, pEncoding1); + } - // Ignore comments - if ( m_pOptions->m_bIgnoreComments ) - { - m_lmppData.removeComments(); - int vSize = min2(m_normalData.m_vSize, m_lmppData.m_vSize); - for(int i=0; im_PreProcessorCmd; + fileNameOut1 = FileAccess::tempFileName(); - // Remove unneeded temporary files. (A temp file from clipboard must not be deleted.) - if ( !bTempFileFromClipboard && !m_tempInputFileName.isEmpty() ) - { - FileAccess::removeTempFile( m_tempInputFileName ); - m_tempInputFileName = ""; - } + QProcess ppProcess; + ppProcess.setStandardInputFile(fileNameInPP); + ppProcess.setStandardOutputFile(fileNameOut1); + QString program; + QStringList args; + QString errorReason = getArguments(ppCmd, program, args); + if(errorReason.isEmpty()) + { + ppProcess.start(program, args); + ppProcess.waitForFinished(-1); + } + else + errorReason = "\n(" + errorReason + ")"; + //QString cmd = catCmd + " \"" + fileNameInPP + "\" | " + ppCmd + " >\"" + fileNameOut1+"\""; + //::system( encodeString(cmd) ); + bool bSuccess = errorReason.isEmpty() && m_normalData.readFile(fileNameOut1); + if(fileInSize > 0 && (!bSuccess || m_normalData.m_size == 0)) + { - if ( !fileNameOut1.isEmpty() ) - { - FileAccess::removeTempFile( fileNameOut1 ); - fileNameOut1=""; - } + errors.append( + i18n("Preprocessing possibly failed. Check this command:\n\n %1" + "\n\nThe preprocessing command will be disabled now.") + .arg(ppCmd) + + errorReason); + m_pOptions->m_PreProcessorCmd = ""; + m_normalData.readFile(fileNameIn1); + pEncoding1 = m_pEncoding; + } + if(fileNameInPP != fileNameIn1) + { + FileAccess::removeTempFile(fileNameInPP); + } + } + + // LineMatching Preprocessor + if(!m_pOptions->m_LineMatchingPreProcessorCmd.isEmpty()) + { + fileNameIn2 = fileNameOut1.isEmpty() ? fileNameIn1 : fileNameOut1; + QString fileNameInPP = fileNameIn2; + pEncoding2 = pEncoding1; + if(pEncoding2 != m_pOptions->m_pEncodingPP) + { + // Before running the preprocessor convert to the format that the preprocessor expects. + fileNameInPP = FileAccess::tempFileName(); + pEncoding2 = m_pOptions->m_pEncodingPP; + convertFileEncoding(fileNameIn2, pEncoding1, fileNameInPP, pEncoding2); + } - return errors; + QString ppCmd = m_pOptions->m_LineMatchingPreProcessorCmd; + fileNameOut2 = FileAccess::tempFileName(); + QProcess ppProcess; + ppProcess.setStandardInputFile(fileNameInPP); + ppProcess.setStandardOutputFile(fileNameOut2); + QString program; + QStringList args; + QString errorReason = getArguments(ppCmd, program, args); + if(errorReason.isEmpty()) + { + ppProcess.start(program, args); + ppProcess.waitForFinished(-1); + } + else + errorReason = "\n(" + errorReason + ")"; + //QString cmd = catCmd + " \"" + fileNameInPP + "\" | " + ppCmd + " >\"" + fileNameOut2 + "\""; + //::system( encodeString(cmd) ); + bool bSuccess = errorReason.isEmpty() && m_lmppData.readFile(fileNameOut2); + if(FileAccess(fileNameIn2).size() > 0 && (!bSuccess || m_lmppData.m_size == 0)) + { + errors.append( + i18n("The line-matching-preprocessing possibly failed. Check this command:\n\n %1" + "\n\nThe line-matching-preprocessing command will be disabled now.") + .arg(ppCmd) + + errorReason); + m_pOptions->m_LineMatchingPreProcessorCmd = ""; + m_lmppData.readFile(fileNameIn2); + } + FileAccess::removeTempFile(fileNameOut2); + if(fileNameInPP != fileNameIn2) + { + FileAccess::removeTempFile(fileNameInPP); + } + } + else if(m_pOptions->m_bIgnoreComments || m_pOptions->m_bIgnoreCase) + { + // We need a copy of the normal data. + m_lmppData.copyBufFrom(m_normalData); + } + else + { // We don't need any lmpp data at all. + m_lmppData.reset(); + } + } + + m_normalData.preprocess(m_pOptions->m_bPreserveCarriageReturn, pEncoding1); + m_lmppData.preprocess(false, pEncoding2); + + if(m_lmppData.m_vSize < m_normalData.m_vSize) + { + // This probably is the fault of the LMPP-Command, but not worth reporting. + m_lmppData.m_v.resize(m_normalData.m_vSize); + for(int i = m_lmppData.m_vSize; i < m_normalData.m_vSize; ++i) + { // Set all empty lines to point to the end of the buffer. + m_lmppData.m_v[i].pLine = m_lmppData.m_unicodeBuf.unicode() + m_lmppData.m_unicodeBuf.length(); + } + + m_lmppData.m_vSize = m_normalData.m_vSize; + } + + // Internal Preprocessing: Uppercase-conversion + if(m_pOptions->m_bIgnoreCase) + { + int i; + QChar* pBuf = const_cast(m_lmppData.m_unicodeBuf.unicode()); + int ucSize = m_lmppData.m_unicodeBuf.length(); + for(i = 0; i < ucSize; ++i) + { + pBuf[i] = pBuf[i].toUpper(); + } + } + + // Ignore comments + if(m_pOptions->m_bIgnoreComments) + { + m_lmppData.removeComments(); + int vSize = min2(m_normalData.m_vSize, m_lmppData.m_vSize); + for(int i = 0; i < vSize; ++i) + { + m_normalData.m_v[i].bContainsPureComment = m_lmppData.m_v[i].bContainsPureComment; + } + } + + // Remove unneeded temporary files. (A temp file from clipboard must not be deleted.) + if(!bTempFileFromClipboard && !m_tempInputFileName.isEmpty()) + { + FileAccess::removeTempFile(m_tempInputFileName); + m_tempInputFileName = ""; + } + + if(!fileNameOut1.isEmpty()) + { + FileAccess::removeTempFile(fileNameOut1); + fileNameOut1 = ""; + } + + return errors; } - /** Prepare the linedata vector for every input line.*/ -void SourceData::FileData::preprocess( bool bPreserveCR, QTextCodec* pEncoding ) +void SourceData::FileData::preprocess(bool bPreserveCR, QTextCodec* pEncoding) { - //m_unicodeBuf = decodeString( m_pBuf, m_size, eEncoding ); - - qint64 i; - // detect line end style - QVector vOrigDataLineEndStyle; - m_eLineEndStyle = eLineEndStyleUndefined; - for( i=0; i0 && i+2(m_pBuf)[i]='\n'; // fix it in original data - } - } - else if ( m_pBuf[i]=='\n' ) - { - vOrigDataLineEndStyle.push_back( eLineEndStyleUnix ); - } - } - - if ( ! vOrigDataLineEndStyle.isEmpty() ) - m_eLineEndStyle = vOrigDataLineEndStyle[0]; - - qint64 skipBytes = 0; - QTextCodec* pCodec = ::detectEncoding( m_pBuf, m_size, skipBytes ); - if ( pCodec != pEncoding ) - skipBytes=0; - - QByteArray ba = QByteArray::fromRawData( m_pBuf+skipBytes, m_size-skipBytes ); - QTextStream ts( ba, QIODevice::ReadOnly | QIODevice::Text ); - ts.setCodec( pEncoding); - ts.setAutoDetectUnicode( false ); - m_unicodeBuf = ts.readAll(); - ba.clear(); - - int ucSize = m_unicodeBuf.length(); - const QChar* p = m_unicodeBuf.unicode(); - - m_bIsText = true; - int lines = 1; - m_bIncompleteConversion = false; - for( i=0; i=ucSize || p[i]=='\n' ) - { - ++lines; - } - if ( p[i].isNull() ) - { - m_bIsText = false; - } - if ( p[i]==QChar::ReplacementCharacter ) - { - m_bIncompleteConversion = true; - } - } - - m_v.resize( lines+5 ); - int lineIdx=0; - int lineLength=0; - bool bNonWhiteFound = false; - int whiteLength = 0; - for( i=0; i<=ucSize; ++i ) - { - if ( i>=ucSize || p[i]=='\n' ) - { - m_v[lineIdx].pLine = &p[ i-lineLength ]; - while ( /*!bPreserveCR &&*/ lineLength>0 && m_v[lineIdx].pLine[lineLength-1]=='\r' ) - { - --lineLength; - } - m_v[lineIdx].pFirstNonWhiteChar = m_v[lineIdx].pLine + min2(whiteLength,lineLength); - m_v[lineIdx].size = lineLength; - if ( lineIdx < vOrigDataLineEndStyle.count() && bPreserveCR && i(m_v[lineIdx].pLine)[lineLength] = '\r'; - //switch ( vOrigDataLineEndStyle[lineIdx] ) - //{ - //case eLineEndStyleUnix: const_cast(m_v[lineIdx].pLine)[lineLength] = '\n'; break; - //case eLineEndStyleDos: const_cast(m_v[lineIdx].pLine)[lineLength] = '\r'; break; - //case eLineEndStyleUndefined: const_cast(m_v[lineIdx].pLine)[lineLength] = '\x0b'; break; - //} - } - lineLength = 0; - bNonWhiteFound = false; - whiteLength = 0; - ++lineIdx; - } - else - { - ++lineLength; - - if ( ! bNonWhiteFound && isWhite( p[i] ) ) - ++whiteLength; - else - bNonWhiteFound = true; - } - } - assert( lineIdx == lines ); - - m_vSize = lines; + //m_unicodeBuf = decodeString( m_pBuf, m_size, eEncoding ); + + qint64 i; + // detect line end style + QVector vOrigDataLineEndStyle; + m_eLineEndStyle = eLineEndStyleUndefined; + for(i = 0; i < m_size; ++i) + { + if(m_pBuf[i] == '\r') + { + if(i + 1 < m_size && m_pBuf[i + 1] == '\n') // not 16-bit unicode + { + vOrigDataLineEndStyle.push_back(eLineEndStyleDos); + ++i; + } + else if(i > 0 && i + 2 < m_size && m_pBuf[i - 1] == '\0' && m_pBuf[i + 1] == '\0' && m_pBuf[i + 2] == '\n') // 16-bit unicode + { + vOrigDataLineEndStyle.push_back(eLineEndStyleDos); + i += 2; + } + else // old mac line end style ? + { + vOrigDataLineEndStyle.push_back(eLineEndStyleUndefined); + const_cast(m_pBuf)[i] = '\n'; // fix it in original data + } + } + else if(m_pBuf[i] == '\n') + { + vOrigDataLineEndStyle.push_back(eLineEndStyleUnix); + } + } + + if(!vOrigDataLineEndStyle.isEmpty()) + m_eLineEndStyle = vOrigDataLineEndStyle[0]; + + qint64 skipBytes = 0; + QTextCodec* pCodec = ::detectEncoding(m_pBuf, m_size, skipBytes); + if(pCodec != pEncoding) + skipBytes = 0; + + QByteArray ba = QByteArray::fromRawData(m_pBuf + skipBytes, m_size - skipBytes); + QTextStream ts(ba, QIODevice::ReadOnly | QIODevice::Text); + ts.setCodec(pEncoding); + ts.setAutoDetectUnicode(false); + m_unicodeBuf = ts.readAll(); + ba.clear(); + + int ucSize = m_unicodeBuf.length(); + const QChar* p = m_unicodeBuf.unicode(); + + m_bIsText = true; + int lines = 1; + m_bIncompleteConversion = false; + for(i = 0; i < ucSize; ++i) + { + if(i >= ucSize || p[i] == '\n') + { + ++lines; + } + if(p[i].isNull()) + { + m_bIsText = false; + } + if(p[i] == QChar::ReplacementCharacter) + { + m_bIncompleteConversion = true; + } + } + + m_v.resize(lines + 5); + int lineIdx = 0; + int lineLength = 0; + bool bNonWhiteFound = false; + int whiteLength = 0; + for(i = 0; i <= ucSize; ++i) + { + if(i >= ucSize || p[i] == '\n') + { + m_v[lineIdx].pLine = &p[i - lineLength]; + while(/*!bPreserveCR &&*/ lineLength > 0 && m_v[lineIdx].pLine[lineLength - 1] == '\r') + { + --lineLength; + } + m_v[lineIdx].pFirstNonWhiteChar = m_v[lineIdx].pLine + min2(whiteLength, lineLength); + m_v[lineIdx].size = lineLength; + if(lineIdx < vOrigDataLineEndStyle.count() && bPreserveCR && i < ucSize) + { + ++m_v[lineIdx].size; + const_cast(m_v[lineIdx].pLine)[lineLength] = '\r'; + //switch ( vOrigDataLineEndStyle[lineIdx] ) + //{ + //case eLineEndStyleUnix: const_cast(m_v[lineIdx].pLine)[lineLength] = '\n'; break; + //case eLineEndStyleDos: const_cast(m_v[lineIdx].pLine)[lineLength] = '\r'; break; + //case eLineEndStyleUndefined: const_cast(m_v[lineIdx].pLine)[lineLength] = '\x0b'; break; + //} + } + lineLength = 0; + bNonWhiteFound = false; + whiteLength = 0; + ++lineIdx; + } + else + { + ++lineLength; + + if(!bNonWhiteFound && isWhite(p[i])) + ++whiteLength; + else + bNonWhiteFound = true; + } + } + assert(lineIdx == lines); + + m_vSize = lines; } - // Must not be entered, when within a comment. // Returns either at a newline-character p[i]=='\n' or when i==size. // A line that contains only comments is still "white". // Comments in white lines must remain, while comments in // non-white lines are overwritten with spaces. static void checkLineForComments( - QChar* p, // pointer to start of buffer - int& i, // index of current position (in, out) - int size, // size of buffer - bool& bWhite, // false if this line contains nonwhite characters (in, out) - bool& bCommentInLine, // true if any comment is within this line (in, out) - bool& bStartsOpenComment // true if the line ends within an comment (out) - ) + QChar* p, // pointer to start of buffer + int& i, // index of current position (in, out) + int size, // size of buffer + bool& bWhite, // false if this line contains nonwhite characters (in, out) + bool& bCommentInLine, // true if any comment is within this line (in, out) + bool& bStartsOpenComment // true if the line ends within an comment (out) + ) { - bStartsOpenComment = false; - for(; i(m_unicodeBuf.unicode()); - bool bWithinComment=false; - int size = m_unicodeBuf.length(); - for(int i=0; i(m_unicodeBuf.unicode()); + bool bWithinComment = false; + int size = m_unicodeBuf.length(); + for(int i = 0; i < size; ++i) + { + // std::cout << "2 " << std::string(&p[i], m_v[line].size) << std::endl; + bool bWhite = true; + bool bCommentInLine = false; + + if(bWithinComment) + { + int commentStart = i; + bCommentInLine = true; + + for(; !isLineOrBufEnd(p, i, size); ++i) { - i+=2; + if(i + 1 < size && p[i] == '*' && p[i + 1] == '/') // end of the comment + { + i += 2; - // More comments in the line? - checkLineForComments( p, i, size, bWhite, bCommentInLine, bWithinComment ); - if ( !bWhite ) - { - memset( &p[commentStart], ' ', i-commentStart ); - } - break; + // More comments in the line? + checkLineForComments(p, i, size, bWhite, bCommentInLine, bWithinComment); + if(!bWhite) + { + memset(&p[commentStart], ' ', i - commentStart); + } + break; + } } - } - } - else - { - checkLineForComments( p, i, size, bWhite, bCommentInLine, bWithinComment ); - } - - // end of line - assert( isLineOrBufEnd(p,i,size)); - m_v[line].bContainsPureComment = bCommentInLine && bWhite; -/* std::cout << line << " : " << + } + else + { + checkLineForComments(p, i, size, bWhite, bCommentInLine, bWithinComment); + } + + // end of line + assert(isLineOrBufEnd(p, i, size)); + m_v[line].bContainsPureComment = bCommentInLine && bWhite; + /* std::cout << line << " : " << ( bCommentInLine ? "c" : " " ) << ( bWhite ? "w " : " ") << std::string(pLD[line].pLine, pLD[line].size) << std::endl;*/ - ++line; - } + ++line; + } } - - // First step void calcDiff3LineListUsingAB( - const DiffList* pDiffListAB, - Diff3LineList& d3ll - ) + const DiffList* pDiffListAB, + Diff3LineList& d3ll) { - // First make d3ll for AB (from pDiffListAB) - - DiffList::const_iterator i=pDiffListAB->begin(); - int lineA=0; - int lineB=0; - Diff d(0,0,0); - - for(;;) - { - if ( d.nofEquals==0 && d.diff1==0 && d.diff2==0 ) - { - if ( i!=pDiffListAB->end() ) - { - d=*i; - ++i; - } - else - break; - } - - Diff3Line d3l; - if( d.nofEquals>0 ) - { - d3l.bAEqB = true; - d3l.lineA = lineA; - d3l.lineB = lineB; - --d.nofEquals; - ++lineA; - ++lineB; - } - else if ( d.diff1>0 && d.diff2>0 ) - { - d3l.lineA = lineA; - d3l.lineB = lineB; - --d.diff1; - --d.diff2; - ++lineA; - ++lineB; - } - else if ( d.diff1>0 ) - { - d3l.lineA = lineA; - --d.diff1; - ++lineA; - } - else if ( d.diff2>0 ) - { - d3l.lineB = lineB; - --d.diff2; - ++lineB; - } - else if ( d.nofEquals < 0 ) - { - assert(false); - } - - d3ll.push_back( d3l ); - } + // First make d3ll for AB (from pDiffListAB) + + DiffList::const_iterator i = pDiffListAB->begin(); + int lineA = 0; + int lineB = 0; + Diff d(0, 0, 0); + + for(;;) + { + if(d.nofEquals == 0 && d.diff1 == 0 && d.diff2 == 0) + { + if(i != pDiffListAB->end()) + { + d = *i; + ++i; + } + else + break; + } + + Diff3Line d3l; + if(d.nofEquals > 0) + { + d3l.bAEqB = true; + d3l.lineA = lineA; + d3l.lineB = lineB; + --d.nofEquals; + ++lineA; + ++lineB; + } + else if(d.diff1 > 0 && d.diff2 > 0) + { + d3l.lineA = lineA; + d3l.lineB = lineB; + --d.diff1; + --d.diff2; + ++lineA; + ++lineB; + } + else if(d.diff1 > 0) + { + d3l.lineA = lineA; + --d.diff1; + ++lineA; + } + else if(d.diff2 > 0) + { + d3l.lineB = lineB; + --d.diff2; + ++lineB; + } + else if(d.nofEquals < 0) + { + assert(false); + } + + d3ll.push_back(d3l); + } } - // Second step void calcDiff3LineListUsingAC( - const DiffList* pDiffListAC, - Diff3LineList& d3ll - ) + 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 ) + //////////////// + // 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; - - (*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; - } - } -} + } + 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 - ) + 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; + //////////////// + // 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; + } - while( i3c!=d3ll.end() && (*i3c).lineC!=lineC ) - ++i3c; + Diff3Line d3l; + if(d.nofEquals > 0) + { + // Find the corresponding lineB and lineC + while(i3b != d3ll.end() && (*i3b).lineB != lineB) + ++i3b; - assert(i3b!=d3ll.end()); - assert(i3c!=d3ll.end()); + while(i3c != d3ll.end() && (*i3c).lineC != lineC) + ++i3c; - if ( i3b==i3c ) - { - assert( (*i3b).lineC == lineC ); - (*i3b).bBEqC = true; - } - else - { - // Is it possible to move this line up? - // Test if no other B's are used between i3c and i3b + assert(i3b != d3ll.end()); + assert(i3c != d3ll.end()); - // First test which is before: i3c or i3b ? - Diff3LineList::iterator i3c1 = i3c; - Diff3LineList::iterator i3b1 = i3b; - while( i3c1!=i3b && i3b1!=i3c ) + if(i3b == i3c) { - assert(i3b1!=d3ll.end() || i3c1!=d3ll.end()); - if( i3c1!=d3ll.end() ) ++i3c1; - if( i3b1!=d3ll.end() ) ++i3b1; + assert((*i3b).lineC == lineC); + (*i3b).bBEqC = true; } - - if( i3c1==i3b && !(*i3b).bAEqB ) // i3c before i3b + else { - Diff3LineList::iterator i3 = i3c; - int nofDisturbingLines = 0; - while( i3 != i3b && i3!=d3ll.end() ) - { - if ( (*i3).lineB != -1 ) - ++nofDisturbingLines; - ++i3; - } - - if ( nofDisturbingLines>0 )//&& nofDisturbingLines < d.nofEquals*d.nofEquals+4 ) - { - Diff3LineList::iterator i3_last_equal_A = d3ll.end(); - - i3 = i3c; - while( i3 != i3b ) - { - if(i3->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()) { - i3_last_equal_A = i3; + if((*i3).lineB != -1) + ++nofDisturbingLines; + ++i3; } - i3++; - } - /* If i3_last_equal_A isn't still set to d3ll.end(), then + if(nofDisturbingLines > 0) //&& nofDisturbingLines < d.nofEquals*d.nofEquals+4 ) + { + Diff3LineList::iterator i3_last_equal_A = d3ll.end(); + + i3 = i3c; + while(i3 != i3b) + { + if(i3->bAEqB) + { + i3_last_equal_A = i3; + } + i3++; + } + + /* If i3_last_equal_A isn't still set to d3ll.end(), then * we've found a line in A that is equal to one in B * somewhere between i3c and i3b */ - bool before_or_on_equal_line_in_A = (i3_last_equal_A != d3ll.end()); - - // Move the disturbing lines up, out of sight. - i3 = i3c; - while( i3 != i3b ) - { - if ( (*i3).lineB != -1 || - (before_or_on_equal_line_in_A && i3->lineA != -1) ) - { - Diff3Line d3l; - d3l.lineB = (*i3).lineB; - (*i3).lineB = -1; - - // Move A along if it matched B - if(before_or_on_equal_line_in_A) + bool before_or_on_equal_line_in_A = (i3_last_equal_A != d3ll.end()); + + // Move the disturbing lines up, out of sight. + i3 = i3c; + while(i3 != i3b) { - d3l.lineA = i3->lineA; - d3l.bAEqB = i3->bAEqB; - i3->lineA = -1; - i3->bAEqC = false; + if((*i3).lineB != -1 || + (before_or_on_equal_line_in_A && i3->lineA != -1)) + { + Diff3Line d3l; + d3l.lineB = (*i3).lineB; + (*i3).lineB = -1; + + // Move A along if it matched B + if(before_or_on_equal_line_in_A) + { + d3l.lineA = i3->lineA; + d3l.bAEqB = i3->bAEqB; + i3->lineA = -1; + i3->bAEqC = false; + } + + (*i3).bAEqB = false; + (*i3).bBEqC = false; + d3ll.insert(i3c, d3l); + } + + if(i3 == i3_last_equal_A) + { + before_or_on_equal_line_in_A = false; + } + + ++i3; } + nofDisturbingLines = 0; + } - (*i3).bAEqB = false; - (*i3).bBEqC = false; - d3ll.insert( i3c, d3l ); - } - - if (i3 == i3_last_equal_A) - { - before_or_on_equal_line_in_A = false; - } - - ++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).bBEqC = false; - (*i3c).lineB = lineB; - (*i3c).bBEqC = true; - (*i3c).bAEqB = (*i3c).bAEqC; - } - } - else if( i3b1==i3c && !(*i3c).bAEqC) - { - Diff3LineList::iterator i3 = i3b; - int nofDisturbingLines = 0; - while( i3 != i3c && i3!=d3ll.end() ) - { - if ( (*i3).lineC != -1 ) - ++nofDisturbingLines; - ++i3; - } - - if ( nofDisturbingLines>0 )//&& nofDisturbingLines < d.nofEquals*d.nofEquals+4 ) - { - Diff3LineList::iterator i3_last_equal_A = d3ll.end(); - - i3 = i3b; - while( i3 != i3c ) - { - if(i3->bAEqC) + if(nofDisturbingLines == 0) { - i3_last_equal_A = i3; + // Yes, the line from B can be moved. + (*i3b).lineB = -1; // This might leave an empty line: removed later. + (*i3b).bAEqB = false; + (*i3b).bBEqC = false; + (*i3c).lineB = lineB; + (*i3c).bBEqC = true; + (*i3c).bAEqB = (*i3c).bAEqC; + } + } + else if(i3b1 == i3c && !(*i3c).bAEqC) + { + Diff3LineList::iterator i3 = i3b; + int nofDisturbingLines = 0; + while(i3 != i3c && i3 != d3ll.end()) + { + if((*i3).lineC != -1) + ++nofDisturbingLines; + ++i3; } - i3++; - } - /* If i3_last_equal_A isn't still set to d3ll.end(), then + if(nofDisturbingLines > 0) //&& nofDisturbingLines < d.nofEquals*d.nofEquals+4 ) + { + Diff3LineList::iterator i3_last_equal_A = d3ll.end(); + + i3 = i3b; + while(i3 != i3c) + { + if(i3->bAEqC) + { + i3_last_equal_A = i3; + } + i3++; + } + + /* If i3_last_equal_A isn't still set to d3ll.end(), then * we've found a line in A that is equal to one in C * somewhere between i3b and i3c */ - bool before_or_on_equal_line_in_A = (i3_last_equal_A != d3ll.end()); - - // Move the disturbing lines up. - i3 = i3b; - while( i3 != i3c ) - { - if ( (*i3).lineC != -1 || - (before_or_on_equal_line_in_A && i3->lineA != -1) ) - { - Diff3Line d3l; - d3l.lineC = (*i3).lineC; - (*i3).lineC = -1; - - // Move A along if it matched C - if(before_or_on_equal_line_in_A) + bool before_or_on_equal_line_in_A = (i3_last_equal_A != d3ll.end()); + + // Move the disturbing lines up. + i3 = i3b; + while(i3 != i3c) { - d3l.lineA = i3->lineA; - d3l.bAEqC = i3->bAEqC; - i3->lineA = -1; - i3->bAEqB = false; + if((*i3).lineC != -1 || + (before_or_on_equal_line_in_A && i3->lineA != -1)) + { + Diff3Line d3l; + d3l.lineC = (*i3).lineC; + (*i3).lineC = -1; + + // Move A along if it matched C + if(before_or_on_equal_line_in_A) + { + d3l.lineA = i3->lineA; + d3l.bAEqC = i3->bAEqC; + i3->lineA = -1; + i3->bAEqB = false; + } + + (*i3).bAEqC = false; + (*i3).bBEqC = false; + d3ll.insert(i3b, d3l); + } + + if(i3 == i3_last_equal_A) + { + before_or_on_equal_line_in_A = false; + } + + ++i3; } + nofDisturbingLines = 0; + } - (*i3).bAEqC = false; - (*i3).bBEqC = false; - d3ll.insert( i3b, d3l ); - } - - if (i3 == i3_last_equal_A) - { - before_or_on_equal_line_in_A = false; - } - - ++i3; - } - nofDisturbingLines=0; - } - - if ( nofDisturbingLines == 0 ) - { - // Yes, the line from C can be moved. - (*i3c).lineC = -1; // This might leave an empty line: removed later. - (*i3c).bAEqC = false; - (*i3c).bBEqC = false; - (*i3b).lineC = lineC; - (*i3b).bBEqC = true; - (*i3b).bAEqC = (*i3b).bAEqB; - } + if(nofDisturbingLines == 0) + { + // Yes, the line from C can be moved. + (*i3c).lineC = -1; // This might leave an empty line: removed later. + (*i3c).bAEqC = false; + (*i3c).bBEqC = false; + (*i3b).lineC = lineC; + (*i3b).bBEqC = true; + (*i3b).bAEqC = (*i3b).bAEqB; + } + } } - } - --d.nofEquals; - ++lineB; - ++lineC; - ++i3b; - ++i3c; - } - else if ( d.diff1>0 ) - { - Diff3LineList::iterator i3 = i3b; - while( (*i3).lineB!=lineB ) - ++i3; - if( i3 != i3b && (*i3).bAEqB==false ) - { - // Take B from this line and move it up as far as possible - d3l.lineB = lineB; - d3ll.insert( i3b, d3l ); - (*i3).lineB = -1; - } - else - { - i3b=i3; - } - --d.diff1; - ++lineB; - ++i3b; + --d.nofEquals; + ++lineB; + ++lineC; + ++i3b; + ++i3c; + } + else if(d.diff1 > 0) + { + Diff3LineList::iterator i3 = i3b; + while((*i3).lineB != lineB) + ++i3; + if(i3 != i3b && (*i3).bAEqB == false) + { + // Take B from this line and move it up as far as possible + d3l.lineB = lineB; + d3ll.insert(i3b, d3l); + (*i3).lineB = -1; + } + else + { + i3b = i3; + } + --d.diff1; + ++lineB; + ++i3b; - if( d.diff2>0 ) - { + if(d.diff2 > 0) + { + --d.diff2; + ++lineC; + } + } + else if(d.diff2 > 0) + { --d.diff2; ++lineC; - } - } - else if ( d.diff2>0 ) - { - --d.diff2; - ++lineC; - } - } -/* + } + } + /* Diff3LineList::iterator it = d3ll.begin(); int li=0; for( ; it!=d3ll.end(); ++it, ++li ) { printf( "%4d %4d %4d %4d A%c=B A%c=C B%c=C\n", li, (*it).lineA, (*it).lineB, (*it).lineC, (*it).bAEqB ? '=' : '!', (*it).bAEqC ? '=' : '!', (*it).bBEqC ? '=' : '!' ); } printf("\n");*/ } #ifdef _WIN32 using ::equal; #endif // Test if the move would pass a barrier. Return true if not. -static bool isValidMove( ManualDiffHelpList* pManualDiffHelpList, int line1, int line2, int winIdx1, int winIdx2 ) +static bool isValidMove(ManualDiffHelpList* pManualDiffHelpList, int line1, int line2, int winIdx1, int winIdx2) { - if (line1>=0 && line2>=0) - { - ManualDiffHelpList::const_iterator i; - for( i = pManualDiffHelpList->begin(); i!=pManualDiffHelpList->end(); ++i ) - { - const ManualDiffHelpEntry& mdhe = *i; - - // Barrier - int l1 = winIdx1 == 1 ? mdhe.lineA1 : winIdx1==2 ? mdhe.lineB1 : mdhe.lineC1 ; - int l2 = winIdx2 == 1 ? mdhe.lineA1 : winIdx2==2 ? mdhe.lineB1 : mdhe.lineC1 ; - - if ( l1>=0 && l2>=0 ) - { - if ( (line1>=l1 && line2=l2) ) - return false; - l1 = winIdx1 == 1 ? mdhe.lineA2 : winIdx1==2 ? mdhe.lineB2 : mdhe.lineC2 ; - l2 = winIdx2 == 1 ? mdhe.lineA2 : winIdx2==2 ? mdhe.lineB2 : mdhe.lineC2 ; - ++l1; - ++l2; - if ( (line1>=l1 && line2=l2) ) - return false; - } - } - } - return true; // no barrier passed. + if(line1 >= 0 && line2 >= 0) + { + ManualDiffHelpList::const_iterator i; + for(i = pManualDiffHelpList->begin(); i != pManualDiffHelpList->end(); ++i) + { + const ManualDiffHelpEntry& mdhe = *i; + + // Barrier + int l1 = winIdx1 == 1 ? mdhe.lineA1 : winIdx1 == 2 ? mdhe.lineB1 : mdhe.lineC1; + int l2 = winIdx2 == 1 ? mdhe.lineA1 : winIdx2 == 2 ? mdhe.lineB1 : mdhe.lineC1; + + if(l1 >= 0 && l2 >= 0) + { + if((line1 >= l1 && line2 < l2) || (line1 < l1 && line2 >= l2)) + return false; + l1 = winIdx1 == 1 ? mdhe.lineA2 : winIdx1 == 2 ? mdhe.lineB2 : mdhe.lineC2; + l2 = winIdx2 == 1 ? mdhe.lineA2 : winIdx2 == 2 ? mdhe.lineB2 : mdhe.lineC2; + ++l1; + ++l2; + if((line1 >= l1 && line2 < l2) || (line1 < l1 && line2 >= l2)) + return false; + } + } + } + return true; // no barrier passed. } -static bool runDiff( const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList, - Options *pOptions) +static bool runDiff(const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList, + Options* pOptions) { - ProgressProxy pp; - static GnuDiff gnuDiff; // All values are initialized with zeros. - - pp.setCurrent(0); - - diffList.clear(); - if ( p1[0].pLine==0 || p2[0].pLine==0 || size1==0 || size2==0 ) - { - Diff d( 0,0,0); - if ( p1[0].pLine==0 && p2[0].pLine==0 && size1 == size2 ) - d.nofEquals = size1; - else - { - d.diff1=size1; - d.diff2=size2; - } - - diffList.push_back(d); - } - else - { - GnuDiff::comparison comparisonInput; - memset( &comparisonInput, 0, sizeof(comparisonInput) ); - comparisonInput.parent = 0; - comparisonInput.file[0].buffer = p1[0].pLine;//ptr to buffer - comparisonInput.file[0].buffered = (p1[size1-1].pLine-p1[0].pLine+p1[size1-1].size); // size of buffer - comparisonInput.file[1].buffer = p2[0].pLine;//ptr to buffer - comparisonInput.file[1].buffered = (p2[size2-1].pLine-p2[0].pLine+p2[size2-1].size); // size of buffer - - gnuDiff.ignore_white_space = GnuDiff::IGNORE_ALL_SPACE; // I think nobody needs anything else ... - gnuDiff.bIgnoreWhiteSpace = true; - gnuDiff.bIgnoreNumbers = pOptions->m_bIgnoreNumbers; - gnuDiff.minimal = pOptions->m_bTryHard; - gnuDiff.ignore_case = false; - GnuDiff::change* script = gnuDiff.diff_2_files( &comparisonInput ); - - int equalLinesAtStart = comparisonInput.file[0].prefix_lines; - int currentLine1 = 0; - int currentLine2 = 0; - GnuDiff::change* p=0; - for (GnuDiff::change* e = script; e; e = p) - { - Diff d(0,0,0); - d.nofEquals = e->line0 - currentLine1; - assert( d.nofEquals == e->line1 - currentLine2 ); - d.diff1 = e->deleted; - d.diff2 = e->inserted; - currentLine1 += d.nofEquals + d.diff1; - currentLine2 += d.nofEquals + d.diff2; - diffList.push_back(d); + ProgressProxy pp; + static GnuDiff gnuDiff; // All values are initialized with zeros. + + pp.setCurrent(0); + + diffList.clear(); + if(p1[0].pLine == 0 || p2[0].pLine == 0 || size1 == 0 || size2 == 0) + { + Diff d(0, 0, 0); + if(p1[0].pLine == 0 && p2[0].pLine == 0 && size1 == size2) + d.nofEquals = size1; + else + { + d.diff1 = size1; + d.diff2 = size2; + } + + diffList.push_back(d); + } + else + { + GnuDiff::comparison comparisonInput; + memset(&comparisonInput, 0, sizeof(comparisonInput)); + comparisonInput.parent = 0; + comparisonInput.file[0].buffer = p1[0].pLine; //ptr to buffer + comparisonInput.file[0].buffered = (p1[size1 - 1].pLine - p1[0].pLine + p1[size1 - 1].size); // size of buffer + comparisonInput.file[1].buffer = p2[0].pLine; //ptr to buffer + comparisonInput.file[1].buffered = (p2[size2 - 1].pLine - p2[0].pLine + p2[size2 - 1].size); // size of buffer + + gnuDiff.ignore_white_space = GnuDiff::IGNORE_ALL_SPACE; // I think nobody needs anything else ... + gnuDiff.bIgnoreWhiteSpace = true; + gnuDiff.bIgnoreNumbers = pOptions->m_bIgnoreNumbers; + gnuDiff.minimal = pOptions->m_bTryHard; + gnuDiff.ignore_case = false; + GnuDiff::change* script = gnuDiff.diff_2_files(&comparisonInput); + + int equalLinesAtStart = comparisonInput.file[0].prefix_lines; + int currentLine1 = 0; + int currentLine2 = 0; + GnuDiff::change* p = 0; + for(GnuDiff::change* e = script; e; e = p) + { + Diff d(0, 0, 0); + d.nofEquals = e->line0 - currentLine1; + assert(d.nofEquals == e->line1 - currentLine2); + d.diff1 = e->deleted; + d.diff2 = e->inserted; + currentLine1 += d.nofEquals + d.diff1; + currentLine2 += d.nofEquals + d.diff2; + diffList.push_back(d); - p = e->link; - free (e); - } + p = e->link; + free(e); + } - if ( diffList.empty() ) - { - Diff d(0,0,0); - d.nofEquals = min2(size1,size2); - d.diff1 = size1 - d.nofEquals; - d.diff2 = size2 - d.nofEquals; - diffList.push_back(d); -/* Diff d(0,0,0); + if(diffList.empty()) + { + Diff d(0, 0, 0); + d.nofEquals = min2(size1, size2); + d.diff1 = size1 - d.nofEquals; + d.diff2 = size2 - d.nofEquals; + diffList.push_back(d); + /* Diff d(0,0,0); d.nofEquals = equalLinesAtStart; if ( gnuDiff.files[0].missing_newline != gnuDiff.files[1].missing_newline ) { d.diff1 = gnuDiff.files[0].missing_newline ? 0 : 1; d.diff2 = gnuDiff.files[1].missing_newline ? 0 : 1; ++d.nofEquals; } else if ( !gnuDiff.files[0].missing_newline ) { ++d.nofEquals; } diffList.push_back(d); */ - } - else - { - diffList.front().nofEquals += equalLinesAtStart; - currentLine1 += equalLinesAtStart; - currentLine2 += equalLinesAtStart; - - int nofEquals = min2(size1-currentLine1,size2-currentLine2); - if ( nofEquals==0 ) - { - diffList.back().diff1 += size1-currentLine1; - diffList.back().diff2 += size2-currentLine2; - } - else - { - Diff d( nofEquals,size1-currentLine1-nofEquals,size2-currentLine2-nofEquals); - diffList.push_back(d); - } + } + else + { + diffList.front().nofEquals += equalLinesAtStart; + currentLine1 += equalLinesAtStart; + currentLine2 += equalLinesAtStart; + + int nofEquals = min2(size1 - currentLine1, size2 - currentLine2); + if(nofEquals == 0) + { + diffList.back().diff1 += size1 - currentLine1; + diffList.back().diff2 += size2 - currentLine2; + } + else + { + Diff d(nofEquals, size1 - currentLine1 - nofEquals, size2 - currentLine2 - nofEquals); + diffList.push_back(d); + } - /* + /* if ( gnuDiff.files[0].missing_newline != gnuDiff.files[1].missing_newline ) { diffList.back().diff1 += gnuDiff.files[0].missing_newline ? 0 : 1; diffList.back().diff2 += gnuDiff.files[1].missing_newline ? 0 : 1; } else if ( !gnuDiff.files[0].missing_newline ) { ++ diffList.back().nofEquals; } */ - } - } + } + } #ifndef NDEBUG - // Verify difflist - { - int l1=0; - int l2=0; - DiffList::iterator i; - for( i = diffList.begin(); i!=diffList.end(); ++i ) - { - l1+= i->nofEquals + i->diff1; - l2+= i->nofEquals + i->diff2; - } - - //if( l1!=p1-p1start || l2!=p2-p2start ) - if( l1!=size1 || l2!=size2 ) - assert( false ); - } + // Verify difflist + { + int l1 = 0; + int l2 = 0; + DiffList::iterator i; + for(i = diffList.begin(); i != diffList.end(); ++i) + { + l1 += i->nofEquals + i->diff1; + l2 += i->nofEquals + i->diff2; + } + + //if( l1!=p1-p1start || l2!=p2-p2start ) + if(l1 != size1 || l2 != size2) + assert(false); + } #endif - pp.setCurrent(1.0); + pp.setCurrent(1.0); - return true; + return true; } -bool runDiff( const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList, - int winIdx1, int winIdx2, - ManualDiffHelpList *pManualDiffHelpList, - Options *pOptions) +bool runDiff(const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList, + int winIdx1, int winIdx2, + ManualDiffHelpList* pManualDiffHelpList, + Options* pOptions) { - diffList.clear(); - DiffList diffList2; - - int l1begin = 0; - int l2begin = 0; - ManualDiffHelpList::const_iterator i; - for( i = pManualDiffHelpList->begin(); i!=pManualDiffHelpList->end(); ++i ) - { - const ManualDiffHelpEntry& mdhe = *i; - - int l1end = winIdx1 == 1 ? mdhe.lineA1 : winIdx1==2 ? mdhe.lineB1 : mdhe.lineC1 ; - int l2end = winIdx2 == 1 ? mdhe.lineA1 : winIdx2==2 ? mdhe.lineB1 : mdhe.lineC1 ; - - if ( l1end>=0 && l2end>=0 ) - { - runDiff( p1+l1begin, l1end-l1begin, p2+l2begin, l2end-l2begin, diffList2, pOptions); - diffList.splice( diffList.end(), diffList2 ); - l1begin = l1end; - l2begin = l2end; - - l1end = winIdx1 == 1 ? mdhe.lineA2 : winIdx1==2 ? mdhe.lineB2 : mdhe.lineC2 ; - l2end = winIdx2 == 1 ? mdhe.lineA2 : winIdx2==2 ? mdhe.lineB2 : mdhe.lineC2 ; - - if ( l1end>=0 && l2end>=0 ) - { - ++l1end; // point to line after last selected line - ++l2end; - runDiff( p1+l1begin, l1end-l1begin, p2+l2begin, l2end-l2begin, diffList2, pOptions); - diffList.splice( diffList.end(), diffList2 ); + diffList.clear(); + DiffList diffList2; + + int l1begin = 0; + int l2begin = 0; + ManualDiffHelpList::const_iterator i; + for(i = pManualDiffHelpList->begin(); i != pManualDiffHelpList->end(); ++i) + { + const ManualDiffHelpEntry& mdhe = *i; + + int l1end = winIdx1 == 1 ? mdhe.lineA1 : winIdx1 == 2 ? mdhe.lineB1 : mdhe.lineC1; + int l2end = winIdx2 == 1 ? mdhe.lineA1 : winIdx2 == 2 ? mdhe.lineB1 : mdhe.lineC1; + + if(l1end >= 0 && l2end >= 0) + { + runDiff(p1 + l1begin, l1end - l1begin, p2 + l2begin, l2end - l2begin, diffList2, pOptions); + diffList.splice(diffList.end(), diffList2); l1begin = l1end; l2begin = l2end; - } - } - } - runDiff( p1+l1begin, size1-l1begin, p2+l2begin, size2-l2begin, diffList2, pOptions); - diffList.splice( diffList.end(), diffList2 ); - return true; -} - -void correctManualDiffAlignment( Diff3LineList& d3ll, ManualDiffHelpList* pManualDiffHelpList ) -{ - if ( pManualDiffHelpList->empty() ) - return; - // If a line appears unaligned in comparison to the manual alignment, correct this. + l1end = winIdx1 == 1 ? mdhe.lineA2 : winIdx1 == 2 ? mdhe.lineB2 : mdhe.lineC2; + l2end = winIdx2 == 1 ? mdhe.lineA2 : winIdx2 == 2 ? mdhe.lineB2 : mdhe.lineC2; - ManualDiffHelpList::iterator iMDHL; - for( iMDHL = pManualDiffHelpList->begin(); iMDHL != pManualDiffHelpList->end(); ++iMDHL ) - { - Diff3LineList::iterator i3 = d3ll.begin(); - int missingWinIdx = 0; - int alignedSum = (iMDHL->lineA1<0?0:1) + (iMDHL->lineB1<0?0:1) + (iMDHL->lineC1<0?0:1); - if (alignedSum==2) - { - // If only A & B are aligned then let C rather be aligned with A - // If only A & C are aligned then let B rather be aligned with A - // If only B & C are aligned then let A rather be aligned with B - missingWinIdx = iMDHL->lineA1<0 ? 1 : (iMDHL->lineB1<0 ? 2 : 3 ); - } - else if (alignedSum<=1) - { - return; - } - - // At the first aligned line, move up the two other lines into new d3ls until the second input is aligned - // Then move up the third input until all three lines are aligned. - int wi=0; - for( ; i3!=d3ll.end(); ++i3 ) - { - for ( wi=1; wi<=3; ++wi ) - { - if ( i3->getLineInFile(wi) >= 0 && iMDHL->firstLine(wi) == i3->getLineInFile(wi) ) - break; - } - if ( wi<=3 ) - break; - } - - if (wi>=1 && wi <= 3) - { - // Found manual alignment for one source - Diff3LineList::iterator iDest = i3; - - // Move lines up until the next firstLine is found. Omit wi from move and search. - int wi2=0; - for( ; i3!=d3ll.end(); ++i3 ) - { - for ( wi2=1; wi2<=3; ++wi2 ) + if(l1end >= 0 && l2end >= 0) { - if ( wi!=wi2 && i3->getLineInFile(wi2) >= 0 && iMDHL->firstLine(wi2) == i3->getLineInFile(wi2) ) - break; + ++l1end; // point to line after last selected line + ++l2end; + runDiff(p1 + l1begin, l1end - l1begin, p2 + l2begin, l2end - l2begin, diffList2, pOptions); + diffList.splice(diffList.end(), diffList2); + l1begin = l1end; + l2begin = l2end; } - if (wi2>3) - { // Not yet found - // Move both others up - Diff3Line d3l; - // Move both up - if (wi==1) // Move B and C up - { - d3l.bBEqC = i3->bBEqC; - d3l.lineB = i3->lineB; - d3l.lineC = i3->lineC; - i3->lineB = -1; - i3->lineC = -1; - } - if (wi==2) // Move A and C up - { - d3l.bAEqC = i3->bAEqC; - d3l.lineA = i3->lineA; - d3l.lineC = i3->lineC; - i3->lineA = -1; - i3->lineC = -1; - } - if (wi==3) // Move A and B up - { - d3l.bAEqB = i3->bAEqB; - d3l.lineA = i3->lineA; - d3l.lineB = i3->lineB; - i3->lineA = -1; - i3->lineB = -1; - } - i3->bAEqB = false; - i3->bAEqC = false; - i3->bBEqC = false; - d3ll.insert( iDest, d3l ); + } + } + runDiff(p1 + l1begin, size1 - l1begin, p2 + l2begin, size2 - l2begin, diffList2, pOptions); + diffList.splice(diffList.end(), diffList2); + return true; +} + +void correctManualDiffAlignment(Diff3LineList& d3ll, ManualDiffHelpList* pManualDiffHelpList) +{ + if(pManualDiffHelpList->empty()) + return; + + // If a line appears unaligned in comparison to the manual alignment, correct this. + + ManualDiffHelpList::iterator iMDHL; + for(iMDHL = pManualDiffHelpList->begin(); iMDHL != pManualDiffHelpList->end(); ++iMDHL) + { + Diff3LineList::iterator i3 = d3ll.begin(); + int missingWinIdx = 0; + int alignedSum = (iMDHL->lineA1 < 0 ? 0 : 1) + (iMDHL->lineB1 < 0 ? 0 : 1) + (iMDHL->lineC1 < 0 ? 0 : 1); + if(alignedSum == 2) + { + // If only A & B are aligned then let C rather be aligned with A + // If only A & C are aligned then let B rather be aligned with A + // If only B & C are aligned then let A rather be aligned with B + missingWinIdx = iMDHL->lineA1 < 0 ? 1 : (iMDHL->lineB1 < 0 ? 2 : 3); + } + else if(alignedSum <= 1) + { + return; + } + + // At the first aligned line, move up the two other lines into new d3ls until the second input is aligned + // Then move up the third input until all three lines are aligned. + int wi = 0; + for(; i3 != d3ll.end(); ++i3) + { + for(wi = 1; wi <= 3; ++wi) + { + if(i3->getLineInFile(wi) >= 0 && iMDHL->firstLine(wi) == i3->getLineInFile(wi)) + break; } - else + if(wi <= 3) + break; + } + + if(wi >= 1 && wi <= 3) + { + // Found manual alignment for one source + Diff3LineList::iterator iDest = i3; + + // Move lines up until the next firstLine is found. Omit wi from move and search. + int wi2 = 0; + for(; i3 != d3ll.end(); ++i3) { - // align the found line with the line we already have here - if ( i3 != iDest ) - { - if (wi2==1) - { - iDest->lineA = i3->lineA; - i3->lineA = -1; - i3->bAEqB = false; - i3->bAEqC = false; - } - else if (wi2==2) - { - iDest->lineB = i3->lineB; - i3->lineB = -1; - i3->bAEqB = false; - i3->bBEqC = false; - } - else if (wi2==3) - { - iDest->lineC = i3->lineC; - i3->lineC = -1; - i3->bBEqC = false; - i3->bAEqC = false; - } - } - - if ( missingWinIdx!=0 ) - { - for( ; i3!=d3ll.end(); ++i3 ) - { - int wi3 = missingWinIdx; - if ( i3->getLineInFile(wi3) >= 0 ) - { - // not found, move the line before iDest - Diff3Line d3l; - if ( wi3==1 ) + for(wi2 = 1; wi2 <= 3; ++wi2) + { + if(wi != wi2 && i3->getLineInFile(wi2) >= 0 && iMDHL->firstLine(wi2) == i3->getLineInFile(wi2)) + break; + } + if(wi2 > 3) + { // Not yet found + // Move both others up + Diff3Line d3l; + // Move both up + if(wi == 1) // Move B and C up + { + d3l.bBEqC = i3->bBEqC; + d3l.lineB = i3->lineB; + d3l.lineC = i3->lineC; + i3->lineB = -1; + i3->lineC = -1; + } + if(wi == 2) // Move A and C up + { + d3l.bAEqC = i3->bAEqC; + d3l.lineA = i3->lineA; + d3l.lineC = i3->lineC; + i3->lineA = -1; + i3->lineC = -1; + } + if(wi == 3) // Move A and B up + { + d3l.bAEqB = i3->bAEqB; + d3l.lineA = i3->lineA; + d3l.lineB = i3->lineB; + i3->lineA = -1; + i3->lineB = -1; + } + i3->bAEqB = false; + i3->bAEqC = false; + i3->bBEqC = false; + d3ll.insert(iDest, d3l); + } + else + { + // align the found line with the line we already have here + if(i3 != iDest) + { + if(wi2 == 1) { - if (i3->bAEqB) // Stop moving lines up if one equal is found. - break; - d3l.lineA = i3->lineA; - i3->lineA = -1; - i3->bAEqB = false; - i3->bAEqC = false; + iDest->lineA = i3->lineA; + i3->lineA = -1; + i3->bAEqB = false; + i3->bAEqC = false; } - if ( wi3==2 ) + else if(wi2 == 2) { - if (i3->bAEqB) - break; - d3l.lineB = i3->lineB; - i3->lineB = -1; - i3->bAEqB = false; - i3->bBEqC = false; + iDest->lineB = i3->lineB; + i3->lineB = -1; + i3->bAEqB = false; + i3->bBEqC = false; } - if ( wi3==3 ) + else if(wi2 == 3) { - if (i3->bAEqC) - break; - d3l.lineC = i3->lineC; - i3->lineC = -1; - i3->bAEqC = false; - i3->bBEqC = false; + iDest->lineC = i3->lineC; + i3->lineC = -1; + i3->bBEqC = false; + i3->bAEqC = false; } - d3ll.insert( iDest, d3l ); - } - } // for(), searching for wi3 - } - break; - } - } // for(), searching for wi2 - } // if, wi found - } // for (iMDHL) + } + + if(missingWinIdx != 0) + { + for(; i3 != d3ll.end(); ++i3) + { + int wi3 = missingWinIdx; + if(i3->getLineInFile(wi3) >= 0) + { + // not found, move the line before iDest + Diff3Line d3l; + if(wi3 == 1) + { + if(i3->bAEqB) // Stop moving lines up if one equal is found. + break; + d3l.lineA = i3->lineA; + i3->lineA = -1; + i3->bAEqB = false; + i3->bAEqC = false; + } + if(wi3 == 2) + { + if(i3->bAEqB) + break; + d3l.lineB = i3->lineB; + i3->lineB = -1; + i3->bAEqB = false; + i3->bBEqC = false; + } + if(wi3 == 3) + { + if(i3->bAEqC) + break; + d3l.lineC = i3->lineC; + i3->lineC = -1; + i3->bAEqC = false; + i3->bBEqC = false; + } + d3ll.insert(iDest, d3l); + } + } // for(), searching for wi3 + } + break; + } + } // for(), searching for wi2 + } // if, wi found + } // for (iMDHL) } // Fourth step void calcDiff3LineListTrim( - Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC, ManualDiffHelpList* pManualDiffHelpList - ) + Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC, ManualDiffHelpList* pManualDiffHelpList) { - const Diff3Line d3l_empty; - d3ll.removeAll( d3l_empty ); - - Diff3LineList::iterator i3 = d3ll.begin(); - Diff3LineList::iterator i3A = d3ll.begin(); - Diff3LineList::iterator i3B = d3ll.begin(); - Diff3LineList::iterator i3C = d3ll.begin(); - - int line=0; // diff3line counters - int lineA=0; // - int lineB=0; - int lineC=0; - - ManualDiffHelpList::iterator iMDHL = pManualDiffHelpList->begin(); - // The iterator i3 and the variable line look ahead. - // The iterators i3A, i3B, i3C and corresponding lineA, lineB and lineC stop at empty lines, if found. - // If possible, then the texts from the look ahead will be moved back to the empty places. - - for( ; i3!=d3ll.end(); ++i3, ++line ) - { - if ( iMDHL!=pManualDiffHelpList->end() ) - { - if ( (i3->lineA >= 0 && i3->lineA==iMDHL->lineA1) || - (i3->lineB >= 0 && i3->lineB==iMDHL->lineB1) || - (i3->lineC >= 0 && i3->lineC==iMDHL->lineC1) ) - { - i3A = i3; - i3B = i3; - i3C = i3; - lineA = line; - lineB = line; - lineC = line; - ++iMDHL; - } - } - - if( line>lineA && (*i3).lineA != -1 && (*i3A).lineB!=-1 && (*i3A).bBEqC && - ::equal( pldA[(*i3).lineA], pldB[(*i3A).lineB], false ) && - isValidMove( pManualDiffHelpList, (*i3).lineA, (*i3A).lineB, 1, 2 ) && - isValidMove( pManualDiffHelpList, (*i3).lineA, (*i3A).lineC, 1, 3 ) ) - { - // Empty space for A. A matches B and C in the empty line. Move it up. - (*i3A).lineA = (*i3).lineA; - (*i3A).bAEqB = true; - (*i3A).bAEqC = true; - - (*i3).lineA = -1; - (*i3).bAEqB = false; - (*i3).bAEqC = false; - ++i3A; - ++lineA; - } - - if( line>lineB && (*i3).lineB != -1 && (*i3B).lineA!=-1 && (*i3B).bAEqC && - ::equal( pldB[(*i3).lineB], pldA[(*i3B).lineA], false ) && - isValidMove( pManualDiffHelpList, (*i3).lineB, (*i3B).lineA, 2, 1 ) && - isValidMove( pManualDiffHelpList, (*i3).lineB, (*i3B).lineC, 2, 3 ) ) - { - // Empty space for B. B matches A and C in the empty line. Move it up. - (*i3B).lineB = (*i3).lineB; - (*i3B).bAEqB = true; - (*i3B).bBEqC = true; - (*i3).lineB = -1; - (*i3).bAEqB = false; - (*i3).bBEqC = false; - ++i3B; - ++lineB; - } - - if( line>lineC && (*i3).lineC != -1 && (*i3C).lineA!=-1 && (*i3C).bAEqB && - ::equal( pldC[(*i3).lineC], pldA[(*i3C).lineA], false )&& - isValidMove( pManualDiffHelpList, (*i3).lineC, (*i3C).lineA, 3, 1 ) && - isValidMove( pManualDiffHelpList, (*i3).lineC, (*i3C).lineB, 3, 2 ) ) - { - // Empty space for C. C matches A and B in the empty line. Move it up. - (*i3C).lineC = (*i3).lineC; - (*i3C).bAEqC = true; - (*i3C).bBEqC = true; - (*i3).lineC = -1; - (*i3).bAEqC = false; - (*i3).bBEqC = false; - ++i3C; - ++lineC; - } - - if( line>lineA && (*i3).lineA != -1 && !(*i3).bAEqB && !(*i3).bAEqC && - isValidMove( pManualDiffHelpList, (*i3).lineA, (*i3A).lineB, 1, 2 ) && - isValidMove( pManualDiffHelpList, (*i3).lineA, (*i3A).lineC, 1, 3 ) ) { - // Empty space for A. A doesn't match B or C. Move it up. - (*i3A).lineA = (*i3).lineA; - (*i3).lineA = -1; - - if(i3A->lineB != -1 && ::equal( pldA[i3A->lineA], pldB[i3A->lineB], false )) - { - i3A->bAEqB = true; - } - if((i3A->bAEqB && i3A->bBEqC) || - (i3A->lineC != -1 && ::equal( pldA[i3A->lineA], pldC[i3A->lineC], false ))) - { - i3A->bAEqC = true; - } - - ++i3A; - ++lineA; - } - - if( line>lineB && (*i3).lineB != -1 && !(*i3).bAEqB && !(*i3).bBEqC && - isValidMove( pManualDiffHelpList, (*i3).lineB, (*i3B).lineA, 2, 1 ) && - isValidMove( pManualDiffHelpList, (*i3).lineB, (*i3B).lineC, 2, 3 ) ) - { - // Empty space for B. B matches neither A nor C. Move B up. - (*i3B).lineB = (*i3).lineB; - (*i3).lineB = -1; - - if(i3B->lineA != -1 && ::equal( pldA[i3B->lineA], pldB[i3B->lineB], false )) - { - i3B->bAEqB = true; - } - if((i3B->bAEqB && i3B->bAEqC) || - (i3B->lineC != -1 && ::equal( pldB[i3B->lineB], pldC[i3B->lineC], false ))) - { - i3B->bBEqC = true; - } - - ++i3B; - ++lineB; - } - - if( line>lineC && (*i3).lineC != -1 && !(*i3).bAEqC && !(*i3).bBEqC && - isValidMove( pManualDiffHelpList, (*i3).lineC, (*i3C).lineA, 3, 1 ) && - isValidMove( pManualDiffHelpList, (*i3).lineC, (*i3C).lineB, 3, 2 ) ) - { - // Empty space for C. C matches neither A nor B. Move C up. - (*i3C).lineC = (*i3).lineC; - (*i3).lineC = -1; + const Diff3Line d3l_empty; + d3ll.removeAll(d3l_empty); + + Diff3LineList::iterator i3 = d3ll.begin(); + Diff3LineList::iterator i3A = d3ll.begin(); + Diff3LineList::iterator i3B = d3ll.begin(); + Diff3LineList::iterator i3C = d3ll.begin(); + + int line = 0; // diff3line counters + int lineA = 0; // + int lineB = 0; + int lineC = 0; + + ManualDiffHelpList::iterator iMDHL = pManualDiffHelpList->begin(); + // The iterator i3 and the variable line look ahead. + // The iterators i3A, i3B, i3C and corresponding lineA, lineB and lineC stop at empty lines, if found. + // If possible, then the texts from the look ahead will be moved back to the empty places. + + for(; i3 != d3ll.end(); ++i3, ++line) + { + if(iMDHL != pManualDiffHelpList->end()) + { + if((i3->lineA >= 0 && i3->lineA == iMDHL->lineA1) || + (i3->lineB >= 0 && i3->lineB == iMDHL->lineB1) || + (i3->lineC >= 0 && i3->lineC == iMDHL->lineC1)) + { + i3A = i3; + i3B = i3; + i3C = i3; + lineA = line; + lineB = line; + lineC = line; + ++iMDHL; + } + } + + if(line > lineA && (*i3).lineA != -1 && (*i3A).lineB != -1 && (*i3A).bBEqC && + ::equal(pldA[(*i3).lineA], pldB[(*i3A).lineB], false) && + isValidMove(pManualDiffHelpList, (*i3).lineA, (*i3A).lineB, 1, 2) && + isValidMove(pManualDiffHelpList, (*i3).lineA, (*i3A).lineC, 1, 3)) + { + // Empty space for A. A matches B and C in the empty line. Move it up. + (*i3A).lineA = (*i3).lineA; + (*i3A).bAEqB = true; + (*i3A).bAEqC = true; - if(i3C->lineA != -1 && ::equal( pldA[i3C->lineA], pldC[i3C->lineC], false )) - { - i3C->bAEqC = true; - } - if((i3C->bAEqC && i3C->bAEqB) || - (i3C->lineB != -1 && ::equal( pldB[i3C->lineB], pldC[i3C->lineC], false ))) - { - i3C->bBEqC = true; - } + (*i3).lineA = -1; + (*i3).bAEqB = false; + (*i3).bAEqC = false; + ++i3A; + ++lineA; + } + + if(line > lineB && (*i3).lineB != -1 && (*i3B).lineA != -1 && (*i3B).bAEqC && + ::equal(pldB[(*i3).lineB], pldA[(*i3B).lineA], false) && + isValidMove(pManualDiffHelpList, (*i3).lineB, (*i3B).lineA, 2, 1) && + isValidMove(pManualDiffHelpList, (*i3).lineB, (*i3B).lineC, 2, 3)) + { + // Empty space for B. B matches A and C in the empty line. Move it up. + (*i3B).lineB = (*i3).lineB; + (*i3B).bAEqB = true; + (*i3B).bBEqC = true; + (*i3).lineB = -1; + (*i3).bAEqB = false; + (*i3).bBEqC = false; + ++i3B; + ++lineB; + } + + if(line > lineC && (*i3).lineC != -1 && (*i3C).lineA != -1 && (*i3C).bAEqB && + ::equal(pldC[(*i3).lineC], pldA[(*i3C).lineA], false) && + isValidMove(pManualDiffHelpList, (*i3).lineC, (*i3C).lineA, 3, 1) && + isValidMove(pManualDiffHelpList, (*i3).lineC, (*i3C).lineB, 3, 2)) + { + // Empty space for C. C matches A and B in the empty line. Move it up. + (*i3C).lineC = (*i3).lineC; + (*i3C).bAEqC = true; + (*i3C).bBEqC = true; + (*i3).lineC = -1; + (*i3).bAEqC = false; + (*i3).bBEqC = false; + ++i3C; + ++lineC; + } - ++i3C; - ++lineC; - } + if(line > lineA && (*i3).lineA != -1 && !(*i3).bAEqB && !(*i3).bAEqC && + isValidMove(pManualDiffHelpList, (*i3).lineA, (*i3A).lineB, 1, 2) && + isValidMove(pManualDiffHelpList, (*i3).lineA, (*i3A).lineC, 1, 3)) { + // Empty space for A. A doesn't match B or C. Move it up. + (*i3A).lineA = (*i3).lineA; + (*i3).lineA = -1; - if( line>lineA && line>lineB && (*i3).lineA != -1 && (*i3).bAEqB && !(*i3).bAEqC ) - { - // Empty space for A and B. A matches B, but not C. Move A & B up. - Diff3LineList::iterator i = lineA > lineB ? i3A : i3B; - int l = lineA > lineB ? lineA : lineB; + if(i3A->lineB != -1 && ::equal(pldA[i3A->lineA], pldB[i3A->lineB], false)) + { + i3A->bAEqB = true; + } + if((i3A->bAEqB && i3A->bBEqC) || + (i3A->lineC != -1 && ::equal(pldA[i3A->lineA], pldC[i3A->lineC], false))) + { + i3A->bAEqC = true; + } - if ( isValidMove( pManualDiffHelpList, i->lineC, (*i3).lineA, 3, 1 ) && - isValidMove( pManualDiffHelpList, i->lineC, (*i3).lineB, 3, 2 ) ) - { - (*i).lineA = (*i3).lineA; - (*i).lineB = (*i3).lineB; - (*i).bAEqB = true; + ++i3A; + ++lineA; + } + + if(line > lineB && (*i3).lineB != -1 && !(*i3).bAEqB && !(*i3).bBEqC && + isValidMove(pManualDiffHelpList, (*i3).lineB, (*i3B).lineA, 2, 1) && + isValidMove(pManualDiffHelpList, (*i3).lineB, (*i3B).lineC, 2, 3)) + { + // Empty space for B. B matches neither A nor C. Move B up. + (*i3B).lineB = (*i3).lineB; + (*i3).lineB = -1; - if(i->lineC != -1 && ::equal( pldA[i->lineA], pldC[i->lineC], false )) + if(i3B->lineA != -1 && ::equal(pldA[i3B->lineA], pldB[i3B->lineB], false)) + { + i3B->bAEqB = true; + } + if((i3B->bAEqB && i3B->bAEqC) || + (i3B->lineC != -1 && ::equal(pldB[i3B->lineB], pldC[i3B->lineC], false))) { - (*i).bAEqC = true; - (*i).bBEqC = true; + i3B->bBEqC = true; } - (*i3).lineA = -1; - (*i3).lineB = -1; - (*i3).bAEqB = false; - i3A = i; - i3B = i; - ++i3A; ++i3B; - lineA=l+1; - lineB=l+1; - } - } - else if( line>lineA && line>lineC && (*i3).lineA != -1 && (*i3).bAEqC && !(*i3).bAEqB ) - { - // Empty space for A and C. A matches C, but not B. Move A & C up. - Diff3LineList::iterator i = lineA > lineC ? i3A : i3C; - int l = lineA > lineC ? lineA : lineC; - - if ( isValidMove( pManualDiffHelpList, i->lineB, (*i3).lineA, 2, 1 ) && - isValidMove( pManualDiffHelpList, i->lineB, (*i3).lineC, 2, 3 ) ) - { - (*i).lineA = (*i3).lineA; - (*i).lineC = (*i3).lineC; - (*i).bAEqC = true; + ++lineB; + } + + if(line > lineC && (*i3).lineC != -1 && !(*i3).bAEqC && !(*i3).bBEqC && + isValidMove(pManualDiffHelpList, (*i3).lineC, (*i3C).lineA, 3, 1) && + isValidMove(pManualDiffHelpList, (*i3).lineC, (*i3C).lineB, 3, 2)) + { + // Empty space for C. C matches neither A nor B. Move C up. + (*i3C).lineC = (*i3).lineC; + (*i3).lineC = -1; - if(i->lineB != -1 && ::equal( pldA[i->lineA], pldB[i->lineB], false )) + if(i3C->lineA != -1 && ::equal(pldA[i3C->lineA], pldC[i3C->lineC], false)) + { + i3C->bAEqC = true; + } + if((i3C->bAEqC && i3C->bAEqB) || + (i3C->lineB != -1 && ::equal(pldB[i3C->lineB], pldC[i3C->lineC], false))) { - (*i).bAEqB = true; - (*i).bBEqC = true; + i3C->bBEqC = true; } - (*i3).lineA = -1; - (*i3).lineC = -1; - (*i3).bAEqC = false; - i3A = i; - i3C = i; - ++i3A; ++i3C; - lineA=l+1; - lineC=l+1; - } - } - else if( line>lineB && line>lineC && (*i3).lineB != -1 && (*i3).bBEqC && !(*i3).bAEqC ) - { - // Empty space for B and C. B matches C, but not A. Move B & C up. - Diff3LineList::iterator i = lineB > lineC ? i3B : i3C; - int l = lineB > lineC ? lineB : lineC; - - if ( isValidMove( pManualDiffHelpList, i->lineA, (*i3).lineB, 1, 2 ) && - isValidMove( pManualDiffHelpList, i->lineA, (*i3).lineC, 1, 3 ) ) - { - (*i).lineB = (*i3).lineB; - (*i).lineC = (*i3).lineC; - (*i).bBEqC = true; + ++lineC; + } - if(i->lineA != -1 && ::equal( pldA[i->lineA], pldB[i->lineB], false )) + if(line > lineA && line > lineB && (*i3).lineA != -1 && (*i3).bAEqB && !(*i3).bAEqC) + { + // Empty space for A and B. A matches B, but not C. Move A & B up. + Diff3LineList::iterator i = lineA > lineB ? i3A : i3B; + int l = lineA > lineB ? lineA : lineB; + + if(isValidMove(pManualDiffHelpList, i->lineC, (*i3).lineA, 3, 1) && + isValidMove(pManualDiffHelpList, i->lineC, (*i3).lineB, 3, 2)) + { + (*i).lineA = (*i3).lineA; + (*i).lineB = (*i3).lineB; + (*i).bAEqB = true; + + if(i->lineC != -1 && ::equal(pldA[i->lineA], pldC[i->lineC], false)) + { + (*i).bAEqC = true; + (*i).bBEqC = true; + } + + (*i3).lineA = -1; + (*i3).lineB = -1; + (*i3).bAEqB = false; + i3A = i; + i3B = i; + ++i3A; + ++i3B; + lineA = l + 1; + lineB = l + 1; + } + } + else if(line > lineA && line > lineC && (*i3).lineA != -1 && (*i3).bAEqC && !(*i3).bAEqB) + { + // Empty space for A and C. A matches C, but not B. Move A & C up. + Diff3LineList::iterator i = lineA > lineC ? i3A : i3C; + int l = lineA > lineC ? lineA : lineC; + + if(isValidMove(pManualDiffHelpList, i->lineB, (*i3).lineA, 2, 1) && + isValidMove(pManualDiffHelpList, i->lineB, (*i3).lineC, 2, 3)) + { + (*i).lineA = (*i3).lineA; + (*i).lineC = (*i3).lineC; + (*i).bAEqC = true; + + if(i->lineB != -1 && ::equal(pldA[i->lineA], pldB[i->lineB], false)) + { + (*i).bAEqB = true; + (*i).bBEqC = true; + } + + (*i3).lineA = -1; + (*i3).lineC = -1; + (*i3).bAEqC = false; + i3A = i; + i3C = i; + ++i3A; + ++i3C; + lineA = l + 1; + lineC = l + 1; + } + } + else if(line > lineB && line > lineC && (*i3).lineB != -1 && (*i3).bBEqC && !(*i3).bAEqC) + { + // Empty space for B and C. B matches C, but not A. Move B & C up. + Diff3LineList::iterator i = lineB > lineC ? i3B : i3C; + int l = lineB > lineC ? lineB : lineC; + + if(isValidMove(pManualDiffHelpList, i->lineA, (*i3).lineB, 1, 2) && + isValidMove(pManualDiffHelpList, i->lineA, (*i3).lineC, 1, 3)) { - (*i).bAEqB = true; - (*i).bAEqC = true; + (*i).lineB = (*i3).lineB; + (*i).lineC = (*i3).lineC; + (*i).bBEqC = true; + + if(i->lineA != -1 && ::equal(pldA[i->lineA], pldB[i->lineB], false)) + { + (*i).bAEqB = true; + (*i).bAEqC = true; + } + + (*i3).lineB = -1; + (*i3).lineC = -1; + (*i3).bBEqC = false; + i3B = i; + i3C = i; + ++i3B; + ++i3C; + lineB = l + 1; + lineC = l + 1; } + } - (*i3).lineB = -1; - (*i3).lineC = -1; - (*i3).bBEqC = false; - i3B = i; - i3C = i; + 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; - 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.removeAll( d3l_empty ); + d3ll.removeAll(d3l_empty); -/* + /* Diff3LineList::iterator it = d3ll.begin(); int li=0; for( ; it!=d3ll.end(); ++it, ++li ) { printf( "%4d %4d %4d %4d A%c=B A%c=C B%c=C\n", li, (*it).lineA, (*it).lineB, (*it).lineC, (*it).bAEqB ? '=' : '!', (*it).bAEqC ? '=' : '!', (*it).bBEqC ? '=' : '!' ); } */ } -void DiffBufferInfo::init( Diff3LineList* pD3ll, const Diff3LineVector* pD3lv, - const LineData* pldA, int sizeA, const LineData* pldB, int sizeB, const LineData* pldC, int sizeC ) +void DiffBufferInfo::init(Diff3LineList* pD3ll, const Diff3LineVector* pD3lv, + const LineData* pldA, int sizeA, const LineData* pldB, int sizeB, const LineData* pldC, int sizeC) { - m_pDiff3LineList = pD3ll; - m_pDiff3LineVector = pD3lv; - m_pLineDataA = pldA; - m_pLineDataB = pldB; - m_pLineDataC = pldC; - m_sizeA = sizeA; - m_sizeB = sizeB; - m_sizeC = sizeC; - Diff3LineList::iterator i3 = pD3ll->begin(); - for( ; i3!=pD3ll->end(); ++i3 ) - { - i3->m_pDiffBufferInfo = this; - } + m_pDiff3LineList = pD3ll; + m_pDiff3LineVector = pD3lv; + m_pLineDataA = pldA; + m_pLineDataB = pldB; + m_pLineDataC = pldC; + m_sizeA = sizeA; + m_sizeB = sizeB; + m_sizeC = sizeC; + Diff3LineList::iterator i3 = pD3ll->begin(); + for(; i3 != pD3ll->end(); ++i3) + { + i3->m_pDiffBufferInfo = this; + } } void calcWhiteDiff3Lines( - Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC - ) + Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC) { - Diff3LineList::iterator i3 = d3ll.begin(); - - for( ; i3!=d3ll.end(); ++i3 ) - { - i3->bWhiteLineA = ( (*i3).lineA == -1 || pldA==0 || pldA[(*i3).lineA].whiteLine() || pldA[(*i3).lineA].bContainsPureComment ); - i3->bWhiteLineB = ( (*i3).lineB == -1 || pldB==0 || pldB[(*i3).lineB].whiteLine() || pldB[(*i3).lineB].bContainsPureComment ); - i3->bWhiteLineC = ( (*i3).lineC == -1 || pldC==0 || pldC[(*i3).lineC].whiteLine() || pldC[(*i3).lineC].bContainsPureComment ); - } + Diff3LineList::iterator i3 = d3ll.begin(); + + for(; i3 != d3ll.end(); ++i3) + { + i3->bWhiteLineA = ((*i3).lineA == -1 || pldA == 0 || pldA[(*i3).lineA].whiteLine() || pldA[(*i3).lineA].bContainsPureComment); + i3->bWhiteLineB = ((*i3).lineB == -1 || pldB == 0 || pldB[(*i3).lineB].whiteLine() || pldB[(*i3).lineB].bContainsPureComment); + i3->bWhiteLineC = ((*i3).lineC == -1 || pldC == 0 || pldC[(*i3).lineC].whiteLine() || pldC[(*i3).lineC].bContainsPureComment); + } } -inline bool equal( QChar c1, QChar c2, bool /*bStrict*/ ) +inline bool equal(QChar c1, QChar c2, bool /*bStrict*/) { - // If bStrict then white space doesn't match + // If bStrict then white space doesn't match - //if ( bStrict && ( c1==' ' || c1=='\t' ) ) - // return false; + //if ( bStrict && ( c1==' ' || c1=='\t' ) ) + // return false; - return c1==c2; + 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 ) +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 ) + 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)) { - --d.diff1; - --d.diff2; - --nofUnmatched; + break; } - else if ( d.nofEquals > 0 ) + for(i2 = 0; i2 < maxSearchRange; ++i2) { - --d.nofEquals; - --nofUnmatched; + if(&p2[i2] == p2end || (bBestValid && i1 + i2 >= bestI1 + bestI2)) + { + break; + } + else if(equal(p2[i2], p1[i1], true) && + (match == 1 || abs(i1 - i2) < 3 || (&p2[i2 + 1] == p2end && &p1[i1 + 1] == p1end) || + (&p2[i2 + 1] != p2end && &p1[i1 + 1] != p1end && equal(p2[i2 + 1], p1[i1 + 1], false)))) + { + if(i1 + i2 < bestI1 + bestI2 || bBestValid == false) + { + bestI1 = i1; + bestI2 = i2; + bBestValid = true; + break; + } + } } + } + + // The match was found using the strict search. Go back if there are non-strict + // matches. + while(bestI1 >= 1 && bestI2 >= 1 && equal(p1[bestI1 - 1], p2[bestI2 - 1], false)) + { + --bestI1; + --bestI2; + } + + bool bEndReached = false; + if(bBestValid) + { + // continue somehow + Diff d(nofEquals, bestI1, bestI2); + diffList.push_back(d); + + p1 += bestI1; + p2 += bestI2; + } + else + { + // Nothing else to match. + Diff d(nofEquals, p1end - p1, p2end - p2); + diffList.push_back(d); - if ( d.nofEquals==0 && (d.diff1==0 || d.diff2==0) && nofUnmatched>0 ) + 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 ( diffList.empty() ) - break; - d.nofEquals += diffList.back().nofEquals; - d.diff1 += diffList.back().diff1; - d.diff2 += diffList.back().diff2; - diffList.pop_back(); - bEndReached = false; + 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 - { + if(bEndReached) + diffList.push_back(origBack); + else + { - p1 = pu1 + 1 + nofUnmatched; - p2 = pu2 + 1 + nofUnmatched; - diffList.push_back( d ); - } - } - if ( bEndReached ) - break; - } + 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 ); - } + // 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 } bool fineDiff( - Diff3LineList& diff3LineList, - int selector, - const LineData* v1, - const LineData* v2 - ) + Diff3LineList& diff3LineList, + int selector, + const LineData* v1, + const LineData* v2) { - // Finetuning: Diff each line with deltas - ProgressProxy pp; - int maxSearchLength=500; - Diff3LineList::iterator i; - int k1=0; - int k2=0; - bool bTextsTotalEqual = true; - int listSize = diff3LineList.size(); - pp.setMaxNofSteps( listSize ); - int listIdx = 0; - for( i= diff3LineList.begin(); i!= diff3LineList.end(); ++i) - { - if (selector==1){ k1=i->lineA; k2=i->lineB; } - else if (selector==2){ k1=i->lineB; k2=i->lineC; } - else if (selector==3){ k1=i->lineC; k2=i->lineA; } - else assert(false); - if( (k1==-1 && k2!=-1) || (k1!=-1 && k2==-1) ) bTextsTotalEqual=false; - if( k1!=-1 && k2!=-1 ) - { - if ( v1[k1].size != v2[k2].size || memcmp( v1[k1].pLine, v2[k2].pLine, v1[k1].size<<1)!=0 ) - { - bTextsTotalEqual = false; - DiffList* pDiffList = new DiffList; - calcDiff( v1[k1].pLine, v1[k1].size, v2[k2].pLine, v2[k2].size, *pDiffList, 2, maxSearchLength ); - - // Optimize the diff list. - DiffList::iterator dli; - bool bUsefulFineDiff = false; - for( dli = pDiffList->begin(); dli!=pDiffList->end(); ++dli) + // Finetuning: Diff each line with deltas + ProgressProxy pp; + int maxSearchLength = 500; + Diff3LineList::iterator i; + int k1 = 0; + int k2 = 0; + bool bTextsTotalEqual = true; + int listSize = diff3LineList.size(); + pp.setMaxNofSteps(listSize); + int listIdx = 0; + for(i = diff3LineList.begin(); i != diff3LineList.end(); ++i) + { + if(selector == 1) { + k1 = i->lineA; + k2 = i->lineB; + } + else if(selector == 2) + { + k1 = i->lineB; + k2 = i->lineC; + } + else if(selector == 3) + { + k1 = i->lineC; + k2 = i->lineA; + } + else + assert(false); + if((k1 == -1 && k2 != -1) || (k1 != -1 && k2 == -1)) bTextsTotalEqual = false; + if(k1 != -1 && k2 != -1) + { + if(v1[k1].size != v2[k2].size || memcmp(v1[k1].pLine, v2[k2].pLine, v1[k1].size << 1) != 0) { - if( dli->nofEquals >= 4 ) - { - bUsefulFineDiff = true; - break; - } + bTextsTotalEqual = false; + DiffList* pDiffList = new DiffList; + calcDiff(v1[k1].pLine, v1[k1].size, v2[k2].pLine, v2[k2].size, *pDiffList, 2, maxSearchLength); + + // Optimize the diff list. + DiffList::iterator dli; + bool bUsefulFineDiff = false; + for(dli = pDiffList->begin(); dli != pDiffList->end(); ++dli) + { + if(dli->nofEquals >= 4) + { + bUsefulFineDiff = true; + break; + } + } + + for(dli = pDiffList->begin(); dli != pDiffList->end(); ++dli) + { + if(dli->nofEquals < 4 && (dli->diff1 > 0 || dli->diff2 > 0) && !(bUsefulFineDiff && dli == pDiffList->begin())) + { + dli->diff1 += dli->nofEquals; + dli->diff2 += dli->nofEquals; + dli->nofEquals = 0; + } + } + + if(selector == 1) { + delete(*i).pFineAB; + (*i).pFineAB = pDiffList; + } + else if(selector == 2) + { + delete(*i).pFineBC; + (*i).pFineBC = pDiffList; + } + else if(selector == 3) + { + delete(*i).pFineCA; + (*i).pFineCA = pDiffList; + } + else + assert(false); } - for( dli = pDiffList->begin(); dli!=pDiffList->end(); ++dli) + if((v1[k1].bContainsPureComment || v1[k1].whiteLine()) && (v2[k2].bContainsPureComment || v2[k2].whiteLine())) { - if( dli->nofEquals < 4 && (dli->diff1>0 || dli->diff2>0) - && !( bUsefulFineDiff && dli==pDiffList->begin() ) - ) - { - dli->diff1 += dli->nofEquals; - dli->diff2 += dli->nofEquals; - dli->nofEquals = 0; - } + if(selector == 1) { + i->bAEqB = true; + } + else if(selector == 2) + { + i->bBEqC = true; + } + else if(selector == 3) + { + i->bAEqC = true; + } + else + assert(false); } - - if (selector==1){ delete (*i).pFineAB; (*i).pFineAB = pDiffList; } - else if (selector==2){ delete (*i).pFineBC; (*i).pFineBC = pDiffList; } - else if (selector==3){ delete (*i).pFineCA; (*i).pFineCA = pDiffList; } - else assert(false); - } - - if ( (v1[k1].bContainsPureComment || v1[k1].whiteLine()) && (v2[k2].bContainsPureComment || v2[k2].whiteLine())) - { - if (selector==1){ i->bAEqB = true; } - else if (selector==2){ i->bBEqC = true; } - else if (selector==3){ i->bAEqC = true; } - else assert(false); - } - } - ++listIdx; - pp.step(); - } - return bTextsTotalEqual; + } + ++listIdx; + pp.step(); + } + return bTextsTotalEqual; } - // Convert the list to a vector of pointers -void calcDiff3LineVector( Diff3LineList& d3ll, Diff3LineVector& d3lv ) +void calcDiff3LineVector(Diff3LineList& d3ll, Diff3LineVector& d3lv) { - d3lv.resize( d3ll.size() ); - Diff3LineList::iterator i; - int j=0; - for( i= d3ll.begin(); i!= d3ll.end(); ++i, ++j) - { - d3lv[j] = &(*i); - } - assert( j==(int)d3lv.size() ); + d3lv.resize(d3ll.size()); + Diff3LineList::iterator i; + int j = 0; + for(i = d3ll.begin(); i != d3ll.end(); ++i, ++j) + { + d3lv[j] = &(*i); + } + assert(j == (int)d3lv.size()); } - - diff --git a/src/difftextwindow.cpp b/src/difftextwindow.cpp index 50cfcee..46ae0fb 100644 --- a/src/difftextwindow.cpp +++ b/src/difftextwindow.cpp @@ -1,2144 +1,2172 @@ /*************************************************************************** difftextwindow.cpp - description ------------------- begin : Mon Apr 8 2002 copyright : (C) 2002-2007 by Joachim Eibl email : joachim.eibl at gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "difftextwindow.h" #include "kdiff3.h" #include "merger.h" #include "options.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 -#include +#include +#include +#include #include +#include #include #include -#include static QAtomicInt s_runnableCount = 0; - class DiffTextWindowData { -public: - DiffTextWindowData( DiffTextWindow* p ) - { - m_pDiffTextWindow = p; - m_bPaintingAllowed = false; - m_pLineData = 0; - m_size = 0; - m_bWordWrap = false; - m_delayedDrawTimer = 0; - m_pDiff3LineVector = 0; - m_pManualDiffHelpList = 0; - m_pOptions = 0; - m_fastSelectorLine1 = 0; - m_fastSelectorNofLines = 0; - m_bTriple = 0; - m_winIdx = 0; - m_firstLine = 0; - m_oldFirstLine = 0; - m_horizScrollOffset = 0; - m_lineNumberWidth = 0; - m_maxTextWidth = -1; - m_pStatusBar = 0; - m_scrollDeltaX = 0; - m_scrollDeltaY = 0; - m_bMyUpdate = false; - m_bSelectionInProgress = false; - m_pTextCodec = 0; - #if defined(_WIN32) || defined(Q_OS_OS2) - m_eLineEndStyle = eLineEndStyleDos; - #else - m_eLineEndStyle = eLineEndStyleUnix; - #endif - } - DiffTextWindow* m_pDiffTextWindow; - DiffTextWindowFrame* m_pDiffTextWindowFrame; - QTextCodec* m_pTextCodec; - e_LineEndStyle m_eLineEndStyle; - - bool m_bPaintingAllowed; - const LineData* m_pLineData; - int m_size; - QString m_filename; - bool m_bWordWrap; - int m_delayedDrawTimer; - - const Diff3LineVector* m_pDiff3LineVector; - Diff3WrapLineVector m_diff3WrapLineVector; - const ManualDiffHelpList* m_pManualDiffHelpList; - - class WrapLineCacheData - { - public: - WrapLineCacheData() : m_d3LineIdx(0), m_textStart(0), m_textLength(0) {} - WrapLineCacheData( int d3LineIdx, int textStart, int textLength ) - : m_d3LineIdx(d3LineIdx), m_textStart(textStart), m_textLength(textLength) {} - int m_d3LineIdx; int m_textStart; int m_textLength; - }; - QList< QVector > m_wrapLineCacheList; - - Options* m_pOptions; - QColor m_cThis; - QColor m_cDiff1; - QColor m_cDiff2; - QColor m_cDiffBoth; - - int m_fastSelectorLine1; - int m_fastSelectorNofLines; - - bool m_bTriple; - int m_winIdx; - int m_firstLine; - int m_oldFirstLine; - int m_horizScrollOffset; - int m_lineNumberWidth; - QAtomicInt m_maxTextWidth; - - void getLineInfo( - const Diff3Line& d, - int& lineIdx, - DiffList*& pFineDiff1, DiffList*& pFineDiff2, // return values - int& changed, int& changed2 ); - - QString getString( int d3lIdx ); - QString getLineString( int line ); - - void writeLine( - MyPainter& p, const LineData* pld, - const DiffList* pLineDiff1, const DiffList* pLineDiff2, int line, - int whatChanged, int whatChanged2, int srcLineIdx, - int wrapLineOffset, int wrapLineLength, bool bWrapLine, const QRect& invalidRect, int deviceWidth - ); - - void draw( MyPainter& p, const QRect& invalidRect, int deviceWidth, int beginLine, int endLine ); - - QStatusBar* m_pStatusBar; - - Selection m_selection; - - int m_scrollDeltaX; - int m_scrollDeltaY; - - bool m_bMyUpdate; - void myUpdate(int afterMilliSecs ); - - int leftInfoWidth() { return 4+m_lineNumberWidth; } // Nr of information columns on left side - int convertLineOnScreenToLineInSource( int lineOnScreen, e_CoordType coordType, bool bFirstLine ); - - bool m_bSelectionInProgress; - QPoint m_lastKnownMousePos; - void prepareTextLayout( QTextLayout& textLayout, bool bFirstLine, int visibleTextWidth=-1 ); + public: + DiffTextWindowData(DiffTextWindow* p) + { + m_pDiffTextWindow = p; + m_bPaintingAllowed = false; + m_pLineData = 0; + m_size = 0; + m_bWordWrap = false; + m_delayedDrawTimer = 0; + m_pDiff3LineVector = 0; + m_pManualDiffHelpList = 0; + m_pOptions = 0; + m_fastSelectorLine1 = 0; + m_fastSelectorNofLines = 0; + m_bTriple = 0; + m_winIdx = 0; + m_firstLine = 0; + m_oldFirstLine = 0; + m_horizScrollOffset = 0; + m_lineNumberWidth = 0; + m_maxTextWidth = -1; + m_pStatusBar = 0; + m_scrollDeltaX = 0; + m_scrollDeltaY = 0; + m_bMyUpdate = false; + m_bSelectionInProgress = false; + m_pTextCodec = 0; +#if defined(_WIN32) || defined(Q_OS_OS2) + m_eLineEndStyle = eLineEndStyleDos; +#else + m_eLineEndStyle = eLineEndStyleUnix; +#endif + } + DiffTextWindow* m_pDiffTextWindow; + DiffTextWindowFrame* m_pDiffTextWindowFrame; + QTextCodec* m_pTextCodec; + e_LineEndStyle m_eLineEndStyle; + + bool m_bPaintingAllowed; + const LineData* m_pLineData; + int m_size; + QString m_filename; + bool m_bWordWrap; + int m_delayedDrawTimer; + + const Diff3LineVector* m_pDiff3LineVector; + Diff3WrapLineVector m_diff3WrapLineVector; + const ManualDiffHelpList* m_pManualDiffHelpList; + + class WrapLineCacheData + { + public: + WrapLineCacheData() : m_d3LineIdx(0), m_textStart(0), m_textLength(0) {} + WrapLineCacheData(int d3LineIdx, int textStart, int textLength) + : m_d3LineIdx(d3LineIdx), m_textStart(textStart), m_textLength(textLength) {} + int m_d3LineIdx; + int m_textStart; + int m_textLength; + }; + QList> m_wrapLineCacheList; + + Options* m_pOptions; + QColor m_cThis; + QColor m_cDiff1; + QColor m_cDiff2; + QColor m_cDiffBoth; + + int m_fastSelectorLine1; + int m_fastSelectorNofLines; + + bool m_bTriple; + int m_winIdx; + int m_firstLine; + int m_oldFirstLine; + int m_horizScrollOffset; + int m_lineNumberWidth; + QAtomicInt m_maxTextWidth; + + void getLineInfo( + const Diff3Line& d, + int& lineIdx, + DiffList*& pFineDiff1, DiffList*& pFineDiff2, // return values + int& changed, int& changed2); + + QString getString(int d3lIdx); + QString getLineString(int line); + + void writeLine( + MyPainter& p, const LineData* pld, + const DiffList* pLineDiff1, const DiffList* pLineDiff2, int line, + int whatChanged, int whatChanged2, int srcLineIdx, + int wrapLineOffset, int wrapLineLength, bool bWrapLine, const QRect& invalidRect, int deviceWidth); + + void draw(MyPainter& p, const QRect& invalidRect, int deviceWidth, int beginLine, int endLine); + + QStatusBar* m_pStatusBar; + + Selection m_selection; + + int m_scrollDeltaX; + int m_scrollDeltaY; + + bool m_bMyUpdate; + void myUpdate(int afterMilliSecs); + + int leftInfoWidth() { return 4 + m_lineNumberWidth; } // Nr of information columns on left side + int convertLineOnScreenToLineInSource(int lineOnScreen, e_CoordType coordType, bool bFirstLine); + + bool m_bSelectionInProgress; + QPoint m_lastKnownMousePos; + void prepareTextLayout(QTextLayout& textLayout, bool bFirstLine, int visibleTextWidth = -1); }; DiffTextWindow::DiffTextWindow( - DiffTextWindowFrame* pParent, - QStatusBar* pStatusBar, - Options* pOptions, - int winIdx - ) - : QWidget(pParent) + DiffTextWindowFrame* pParent, + QStatusBar* pStatusBar, + Options* pOptions, + int winIdx) + : QWidget(pParent) { - setObjectName(QString("DiffTextWindow%1").arg(winIdx)); - setAttribute( Qt::WA_OpaquePaintEvent ); - //setAttribute( Qt::WA_PaintOnScreen ); + setObjectName(QString("DiffTextWindow%1").arg(winIdx)); + setAttribute(Qt::WA_OpaquePaintEvent); + //setAttribute( Qt::WA_PaintOnScreen ); - d = new DiffTextWindowData(this); - d->m_pDiffTextWindowFrame = pParent; - setFocusPolicy( Qt::ClickFocus ); - setAcceptDrops( true ); + d = new DiffTextWindowData(this); + d->m_pDiffTextWindowFrame = pParent; + setFocusPolicy(Qt::ClickFocus); + setAcceptDrops(true); - d->m_pOptions = pOptions; - init( 0, 0, d->m_eLineEndStyle, 0, 0, 0, 0, false ); + d->m_pOptions = pOptions; + init(0, 0, d->m_eLineEndStyle, 0, 0, 0, 0, false); - setMinimumSize(QSize(20,20)); + setMinimumSize(QSize(20, 20)); - d->m_pStatusBar = pStatusBar; - d->m_bPaintingAllowed = true; - d->m_bWordWrap = false; - d->m_winIdx = winIdx; + d->m_pStatusBar = pStatusBar; + d->m_bPaintingAllowed = true; + d->m_bWordWrap = false; + d->m_winIdx = winIdx; - setFont(d->m_pOptions->m_font); + setFont(d->m_pOptions->m_font); } DiffTextWindow::~DiffTextWindow() { - delete d; + delete d; } void DiffTextWindow::init( - const QString& filename, - QTextCodec* pTextCodec, - e_LineEndStyle eLineEndStyle, - const LineData* pLineData, - int size, - const Diff3LineVector* pDiff3LineVector, - const ManualDiffHelpList* pManualDiffHelpList, - bool bTriple - ) -{ - d->m_filename = filename; - d->m_pLineData = pLineData; - d->m_size = size; - d->m_pDiff3LineVector = pDiff3LineVector; - d->m_diff3WrapLineVector.clear(); - d->m_pManualDiffHelpList = pManualDiffHelpList; - - d->m_firstLine = 0; - d->m_oldFirstLine = -1; - d->m_horizScrollOffset = 0; - d->m_bTriple = bTriple; - d->m_scrollDeltaX=0; - d->m_scrollDeltaY=0; - d->m_bMyUpdate = false; - d->m_fastSelectorLine1 = 0; - d->m_fastSelectorNofLines = 0; - d->m_lineNumberWidth = 0; - d->m_maxTextWidth = -1; - d->m_selection.reset(); - d->m_selection.oldFirstLine = -1; // reset is not enough here. - d->m_selection.oldLastLine = -1; - d->m_selection.lastLine = -1; - - d->m_pTextCodec = pTextCodec; - d->m_eLineEndStyle = eLineEndStyle; - - update(); - d->m_pDiffTextWindowFrame->init(); + const QString& filename, + QTextCodec* pTextCodec, + e_LineEndStyle eLineEndStyle, + const LineData* pLineData, + int size, + const Diff3LineVector* pDiff3LineVector, + const ManualDiffHelpList* pManualDiffHelpList, + bool bTriple) +{ + d->m_filename = filename; + d->m_pLineData = pLineData; + d->m_size = size; + d->m_pDiff3LineVector = pDiff3LineVector; + d->m_diff3WrapLineVector.clear(); + d->m_pManualDiffHelpList = pManualDiffHelpList; + + d->m_firstLine = 0; + d->m_oldFirstLine = -1; + d->m_horizScrollOffset = 0; + d->m_bTriple = bTriple; + d->m_scrollDeltaX = 0; + d->m_scrollDeltaY = 0; + d->m_bMyUpdate = false; + d->m_fastSelectorLine1 = 0; + d->m_fastSelectorNofLines = 0; + d->m_lineNumberWidth = 0; + d->m_maxTextWidth = -1; + d->m_selection.reset(); + d->m_selection.oldFirstLine = -1; // reset is not enough here. + d->m_selection.oldLastLine = -1; + d->m_selection.lastLine = -1; + + d->m_pTextCodec = pTextCodec; + d->m_eLineEndStyle = eLineEndStyle; + + update(); + d->m_pDiffTextWindowFrame->init(); } void DiffTextWindow::reset() { - d->m_pLineData=0; - d->m_size=0; - d->m_pDiff3LineVector=0; - d->m_filename=""; - d->m_diff3WrapLineVector.clear(); + d->m_pLineData = 0; + d->m_size = 0; + d->m_pDiff3LineVector = 0; + d->m_filename = ""; + d->m_diff3WrapLineVector.clear(); } -void DiffTextWindow::setPaintingAllowed( bool bAllowPainting ) +void DiffTextWindow::setPaintingAllowed(bool bAllowPainting) { - if (d->m_bPaintingAllowed != bAllowPainting) - { - d->m_bPaintingAllowed = bAllowPainting; - if ( d->m_bPaintingAllowed ) update(); - else reset(); - } + if(d->m_bPaintingAllowed != bAllowPainting) + { + d->m_bPaintingAllowed = bAllowPainting; + if(d->m_bPaintingAllowed) + update(); + else + reset(); + } } -void DiffTextWindow::dragEnterEvent( QDragEnterEvent* e ) +void DiffTextWindow::dragEnterEvent(QDragEnterEvent* e) { - e->setAccepted( e->mimeData()->hasUrls() || e->mimeData()->hasText() ); - // Note that the corresponding drop is handled in KDiff3App::eventFilter(). + e->setAccepted(e->mimeData()->hasUrls() || e->mimeData()->hasText()); + // Note that the corresponding drop is handled in KDiff3App::eventFilter(). } - void DiffTextWindow::setFirstLine(int firstLine) { - int fontHeight = fontMetrics().lineSpacing(); + int fontHeight = fontMetrics().lineSpacing(); - int newFirstLine = max2(0,firstLine); + int newFirstLine = max2(0, firstLine); - int deltaY = fontHeight * ( d->m_firstLine - newFirstLine ); + int deltaY = fontHeight * (d->m_firstLine - newFirstLine); - d->m_firstLine = newFirstLine; + d->m_firstLine = newFirstLine; - if ( d->m_bSelectionInProgress && d->m_selection.firstLine != -1 ) - { - int line, pos; - convertToLinePos( d->m_lastKnownMousePos.x(), d->m_lastKnownMousePos.y(), line, pos ); - d->m_selection.end( line, pos ); - update(); - } - else - { - QWidget::scroll( 0, deltaY ); - } - d->m_pDiffTextWindowFrame->setFirstLine( d->m_firstLine ); + if(d->m_bSelectionInProgress && d->m_selection.firstLine != -1) + { + int line, pos; + convertToLinePos(d->m_lastKnownMousePos.x(), d->m_lastKnownMousePos.y(), line, pos); + d->m_selection.end(line, pos); + update(); + } + else + { + QWidget::scroll(0, deltaY); + } + d->m_pDiffTextWindowFrame->setFirstLine(d->m_firstLine); } int DiffTextWindow::getFirstLine() { - return d->m_firstLine; + return d->m_firstLine; } void DiffTextWindow::setHorizScrollOffset(int horizScrollOffset) { - int fontWidth = fontMetrics().width('0'); - int xOffset = d->leftInfoWidth() * fontWidth; + int fontWidth = fontMetrics().width('0'); + int xOffset = d->leftInfoWidth() * fontWidth; - int deltaX = d->m_horizScrollOffset - qMax(0,horizScrollOffset); + int deltaX = d->m_horizScrollOffset - qMax(0, horizScrollOffset); - d->m_horizScrollOffset = qMax(0,horizScrollOffset); + d->m_horizScrollOffset = qMax(0, horizScrollOffset); - QRect r( xOffset, 0, width()-xOffset, height() ); + QRect r(xOffset, 0, width() - xOffset, height()); - if ( d->m_pOptions->m_bRightToLeftLanguage ) - { - deltaX = -deltaX; - r = QRect( width()-xOffset-2, 0, -(width()-xOffset), height() ).normalized(); - } + if(d->m_pOptions->m_bRightToLeftLanguage) + { + deltaX = -deltaX; + r = QRect(width() - xOffset - 2, 0, -(width() - xOffset), height()).normalized(); + } - if ( d->m_bSelectionInProgress && d->m_selection.firstLine != -1 ) - { - int line, pos; - convertToLinePos( d->m_lastKnownMousePos.x(), d->m_lastKnownMousePos.y(), line, pos ); - d->m_selection.end( line, pos ); - update(); - } - else - { - QWidget::scroll( deltaX, 0, r ); - } + if(d->m_bSelectionInProgress && d->m_selection.firstLine != -1) + { + int line, pos; + convertToLinePos(d->m_lastKnownMousePos.x(), d->m_lastKnownMousePos.y(), line, pos); + d->m_selection.end(line, pos); + update(); + } + else + { + QWidget::scroll(deltaX, 0, r); + } } int DiffTextWindow::getMaxTextWidth() { - if (d->m_bWordWrap) - { - return getVisibleTextAreaWidth(); - } - else if ( getAtomic( d->m_maxTextWidth ) < 0 ) - { - d->m_maxTextWidth = 0; - QTextLayout textLayout(QString(), font(), this); - for( int i = 0; i< d->m_size; ++i ) - { - textLayout.clearLayout(); - textLayout.setText(d->getString(i)); - d->prepareTextLayout( textLayout, true ); - if ( textLayout.maximumWidth() > getAtomic( d->m_maxTextWidth ) ) - d->m_maxTextWidth = textLayout.maximumWidth(); - } - } - return getAtomic( d->m_maxTextWidth ); + if(d->m_bWordWrap) + { + return getVisibleTextAreaWidth(); + } + else if(getAtomic(d->m_maxTextWidth) < 0) + { + d->m_maxTextWidth = 0; + QTextLayout textLayout(QString(), font(), this); + for(int i = 0; i < d->m_size; ++i) + { + textLayout.clearLayout(); + textLayout.setText(d->getString(i)); + d->prepareTextLayout(textLayout, true); + if(textLayout.maximumWidth() > getAtomic(d->m_maxTextWidth)) + d->m_maxTextWidth = textLayout.maximumWidth(); + } + } + return getAtomic(d->m_maxTextWidth); } int DiffTextWindow::getNofLines() { - return d->m_bWordWrap ? d->m_diff3WrapLineVector.size() : - d->m_pDiff3LineVector->size(); + return d->m_bWordWrap ? d->m_diff3WrapLineVector.size() : d->m_pDiff3LineVector->size(); } - -int DiffTextWindow::convertLineToDiff3LineIdx( int line ) +int DiffTextWindow::convertLineToDiff3LineIdx(int line) { - if ( line>=0 && d->m_bWordWrap && d->m_diff3WrapLineVector.size()>0 ) - return d->m_diff3WrapLineVector[ min2( line, (int)d->m_diff3WrapLineVector.size()-1 ) ].diff3LineIndex; - else - return line; + if(line >= 0 && d->m_bWordWrap && d->m_diff3WrapLineVector.size() > 0) + return d->m_diff3WrapLineVector[min2(line, (int)d->m_diff3WrapLineVector.size() - 1)].diff3LineIndex; + else + return line; } -int DiffTextWindow::convertDiff3LineIdxToLine( int d3lIdx ) +int DiffTextWindow::convertDiff3LineIdxToLine(int d3lIdx) { - if ( d->m_bWordWrap && d->m_pDiff3LineVector!=0 && d->m_pDiff3LineVector->size()>0 ) - return (*d->m_pDiff3LineVector)[ min2( d3lIdx, (int)d->m_pDiff3LineVector->size()-1 ) ]->sumLinesNeededForDisplay; - else - return d3lIdx; + if(d->m_bWordWrap && d->m_pDiff3LineVector != 0 && d->m_pDiff3LineVector->size() > 0) + return (*d->m_pDiff3LineVector)[min2(d3lIdx, (int)d->m_pDiff3LineVector->size() - 1)]->sumLinesNeededForDisplay; + else + return d3lIdx; } /** Returns a line number where the linerange [line, line+nofLines] can be displayed best. If it fits into the currently visible range then the returned value is the current firstLine. */ -int getBestFirstLine( int line, int nofLines, int firstLine, int visibleLines ) +int 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); - } + 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; + return newFirstLine; } +void DiffTextWindow::setFastSelectorRange(int line1, int nofLines) +{ + d->m_fastSelectorLine1 = line1; + d->m_fastSelectorNofLines = nofLines; + if(isVisible()) + { + int newFirstLine = getBestFirstLine( + convertDiff3LineIdxToLine(d->m_fastSelectorLine1), + convertDiff3LineIdxToLine(d->m_fastSelectorLine1 + d->m_fastSelectorNofLines) - convertDiff3LineIdxToLine(d->m_fastSelectorLine1), + d->m_firstLine, + getNofVisibleLines()); + if(newFirstLine != d->m_firstLine) + { + scroll(0, newFirstLine - d->m_firstLine); + } + + update(); + } +} -void DiffTextWindow::setFastSelectorRange( int line1, int nofLines ) +void DiffTextWindow::showStatusLine(int line) { - d->m_fastSelectorLine1 = line1; - d->m_fastSelectorNofLines = nofLines; - if ( isVisible() ) - { - int newFirstLine = getBestFirstLine( - convertDiff3LineIdxToLine(d->m_fastSelectorLine1), - convertDiff3LineIdxToLine(d->m_fastSelectorLine1+d->m_fastSelectorNofLines)-convertDiff3LineIdxToLine(d->m_fastSelectorLine1), - d->m_firstLine, - getNofVisibleLines() - ); - if ( newFirstLine != d->m_firstLine ) - { - scroll( 0, newFirstLine - d->m_firstLine ); - } + int d3lIdx = convertLineToDiff3LineIdx(line); + if(d->m_pDiff3LineVector != 0 && d3lIdx >= 0 && d3lIdx < (int)d->m_pDiff3LineVector->size()) + { + const Diff3Line* pD3l = (*d->m_pDiff3LineVector)[d3lIdx]; + if(pD3l != 0) + { + int l = pD3l->getLineInFile(d->m_winIdx); + + QString s = i18n("File") + " " + d->m_filename; + if(l != -1) + s += ": " + i18n("Line") + " " + QString::number(l + 1); + else + s += ": " + i18n("Line not available"); + if(d->m_pStatusBar != 0) d->m_pStatusBar->showMessage(s); - update(); - } + emit lineClicked(d->m_winIdx, l); + } + } } +void DiffTextWindow::focusInEvent(QFocusEvent* e) +{ + emit gotFocus(); + QWidget::focusInEvent(e); +} -void DiffTextWindow::showStatusLine(int line ) +void DiffTextWindow::mousePressEvent(QMouseEvent* e) { - int d3lIdx = convertLineToDiff3LineIdx( line ); - if( d->m_pDiff3LineVector!=0 && d3lIdx >= 0 && d3lIdx<(int)d->m_pDiff3LineVector->size() ) - { - const Diff3Line* pD3l = (*d->m_pDiff3LineVector)[d3lIdx]; - if ( pD3l != 0 ) - { - int l = pD3l->getLineInFile( d->m_winIdx ); + if(e->button() == Qt::LeftButton) + { + int line; + int pos; + convertToLinePos(e->x(), e->y(), line, pos); - QString s = i18n("File") + " " + d->m_filename; - if ( l!=-1 ) - s += ": " + i18n("Line") + " " + QString::number( l+1 ); - else - s += ": " + i18n("Line not available"); - if (d->m_pStatusBar!=0) d->m_pStatusBar->showMessage(s); + int fontWidth = fontMetrics().width('0'); + int xOffset = d->leftInfoWidth() * fontWidth; - emit lineClicked( d->m_winIdx, l ); - } - } + if((!d->m_pOptions->m_bRightToLeftLanguage && e->x() < xOffset) || (d->m_pOptions->m_bRightToLeftLanguage && e->x() > width() - xOffset)) + { + emit setFastSelectorLine(convertLineToDiff3LineIdx(line)); + d->m_selection.firstLine = -1; // Disable current d->m_selection + } + else + { // Selection + resetSelection(); + d->m_selection.start(line, pos); + d->m_selection.end(line, pos); + d->m_bSelectionInProgress = true; + d->m_lastKnownMousePos = e->pos(); + + showStatusLine(line); + } + } } -void DiffTextWindow::focusInEvent(QFocusEvent* e) +bool isCTokenChar(QChar c) { - emit gotFocus(); - QWidget::focusInEvent(e); + return (c == '_') || + (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9'); } -void DiffTextWindow::mousePressEvent ( QMouseEvent* e ) +/// Calculate where a token starts and ends, given the x-position on screen. +void calcTokenPos(const QString& s, int posOnScreen, int& pos1, int& pos2, int tabSize) { - if ( e->button() == Qt::LeftButton ) - { - int line; - int pos; - convertToLinePos( e->x(), e->y(), line, pos ); + // Cursor conversions that consider g_tabSize + int pos = convertToPosInText(s, max2(0, posOnScreen), tabSize); + if(pos >= (int)s.length()) + { + pos1 = s.length(); + pos2 = s.length(); + return; + } - int fontWidth = fontMetrics().width('0'); - int xOffset = d->leftInfoWidth() * fontWidth; + pos1 = pos; + pos2 = pos + 1; - if ( (! d->m_pOptions->m_bRightToLeftLanguage && e->x() < xOffset ) - || ( d->m_pOptions->m_bRightToLeftLanguage && e->x() > width() - xOffset ) ) - { - emit setFastSelectorLine( convertLineToDiff3LineIdx(line) ); - d->m_selection.firstLine = -1; // Disable current d->m_selection - } - else - { // Selection - resetSelection(); - d->m_selection.start( line, pos ); - d->m_selection.end( line, pos ); - d->m_bSelectionInProgress = true; - d->m_lastKnownMousePos = e->pos(); + if(isCTokenChar(s[pos1])) + { + while(pos1 >= 0 && isCTokenChar(s[pos1])) + --pos1; + ++pos1; - showStatusLine( line ); - } - } + while(pos2 < (int)s.length() && isCTokenChar(s[pos2])) + ++pos2; + } } -bool isCTokenChar( QChar c ) +void DiffTextWindow::mouseDoubleClickEvent(QMouseEvent* e) { - return (c=='_') || - ( c>='A' && c<='Z' ) || ( c>='a' && c<='z' ) || - (c>='0' && c<='9'); + d->m_bSelectionInProgress = false; + d->m_lastKnownMousePos = e->pos(); + if(e->button() == Qt::LeftButton) + { + int line; + int pos; + convertToLinePos(e->x(), e->y(), line, pos); + + // Get the string data of the current line + QString s; + if(d->m_bWordWrap) + { + if(line < 0 || line >= (int)d->m_diff3WrapLineVector.size()) + return; + const Diff3WrapLine& d3wl = d->m_diff3WrapLineVector[line]; + s = d->getString(d3wl.diff3LineIndex).mid(d3wl.wrapLineOffset, d3wl.wrapLineLength); + } + else + { + if(line < 0 || line >= (int)d->m_pDiff3LineVector->size()) + return; + s = d->getString(line); + } + + if(!s.isEmpty()) + { + int pos1, pos2; + calcTokenPos(s, pos, pos1, pos2, d->m_pOptions->m_tabSize); + + resetSelection(); + d->m_selection.start(line, convertToPosOnScreen(s, pos1, d->m_pOptions->m_tabSize)); + d->m_selection.end(line, convertToPosOnScreen(s, pos2, d->m_pOptions->m_tabSize)); + update(); + // emit d->m_selectionEnd() happens in the mouseReleaseEvent. + showStatusLine(line); + } + } } -/// Calculate where a token starts and ends, given the x-position on screen. -void calcTokenPos( const QString& s, int posOnScreen, int& pos1, int& pos2, int tabSize ) -{ - // Cursor conversions that consider g_tabSize - int pos = convertToPosInText( s, max2( 0, posOnScreen ), tabSize ); - if ( pos>=(int)s.length() ) - { - pos1=s.length(); - pos2=s.length(); - return; - } - - pos1 = pos; - pos2 = pos+1; - - if( isCTokenChar( s[pos1] ) ) - { - while( pos1>=0 && isCTokenChar( s[pos1] ) ) - --pos1; - ++pos1; - - while( pos2<(int)s.length() && isCTokenChar( s[pos2] ) ) - ++pos2; - } -} - -void DiffTextWindow::mouseDoubleClickEvent( QMouseEvent* e ) -{ - d->m_bSelectionInProgress = false; - d->m_lastKnownMousePos = e->pos(); - if ( e->button() == Qt::LeftButton ) - { - int line; - int pos; - convertToLinePos( e->x(), e->y(), line, pos ); - - // Get the string data of the current line - QString s; - if ( d->m_bWordWrap ) - { - if ( line<0 || line >= (int)d->m_diff3WrapLineVector.size() ) - return; - const Diff3WrapLine& d3wl = d->m_diff3WrapLineVector[line]; - s = d->getString( d3wl.diff3LineIndex ).mid( d3wl.wrapLineOffset, d3wl.wrapLineLength ); - } - else - { - if ( line<0 || line >= (int)d->m_pDiff3LineVector->size() ) - return; - s = d->getString( line ); - } - - if ( ! s.isEmpty() ) - { - int pos1, pos2; - calcTokenPos( s, pos, pos1, pos2, d->m_pOptions->m_tabSize ); - - resetSelection(); - d->m_selection.start( line, convertToPosOnScreen( s, pos1, d->m_pOptions->m_tabSize ) ); - d->m_selection.end( line, convertToPosOnScreen( s, pos2, d->m_pOptions->m_tabSize ) ); - update(); - // emit d->m_selectionEnd() happens in the mouseReleaseEvent. - showStatusLine( line ); - } - } -} - -void DiffTextWindow::mouseReleaseEvent ( QMouseEvent* e ) -{ - d->m_bSelectionInProgress = false; - d->m_lastKnownMousePos = e->pos(); - //if ( e->button() == LeftButton ) - { - if (d->m_delayedDrawTimer) - killTimer(d->m_delayedDrawTimer); - d->m_delayedDrawTimer = 0; - if (d->m_selection.firstLine != -1 ) - { - emit selectionEnd(); - } - } - d->m_scrollDeltaX=0; - d->m_scrollDeltaY=0; -} - -inline int sqr(int x){return x*x;} - -void DiffTextWindow::mouseMoveEvent ( QMouseEvent * e ) -{ - int line; - int pos; - convertToLinePos( e->x(), e->y(), line, pos ); - d->m_lastKnownMousePos = e->pos(); - - if (d->m_selection.firstLine != -1 ) - { - d->m_selection.end( line, pos ); - - showStatusLine( line ); - - // Scroll because mouse moved out of the window - const QFontMetrics& fm = fontMetrics(); - int fontWidth = fm.width('0'); - int deltaX=0; - int deltaY=0; - if ( ! d->m_pOptions->m_bRightToLeftLanguage ) - { - if ( e->x() < d->leftInfoWidth()*fontWidth ) deltaX = -1 - abs(e->x()-d->leftInfoWidth()*fontWidth)/fontWidth; - if ( e->x() > width() ) deltaX = +1 + abs(e->x()-width())/fontWidth; - } - else - { - if ( e->x() > width()-1-d->leftInfoWidth()*fontWidth ) deltaX=+1+ abs(e->x() - (width()-1-d->leftInfoWidth()*fontWidth)) / fontWidth; - if ( e->x() < fontWidth ) deltaX=-1- abs(e->x()-fontWidth)/fontWidth; - } - if ( e->y() < 0 ) deltaY = -1 - sqr( e->y() ) / sqr(fm.lineSpacing()); - if ( e->y() > height() ) deltaY = +1 + sqr( e->y() - height() ) / sqr(fm.lineSpacing()); - if ( (deltaX != 0 && d->m_scrollDeltaX!=deltaX) || (deltaY!= 0 && d->m_scrollDeltaY!=deltaY) ) - { - d->m_scrollDeltaX = deltaX; - d->m_scrollDeltaY = deltaY; - emit scroll( deltaX, deltaY ); - if (d->m_delayedDrawTimer) - killTimer( d->m_delayedDrawTimer ); - d->m_delayedDrawTimer = startTimer(50); - } - else - { - d->m_scrollDeltaX = deltaX; - d->m_scrollDeltaY = deltaY; - d->myUpdate(0); - } - } +void DiffTextWindow::mouseReleaseEvent(QMouseEvent* e) +{ + d->m_bSelectionInProgress = false; + d->m_lastKnownMousePos = e->pos(); + //if ( e->button() == LeftButton ) + { + if(d->m_delayedDrawTimer) + killTimer(d->m_delayedDrawTimer); + d->m_delayedDrawTimer = 0; + if(d->m_selection.firstLine != -1) + { + emit selectionEnd(); + } + } + d->m_scrollDeltaX = 0; + d->m_scrollDeltaY = 0; } +inline int sqr(int x) { return x * x; } + +void DiffTextWindow::mouseMoveEvent(QMouseEvent* e) +{ + int line; + int pos; + convertToLinePos(e->x(), e->y(), line, pos); + d->m_lastKnownMousePos = e->pos(); + + if(d->m_selection.firstLine != -1) + { + d->m_selection.end(line, pos); + + showStatusLine(line); + + // Scroll because mouse moved out of the window + const QFontMetrics& fm = fontMetrics(); + int fontWidth = fm.width('0'); + int deltaX = 0; + int deltaY = 0; + if(!d->m_pOptions->m_bRightToLeftLanguage) + { + if(e->x() < d->leftInfoWidth() * fontWidth) deltaX = -1 - abs(e->x() - d->leftInfoWidth() * fontWidth) / fontWidth; + if(e->x() > width()) deltaX = +1 + abs(e->x() - width()) / fontWidth; + } + else + { + if(e->x() > width() - 1 - d->leftInfoWidth() * fontWidth) deltaX = +1 + abs(e->x() - (width() - 1 - d->leftInfoWidth() * fontWidth)) / fontWidth; + if(e->x() < fontWidth) deltaX = -1 - abs(e->x() - fontWidth) / fontWidth; + } + if(e->y() < 0) deltaY = -1 - sqr(e->y()) / sqr(fm.lineSpacing()); + if(e->y() > height()) deltaY = +1 + sqr(e->y() - height()) / sqr(fm.lineSpacing()); + if((deltaX != 0 && d->m_scrollDeltaX != deltaX) || (deltaY != 0 && d->m_scrollDeltaY != deltaY)) + { + d->m_scrollDeltaX = deltaX; + d->m_scrollDeltaY = deltaY; + emit scroll(deltaX, deltaY); + if(d->m_delayedDrawTimer) + killTimer(d->m_delayedDrawTimer); + d->m_delayedDrawTimer = startTimer(50); + } + else + { + d->m_scrollDeltaX = deltaX; + d->m_scrollDeltaY = deltaY; + d->myUpdate(0); + } + } +} void DiffTextWindowData::myUpdate(int afterMilliSecs) { - if (m_delayedDrawTimer) - m_pDiffTextWindow->killTimer( m_delayedDrawTimer ); - m_bMyUpdate = true; - m_delayedDrawTimer = m_pDiffTextWindow->startTimer( afterMilliSecs ); + if(m_delayedDrawTimer) + m_pDiffTextWindow->killTimer(m_delayedDrawTimer); + m_bMyUpdate = true; + m_delayedDrawTimer = m_pDiffTextWindow->startTimer(afterMilliSecs); } void DiffTextWindow::timerEvent(QTimerEvent*) { - killTimer(d->m_delayedDrawTimer); - d->m_delayedDrawTimer = 0; - - if ( d->m_bMyUpdate ) - { - int fontHeight = fontMetrics().lineSpacing(); - - if ( d->m_selection.oldLastLine != -1 ) - { - int lastLine; - int firstLine; - if ( d->m_selection.oldFirstLine != -1 ) - { - firstLine = min3( d->m_selection.oldFirstLine, d->m_selection.lastLine, d->m_selection.oldLastLine ); - lastLine = max3( d->m_selection.oldFirstLine, d->m_selection.lastLine, d->m_selection.oldLastLine ); - } - else - { - firstLine = min2( d->m_selection.lastLine, d->m_selection.oldLastLine ); - lastLine = max2( d->m_selection.lastLine, d->m_selection.oldLastLine ); - } - int y1 = ( firstLine - d->m_firstLine ) * fontHeight; - int y2 = min2( height(), ( lastLine - d->m_firstLine + 1 ) * fontHeight ); - - if ( y10 ) - { - QRect invalidRect = QRect( 0, y1-1, width(), y2-y1+fontHeight); // Some characters in exotic exceed the regular bottom. - update( invalidRect ); - } - } - - d->m_bMyUpdate = false; - } - - if ( d->m_scrollDeltaX != 0 || d->m_scrollDeltaY != 0 ) - { - d->m_selection.end( d->m_selection.lastLine + d->m_scrollDeltaY, d->m_selection.lastPos + d->m_scrollDeltaX ); - emit scroll( d->m_scrollDeltaX, d->m_scrollDeltaY ); - killTimer(d->m_delayedDrawTimer); - d->m_delayedDrawTimer = startTimer(50); - } + killTimer(d->m_delayedDrawTimer); + d->m_delayedDrawTimer = 0; + + if(d->m_bMyUpdate) + { + int fontHeight = fontMetrics().lineSpacing(); + + if(d->m_selection.oldLastLine != -1) + { + int lastLine; + int firstLine; + if(d->m_selection.oldFirstLine != -1) + { + firstLine = min3(d->m_selection.oldFirstLine, d->m_selection.lastLine, d->m_selection.oldLastLine); + lastLine = max3(d->m_selection.oldFirstLine, d->m_selection.lastLine, d->m_selection.oldLastLine); + } + else + { + firstLine = min2(d->m_selection.lastLine, d->m_selection.oldLastLine); + lastLine = max2(d->m_selection.lastLine, d->m_selection.oldLastLine); + } + int y1 = (firstLine - d->m_firstLine) * fontHeight; + int y2 = min2(height(), (lastLine - d->m_firstLine + 1) * fontHeight); + + if(y1 < height() && y2 > 0) + { + QRect invalidRect = QRect(0, y1 - 1, width(), y2 - y1 + fontHeight); // Some characters in exotic exceed the regular bottom. + update(invalidRect); + } + } + + d->m_bMyUpdate = false; + } + + if(d->m_scrollDeltaX != 0 || d->m_scrollDeltaY != 0) + { + d->m_selection.end(d->m_selection.lastLine + d->m_scrollDeltaY, d->m_selection.lastPos + d->m_scrollDeltaX); + emit scroll(d->m_scrollDeltaX, d->m_scrollDeltaY); + killTimer(d->m_delayedDrawTimer); + d->m_delayedDrawTimer = startTimer(50); + } } void DiffTextWindow::resetSelection() { - d->m_selection.reset(); - update(); + d->m_selection.reset(); + update(); } -void DiffTextWindow::convertToLinePos( int x, int y, int& line, int& pos ) +void DiffTextWindow::convertToLinePos(int x, int y, int& line, int& pos) { - const QFontMetrics& fm = fontMetrics(); - int fontHeight = fm.lineSpacing(); + const QFontMetrics& fm = fontMetrics(); + int fontHeight = fm.lineSpacing(); - int yOffset = - d->m_firstLine * fontHeight; + int yOffset = -d->m_firstLine * fontHeight; - line = ( y - yOffset ) / fontHeight; - if ( line >= 0 && (!d->m_pOptions->m_bWordWrap || line < d->m_diff3WrapLineVector.count()) ) - { - QString s = d->getLineString( line ); - QTextLayout textLayout( s, font(), this ); - d->prepareTextLayout( textLayout, !d->m_pOptions->m_bWordWrap || d->m_diff3WrapLineVector[line].wrapLineOffset==0 ); - pos = textLayout.lineAt(0).xToCursor( x - textLayout.position().x() ); - } - else - pos = -1; + line = (y - yOffset) / fontHeight; + if(line >= 0 && (!d->m_pOptions->m_bWordWrap || line < d->m_diff3WrapLineVector.count())) + { + QString s = d->getLineString(line); + QTextLayout textLayout(s, font(), this); + d->prepareTextLayout(textLayout, !d->m_pOptions->m_bWordWrap || d->m_diff3WrapLineVector[line].wrapLineOffset == 0); + pos = textLayout.lineAt(0).xToCursor(x - textLayout.position().x()); + } + else + pos = -1; } int Selection::firstPosInLine(int l) { - assert( firstLine != -1 ); + 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); } + 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; + if(l == l1) + return p1; + return 0; } int Selection::lastPosInLine(int l) { - assert( firstLine != -1 ); + assert(firstLine != -1); - int l1 = firstLine; - int l2 = lastLine; - int p1 = firstPos; - int p2 = lastPos; + 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 > 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; + if(l == l2) + return p2; + return INT_MAX; } -bool Selection::within( int l, int p ) +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 p l2) { + std::swap(l1, l2); + std::swap(p1, p2); + } + if(l1 == l2 && p1 > p2) { + std::swap(p1, p2); + } + if(l1 <= l && l <= l2) + { + if(l1 == l2) + return p >= p1 && p < p2; + if(l == l1) + return p >= p1; + if(l == l2) + return p < p2; + return true; + } + return false; } -bool Selection::lineWithin( int l ) +bool Selection::lineWithin(int l) { - if ( firstLine == -1 ) return false; - int l1 = firstLine; - int l2 = lastLine; + if(firstLine == -1) return false; + int l1 = firstLine; + int l2 = lastLine; - if ( l1>l2 ){ std::swap(l1,l2); } + if(l1 > l2) { + std::swap(l1, l2); + } - return ( l1 <= l && l <= l2 ); + return (l1 <= l && l <= l2); } - class FormatRangeHelper { -private: - QFont m_font; - QPen m_pen; - QColor m_background; - int m_currentPos; -public: - QVector m_formatRanges; - - FormatRangeHelper() - { - m_pen = QColor(Qt::black); - m_background = QColor(Qt::white); - m_currentPos = 0; - } - void setFont( const QFont& f ) - { - m_font = f; - } - void setPen( const QPen& pen ) - { - m_pen = pen; - } - void setBackground( const QColor& background ) - { - m_background = background; - } - - void next() - { - if ( m_formatRanges.isEmpty() - || m_formatRanges.back().format.foreground().color() != m_pen.color() - || m_formatRanges.back().format.background().color() != m_background - ) - { - QTextLayout::FormatRange fr; - fr.length = 1; - fr.start = m_currentPos; - fr.format.setForeground( m_pen.color() ); - fr.format.setBackground( m_background ); - m_formatRanges.append( fr ); - } - else - { - ++m_formatRanges.back().length; - } - ++m_currentPos; - } + private: + QFont m_font; + QPen m_pen; + QColor m_background; + int m_currentPos; + + public: + QVector m_formatRanges; + + FormatRangeHelper() + { + m_pen = QColor(Qt::black); + m_background = QColor(Qt::white); + m_currentPos = 0; + } + void setFont(const QFont& f) + { + m_font = f; + } + void setPen(const QPen& pen) + { + m_pen = pen; + } + void setBackground(const QColor& background) + { + m_background = background; + } + + void next() + { + if(m_formatRanges.isEmpty() || m_formatRanges.back().format.foreground().color() != m_pen.color() || m_formatRanges.back().format.background().color() != m_background) + { + QTextLayout::FormatRange fr; + fr.length = 1; + fr.start = m_currentPos; + fr.format.setForeground(m_pen.color()); + fr.format.setBackground(m_background); + m_formatRanges.append(fr); + } + else + { + ++m_formatRanges.back().length; + } + ++m_currentPos; + } }; void DiffTextWindowData::prepareTextLayout(QTextLayout& textLayout, bool /*bFirstLine*/, int visibleTextWidth) { QTextOption textOption; textOption.setTabStop(QFontMetricsF(m_pDiffTextWindow->font()).width(' ') * m_pOptions->m_tabSize); if(m_pOptions->m_bShowWhiteSpaceCharacters) textOption.setFlags(QTextOption::ShowTabsAndSpaces); if(m_pOptions->m_bRightToLeftLanguage) textOption.setAlignment(Qt::AlignRight); // only relevant for multi line text layout if(visibleTextWidth >= 0) textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); textLayout.setTextOption(textOption); if(m_pOptions->m_bShowWhiteSpaceCharacters) { // This additional format is only necessary for the tab arrow QList formats; QTextLayout::FormatRange formatRange; formatRange.start = 0; formatRange.length = textLayout.text().length(); formatRange.format.setFont(m_pDiffTextWindow->font()); formats.append(formatRange); textLayout.setAdditionalFormats(formats); } textLayout.beginLayout(); int leading = m_pDiffTextWindow->fontMetrics().leading(); int height = 0; int fontWidth = m_pDiffTextWindow->fontMetrics().width('0'); int xOffset = leftInfoWidth() * fontWidth - m_horizScrollOffset; int textWidth = visibleTextWidth; if(textWidth < 0) textWidth = m_pDiffTextWindow->width() - xOffset; int indentation = 0; while(1) { QTextLine line = textLayout.createLine(); if(!line.isValid()) break; height += leading; //if ( !bFirstLine ) // indentation = m_pDiffTextWindow->fontMetrics().width(' ') * m_pOptions->m_tabSize; if(visibleTextWidth >= 0) { line.setLineWidth(visibleTextWidth - indentation); line.setPosition(QPointF(indentation, height)); height += line.height(); //bFirstLine = false; } else // only one line { line.setPosition(QPointF(indentation, height)); break; } } textLayout.endLayout(); if(m_pOptions->m_bRightToLeftLanguage) textLayout.setPosition(QPointF(textWidth - textLayout.maximumWidth(), 0)); else textLayout.setPosition(QPointF(xOffset, 0)); } void DiffTextWindowData::writeLine( - MyPainter& p, - const LineData* pld, - const DiffList* pLineDiff1, - const DiffList* pLineDiff2, - int line, - int whatChanged, - int whatChanged2, - int srcLineIdx, - int wrapLineOffset, - int wrapLineLength, - bool bWrapLine, - const QRect& invalidRect, - int deviceWidth - ) -{ - QFont normalFont = p.font(); - QFont diffFont = normalFont; - diffFont.setItalic( m_pOptions->m_bItalicForDeltas ); - const QFontMetrics& fm = p.fontMetrics(); - int fontHeight = fm.lineSpacing(); - int fontAscent = fm.ascent(); - int fontWidth = fm.width('0'); - - int xOffset = leftInfoWidth() * fontWidth - m_horizScrollOffset; - int yOffset = (line-m_firstLine) * fontHeight; - - QRect lineRect( 0, yOffset, deviceWidth, fontHeight ); - if ( ! invalidRect.intersects( lineRect ) ) - { - return; - } - - int fastSelectorLine1 = m_pDiffTextWindow->convertDiff3LineIdxToLine(m_fastSelectorLine1); - int fastSelectorLine2 = m_pDiffTextWindow->convertDiff3LineIdxToLine(m_fastSelectorLine1+m_fastSelectorNofLines)-1; - - bool bFastSelectionRange = (line>=fastSelectorLine1 && line<= fastSelectorLine2 ); - QColor bgColor = m_pOptions->m_bgColor; - QColor diffBgColor = m_pOptions->m_diffBgColor; - - if ( bFastSelectionRange ) - { - bgColor = m_pOptions->m_currentRangeBgColor; - diffBgColor = m_pOptions->m_currentRangeDiffBgColor; - } - - if ( yOffset+fontHeightm_fgColor; - p.setPen(c); - if ( changed == 2 ) { - c = m_cDiff2; - } else if ( changed == 1 ) { - c = m_cDiff1; - } else if ( changed == 3 ) { - c = m_cDiffBoth; - } - - if (pld!=0) - { - // First calculate the "changed" information for each character. - int i=0; - QString lineString( pld->pLine, pld->size ); - if ( !lineString.isEmpty() ) - { - switch ( lineString[lineString.length()-1].unicode() ) - { - case '\n' : lineString[lineString.length()-1] = 0x00B6; break; // "Pilcrow", "paragraph mark" - case '\r' : lineString[lineString.length()-1] = 0x00A4; break; // Currency sign ;0x2761 "curved stem paragraph sign ornament" - //case '\0b' : lineString[lineString.length()-1] = 0x2756; break; // some other nice looking character - } - } - QVector charChanged( pld->size ); - Merger merger( pLineDiff1, pLineDiff2 ); - while( ! merger.isEndReached() && isize ) - { - if ( i < pld->size ) - { - charChanged[i] = merger.whatChanged(); - ++i; - } - merger.next(); - } - - int outPos = 0; - - int lineLength = m_bWordWrap ? wrapLineOffset+wrapLineLength : lineString.length(); - - FormatRangeHelper frh; - - for( i=wrapLineOffset; im_fgColor; - int cchanged = charChanged[i] | whatChanged; - - if ( cchanged == 2 ) { - c = m_cDiff2; - } else if ( cchanged == 1 ) { - c = m_cDiff1; - } else if ( cchanged == 3 ) { - c = m_cDiffBoth; - } - - if ( c!=m_pOptions->m_fgColor && whatChanged2==0 && !m_pOptions->m_bShowWhiteSpace ) - { - // The user doesn't want to see highlighted white space. - c = m_pOptions->m_fgColor; - } - - //QRect outRect( xOffset + outPixelPos, yOffset, charWidth*spaces, fontHeight ); - //if ( m_pOptions->m_bRightToLeftLanguage ) - // outRect = QRect( deviceWidth-1-(xOffset + outPixelPos), yOffset, -charWidth*spaces, fontHeight ).normalized(); - //if ( invalidRect.intersects( outRect ) ) - { - frh.setBackground( bgColor ); - if( !m_selection.within( line, outPos ) ) + MyPainter& p, + const LineData* pld, + const DiffList* pLineDiff1, + const DiffList* pLineDiff2, + int line, + int whatChanged, + int whatChanged2, + int srcLineIdx, + int wrapLineOffset, + int wrapLineLength, + bool bWrapLine, + const QRect& invalidRect, + int deviceWidth) +{ + QFont normalFont = p.font(); + QFont diffFont = normalFont; + diffFont.setItalic(m_pOptions->m_bItalicForDeltas); + const QFontMetrics& fm = p.fontMetrics(); + int fontHeight = fm.lineSpacing(); + int fontAscent = fm.ascent(); + int fontWidth = fm.width('0'); + + int xOffset = leftInfoWidth() * fontWidth - m_horizScrollOffset; + int yOffset = (line - m_firstLine) * fontHeight; + + QRect lineRect(0, yOffset, deviceWidth, fontHeight); + if(!invalidRect.intersects(lineRect)) + { + return; + } + + int fastSelectorLine1 = m_pDiffTextWindow->convertDiff3LineIdxToLine(m_fastSelectorLine1); + int fastSelectorLine2 = m_pDiffTextWindow->convertDiff3LineIdxToLine(m_fastSelectorLine1 + m_fastSelectorNofLines) - 1; + + bool bFastSelectionRange = (line >= fastSelectorLine1 && line <= fastSelectorLine2); + QColor bgColor = m_pOptions->m_bgColor; + QColor diffBgColor = m_pOptions->m_diffBgColor; + + if(bFastSelectionRange) + { + bgColor = m_pOptions->m_currentRangeBgColor; + diffBgColor = m_pOptions->m_currentRangeDiffBgColor; + } + + if(yOffset + fontHeight < invalidRect.top() || invalidRect.bottom() < yOffset - fontHeight) + return; + + int changed = whatChanged; + if(pLineDiff1 != 0) changed |= 1; + if(pLineDiff2 != 0) changed |= 2; + + QColor c = m_pOptions->m_fgColor; + p.setPen(c); + if(changed == 2) { + c = m_cDiff2; + } + else if(changed == 1) + { + c = m_cDiff1; + } + else if(changed == 3) + { + c = m_cDiffBoth; + } + + if(pld != 0) + { + // First calculate the "changed" information for each character. + int i = 0; + QString lineString(pld->pLine, pld->size); + if(!lineString.isEmpty()) + { + switch(lineString[lineString.length() - 1].unicode()) + { + case '\n': + lineString[lineString.length() - 1] = 0x00B6; + break; // "Pilcrow", "paragraph mark" + case '\r': + lineString[lineString.length() - 1] = 0x00A4; + break; // Currency sign ;0x2761 "curved stem paragraph sign ornament" + //case '\0b' : lineString[lineString.length()-1] = 0x2756; break; // some other nice looking character + } + } + QVector charChanged(pld->size); + Merger merger(pLineDiff1, pLineDiff2); + while(!merger.isEndReached() && i < pld->size) + { + if(i < pld->size) { + charChanged[i] = merger.whatChanged(); + ++i; + } + merger.next(); + } + + int outPos = 0; + + int lineLength = m_bWordWrap ? wrapLineOffset + wrapLineLength : lineString.length(); + + FormatRangeHelper frh; - if( c!=m_pOptions->m_fgColor ) - { - QColor lightc = diffBgColor; - frh.setBackground(lightc); - // Setting italic font here doesn't work: Changing the font only when drawing is too late - } + for(i = wrapLineOffset; i < lineLength; ++i) + { + QColor c = m_pOptions->m_fgColor; + int cchanged = charChanged[i] | whatChanged; - frh.setPen( c ); - frh.next(); - frh.setFont(normalFont); + if(cchanged == 2) { + c = m_cDiff2; } - else + else if(cchanged == 1) + { + c = m_cDiff1; + } + else if(cchanged == 3) { - frh.setBackground(m_pDiffTextWindow->palette().highlight().color()); - frh.setPen( m_pDiffTextWindow->palette().highlightedText().color() ); - frh.next(); + c = m_cDiffBoth; + } + + if(c != m_pOptions->m_fgColor && whatChanged2 == 0 && !m_pOptions->m_bShowWhiteSpace) + { + // The user doesn't want to see highlighted white space. + c = m_pOptions->m_fgColor; + } - m_selection.bSelectionContainsData = true; + //QRect outRect( xOffset + outPixelPos, yOffset, charWidth*spaces, fontHeight ); + //if ( m_pOptions->m_bRightToLeftLanguage ) + // outRect = QRect( deviceWidth-1-(xOffset + outPixelPos), yOffset, -charWidth*spaces, fontHeight ).normalized(); + //if ( invalidRect.intersects( outRect ) ) + { + frh.setBackground(bgColor); + if(!m_selection.within(line, outPos)) + { + + if(c != m_pOptions->m_fgColor) + { + QColor lightc = diffBgColor; + frh.setBackground(lightc); + // Setting italic font here doesn't work: Changing the font only when drawing is too late + } + + frh.setPen(c); + frh.next(); + frh.setFont(normalFont); + } + else + { + frh.setBackground(m_pDiffTextWindow->palette().highlight().color()); + frh.setPen(m_pDiffTextWindow->palette().highlightedText().color()); + frh.next(); + + m_selection.bSelectionContainsData = true; + } } - } - - ++outPos; - } // end for - - QTextLayout textLayout( lineString.mid( wrapLineOffset, lineLength-wrapLineOffset), m_pDiffTextWindow->font(), m_pDiffTextWindow ); - prepareTextLayout( textLayout, !m_bWordWrap || wrapLineOffset==0 ); - textLayout.draw ( &p, QPoint(0, yOffset), frh.m_formatRanges /*, const QRectF & clip = QRectF() */); - } - - p.fillRect( 0, yOffset, leftInfoWidth()*fontWidth, fontHeight, m_pOptions->m_bgColor ); - - xOffset = (m_lineNumberWidth+2)*fontWidth; - int xLeft = m_lineNumberWidth*fontWidth; - p.setPen( m_pOptions->m_fgColor ); - if ( pld!=0 ) - { - if ( m_pOptions->m_bShowLineNumbers && !bWrapLine ) - { - QString num; - num.sprintf( "%0*d", m_lineNumberWidth, srcLineIdx+1); - p.drawText( 0, yOffset + fontAscent, num ); - //p.drawLine( xLeft -1, yOffset, xLeft -1, yOffset+fontHeight-1 ); - } - if ( !bWrapLine || wrapLineLength>0 ) - { + + ++outPos; + } // end for + + QTextLayout textLayout(lineString.mid(wrapLineOffset, lineLength - wrapLineOffset), m_pDiffTextWindow->font(), m_pDiffTextWindow); + prepareTextLayout(textLayout, !m_bWordWrap || wrapLineOffset == 0); + textLayout.draw(&p, QPoint(0, yOffset), frh.m_formatRanges /*, const QRectF & clip = QRectF() */); + } + + p.fillRect(0, yOffset, leftInfoWidth() * fontWidth, fontHeight, m_pOptions->m_bgColor); + + xOffset = (m_lineNumberWidth + 2) * fontWidth; + int xLeft = m_lineNumberWidth * fontWidth; + p.setPen(m_pOptions->m_fgColor); + if(pld != 0) + { + if(m_pOptions->m_bShowLineNumbers && !bWrapLine) + { + QString num; + num.sprintf("%0*d", m_lineNumberWidth, srcLineIdx + 1); + p.drawText(0, yOffset + fontAscent, num); + //p.drawLine( xLeft -1, yOffset, xLeft -1, yOffset+fontHeight-1 ); + } + if(!bWrapLine || wrapLineLength > 0) + { #if defined(__APPLE__) && (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) - Qt::PenStyle wrapLinePenStyle = Qt::DashLine; // Qt::DotLine doesn't work on Mac (Qt4.8.6). + Qt::PenStyle wrapLinePenStyle = Qt::DashLine; // Qt::DotLine doesn't work on Mac (Qt4.8.6). #else - Qt::PenStyle wrapLinePenStyle = Qt::DotLine; + Qt::PenStyle wrapLinePenStyle = Qt::DotLine; #endif - p.setPen( QPen( m_pOptions->m_fgColor, 0, bWrapLine ? wrapLinePenStyle : Qt::SolidLine) ); - p.drawLine( xOffset +1, yOffset, xOffset +1, yOffset+fontHeight-1 ); - p.setPen( QPen( m_pOptions->m_fgColor, 0, Qt::SolidLine) ); - } - } - if ( c!=m_pOptions->m_fgColor && whatChanged2==0 )//&& whatChanged==0 ) - { - if ( m_pOptions->m_bShowWhiteSpace ) - { - p.setBrushOrigin(0,0); - p.fillRect( xLeft, yOffset, fontWidth*2-1, fontHeight, QBrush(c,Qt::Dense5Pattern) ); - } - } - else - { - p.fillRect( xLeft, yOffset, fontWidth*2-1, fontHeight, c==m_pOptions->m_fgColor ? bgColor : c ); - } - - if ( bFastSelectionRange ) - { - p.fillRect( xOffset + fontWidth-1, yOffset, 3, fontHeight, m_pOptions->m_fgColor ); - } - - // Check if line needs a manual diff help mark - ManualDiffHelpList::const_iterator ci; - for( ci = m_pManualDiffHelpList->begin(); ci!=m_pManualDiffHelpList->end(); ++ci) - { - const ManualDiffHelpEntry& mdhe=*ci; - int rangeLine1 = -1; - int rangeLine2 = -1; - if (m_winIdx==1 ) { rangeLine1 = mdhe.lineA1; rangeLine2= mdhe.lineA2; } - if (m_winIdx==2 ) { rangeLine1 = mdhe.lineB1; rangeLine2= mdhe.lineB2; } - if (m_winIdx==3 ) { rangeLine1 = mdhe.lineC1; rangeLine2= mdhe.lineC2; } - if ( rangeLine1>=0 && rangeLine2>=0 && srcLineIdx >= rangeLine1 && srcLineIdx <= rangeLine2 ) - { - p.fillRect( xOffset - fontWidth, yOffset, fontWidth-1, fontHeight, m_pOptions->m_manualHelpRangeColor ); - break; - } - } -} - -void DiffTextWindow::paintEvent( QPaintEvent* e ) -{ - QRect invalidRect = e->rect(); - if ( invalidRect.isEmpty() || ! d->m_bPaintingAllowed ) - return; - - if ( d->m_pDiff3LineVector==0 || ( d->m_diff3WrapLineVector.empty() && d->m_bWordWrap ) ) - { - QPainter p(this); - p.fillRect( invalidRect, d->m_pOptions->m_bgColor ); - return; - } - - bool bOldSelectionContainsData = d->m_selection.bSelectionContainsData; - d->m_selection.bSelectionContainsData = false; - - int endLine = min2( d->m_firstLine + getNofVisibleLines()+2, getNofLines() ); - - - MyPainter p( this, d->m_pOptions->m_bRightToLeftLanguage, width(), fontMetrics().width('0') ); - - p.setFont( font() ); - p.QPainter::fillRect( invalidRect, d->m_pOptions->m_bgColor ); - - d->draw( p, invalidRect, width(), d->m_firstLine, endLine ); - p.end(); - - d->m_oldFirstLine = d->m_firstLine; - d->m_selection.oldLastLine = -1; - if ( d->m_selection.oldFirstLine !=-1 ) - d->m_selection.oldFirstLine = -1; - - if( !bOldSelectionContainsData && d->m_selection.bSelectionContainsData ) - emit newSelection(); -} - -void DiffTextWindow::print( MyPainter& p, const QRect&, int firstLine, int nofLinesPerPage ) -{ - if ( d->m_pDiff3LineVector==0 || ! d->m_bPaintingAllowed || - ( d->m_diff3WrapLineVector.empty() && d->m_bWordWrap ) ) - return; - resetSelection(); - int oldFirstLine = d->m_firstLine; - d->m_firstLine = firstLine; - QRect invalidRect = QRect(0,0,1000000000,1000000000); - QColor bgColor = d->m_pOptions->m_bgColor; - d->m_pOptions->m_bgColor = Qt::white; - d->draw( p, invalidRect, p.window().width(), firstLine, min2(firstLine+nofLinesPerPage,getNofLines()) ); - d->m_pOptions->m_bgColor = bgColor; - d->m_firstLine = oldFirstLine; -} - -void DiffTextWindowData::draw( MyPainter& p, const QRect& invalidRect, int deviceWidth, int beginLine, int endLine ) -{ - m_lineNumberWidth = m_pOptions->m_bShowLineNumbers ? (int)log10((double)qMax(m_size,1))+1 : 0; - - if ( m_winIdx==1 ) - { - m_cThis = m_pOptions->m_colorA; - m_cDiff1 = m_pOptions->m_colorB; - m_cDiff2 = m_pOptions->m_colorC; - } - if ( m_winIdx==2 ) - { - m_cThis = m_pOptions->m_colorB; - m_cDiff1 = m_pOptions->m_colorC; - m_cDiff2 = m_pOptions->m_colorA; - } - if ( m_winIdx==3 ) - { - m_cThis = m_pOptions->m_colorC; - m_cDiff1 = m_pOptions->m_colorA; - m_cDiff2 = m_pOptions->m_colorB; - } - m_cDiffBoth = m_pOptions->m_colorForConflict; // Conflict color - - p.setPen( m_cThis ); - - for ( int line = beginLine; line 0 && m_diff3WrapLineVector[line-1].pD3L == d3l; - } - else - { - d3l = (*m_pDiff3LineVector)[line]; - } - DiffList* pFineDiff1; - DiffList* pFineDiff2; - int changed=0; - int changed2=0; - - int srcLineIdx=-1; - getLineInfo( *d3l, srcLineIdx, pFineDiff1, pFineDiff2, changed, changed2 ); - - writeLine( - p, // QPainter - srcLineIdx == -1 ? 0 : &m_pLineData[srcLineIdx], // Text in this line - pFineDiff1, - pFineDiff2, - line, // Line on the screen - changed, - changed2, - srcLineIdx, - wrapLineOffset, - wrapLineLength, - bWrapLine, - invalidRect, - deviceWidth - ); - } -} - -QString DiffTextWindowData::getString( int d3lIdx ) -{ - if ( d3lIdx<0 || d3lIdx>=(int)m_pDiff3LineVector->size() ) - return QString(); - const Diff3Line* d3l = (*m_pDiff3LineVector)[d3lIdx]; - DiffList* pFineDiff1; - DiffList* pFineDiff2; - int changed=0; - int changed2=0; - int lineIdx; - getLineInfo( *d3l, lineIdx, pFineDiff1, pFineDiff2, changed, changed2 ); - - if (lineIdx==-1) return QString(); - else - { - const LineData* ld = &m_pLineData[lineIdx]; - return QString( ld->pLine, ld->size ); - } - return QString(); -} - -QString DiffTextWindowData::getLineString( int line ) -{ - if ( m_bWordWrap ) - { - if ( line < m_diff3WrapLineVector.count() ) - { - int d3LIdx = m_pDiffTextWindow->convertLineToDiff3LineIdx(line); - return getString( d3LIdx ).mid( m_diff3WrapLineVector[line].wrapLineOffset, m_diff3WrapLineVector[line].wrapLineLength ); - } - else - return QString(); - } - else - { - return getString( line ); - } + p.setPen(QPen(m_pOptions->m_fgColor, 0, bWrapLine ? wrapLinePenStyle : Qt::SolidLine)); + p.drawLine(xOffset + 1, yOffset, xOffset + 1, yOffset + fontHeight - 1); + p.setPen(QPen(m_pOptions->m_fgColor, 0, Qt::SolidLine)); + } + } + if(c != m_pOptions->m_fgColor && whatChanged2 == 0) //&& whatChanged==0 ) + { + if(m_pOptions->m_bShowWhiteSpace) + { + p.setBrushOrigin(0, 0); + p.fillRect(xLeft, yOffset, fontWidth * 2 - 1, fontHeight, QBrush(c, Qt::Dense5Pattern)); + } + } + else + { + p.fillRect(xLeft, yOffset, fontWidth * 2 - 1, fontHeight, c == m_pOptions->m_fgColor ? bgColor : c); + } + + if(bFastSelectionRange) + { + p.fillRect(xOffset + fontWidth - 1, yOffset, 3, fontHeight, m_pOptions->m_fgColor); + } + + // Check if line needs a manual diff help mark + ManualDiffHelpList::const_iterator ci; + for(ci = m_pManualDiffHelpList->begin(); ci != m_pManualDiffHelpList->end(); ++ci) + { + const ManualDiffHelpEntry& mdhe = *ci; + int rangeLine1 = -1; + int rangeLine2 = -1; + if(m_winIdx == 1) { + rangeLine1 = mdhe.lineA1; + rangeLine2 = mdhe.lineA2; + } + if(m_winIdx == 2) { + rangeLine1 = mdhe.lineB1; + rangeLine2 = mdhe.lineB2; + } + if(m_winIdx == 3) { + rangeLine1 = mdhe.lineC1; + rangeLine2 = mdhe.lineC2; + } + if(rangeLine1 >= 0 && rangeLine2 >= 0 && srcLineIdx >= rangeLine1 && srcLineIdx <= rangeLine2) + { + p.fillRect(xOffset - fontWidth, yOffset, fontWidth - 1, fontHeight, m_pOptions->m_manualHelpRangeColor); + break; + } + } +} + +void DiffTextWindow::paintEvent(QPaintEvent* e) +{ + QRect invalidRect = e->rect(); + if(invalidRect.isEmpty() || !d->m_bPaintingAllowed) + return; + + if(d->m_pDiff3LineVector == 0 || (d->m_diff3WrapLineVector.empty() && d->m_bWordWrap)) + { + QPainter p(this); + p.fillRect(invalidRect, d->m_pOptions->m_bgColor); + return; + } + + bool bOldSelectionContainsData = d->m_selection.bSelectionContainsData; + d->m_selection.bSelectionContainsData = false; + + int endLine = min2(d->m_firstLine + getNofVisibleLines() + 2, getNofLines()); + + MyPainter p(this, d->m_pOptions->m_bRightToLeftLanguage, width(), fontMetrics().width('0')); + + p.setFont(font()); + p.QPainter::fillRect(invalidRect, d->m_pOptions->m_bgColor); + + d->draw(p, invalidRect, width(), d->m_firstLine, endLine); + p.end(); + + d->m_oldFirstLine = d->m_firstLine; + d->m_selection.oldLastLine = -1; + if(d->m_selection.oldFirstLine != -1) + d->m_selection.oldFirstLine = -1; + + if(!bOldSelectionContainsData && d->m_selection.bSelectionContainsData) + emit newSelection(); +} + +void DiffTextWindow::print(MyPainter& p, const QRect&, int firstLine, int nofLinesPerPage) +{ + if(d->m_pDiff3LineVector == 0 || !d->m_bPaintingAllowed || + (d->m_diff3WrapLineVector.empty() && d->m_bWordWrap)) + return; + resetSelection(); + int oldFirstLine = d->m_firstLine; + d->m_firstLine = firstLine; + QRect invalidRect = QRect(0, 0, 1000000000, 1000000000); + QColor bgColor = d->m_pOptions->m_bgColor; + d->m_pOptions->m_bgColor = Qt::white; + d->draw(p, invalidRect, p.window().width(), firstLine, min2(firstLine + nofLinesPerPage, getNofLines())); + d->m_pOptions->m_bgColor = bgColor; + d->m_firstLine = oldFirstLine; +} + +void DiffTextWindowData::draw(MyPainter& p, const QRect& invalidRect, int deviceWidth, int beginLine, int endLine) +{ + m_lineNumberWidth = m_pOptions->m_bShowLineNumbers ? (int)log10((double)qMax(m_size, 1)) + 1 : 0; + + if(m_winIdx == 1) + { + m_cThis = m_pOptions->m_colorA; + m_cDiff1 = m_pOptions->m_colorB; + m_cDiff2 = m_pOptions->m_colorC; + } + if(m_winIdx == 2) + { + m_cThis = m_pOptions->m_colorB; + m_cDiff1 = m_pOptions->m_colorC; + m_cDiff2 = m_pOptions->m_colorA; + } + if(m_winIdx == 3) + { + m_cThis = m_pOptions->m_colorC; + m_cDiff1 = m_pOptions->m_colorA; + m_cDiff2 = m_pOptions->m_colorB; + } + m_cDiffBoth = m_pOptions->m_colorForConflict; // Conflict color + + p.setPen(m_cThis); + + for(int line = beginLine; line < endLine; ++line) + { + int wrapLineOffset = 0; + int wrapLineLength = 0; + const Diff3Line* d3l = 0; + bool bWrapLine = false; + if(m_bWordWrap) + { + Diff3WrapLine& d3wl = m_diff3WrapLineVector[line]; + wrapLineOffset = d3wl.wrapLineOffset; + wrapLineLength = d3wl.wrapLineLength; + d3l = d3wl.pD3L; + bWrapLine = line > 0 && m_diff3WrapLineVector[line - 1].pD3L == d3l; + } + else + { + d3l = (*m_pDiff3LineVector)[line]; + } + DiffList* pFineDiff1; + DiffList* pFineDiff2; + int changed = 0; + int changed2 = 0; + + int srcLineIdx = -1; + getLineInfo(*d3l, srcLineIdx, pFineDiff1, pFineDiff2, changed, changed2); + + writeLine( + p, // QPainter + srcLineIdx == -1 ? 0 : &m_pLineData[srcLineIdx], // Text in this line + pFineDiff1, + pFineDiff2, + line, // Line on the screen + changed, + changed2, + srcLineIdx, + wrapLineOffset, + wrapLineLength, + bWrapLine, + invalidRect, + deviceWidth); + } +} + +QString DiffTextWindowData::getString(int d3lIdx) +{ + if(d3lIdx < 0 || d3lIdx >= (int)m_pDiff3LineVector->size()) + return QString(); + const Diff3Line* d3l = (*m_pDiff3LineVector)[d3lIdx]; + DiffList* pFineDiff1; + DiffList* pFineDiff2; + int changed = 0; + int changed2 = 0; + int lineIdx; + getLineInfo(*d3l, lineIdx, pFineDiff1, pFineDiff2, changed, changed2); + + if(lineIdx == -1) + return QString(); + else + { + const LineData* ld = &m_pLineData[lineIdx]; + return QString(ld->pLine, ld->size); + } + return QString(); +} + +QString DiffTextWindowData::getLineString(int line) +{ + if(m_bWordWrap) + { + if(line < m_diff3WrapLineVector.count()) + { + int d3LIdx = m_pDiffTextWindow->convertLineToDiff3LineIdx(line); + return getString(d3LIdx).mid(m_diff3WrapLineVector[line].wrapLineOffset, m_diff3WrapLineVector[line].wrapLineLength); + } + else + return QString(); + } + else + { + return getString(line); + } } void DiffTextWindowData::getLineInfo( - const Diff3Line& d3l, - int& lineIdx, - DiffList*& pFineDiff1, DiffList*& pFineDiff2, // return values - int& changed, int& changed2 - ) -{ - changed=0; - changed2=0; - bool bAEqB = d3l.bAEqB || ( d3l.bWhiteLineA && d3l.bWhiteLineB ); - bool bAEqC = d3l.bAEqC || ( d3l.bWhiteLineA && d3l.bWhiteLineC ); - bool bBEqC = d3l.bBEqC || ( d3l.bWhiteLineB && d3l.bWhiteLineC ); - if ( m_winIdx == 1 ) { - lineIdx=d3l.lineA; - pFineDiff1=d3l.pFineAB; - pFineDiff2=d3l.pFineCA; - changed |= ((d3l.lineB==-1)!=(lineIdx==-1) ? 1 : 0) + - ((d3l.lineC==-1)!=(lineIdx==-1) && m_bTriple ? 2 : 0); - changed2 |= ( bAEqB ? 0 : 1 ) + (bAEqC || !m_bTriple ? 0 : 2); - } - else if ( m_winIdx == 2 ) { - lineIdx=d3l.lineB; - pFineDiff1=d3l.pFineBC; - pFineDiff2=d3l.pFineAB; - changed |= ((d3l.lineC==-1)!=(lineIdx==-1) && m_bTriple ? 1 : 0) + - ((d3l.lineA==-1)!=(lineIdx==-1) ? 2 : 0); - changed2 |= ( bBEqC || !m_bTriple ? 0 : 1 ) + (bAEqB ? 0 : 2); - } - else if ( m_winIdx == 3 ) { - lineIdx=d3l.lineC; - pFineDiff1=d3l.pFineCA; - pFineDiff2=d3l.pFineBC; - changed |= ((d3l.lineA==-1)!=(lineIdx==-1) ? 1 : 0) + - ((d3l.lineB==-1)!=(lineIdx==-1) ? 2 : 0); - changed2 |= ( bAEqC ? 0 : 1 ) + (bBEqC ? 0 : 2); - } - else assert(false); -} - - - -void DiffTextWindow::resizeEvent( QResizeEvent* e ) -{ - QSize s = e->size(); - QFontMetrics fm = fontMetrics(); - int visibleLines = s.height()/fm.lineSpacing()-2; - int visibleColumns = s.width()/fm.width('0') - d->leftInfoWidth(); - if (e->size().height() != e->oldSize().height()) - emit resizeHeightChangedSignal(visibleLines); - if (e->size().width() != e->oldSize().width()) - emit resizeWidthChangedSignal(visibleColumns); - QWidget::resizeEvent(e); + const Diff3Line& d3l, + int& lineIdx, + DiffList*& pFineDiff1, DiffList*& pFineDiff2, // return values + int& changed, int& changed2) +{ + changed = 0; + changed2 = 0; + bool bAEqB = d3l.bAEqB || (d3l.bWhiteLineA && d3l.bWhiteLineB); + bool bAEqC = d3l.bAEqC || (d3l.bWhiteLineA && d3l.bWhiteLineC); + bool bBEqC = d3l.bBEqC || (d3l.bWhiteLineB && d3l.bWhiteLineC); + if(m_winIdx == 1) { + lineIdx = d3l.lineA; + pFineDiff1 = d3l.pFineAB; + pFineDiff2 = d3l.pFineCA; + changed |= ((d3l.lineB == -1) != (lineIdx == -1) ? 1 : 0) + + ((d3l.lineC == -1) != (lineIdx == -1) && m_bTriple ? 2 : 0); + changed2 |= (bAEqB ? 0 : 1) + (bAEqC || !m_bTriple ? 0 : 2); + } + else if(m_winIdx == 2) + { + lineIdx = d3l.lineB; + pFineDiff1 = d3l.pFineBC; + pFineDiff2 = d3l.pFineAB; + changed |= ((d3l.lineC == -1) != (lineIdx == -1) && m_bTriple ? 1 : 0) + + ((d3l.lineA == -1) != (lineIdx == -1) ? 2 : 0); + changed2 |= (bBEqC || !m_bTriple ? 0 : 1) + (bAEqB ? 0 : 2); + } + else if(m_winIdx == 3) + { + lineIdx = d3l.lineC; + pFineDiff1 = d3l.pFineCA; + pFineDiff2 = d3l.pFineBC; + changed |= ((d3l.lineA == -1) != (lineIdx == -1) ? 1 : 0) + + ((d3l.lineB == -1) != (lineIdx == -1) ? 2 : 0); + changed2 |= (bAEqC ? 0 : 1) + (bBEqC ? 0 : 2); + } + else + assert(false); +} + +void DiffTextWindow::resizeEvent(QResizeEvent* e) +{ + QSize s = e->size(); + QFontMetrics fm = fontMetrics(); + int visibleLines = s.height() / fm.lineSpacing() - 2; + int visibleColumns = s.width() / fm.width('0') - d->leftInfoWidth(); + if(e->size().height() != e->oldSize().height()) + emit resizeHeightChangedSignal(visibleLines); + if(e->size().width() != e->oldSize().width()) + emit resizeWidthChangedSignal(visibleColumns); + QWidget::resizeEvent(e); } int DiffTextWindow::getNofVisibleLines() { - QFontMetrics fm = fontMetrics(); - int fmh = fm.lineSpacing(); - int h = height(); - return h/fmh -1; + QFontMetrics fm = fontMetrics(); + int fmh = fm.lineSpacing(); + int h = height(); + return h / fmh - 1; } int DiffTextWindow::getVisibleTextAreaWidth() { - QFontMetrics fm = fontMetrics(); - return width() - d->leftInfoWidth() * fm.width('0'); + QFontMetrics fm = fontMetrics(); + return width() - d->leftInfoWidth() * fm.width('0'); } QString DiffTextWindow::getSelection() { - if ( d->m_pLineData==0 ) - return QString(); - - QString selectionString; - - int line=0; - int lineIdx=0; - - int it; - int vectorSize = d->m_bWordWrap ? d->m_diff3WrapLineVector.size() : d->m_pDiff3LineVector->size(); - for( it=0; itm_bWordWrap ? d->m_diff3WrapLineVector[it].pD3L : (*d->m_pDiff3LineVector)[it]; - if ( d->m_winIdx == 1 ) { lineIdx=d3l->lineA; } - else if ( d->m_winIdx == 2 ) { lineIdx=d3l->lineB; } - else if ( d->m_winIdx == 3 ) { lineIdx=d3l->lineC; } - else assert(false); - - if( lineIdx != -1 ) - { - const QChar* pLine = d->m_pLineData[lineIdx].pLine; - int size = d->m_pLineData[lineIdx].size; - QString lineString = QString( pLine, size ); - - if ( d->m_bWordWrap ) - { - size = d->m_diff3WrapLineVector[it].wrapLineLength; - lineString = lineString.mid( d->m_diff3WrapLineVector[it].wrapLineOffset, size ); - } - - for( int i=0; im_selection.within( line, i ) ) + if(d->m_pLineData == 0) + return QString(); + + QString selectionString; + + int line = 0; + int lineIdx = 0; + + int it; + int vectorSize = d->m_bWordWrap ? d->m_diff3WrapLineVector.size() : d->m_pDiff3LineVector->size(); + for(it = 0; it < vectorSize; ++it) + { + const Diff3Line* d3l = d->m_bWordWrap ? d->m_diff3WrapLineVector[it].pD3L : (*d->m_pDiff3LineVector)[it]; + if(d->m_winIdx == 1) { + lineIdx = d3l->lineA; + } + else if(d->m_winIdx == 2) + { + lineIdx = d3l->lineB; + } + else if(d->m_winIdx == 3) + { + lineIdx = d3l->lineC; + } + else + assert(false); + + if(lineIdx != -1) + { + const QChar* pLine = d->m_pLineData[lineIdx].pLine; + int size = d->m_pLineData[lineIdx].size; + QString lineString = QString(pLine, size); + + if(d->m_bWordWrap) + { + size = d->m_diff3WrapLineVector[it].wrapLineLength; + lineString = lineString.mid(d->m_diff3WrapLineVector[it].wrapLineOffset, size); + } + + for(int i = 0; i < size; ++i) + { + if(d->m_selection.within(line, i)) + { + selectionString += lineString[i]; + } + } + + if(d->m_selection.within(line, size) && + !(d->m_bWordWrap && it + 1 < vectorSize && d3l == d->m_diff3WrapLineVector[it + 1].pD3L)) + { +#if defined(_WIN32) || defined(Q_OS_OS2) + selectionString += '\r'; +#endif + selectionString += '\n'; + } + } + + ++line; + } + + return selectionString; +} + +bool DiffTextWindow::findString(const QString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive) +{ + int it = d3vLine; + int endIt = bDirDown ? (int)d->m_pDiff3LineVector->size() : -1; + int step = bDirDown ? 1 : -1; + int startPos = posInLine; + + for(; it != endIt; it += step) + { + QString line = d->getString(it); + if(!line.isEmpty()) + { + int pos = line.indexOf(s, startPos, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive); + if(pos != -1) { - selectionString += lineString[i]; + d3vLine = it; + posInLine = pos; + return true; } - } - - if( d->m_selection.within( line, size ) && - !( d->m_bWordWrap && it+1m_diff3WrapLineVector[it+1].pD3L ) - ) - { - #if defined(_WIN32) || defined(Q_OS_OS2) - selectionString += '\r'; - #endif - selectionString += '\n'; - } - } - - ++line; - } - - return selectionString; -} - -bool DiffTextWindow::findString( const QString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive ) -{ - int it = d3vLine; - int endIt = bDirDown ? (int)d->m_pDiff3LineVector->size() : -1; - int step = bDirDown ? 1 : -1; - int startPos = posInLine; - - for( ; it!=endIt; it+=step ) - { - QString line = d->getString( it ); - if ( !line.isEmpty() ) - { - int pos = line.indexOf( s, startPos, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive ); - if ( pos != -1 ) - { - d3vLine = it; - posInLine = pos; - return true; - } - - startPos = 0; - } - } - return false; -} - -void DiffTextWindow::convertD3LCoordsToLineCoords( int d3LIdx, int d3LPos, int& line, int& pos ) -{ - if( d->m_bWordWrap ) - { - int wrapPos = d3LPos; - int wrapLine = convertDiff3LineIdxToLine(d3LIdx); - while ( wrapPos > d->m_diff3WrapLineVector[wrapLine].wrapLineLength ) - { - wrapPos -= d->m_diff3WrapLineVector[wrapLine].wrapLineLength; - ++wrapLine; - } - pos = wrapPos; - line = wrapLine; - } - else - { - pos = d3LPos; - line = d3LIdx; - } -} - -void DiffTextWindow::convertLineCoordsToD3LCoords( int line, int pos, int& d3LIdx, int& d3LPos ) -{ - if( d->m_bWordWrap ) - { - d3LPos = pos; - d3LIdx = convertLineToDiff3LineIdx( line ); - int wrapLine = convertDiff3LineIdxToLine(d3LIdx); // First wrap line belonging to this d3LIdx - while ( wrapLine < line ) - { - d3LPos += d->m_diff3WrapLineVector[wrapLine].wrapLineLength; - ++wrapLine; - } - } - else - { - d3LPos = pos; - d3LIdx = line; - } -} - - -void DiffTextWindow::setSelection( int firstLine, int startPos, int lastLine, int endPos, int& l, int& p ) -{ - d->m_selection.reset(); - if ( lastLine >= getNofLines() ) - { - lastLine = getNofLines()-1; - - const Diff3Line* d3l = (*d->m_pDiff3LineVector)[convertLineToDiff3LineIdx(lastLine)]; - int line = -1; - if ( d->m_winIdx==1 ) line = d3l->lineA; - if ( d->m_winIdx==2 ) line = d3l->lineB; - if ( d->m_winIdx==3 ) line = d3l->lineC; - if (line>=0) - endPos = d->m_pLineData[line].width( d->m_pOptions->m_tabSize); - } - - if ( d->m_bWordWrap && d->m_pDiff3LineVector!=0 ) - { - QString s1 = d->getString(firstLine); - int firstWrapLine = convertDiff3LineIdxToLine(firstLine); - int wrapStartPos = startPos; - while ( wrapStartPos > d->m_diff3WrapLineVector[firstWrapLine].wrapLineLength ) - { - wrapStartPos -= d->m_diff3WrapLineVector[firstWrapLine].wrapLineLength; - s1 = s1.mid(d->m_diff3WrapLineVector[firstWrapLine].wrapLineLength); - ++firstWrapLine; - } - - QString s2 = d->getString(lastLine); - int lastWrapLine = convertDiff3LineIdxToLine(lastLine); - int wrapEndPos = endPos; - while ( wrapEndPos > d->m_diff3WrapLineVector[lastWrapLine].wrapLineLength ) - { - wrapEndPos -= d->m_diff3WrapLineVector[lastWrapLine].wrapLineLength; - s2 = s2.mid(d->m_diff3WrapLineVector[lastWrapLine].wrapLineLength); - ++lastWrapLine; - } - - d->m_selection.start( firstWrapLine, convertToPosOnScreen( s1, wrapStartPos, d->m_pOptions->m_tabSize ) ); - d->m_selection.end( lastWrapLine, convertToPosOnScreen( s2, wrapEndPos, d->m_pOptions->m_tabSize ) ); - l=firstWrapLine; - p=wrapStartPos; - } - else - { - d->m_selection.start( firstLine, convertToPosOnScreen( d->getString(firstLine), startPos, d->m_pOptions->m_tabSize ) ); - d->m_selection.end( lastLine, convertToPosOnScreen( d->getString(lastLine), endPos, d->m_pOptions->m_tabSize ) ); - l=firstLine; - p=startPos; - } - update(); -} - -int DiffTextWindowData::convertLineOnScreenToLineInSource( int lineOnScreen, e_CoordType coordType, bool bFirstLine ) -{ - int line=-1; - if (lineOnScreen>=0) - { - if (coordType==eWrapCoords) return lineOnScreen; - int d3lIdx = m_pDiffTextWindow->convertLineToDiff3LineIdx( lineOnScreen ); - if ( !bFirstLine && d3lIdx >= (int)m_pDiff3LineVector->size() ) - d3lIdx = m_pDiff3LineVector->size()-1; - if (coordType==eD3LLineCoords) return d3lIdx; - while ( line<0 && d3lIdx<(int)m_pDiff3LineVector->size() && d3lIdx>=0 ) - { - const Diff3Line* d3l = (*m_pDiff3LineVector)[d3lIdx]; - if ( m_winIdx==1 ) line = d3l->lineA; - if ( m_winIdx==2 ) line = d3l->lineB; - if ( m_winIdx==3 ) line = d3l->lineC; - if ( bFirstLine ) - ++d3lIdx; - else - --d3lIdx; - } - if (coordType==eFileCoords) return line; - } - return line; -} - - -void DiffTextWindow::getSelectionRange( int* pFirstLine, int* pLastLine, e_CoordType coordType ) -{ - if (pFirstLine) - *pFirstLine = d->convertLineOnScreenToLineInSource( d->m_selection.beginLine(), coordType, true ); - if (pLastLine) - *pLastLine = d->convertLineOnScreenToLineInSource( d->m_selection.endLine(), coordType, false ); + + startPos = 0; + } + } + return false; } -void DiffTextWindow::convertSelectionToD3LCoords() +void DiffTextWindow::convertD3LCoordsToLineCoords(int d3LIdx, int d3LPos, int& line, int& pos) +{ + if(d->m_bWordWrap) + { + int wrapPos = d3LPos; + int wrapLine = convertDiff3LineIdxToLine(d3LIdx); + while(wrapPos > d->m_diff3WrapLineVector[wrapLine].wrapLineLength) + { + wrapPos -= d->m_diff3WrapLineVector[wrapLine].wrapLineLength; + ++wrapLine; + } + pos = wrapPos; + line = wrapLine; + } + else + { + pos = d3LPos; + line = d3LIdx; + } +} + +void DiffTextWindow::convertLineCoordsToD3LCoords(int line, int pos, int& d3LIdx, int& d3LPos) { - if ( d->m_pDiff3LineVector==0 || ! d->m_bPaintingAllowed || !isVisible() || d->m_selection.isEmpty() ) - { - return; - } + if(d->m_bWordWrap) + { + d3LPos = pos; + d3LIdx = convertLineToDiff3LineIdx(line); + int wrapLine = convertDiff3LineIdxToLine(d3LIdx); // First wrap line belonging to this d3LIdx + while(wrapLine < line) + { + d3LPos += d->m_diff3WrapLineVector[wrapLine].wrapLineLength; + ++wrapLine; + } + } + else + { + d3LPos = pos; + d3LIdx = line; + } +} +void DiffTextWindow::setSelection(int firstLine, int startPos, int lastLine, int endPos, int& l, int& p) +{ + d->m_selection.reset(); + if(lastLine >= getNofLines()) + { + lastLine = getNofLines() - 1; + + const Diff3Line* d3l = (*d->m_pDiff3LineVector)[convertLineToDiff3LineIdx(lastLine)]; + int line = -1; + if(d->m_winIdx == 1) line = d3l->lineA; + if(d->m_winIdx == 2) line = d3l->lineB; + if(d->m_winIdx == 3) line = d3l->lineC; + if(line >= 0) + endPos = d->m_pLineData[line].width(d->m_pOptions->m_tabSize); + } - // convert the d->m_selection to unwrapped coordinates: Later restore to new coords - int firstD3LIdx, firstD3LPos; - QString s = d->getLineString( d->m_selection.beginLine() ); - int firstPosInText = convertToPosInText( s, d->m_selection.beginPos(), d->m_pOptions->m_tabSize ); - convertLineCoordsToD3LCoords( d->m_selection.beginLine(), firstPosInText, firstD3LIdx, firstD3LPos ); + if(d->m_bWordWrap && d->m_pDiff3LineVector != 0) + { + QString s1 = d->getString(firstLine); + int firstWrapLine = convertDiff3LineIdxToLine(firstLine); + int wrapStartPos = startPos; + while(wrapStartPos > d->m_diff3WrapLineVector[firstWrapLine].wrapLineLength) + { + wrapStartPos -= d->m_diff3WrapLineVector[firstWrapLine].wrapLineLength; + s1 = s1.mid(d->m_diff3WrapLineVector[firstWrapLine].wrapLineLength); + ++firstWrapLine; + } - int lastD3LIdx, lastD3LPos; - s = d->getLineString( d->m_selection.endLine() ); - int lastPosInText = convertToPosInText( s, d->m_selection.endPos(), d->m_pOptions->m_tabSize ); - convertLineCoordsToD3LCoords( d->m_selection.endLine(), lastPosInText, lastD3LIdx, lastD3LPos ); + QString s2 = d->getString(lastLine); + int lastWrapLine = convertDiff3LineIdxToLine(lastLine); + int wrapEndPos = endPos; + while(wrapEndPos > d->m_diff3WrapLineVector[lastWrapLine].wrapLineLength) + { + wrapEndPos -= d->m_diff3WrapLineVector[lastWrapLine].wrapLineLength; + s2 = s2.mid(d->m_diff3WrapLineVector[lastWrapLine].wrapLineLength); + ++lastWrapLine; + } - d->m_selection.start( firstD3LIdx, firstD3LPos ); - d->m_selection.end( lastD3LIdx, lastD3LPos ); + d->m_selection.start(firstWrapLine, convertToPosOnScreen(s1, wrapStartPos, d->m_pOptions->m_tabSize)); + d->m_selection.end(lastWrapLine, convertToPosOnScreen(s2, wrapEndPos, d->m_pOptions->m_tabSize)); + l = firstWrapLine; + p = wrapStartPos; + } + else + { + d->m_selection.start(firstLine, convertToPosOnScreen(d->getString(firstLine), startPos, d->m_pOptions->m_tabSize)); + d->m_selection.end(lastLine, convertToPosOnScreen(d->getString(lastLine), endPos, d->m_pOptions->m_tabSize)); + l = firstLine; + p = startPos; + } + update(); +} + +int DiffTextWindowData::convertLineOnScreenToLineInSource(int lineOnScreen, e_CoordType coordType, bool bFirstLine) +{ + int line = -1; + if(lineOnScreen >= 0) + { + if(coordType == eWrapCoords) return lineOnScreen; + int d3lIdx = m_pDiffTextWindow->convertLineToDiff3LineIdx(lineOnScreen); + if(!bFirstLine && d3lIdx >= (int)m_pDiff3LineVector->size()) + d3lIdx = m_pDiff3LineVector->size() - 1; + if(coordType == eD3LLineCoords) return d3lIdx; + while(line < 0 && d3lIdx < (int)m_pDiff3LineVector->size() && d3lIdx >= 0) + { + const Diff3Line* d3l = (*m_pDiff3LineVector)[d3lIdx]; + if(m_winIdx == 1) line = d3l->lineA; + if(m_winIdx == 2) line = d3l->lineB; + if(m_winIdx == 3) line = d3l->lineC; + if(bFirstLine) + ++d3lIdx; + else + --d3lIdx; + } + if(coordType == eFileCoords) return line; + } + return line; +} + +void DiffTextWindow::getSelectionRange(int* pFirstLine, int* pLastLine, e_CoordType coordType) +{ + if(pFirstLine) + *pFirstLine = d->convertLineOnScreenToLineInSource(d->m_selection.beginLine(), coordType, true); + if(pLastLine) + *pLastLine = d->convertLineOnScreenToLineInSource(d->m_selection.endLine(), coordType, false); +} + +void DiffTextWindow::convertSelectionToD3LCoords() +{ + if(d->m_pDiff3LineVector == 0 || !d->m_bPaintingAllowed || !isVisible() || d->m_selection.isEmpty()) + { + return; + } + + // convert the d->m_selection to unwrapped coordinates: Later restore to new coords + int firstD3LIdx, firstD3LPos; + QString s = d->getLineString(d->m_selection.beginLine()); + int firstPosInText = convertToPosInText(s, d->m_selection.beginPos(), d->m_pOptions->m_tabSize); + convertLineCoordsToD3LCoords(d->m_selection.beginLine(), firstPosInText, firstD3LIdx, firstD3LPos); + + int lastD3LIdx, lastD3LPos; + s = d->getLineString(d->m_selection.endLine()); + int lastPosInText = convertToPosInText(s, d->m_selection.endPos(), d->m_pOptions->m_tabSize); + convertLineCoordsToD3LCoords(d->m_selection.endLine(), lastPosInText, lastD3LIdx, lastD3LPos); + + d->m_selection.start(firstD3LIdx, firstD3LPos); + d->m_selection.end(lastD3LIdx, lastD3LPos); } int s_maxNofRunnables = 0; class RecalcWordWrapRunnable : public QRunnable { - DiffTextWindow* m_pDTW; - // DiffTextWindowData* m_pDTWData; // TODO unused? - int m_visibleTextWidth; - int m_cacheIdx; -public: - RecalcWordWrapRunnable( DiffTextWindow* p, DiffTextWindowData* pData, int visibleTextWidth, int cacheIdx ) - : m_pDTW(p), /* m_pDTWData(pData),*/ m_visibleTextWidth(visibleTextWidth), m_cacheIdx(cacheIdx) - { - Q_UNUSED(pData) // TODO really unused? - setAutoDelete(true); - //++s_runnableCount; // in Qt>=5.3 only - s_runnableCount.fetchAndAddOrdered(1); - } - void run() - { - m_pDTW->recalcWordWrapHelper(0,m_visibleTextWidth,m_cacheIdx); - // int newValue = --s_runnableCount; // in Qt>=5.3 only - int newValue = s_runnableCount.fetchAndAddOrdered(-1) - 1; - g_pProgressDialog->setCurrent(s_maxNofRunnables - getAtomic( s_runnableCount ) ); - if (newValue == 0) - { - QWidget* p = m_pDTW; - while (p ) - { - p = p->parentWidget(); - if (KDiff3App* pKDiff3App = dynamic_cast(p)) + DiffTextWindow* m_pDTW; + // DiffTextWindowData* m_pDTWData; // TODO unused? + int m_visibleTextWidth; + int m_cacheIdx; + + public: + RecalcWordWrapRunnable(DiffTextWindow* p, DiffTextWindowData* pData, int visibleTextWidth, int cacheIdx) + : m_pDTW(p), /* m_pDTWData(pData),*/ m_visibleTextWidth(visibleTextWidth), m_cacheIdx(cacheIdx) + { + Q_UNUSED(pData) // TODO really unused? + setAutoDelete(true); + //++s_runnableCount; // in Qt>=5.3 only + s_runnableCount.fetchAndAddOrdered(1); + } + void run() + { + m_pDTW->recalcWordWrapHelper(0, m_visibleTextWidth, m_cacheIdx); + // int newValue = --s_runnableCount; // in Qt>=5.3 only + int newValue = s_runnableCount.fetchAndAddOrdered(-1) - 1; + g_pProgressDialog->setCurrent(s_maxNofRunnables - getAtomic(s_runnableCount)); + if(newValue == 0) + { + QWidget* p = m_pDTW; + while(p) { - QMetaObject::invokeMethod(pKDiff3App, "slotFinishRecalcWordWrap", Qt::QueuedConnection); - break; + p = p->parentWidget(); + if(KDiff3App* pKDiff3App = dynamic_cast(p)) + { + QMetaObject::invokeMethod(pKDiff3App, "slotFinishRecalcWordWrap", Qt::QueuedConnection); + break; + } } - } - } - } + } + } }; static QList s_runnables; bool startRunnables() { - if ( s_runnables.count()==0 ) - { - return false; - } - else - { - g_pProgressDialog->setStayHidden(true); - g_pProgressDialog->push(); - g_pProgressDialog->setMaxNofSteps(s_runnables.count()); - s_maxNofRunnables = s_runnables.count(); - g_pProgressDialog->setCurrent(0); + if(s_runnables.count() == 0) + { + return false; + } + else + { + g_pProgressDialog->setStayHidden(true); + g_pProgressDialog->push(); + g_pProgressDialog->setMaxNofSteps(s_runnables.count()); + s_maxNofRunnables = s_runnables.count(); + g_pProgressDialog->setCurrent(0); - for (int i = 0; i < s_runnables.count(); ++i) - { - QThreadPool::globalInstance()->start(s_runnables[i]); - } + for(int i = 0; i < s_runnables.count(); ++i) + { + QThreadPool::globalInstance()->start(s_runnables[i]); + } - s_runnables.clear(); - return true; - } + s_runnables.clear(); + return true; + } } static const int s_linesPerRunnable = 2000; -void DiffTextWindow::recalcWordWrap( bool bWordWrap, int wrapLineVectorSize, int visibleTextWidth ) -{ - if (d->m_pDiff3LineVector == 0 || !isVisible()) - { - d->m_bWordWrap = bWordWrap; - if (!bWordWrap) d->m_diff3WrapLineVector.resize( 0 ); - return; - } - - d->m_bWordWrap = bWordWrap; - - if ( bWordWrap ) - { - d->m_lineNumberWidth = d->m_pOptions->m_bShowLineNumbers ? (int)log10((double)qMax(d->m_size,1))+1 : 0; - - d->m_diff3WrapLineVector.resize( wrapLineVectorSize ); - - if ( wrapLineVectorSize==0 ) - d->m_wrapLineCacheList.clear(); - - if ( wrapLineVectorSize == 0 ) - { - d->m_bPaintingAllowed = false; - for (int i = 0, j = 0; im_pDiff3LineVector->size(); i += s_linesPerRunnable, ++j) - //int i=0; - { - d->m_wrapLineCacheList.append(QVector()); - s_runnables.push_back( new RecalcWordWrapRunnable(this,d,visibleTextWidth,j) ); - } - //recalcWordWrap( bWordWrap, wrapLineVectorSize, visibleTextWidth, 0 ); - } - else - { - recalcWordWrapHelper( wrapLineVectorSize, visibleTextWidth, 0 ); - d->m_bPaintingAllowed = true; - } - } - else - { - if (wrapLineVectorSize == 0 && getAtomic( d->m_maxTextWidth ) <0 ) - { - d->m_diff3WrapLineVector.resize(0); - d->m_wrapLineCacheList.clear(); - d->m_bPaintingAllowed = false; - for (int i = 0, j = 0; i < d->m_pDiff3LineVector->size(); i += s_linesPerRunnable, ++j) - { - s_runnables.push_back(new RecalcWordWrapRunnable(this, d, visibleTextWidth, j)); - } - } - else - { - d->m_bPaintingAllowed = true; - } - } -} - -void DiffTextWindow::recalcWordWrapHelper( int wrapLineVectorSize, int visibleTextWidth, int cacheListIdx ) -{ - if ( d->m_bWordWrap ) - { - if ( g_pProgressDialog->wasCancelled() ) - return; - if (visibleTextWidth<0) - visibleTextWidth = getVisibleTextAreaWidth(); - else - visibleTextWidth-= d->leftInfoWidth() * fontMetrics().width('0'); - int i; - int wrapLineIdx = 0; - int size = d->m_pDiff3LineVector->size(); - int firstD3LineIdx = wrapLineVectorSize > 0 ? 0 : cacheListIdx * s_linesPerRunnable; - int endIdx = wrapLineVectorSize > 0 ? size : qMin(firstD3LineIdx + s_linesPerRunnable, size); - QVector& wrapLineCache = d->m_wrapLineCacheList[cacheListIdx]; - int cacheListIdx2 = 0; - QTextLayout textLayout( QString(), font(), this); - for( i=firstD3LineIdx; iwasCancelled()) +void DiffTextWindow::recalcWordWrap(bool bWordWrap, int wrapLineVectorSize, int visibleTextWidth) +{ + if(d->m_pDiff3LineVector == 0 || !isVisible()) + { + d->m_bWordWrap = bWordWrap; + if(!bWordWrap) d->m_diff3WrapLineVector.resize(0); + return; + } + + d->m_bWordWrap = bWordWrap; + + if(bWordWrap) + { + d->m_lineNumberWidth = d->m_pOptions->m_bShowLineNumbers ? (int)log10((double)qMax(d->m_size, 1)) + 1 : 0; + + d->m_diff3WrapLineVector.resize(wrapLineVectorSize); + + if(wrapLineVectorSize == 0) + d->m_wrapLineCacheList.clear(); + + if(wrapLineVectorSize == 0) + { + d->m_bPaintingAllowed = false; + for(int i = 0, j = 0; i < d->m_pDiff3LineVector->size(); i += s_linesPerRunnable, ++j) + //int i=0; + { + d->m_wrapLineCacheList.append(QVector()); + s_runnables.push_back(new RecalcWordWrapRunnable(this, d, visibleTextWidth, j)); + } + //recalcWordWrap( bWordWrap, wrapLineVectorSize, visibleTextWidth, 0 ); + } + else + { + recalcWordWrapHelper(wrapLineVectorSize, visibleTextWidth, 0); + d->m_bPaintingAllowed = true; + } + } + else + { + if(wrapLineVectorSize == 0 && getAtomic(d->m_maxTextWidth) < 0) + { + d->m_diff3WrapLineVector.resize(0); + d->m_wrapLineCacheList.clear(); + d->m_bPaintingAllowed = false; + for(int i = 0, j = 0; i < d->m_pDiff3LineVector->size(); i += s_linesPerRunnable, ++j) + { + s_runnables.push_back(new RecalcWordWrapRunnable(this, d, visibleTextWidth, j)); + } + } + else + { + d->m_bPaintingAllowed = true; + } + } +} + +void DiffTextWindow::recalcWordWrapHelper(int wrapLineVectorSize, int visibleTextWidth, int cacheListIdx) +{ + if(d->m_bWordWrap) + { + if(g_pProgressDialog->wasCancelled()) return; + if(visibleTextWidth < 0) + visibleTextWidth = getVisibleTextAreaWidth(); + else + visibleTextWidth -= d->leftInfoWidth() * fontMetrics().width('0'); + int i; + int wrapLineIdx = 0; + int size = d->m_pDiff3LineVector->size(); + int firstD3LineIdx = wrapLineVectorSize > 0 ? 0 : cacheListIdx * s_linesPerRunnable; + int endIdx = wrapLineVectorSize > 0 ? size : qMin(firstD3LineIdx + s_linesPerRunnable, size); + QVector& wrapLineCache = d->m_wrapLineCacheList[cacheListIdx]; + int cacheListIdx2 = 0; + QTextLayout textLayout(QString(), font(), this); + for(i = firstD3LineIdx; i < endIdx; ++i) + { + if(g_pProgressDialog->wasCancelled()) + return; - int linesNeeded = 0; - if ( wrapLineVectorSize==0 ) - { - QString s = d->getString( i ); - textLayout.clearLayout(); - textLayout.setText( s ); - d->prepareTextLayout( textLayout, true, visibleTextWidth ); - linesNeeded = textLayout.lineCount(); - for( int l=0; lgetString(i); + textLayout.clearLayout(); + textLayout.setText(s); + d->prepareTextLayout(textLayout, true, visibleTextWidth); + linesNeeded = textLayout.lineCount(); + for(int l = 0; l < linesNeeded; ++l) + { + QTextLine line = textLayout.lineAt(l); + wrapLineCache.push_back(DiffTextWindowData::WrapLineCacheData(i, line.textStart(), line.textLength())); + } } - } - else if ( wrapLineVectorSize > 0 && cacheListIdx2 < d->m_wrapLineCacheList.count() ) - { - DiffTextWindowData::WrapLineCacheData* pWrapLineCache = d->m_wrapLineCacheList[cacheListIdx2].data(); - int cacheIdx = 0; - int clc = d->m_wrapLineCacheList.count()-1 ; - int cllc = d->m_wrapLineCacheList.last().count() ; - int curCount = d->m_wrapLineCacheList[cacheListIdx2].count()-1; - int l=0; - while( (cacheListIdx2 < clc - || ( cacheListIdx2 == clc && cacheIdx < cllc ) ) - && pWrapLineCache->m_d3LineIdx<=i ) + else if(wrapLineVectorSize > 0 && cacheListIdx2 < d->m_wrapLineCacheList.count()) { - if ( pWrapLineCache->m_d3LineIdx==i ) - { - Diff3WrapLine* pDiff3WrapLine = &d->m_diff3WrapLineVector[ wrapLineIdx + l ]; - pDiff3WrapLine->wrapLineOffset = pWrapLineCache->m_textStart; - pDiff3WrapLine->wrapLineLength = pWrapLineCache->m_textLength; - ++l; - } - if (cacheIdx < curCount ) - { - ++cacheIdx; - ++pWrapLineCache; - } - else - { - ++cacheListIdx2; - if (cacheListIdx2 >= d->m_wrapLineCacheList.count()) - break; - pWrapLineCache = d->m_wrapLineCacheList[cacheListIdx2].data(); - curCount = d->m_wrapLineCacheList[cacheListIdx2].count(); - cacheIdx = 0; - } + DiffTextWindowData::WrapLineCacheData* pWrapLineCache = d->m_wrapLineCacheList[cacheListIdx2].data(); + int cacheIdx = 0; + int clc = d->m_wrapLineCacheList.count() - 1; + int cllc = d->m_wrapLineCacheList.last().count(); + int curCount = d->m_wrapLineCacheList[cacheListIdx2].count() - 1; + int l = 0; + while((cacheListIdx2 < clc || (cacheListIdx2 == clc && cacheIdx < cllc)) && pWrapLineCache->m_d3LineIdx <= i) + { + if(pWrapLineCache->m_d3LineIdx == i) + { + Diff3WrapLine* pDiff3WrapLine = &d->m_diff3WrapLineVector[wrapLineIdx + l]; + pDiff3WrapLine->wrapLineOffset = pWrapLineCache->m_textStart; + pDiff3WrapLine->wrapLineLength = pWrapLineCache->m_textLength; + ++l; + } + if(cacheIdx < curCount) + { + ++cacheIdx; + ++pWrapLineCache; + } + else + { + ++cacheListIdx2; + if(cacheListIdx2 >= d->m_wrapLineCacheList.count()) + break; + pWrapLineCache = d->m_wrapLineCacheList[cacheListIdx2].data(); + curCount = d->m_wrapLineCacheList[cacheListIdx2].count(); + cacheIdx = 0; + } + } + linesNeeded = l; } - linesNeeded = l; - } - - Diff3Line& d3l = *(*d->m_pDiff3LineVector)[i]; - if ( d3l.linesNeededForDisplay0 ) - { - int j; - for( j=0; jm_pDiff3LineVector)[i]; + if(d3l.linesNeededForDisplay < linesNeeded) { - Diff3WrapLine& d3wl = d->m_diff3WrapLineVector[wrapLineIdx]; - d3wl.diff3LineIndex = i; - d3wl.pD3L = (*d->m_pDiff3LineVector)[i]; - if ( j>=linesNeeded ) - { - d3wl.wrapLineOffset=0; - d3wl.wrapLineLength=0; - } + assert(wrapLineVectorSize == 0); + d3l.linesNeededForDisplay = linesNeeded; } - } - } - - if ( wrapLineVectorSize>0 ) - { - d->m_firstLine = min2( d->m_firstLine, wrapLineVectorSize-1 ); - d->m_horizScrollOffset = 0; - d->m_pDiffTextWindowFrame->setFirstLine( d->m_firstLine ); - } - } - else // no word wrap, just calc the maximum text width - { - if (g_pProgressDialog->wasCancelled()) - return; - int size = d->m_pDiff3LineVector->size(); - int firstD3LineIdx = cacheListIdx * s_linesPerRunnable; - int endIdx = qMin(firstD3LineIdx + s_linesPerRunnable, size); - - int maxTextWidth = getAtomic( d->m_maxTextWidth ); // current value - QTextLayout textLayout(QString(), font(), this); - for (int i = firstD3LineIdx; i< endIdx; ++i) - { - if (g_pProgressDialog->wasCancelled()) + + if(wrapLineVectorSize > 0) + { + int j; + for(j = 0; j < d3l.linesNeededForDisplay; ++j, ++wrapLineIdx) + { + Diff3WrapLine& d3wl = d->m_diff3WrapLineVector[wrapLineIdx]; + d3wl.diff3LineIndex = i; + d3wl.pD3L = (*d->m_pDiff3LineVector)[i]; + if(j >= linesNeeded) + { + d3wl.wrapLineOffset = 0; + d3wl.wrapLineLength = 0; + } + } + } + } + + if(wrapLineVectorSize > 0) + { + d->m_firstLine = min2(d->m_firstLine, wrapLineVectorSize - 1); + d->m_horizScrollOffset = 0; + d->m_pDiffTextWindowFrame->setFirstLine(d->m_firstLine); + } + } + else // no word wrap, just calc the maximum text width + { + if(g_pProgressDialog->wasCancelled()) return; - textLayout.clearLayout(); - textLayout.setText(d->getString(i)); - d->prepareTextLayout(textLayout, true); - if (textLayout.maximumWidth() > maxTextWidth) - maxTextWidth = textLayout.maximumWidth(); - } - - for (;;) - { - int prevMaxTextWidth = d->m_maxTextWidth.fetchAndStoreOrdered(maxTextWidth); - if (prevMaxTextWidth <= maxTextWidth) - break; - maxTextWidth = prevMaxTextWidth; - } - } + int size = d->m_pDiff3LineVector->size(); + int firstD3LineIdx = cacheListIdx * s_linesPerRunnable; + int endIdx = qMin(firstD3LineIdx + s_linesPerRunnable, size); + + int maxTextWidth = getAtomic(d->m_maxTextWidth); // current value + QTextLayout textLayout(QString(), font(), this); + for(int i = firstD3LineIdx; i < endIdx; ++i) + { + if(g_pProgressDialog->wasCancelled()) + return; + textLayout.clearLayout(); + textLayout.setText(d->getString(i)); + d->prepareTextLayout(textLayout, true); + if(textLayout.maximumWidth() > maxTextWidth) + maxTextWidth = textLayout.maximumWidth(); + } + + for(;;) + { + int prevMaxTextWidth = d->m_maxTextWidth.fetchAndStoreOrdered(maxTextWidth); + if(prevMaxTextWidth <= maxTextWidth) + break; + maxTextWidth = prevMaxTextWidth; + } + } - if ( !d->m_selection.isEmpty() && ( !d->m_bWordWrap || wrapLineVectorSize>0 ) ) - { - // Assume unwrapped coordinates - //( Why? ->Conversion to unwrapped coords happened a few lines above in this method. - // Also see KDiff3App::recalcWordWrap() on the role of wrapLineVectorSize) + if(!d->m_selection.isEmpty() && (!d->m_bWordWrap || wrapLineVectorSize > 0)) + { + // Assume unwrapped coordinates + //( Why? ->Conversion to unwrapped coords happened a few lines above in this method. + // Also see KDiff3App::recalcWordWrap() on the role of wrapLineVectorSize) - // Wrap them now. + // Wrap them now. - // convert the d->m_selection to unwrapped coordinates. - int firstLine, firstPos; - convertD3LCoordsToLineCoords( d->m_selection.beginLine(), d->m_selection.beginPos(), firstLine, firstPos ); + // convert the d->m_selection to unwrapped coordinates. + int firstLine, firstPos; + convertD3LCoordsToLineCoords(d->m_selection.beginLine(), d->m_selection.beginPos(), firstLine, firstPos); - int lastLine, lastPos; - convertD3LCoordsToLineCoords( d->m_selection.endLine(), d->m_selection.endPos(), lastLine, lastPos ); + int lastLine, lastPos; + convertD3LCoordsToLineCoords(d->m_selection.endLine(), d->m_selection.endPos(), lastLine, lastPos); - d->m_selection.start( firstLine, convertToPosOnScreen( d->getLineString( firstLine ), firstPos, d->m_pOptions->m_tabSize ) ); - d->m_selection.end( lastLine, convertToPosOnScreen( d->getLineString( lastLine ),lastPos, d->m_pOptions->m_tabSize ) ); - } + d->m_selection.start(firstLine, convertToPosOnScreen(d->getLineString(firstLine), firstPos, d->m_pOptions->m_tabSize)); + d->m_selection.end(lastLine, convertToPosOnScreen(d->getLineString(lastLine), lastPos, d->m_pOptions->m_tabSize)); + } } - class DiffTextWindowFrameData { -public: - DiffTextWindow* m_pDiffTextWindow; - QLineEdit* m_pFileSelection; - QPushButton* m_pBrowseButton; - Options* m_pOptions; - QLabel* m_pLabel; - QLabel* m_pTopLine; - QLabel* m_pEncoding; - QLabel* m_pLineEndStyle; - QWidget* m_pTopLineWidget; - int m_winIdx; - + public: + DiffTextWindow* m_pDiffTextWindow; + QLineEdit* m_pFileSelection; + QPushButton* m_pBrowseButton; + Options* m_pOptions; + QLabel* m_pLabel; + QLabel* m_pTopLine; + QLabel* m_pEncoding; + QLabel* m_pLineEndStyle; + QWidget* m_pTopLineWidget; + int m_winIdx; }; -DiffTextWindowFrame::DiffTextWindowFrame( QWidget* pParent, QStatusBar* pStatusBar, Options* pOptions, int winIdx, SourceData* psd) - : QWidget( pParent ) -{ - d = new DiffTextWindowFrameData; - d->m_winIdx = winIdx; - setAutoFillBackground(true); - d->m_pOptions = pOptions; - d->m_pTopLineWidget = new QWidget(this); - d->m_pFileSelection = new QLineEdit(d->m_pTopLineWidget); - d->m_pBrowseButton = new QPushButton( "...",d->m_pTopLineWidget ); - d->m_pBrowseButton->setFixedWidth( 30 ); - connect(d->m_pBrowseButton, &QPushButton::clicked, this, &DiffTextWindowFrame::slotBrowseButtonClicked); - connect(d->m_pFileSelection, &QLineEdit::returnPressed, this, &DiffTextWindowFrame::slotReturnPressed); - - d->m_pLabel = new QLabel("A:",d->m_pTopLineWidget); - d->m_pTopLine = new QLabel(d->m_pTopLineWidget); - d->m_pDiffTextWindow = 0; - d->m_pDiffTextWindow = new DiffTextWindow( this, pStatusBar, pOptions, winIdx ); - - QVBoxLayout* pVTopLayout = new QVBoxLayout(d->m_pTopLineWidget); - pVTopLayout->setMargin(2); - pVTopLayout->setSpacing(0); - QHBoxLayout* pHL = new QHBoxLayout(); - QHBoxLayout* pHL2 = new QHBoxLayout(); - pVTopLayout->addLayout(pHL); - pVTopLayout->addLayout(pHL2); - - // Upper line: - pHL->setMargin(0); - pHL->setSpacing(2); - - pHL->addWidget( d->m_pLabel, 0 ); - pHL->addWidget( d->m_pFileSelection, 1 ); - pHL->addWidget( d->m_pBrowseButton, 0 ); - pHL->addWidget( d->m_pTopLine, 0 ); - - // Lower line - pHL2->setMargin(0); - pHL2->setSpacing(2); - pHL2->addWidget( d->m_pTopLine, 0 ); - d->m_pEncoding = new EncodingLabel(i18n("Encoding:"), this, psd, pOptions); - - d->m_pLineEndStyle = new QLabel(i18n("Line end style:")); - pHL2->addWidget(d->m_pEncoding); - pHL2->addWidget(d->m_pLineEndStyle); - - QVBoxLayout* pVL = new QVBoxLayout( this ); - pVL->setMargin(0); - pVL->setSpacing(0); - pVL->addWidget( d->m_pTopLineWidget, 0 ); - pVL->addWidget( d->m_pDiffTextWindow, 1 ); - - d->m_pDiffTextWindow->installEventFilter( this ); - d->m_pFileSelection->installEventFilter( this ); - d->m_pBrowseButton->installEventFilter( this ); - init(); +DiffTextWindowFrame::DiffTextWindowFrame(QWidget* pParent, QStatusBar* pStatusBar, Options* pOptions, int winIdx, SourceData* psd) + : QWidget(pParent) +{ + d = new DiffTextWindowFrameData; + d->m_winIdx = winIdx; + setAutoFillBackground(true); + d->m_pOptions = pOptions; + d->m_pTopLineWidget = new QWidget(this); + d->m_pFileSelection = new QLineEdit(d->m_pTopLineWidget); + d->m_pBrowseButton = new QPushButton("...", d->m_pTopLineWidget); + d->m_pBrowseButton->setFixedWidth(30); + connect(d->m_pBrowseButton, &QPushButton::clicked, this, &DiffTextWindowFrame::slotBrowseButtonClicked); + connect(d->m_pFileSelection, &QLineEdit::returnPressed, this, &DiffTextWindowFrame::slotReturnPressed); + + d->m_pLabel = new QLabel("A:", d->m_pTopLineWidget); + d->m_pTopLine = new QLabel(d->m_pTopLineWidget); + d->m_pDiffTextWindow = 0; + d->m_pDiffTextWindow = new DiffTextWindow(this, pStatusBar, pOptions, winIdx); + + QVBoxLayout* pVTopLayout = new QVBoxLayout(d->m_pTopLineWidget); + pVTopLayout->setMargin(2); + pVTopLayout->setSpacing(0); + QHBoxLayout* pHL = new QHBoxLayout(); + QHBoxLayout* pHL2 = new QHBoxLayout(); + pVTopLayout->addLayout(pHL); + pVTopLayout->addLayout(pHL2); + + // Upper line: + pHL->setMargin(0); + pHL->setSpacing(2); + + pHL->addWidget(d->m_pLabel, 0); + pHL->addWidget(d->m_pFileSelection, 1); + pHL->addWidget(d->m_pBrowseButton, 0); + pHL->addWidget(d->m_pTopLine, 0); + + // Lower line + pHL2->setMargin(0); + pHL2->setSpacing(2); + pHL2->addWidget(d->m_pTopLine, 0); + d->m_pEncoding = new EncodingLabel(i18n("Encoding:"), this, psd, pOptions); + + d->m_pLineEndStyle = new QLabel(i18n("Line end style:")); + pHL2->addWidget(d->m_pEncoding); + pHL2->addWidget(d->m_pLineEndStyle); + + QVBoxLayout* pVL = new QVBoxLayout(this); + pVL->setMargin(0); + pVL->setSpacing(0); + pVL->addWidget(d->m_pTopLineWidget, 0); + pVL->addWidget(d->m_pDiffTextWindow, 1); + + d->m_pDiffTextWindow->installEventFilter(this); + d->m_pFileSelection->installEventFilter(this); + d->m_pBrowseButton->installEventFilter(this); + init(); } DiffTextWindowFrame::~DiffTextWindowFrame() { - delete d; + delete d; } void DiffTextWindowFrame::init() { - DiffTextWindow* pDTW = d->m_pDiffTextWindow; - if ( pDTW ) - { - QString s = QDir::toNativeSeparators( pDTW->d->m_filename ); - d->m_pFileSelection->setText( s ); - QString winId = pDTW->d->m_winIdx==1 ? - ( pDTW->d->m_bTriple?"A (Base)":"A") : - ( pDTW->d->m_winIdx==2 ? "B" : "C" ); - d->m_pLabel->setText( winId + ":" ); - d->m_pEncoding->setText( i18n("Encoding:") + " " + (pDTW->d->m_pTextCodec!=0 ? pDTW->d->m_pTextCodec->name() : QString()) ); - d->m_pLineEndStyle->setText( i18n("Line end style:") + " " + (pDTW->d->m_eLineEndStyle==eLineEndStyleDos ? i18n("DOS") : i18n("Unix")) ); - } + DiffTextWindow* pDTW = d->m_pDiffTextWindow; + if(pDTW) + { + QString s = QDir::toNativeSeparators(pDTW->d->m_filename); + d->m_pFileSelection->setText(s); + QString winId = pDTW->d->m_winIdx == 1 ? (pDTW->d->m_bTriple ? "A (Base)" : "A") : (pDTW->d->m_winIdx == 2 ? "B" : "C"); + d->m_pLabel->setText(winId + ":"); + d->m_pEncoding->setText(i18n("Encoding:") + " " + (pDTW->d->m_pTextCodec != 0 ? pDTW->d->m_pTextCodec->name() : QString())); + d->m_pLineEndStyle->setText(i18n("Line end style:") + " " + (pDTW->d->m_eLineEndStyle == eLineEndStyleDos ? i18n("DOS") : i18n("Unix"))); + } } // Search for the first visible line (search loop needed when no line exist for this file.) -int DiffTextWindow::calcTopLineInFile( int firstLine ) +int DiffTextWindow::calcTopLineInFile(int firstLine) { - int l=-1; - for ( int i = convertLineToDiff3LineIdx(firstLine); i<(int)d->m_pDiff3LineVector->size(); ++i ) - { - const Diff3Line* d3l = (*d->m_pDiff3LineVector)[i]; - l = d3l->getLineInFile(d->m_winIdx); - if (l!=-1) break; - } - return l; + int l = -1; + for(int i = convertLineToDiff3LineIdx(firstLine); i < (int)d->m_pDiff3LineVector->size(); ++i) + { + const Diff3Line* d3l = (*d->m_pDiff3LineVector)[i]; + l = d3l->getLineInFile(d->m_winIdx); + if(l != -1) break; + } + return l; } -void DiffTextWindowFrame::setFirstLine( int firstLine ) +void DiffTextWindowFrame::setFirstLine(int firstLine) { - DiffTextWindow* pDTW = d->m_pDiffTextWindow; - if ( pDTW && pDTW->d->m_pDiff3LineVector ) - { - QString s= i18n("Top line"); - int lineNumberWidth = (int)log10((double)qMax(pDTW->d->m_size,1))+1; + DiffTextWindow* pDTW = d->m_pDiffTextWindow; + if(pDTW && pDTW->d->m_pDiff3LineVector) + { + QString s = i18n("Top line"); + int lineNumberWidth = (int)log10((double)qMax(pDTW->d->m_size, 1)) + 1; - int l=pDTW->calcTopLineInFile(firstLine); + int l = pDTW->calcTopLineInFile(firstLine); - int w = d->m_pTopLine->fontMetrics().width( - s+" "+QString().fill('0',lineNumberWidth)); - d->m_pTopLine->setMinimumWidth( w ); + int w = d->m_pTopLine->fontMetrics().width( + s + " " + QString().fill('0', lineNumberWidth)); + d->m_pTopLine->setMinimumWidth(w); - if (l==-1) - s = i18n("End"); - else - s += " " + QString::number( l+1 ); + if(l == -1) + s = i18n("End"); + else + s += " " + QString::number(l + 1); - d->m_pTopLine->setText( s ); - d->m_pTopLine->repaint(); - } + d->m_pTopLine->setText(s); + d->m_pTopLine->repaint(); + } } DiffTextWindow* DiffTextWindowFrame::getDiffTextWindow() { - return d->m_pDiffTextWindow; + return d->m_pDiffTextWindow; } -bool DiffTextWindowFrame::eventFilter( QObject* o, QEvent* e ) +bool DiffTextWindowFrame::eventFilter(QObject* o, QEvent* e) { - DiffTextWindow* pDTW = d->m_pDiffTextWindow; - if ( e->type()==QEvent::FocusIn || e->type()==QEvent::FocusOut ) - { - QColor c1 = d->m_pOptions->m_bgColor; - QColor c2; - if ( d->m_winIdx==1 ) c2 = d->m_pOptions->m_colorA; - else if ( d->m_winIdx==2 ) c2 = d->m_pOptions->m_colorB; - else if ( d->m_winIdx==3 ) c2 = d->m_pOptions->m_colorC; - - QPalette p = d->m_pTopLineWidget->palette(); - if ( e->type()==QEvent::FocusOut ) - std::swap(c1,c2); - - p.setColor(QPalette::Window, c2); - setPalette( p ); - - p.setColor(QPalette::WindowText, c1); - d->m_pLabel->setPalette( p ); - d->m_pTopLine->setPalette( p ); - d->m_pEncoding->setPalette( p ); - d->m_pLineEndStyle->setPalette( p ); - } - if (o == d->m_pFileSelection && e->type()==QEvent::Drop) - { - QDropEvent* d = static_cast(e); + DiffTextWindow* pDTW = d->m_pDiffTextWindow; + if(e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) + { + QColor c1 = d->m_pOptions->m_bgColor; + QColor c2; + if(d->m_winIdx == 1) + c2 = d->m_pOptions->m_colorA; + else if(d->m_winIdx == 2) + c2 = d->m_pOptions->m_colorB; + else if(d->m_winIdx == 3) + c2 = d->m_pOptions->m_colorC; + + QPalette p = d->m_pTopLineWidget->palette(); + if(e->type() == QEvent::FocusOut) + std::swap(c1, c2); + + p.setColor(QPalette::Window, c2); + setPalette(p); + + p.setColor(QPalette::WindowText, c1); + d->m_pLabel->setPalette(p); + d->m_pTopLine->setPalette(p); + d->m_pEncoding->setPalette(p); + d->m_pLineEndStyle->setPalette(p); + } + if(o == d->m_pFileSelection && e->type() == QEvent::Drop) + { + QDropEvent* d = static_cast(e); - if ( d->mimeData()->hasUrls() ) - { - QList lst = d->mimeData()->urls(); + if(d->mimeData()->hasUrls()) + { + QList lst = d->mimeData()->urls(); - if ( lst.count() > 0 ) - { - static_cast(o)->setText( lst[0].toString() ); - static_cast(o)->setFocus(); - emit fileNameChanged( lst[0].toString(), pDTW->d->m_winIdx ); - return true; - } - } - } + if(lst.count() > 0) + { + static_cast(o)->setText(lst[0].toString()); + static_cast(o)->setFocus(); + emit fileNameChanged(lst[0].toString(), pDTW->d->m_winIdx); + return true; + } + } + } - return false; + return false; } void DiffTextWindowFrame::slotReturnPressed() { - DiffTextWindow* pDTW = d->m_pDiffTextWindow; - if ( pDTW->d->m_filename != d->m_pFileSelection->text() ) - { - emit fileNameChanged( d->m_pFileSelection->text(), pDTW->d->m_winIdx ); - } + DiffTextWindow* pDTW = d->m_pDiffTextWindow; + if(pDTW->d->m_filename != d->m_pFileSelection->text()) + { + emit fileNameChanged(d->m_pFileSelection->text(), pDTW->d->m_winIdx); + } } void DiffTextWindowFrame::slotBrowseButtonClicked() { QString current = d->m_pFileSelection->text(); QUrl newURL = QFileDialog::getOpenFileUrl(this, i18n("Open File"), QUrl::fromUserInput(current, QString(), QUrl::AssumeLocalFile)); - if ( !newURL.isEmpty() ) + if(!newURL.isEmpty()) { DiffTextWindow* pDTW = d->m_pDiffTextWindow; - emit fileNameChanged( newURL.url(), pDTW->d->m_winIdx ); + emit fileNameChanged(newURL.url(), pDTW->d->m_winIdx); } } void DiffTextWindowFrame::sendEncodingChangedSignal(QTextCodec* c) { emit encodingChanged(c); } -EncodingLabel::EncodingLabel( const QString & text, DiffTextWindowFrame* pDiffTextWindowFrame, SourceData * pSD, Options* pOptions) +EncodingLabel::EncodingLabel(const QString& text, DiffTextWindowFrame* pDiffTextWindowFrame, SourceData* pSD, Options* pOptions) : QLabel(text) { m_pDiffTextWindowFrame = pDiffTextWindowFrame; m_pOptions = pOptions; m_pSourceData = pSD; m_pContextEncodingMenu = 0; setMouseTracking(true); } -void EncodingLabel::mouseMoveEvent(QMouseEvent *) +void EncodingLabel::mouseMoveEvent(QMouseEvent*) { // When there is no data to display or it came from clipboard, // we will be use UTF-8 only, // in that case there is no possibility to change the encoding in the SourceData // so, we should hide the HandCursor and display usual ArrowCursor - if (m_pSourceData->isFromBuffer()||m_pSourceData->isEmpty()) + if(m_pSourceData->isFromBuffer() || m_pSourceData->isEmpty()) setCursor(QCursor(Qt::ArrowCursor)); - else setCursor(QCursor(Qt::PointingHandCursor)); -} - - -void EncodingLabel::mousePressEvent(QMouseEvent *) -{ - if (!(m_pSourceData->isFromBuffer()||m_pSourceData->isEmpty())) - { - delete m_pContextEncodingMenu; - m_pContextEncodingMenu = new QMenu(this); - QMenu* pContextEncodingSubMenu = new QMenu(m_pContextEncodingMenu); - - int currentTextCodecEnum = m_pSourceData->getEncoding()->mibEnum(); // the codec that will be checked in the context menu - QList mibs = QTextCodec::availableMibs(); - QList codecEnumList; - - // Adding "main" encodings - insertCodec(i18n("Unicode, 8 bit"), QTextCodec::codecForName("UTF-8"), codecEnumList, m_pContextEncodingMenu, currentTextCodecEnum); - if (QTextCodec::codecForName("System")) { - insertCodec(QString(), QTextCodec::codecForName("System"), codecEnumList, m_pContextEncodingMenu, currentTextCodecEnum); - } - - // Adding recent encodings - if (m_pOptions!=0) - { - QStringList& recentEncodings = m_pOptions->m_recentEncodings; - foreach(const QString &s, recentEncodings) - { - insertCodec("", QTextCodec::codecForName(s.toLatin1()), codecEnumList, m_pContextEncodingMenu, currentTextCodecEnum); - } - } - // Submenu to add the rest of available encodings - pContextEncodingSubMenu->setTitle(i18n("Other")); - foreach(int i, mibs) - { - QTextCodec* c = QTextCodec::codecForMib(i); - if ( c!=0 ) - insertCodec("", c, codecEnumList, pContextEncodingSubMenu, currentTextCodecEnum); - } - - m_pContextEncodingMenu->addMenu(pContextEncodingSubMenu); - - m_pContextEncodingMenu->exec(QCursor::pos()); - } -} - -void EncodingLabel::insertCodec( const QString& visibleCodecName, QTextCodec* pCodec, QList &codecEnumList, QMenu* pMenu, int currentTextCodecEnum) -{ - int CodecMIBEnum = pCodec->mibEnum(); - if ( pCodec!=0 && !codecEnumList.contains(CodecMIBEnum) ) - { - QAction* pAction = new QAction( pMenu ); // menu takes ownership, so deleting the menu deletes the action too. - pAction->setText( visibleCodecName.isEmpty() ? QString(pCodec->name()) : visibleCodecName+" ("+pCodec->name()+")" ); - pAction->setData(CodecMIBEnum); - pAction->setCheckable(true); - if (currentTextCodecEnum==CodecMIBEnum) - pAction->setChecked(true); - pMenu->addAction(pAction); - connect(pAction, SIGNAL(triggered()), this, SLOT(slotEncodingChanged())); - codecEnumList.append(CodecMIBEnum); - } + else + setCursor(QCursor(Qt::PointingHandCursor)); +} + +void EncodingLabel::mousePressEvent(QMouseEvent*) +{ + if(!(m_pSourceData->isFromBuffer() || m_pSourceData->isEmpty())) + { + delete m_pContextEncodingMenu; + m_pContextEncodingMenu = new QMenu(this); + QMenu* pContextEncodingSubMenu = new QMenu(m_pContextEncodingMenu); + + int currentTextCodecEnum = m_pSourceData->getEncoding()->mibEnum(); // the codec that will be checked in the context menu + QList mibs = QTextCodec::availableMibs(); + QList codecEnumList; + + // Adding "main" encodings + insertCodec(i18n("Unicode, 8 bit"), QTextCodec::codecForName("UTF-8"), codecEnumList, m_pContextEncodingMenu, currentTextCodecEnum); + if(QTextCodec::codecForName("System")) { + insertCodec(QString(), QTextCodec::codecForName("System"), codecEnumList, m_pContextEncodingMenu, currentTextCodecEnum); + } + + // Adding recent encodings + if(m_pOptions != 0) + { + QStringList& recentEncodings = m_pOptions->m_recentEncodings; + foreach(const QString& s, recentEncodings) + { + insertCodec("", QTextCodec::codecForName(s.toLatin1()), codecEnumList, m_pContextEncodingMenu, currentTextCodecEnum); + } + } + // Submenu to add the rest of available encodings + pContextEncodingSubMenu->setTitle(i18n("Other")); + foreach(int i, mibs) + { + QTextCodec* c = QTextCodec::codecForMib(i); + if(c != 0) + insertCodec("", c, codecEnumList, pContextEncodingSubMenu, currentTextCodecEnum); + } + + m_pContextEncodingMenu->addMenu(pContextEncodingSubMenu); + + m_pContextEncodingMenu->exec(QCursor::pos()); + } +} + +void EncodingLabel::insertCodec(const QString& visibleCodecName, QTextCodec* pCodec, QList& codecEnumList, QMenu* pMenu, int currentTextCodecEnum) +{ + int CodecMIBEnum = pCodec->mibEnum(); + if(pCodec != 0 && !codecEnumList.contains(CodecMIBEnum)) + { + QAction* pAction = new QAction(pMenu); // menu takes ownership, so deleting the menu deletes the action too. + pAction->setText(visibleCodecName.isEmpty() ? QString(pCodec->name()) : visibleCodecName + " (" + pCodec->name() + ")"); + pAction->setData(CodecMIBEnum); + pAction->setCheckable(true); + if(currentTextCodecEnum == CodecMIBEnum) + pAction->setChecked(true); + pMenu->addAction(pAction); + connect(pAction, SIGNAL(triggered()), this, SLOT(slotEncodingChanged())); + codecEnumList.append(CodecMIBEnum); + } } void EncodingLabel::slotEncodingChanged() { - QAction *pAction = qobject_cast(sender()); - if (pAction) - { - QTextCodec * pCodec = QTextCodec::codecForMib(pAction->data().toInt()); - if (pCodec!=0) - { - QString s( pCodec->name() ); - QStringList& recentEncodings = m_pOptions->m_recentEncodings; - if ( !recentEncodings.contains(s) && s!="UTF-8" && s!="System" ) - { - int itemsToRemove = recentEncodings.size() - m_maxRecentEncodings + 1; - for (int i=0; i(sender()); + if(pAction) + { + QTextCodec* pCodec = QTextCodec::codecForMib(pAction->data().toInt()); + if(pCodec != 0) + { + QString s(pCodec->name()); + QStringList& recentEncodings = m_pOptions->m_recentEncodings; + if(!recentEncodings.contains(s) && s != "UTF-8" && s != "System") { - recentEncodings.removeFirst(); + int itemsToRemove = recentEncodings.size() - m_maxRecentEncodings + 1; + for(int i = 0; i < itemsToRemove; ++i) + { + recentEncodings.removeFirst(); + } + recentEncodings.append(s); } - recentEncodings.append(s); - } - } - m_pDiffTextWindowFrame->sendEncodingChangedSignal(pCodec); - } + } + m_pDiffTextWindowFrame->sendEncodingChangedSignal(pCodec); + } } diff --git a/src/directorymergewindow.cpp b/src/directorymergewindow.cpp index f56d1e9..b01477a 100644 --- a/src/directorymergewindow.cpp +++ b/src/directorymergewindow.cpp @@ -1,3500 +1,3736 @@ /*************************************************************************** directorymergewindow.cpp ----------------- begin : Sat Oct 19 2002 copyright : (C) 2002-2011 by Joachim Eibl email : joachim.eibl at gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef _WIN32 #include #endif #include "directorymergewindow.h" #include "guiutils.h" #include "options.h" #include "progress.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 #include static bool conflictingFileTypes(MergeFileInfos& mfi); -static QPixmap getOnePixmap( e_Age eAge, bool bLink, bool bDir ); +static QPixmap getOnePixmap(e_Age eAge, bool bLink, bool bDir); class StatusInfo : public QDialog { - QTextEdit* m_pTextEdit; -public: - StatusInfo(QWidget* pParent) : QDialog( pParent ) - { - QVBoxLayout* pVLayout = new QVBoxLayout( this ); - m_pTextEdit = new QTextEdit(this); - pVLayout->addWidget( m_pTextEdit ); - setObjectName("StatusInfo"); - setWindowFlags(Qt::Dialog); - m_pTextEdit->setWordWrapMode(QTextOption::NoWrap); - m_pTextEdit->setReadOnly(true); - QPushButton* pClose = new QPushButton(tr("Close")); - connect(pClose, &QPushButton::clicked, this, &QDialog::accept); - pVLayout->addWidget(pClose); - } - - bool isEmpty(){ - return m_pTextEdit->toPlainText().isEmpty(); - } - - void addText(const QString& s ) - { - m_pTextEdit->append(s); - } - - void clear() - { - m_pTextEdit->clear(); - } - - void setVisible(bool bVisible) - { - if (bVisible) - { - m_pTextEdit->moveCursor ( QTextCursor::End ); - m_pTextEdit->moveCursor ( QTextCursor::StartOfLine ); - m_pTextEdit->ensureCursorVisible(); - } - - QDialog::setVisible(bVisible); - if ( bVisible ) - setWindowState( windowState() | Qt::WindowMaximized ); - } -}; + QTextEdit* m_pTextEdit; + + public: + StatusInfo(QWidget* pParent) : QDialog(pParent) + { + QVBoxLayout* pVLayout = new QVBoxLayout(this); + m_pTextEdit = new QTextEdit(this); + pVLayout->addWidget(m_pTextEdit); + setObjectName("StatusInfo"); + setWindowFlags(Qt::Dialog); + m_pTextEdit->setWordWrapMode(QTextOption::NoWrap); + m_pTextEdit->setReadOnly(true); + QPushButton* pClose = new QPushButton(tr("Close")); + connect(pClose, &QPushButton::clicked, this, &QDialog::accept); + pVLayout->addWidget(pClose); + } + + bool isEmpty() + { + return m_pTextEdit->toPlainText().isEmpty(); + } + + void addText(const QString& s) + { + m_pTextEdit->append(s); + } + + void clear() + { + m_pTextEdit->clear(); + } + + void setVisible(bool bVisible) + { + if(bVisible) + { + m_pTextEdit->moveCursor(QTextCursor::End); + m_pTextEdit->moveCursor(QTextCursor::StartOfLine); + m_pTextEdit->ensureCursorVisible(); + } + QDialog::setVisible(bVisible); + if(bVisible) + setWindowState(windowState() | Qt::WindowMaximized); + } +}; 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; + 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; - } + if(fa.isLocal()) + { + m_name = origName; + m_bTemp = false; + m_bSuccess = true; + } + else + { + m_name = FileAccess::tempFileName(); + m_bSuccess = fa.copyFile(m_name); + m_bTemp = m_bSuccess; + } } TempRemover::~TempRemover() { - if ( m_bTemp && ! m_name.isEmpty() ) - FileAccess::removeTempFile(m_name); + if(m_bTemp && !m_name.isEmpty()) + FileAccess::removeTempFile(m_name); } - enum Columns { - s_NameCol = 0, - s_ACol = 1, - s_BCol = 2, - s_CCol = 3, - s_OpCol = 4, - s_OpStatusCol = 5, - s_UnsolvedCol = 6, // Nr of unsolved conflicts (for 3 input files) - s_SolvedCol = 7, // Nr of auto-solvable conflicts (for 3 input files) - s_NonWhiteCol = 8, // Nr of nonwhite deltas (for 2 input files) - s_WhiteCol = 9 // Nr of white deltas (for 2 input files) + s_NameCol = 0, + s_ACol = 1, + s_BCol = 2, + s_CCol = 3, + s_OpCol = 4, + s_OpStatusCol = 5, + s_UnsolvedCol = 6, // Nr of unsolved conflicts (for 3 input files) + s_SolvedCol = 7, // Nr of auto-solvable conflicts (for 3 input files) + s_NonWhiteCol = 8, // Nr of nonwhite deltas (for 2 input files) + s_WhiteCol = 9 // Nr of white deltas (for 2 input files) }; enum e_OperationStatus { - eOpStatusNone, - eOpStatusDone, - eOpStatusError, - eOpStatusSkipped, - eOpStatusNotSaved, - eOpStatusInProgress, - eOpStatusToDo + eOpStatusNone, + eOpStatusDone, + eOpStatusError, + eOpStatusSkipped, + eOpStatusNotSaved, + eOpStatusInProgress, + eOpStatusToDo }; class MergeFileInfos { -public: - MergeFileInfos() - { - m_bEqualAB=false; m_bEqualAC=false; m_bEqualBC=false; - m_pParent=0; - m_bOperationComplete=false; m_bSimOpComplete = false; - m_eMergeOperation=eNoOperation; - m_eOpStatus = eOpStatusNone; - m_ageA = eNotThere; m_ageB=eNotThere; m_ageC=eNotThere; - m_bConflictingAges=false; - m_pFileInfoA = 0; m_pFileInfoB = 0; m_pFileInfoC = 0; - } - ~MergeFileInfos() - { - //for( int i=0; i( const MergeFileInfos& ); - QString subPath() const - { - return m_pFileInfoA && m_pFileInfoA->exists() ? m_pFileInfoA->filePath() : - m_pFileInfoB && m_pFileInfoB->exists() ? m_pFileInfoB->filePath() : - m_pFileInfoC && m_pFileInfoC->exists() ? m_pFileInfoC->filePath() : - QString(""); - } - QString fileName() const - { - return m_pFileInfoA && m_pFileInfoA->exists() ? m_pFileInfoA->fileName() : - m_pFileInfoB && m_pFileInfoB->exists() ? m_pFileInfoB->fileName() : - m_pFileInfoC && m_pFileInfoC->exists() ? m_pFileInfoC->fileName() : - QString(""); - } - bool dirA() const { return m_pFileInfoA ? m_pFileInfoA->isDir() : false; } - bool dirB() const { return m_pFileInfoB ? m_pFileInfoB->isDir() : false; } - bool dirC() const { return m_pFileInfoC ? m_pFileInfoC->isDir() : false; } - bool isLinkA() const { return m_pFileInfoA ? m_pFileInfoA->isSymLink() : false; } - bool isLinkB() const { return m_pFileInfoB ? m_pFileInfoB->isSymLink() : false; } - bool isLinkC() const { return m_pFileInfoC ? m_pFileInfoC->isSymLink() : false; } - bool existsInA() const { return m_pFileInfoA!=0; } - bool existsInB() const { return m_pFileInfoB!=0; } - bool existsInC() const { return m_pFileInfoC!=0; } - MergeFileInfos* m_pParent; - FileAccess* m_pFileInfoA; - FileAccess* m_pFileInfoB; - FileAccess* m_pFileInfoC; - TotalDiffStatus m_totalDiffStatus; - QList m_children; - - e_MergeOperation m_eMergeOperation : 5; - e_OperationStatus m_eOpStatus : 4; - - e_Age m_ageA : 3; - e_Age m_ageB : 3; - e_Age m_ageC : 3; - - bool m_bOperationComplete : 1; - bool m_bSimOpComplete : 1; - - bool m_bEqualAB : 1; - bool m_bEqualAC : 1; - bool m_bEqualBC : 1; - bool m_bConflictingAges : 1; // Equal age but files are not! + public: + MergeFileInfos() + { + m_bEqualAB = false; + m_bEqualAC = false; + m_bEqualBC = false; + m_pParent = 0; + m_bOperationComplete = false; + m_bSimOpComplete = false; + m_eMergeOperation = eNoOperation; + m_eOpStatus = eOpStatusNone; + m_ageA = eNotThere; + m_ageB = eNotThere; + m_ageC = eNotThere; + m_bConflictingAges = false; + m_pFileInfoA = 0; + m_pFileInfoB = 0; + m_pFileInfoC = 0; + } + ~MergeFileInfos() + { + //for( int i=0; i( const MergeFileInfos& ); + QString subPath() const + { + return m_pFileInfoA && m_pFileInfoA->exists() ? m_pFileInfoA->filePath() : m_pFileInfoB && m_pFileInfoB->exists() ? m_pFileInfoB->filePath() : m_pFileInfoC && m_pFileInfoC->exists() ? m_pFileInfoC->filePath() : QString(""); + } + QString fileName() const + { + return m_pFileInfoA && m_pFileInfoA->exists() ? m_pFileInfoA->fileName() : m_pFileInfoB && m_pFileInfoB->exists() ? m_pFileInfoB->fileName() : m_pFileInfoC && m_pFileInfoC->exists() ? m_pFileInfoC->fileName() : QString(""); + } + bool dirA() const { return m_pFileInfoA ? m_pFileInfoA->isDir() : false; } + bool dirB() const { return m_pFileInfoB ? m_pFileInfoB->isDir() : false; } + bool dirC() const { return m_pFileInfoC ? m_pFileInfoC->isDir() : false; } + bool isLinkA() const { return m_pFileInfoA ? m_pFileInfoA->isSymLink() : false; } + bool isLinkB() const { return m_pFileInfoB ? m_pFileInfoB->isSymLink() : false; } + bool isLinkC() const { return m_pFileInfoC ? m_pFileInfoC->isSymLink() : false; } + bool existsInA() const { return m_pFileInfoA != 0; } + bool existsInB() const { return m_pFileInfoB != 0; } + bool existsInC() const { return m_pFileInfoC != 0; } + MergeFileInfos* m_pParent; + FileAccess* m_pFileInfoA; + FileAccess* m_pFileInfoB; + FileAccess* m_pFileInfoC; + TotalDiffStatus m_totalDiffStatus; + QList m_children; + + e_MergeOperation m_eMergeOperation : 5; + e_OperationStatus m_eOpStatus : 4; + + e_Age m_ageA : 3; + e_Age m_ageB : 3; + e_Age m_ageC : 3; + + bool m_bOperationComplete : 1; + bool m_bSimOpComplete : 1; + + bool m_bEqualAB : 1; + bool m_bEqualAC : 1; + bool m_bEqualBC : 1; + bool m_bConflictingAges : 1; // Equal age but files are not! }; static Qt::CaseSensitivity s_eCaseSensitivity = Qt::CaseSensitive; class DirectoryMergeWindow::Data : public QAbstractItemModel { -public: - DirectoryMergeWindow* q; - Data( DirectoryMergeWindow* pDMW ) - { - q = pDMW; - m_pOptions = 0; - m_pIconLoader = 0; - m_pDirectoryMergeInfo = 0; - m_bSimulatedMergeStarted=false; - m_bRealMergeStarted=false; - m_bError = false; - m_bSyncMode = false; - m_pStatusInfo = new StatusInfo(q); - m_pStatusInfo->hide(); - m_bScanning = false; - m_bCaseSensitive = true; - m_bUnfoldSubdirs = false; - m_bSkipDirStatus = false; - m_pRoot = new MergeFileInfos; - } - ~Data() - { - delete m_pRoot; - } - // Implement QAbstractItemModel - QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; - //Qt::ItemFlags flags ( const QModelIndex & index ) const - QModelIndex parent ( const QModelIndex & index ) const - { - MergeFileInfos* pMFI = getMFI( index ); - if ( pMFI == 0 || pMFI==m_pRoot || pMFI->m_pParent==m_pRoot ) - return QModelIndex(); - else - { - MergeFileInfos* pParentsParent = pMFI->m_pParent->m_pParent; - return createIndex( pParentsParent->m_children.indexOf(pMFI->m_pParent), 0, pMFI->m_pParent ); - } - } - int rowCount ( const QModelIndex & parent = QModelIndex() ) const - { - MergeFileInfos* pParentMFI = getMFI( parent ); - if ( pParentMFI!=0 ) - return pParentMFI->m_children.count(); - else - return m_pRoot->m_children.count(); - } - int columnCount ( const QModelIndex & /*parent*/ ) const - { - return 10; - } - QModelIndex index ( int row, int column, const QModelIndex & parent ) const - { - MergeFileInfos* pParentMFI = getMFI( parent ); - if ( pParentMFI == 0 && row < m_pRoot->m_children.count() ) - return createIndex( row, column, m_pRoot->m_children[row] ); - else if ( pParentMFI != 0 && row < pParentMFI->m_children.count() ) - return createIndex( row, column, pParentMFI->m_children[row] ); - else - return QModelIndex(); - } - QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; - void sort( int column, Qt::SortOrder order ); - // private data and helper methods - MergeFileInfos* getMFI( const QModelIndex& mi ) const - { - if ( mi.isValid() ) - return (MergeFileInfos*)mi.internalPointer(); - else - return 0; - } - MergeFileInfos* m_pRoot; - - QString fullNameA( const MergeFileInfos& mfi ) - { return mfi.existsInA() ? mfi.m_pFileInfoA->absoluteFilePath() : m_dirA.absoluteFilePath() + "/" + mfi.subPath(); } - QString fullNameB( const MergeFileInfos& mfi ) - { return mfi.existsInB() ? mfi.m_pFileInfoB->absoluteFilePath() : m_dirB.absoluteFilePath() + "/" + mfi.subPath(); } - QString fullNameC( const MergeFileInfos& mfi ) - { return mfi.existsInC() ? mfi.m_pFileInfoC->absoluteFilePath() : m_dirC.absoluteFilePath() + "/" + mfi.subPath(); } - QString fullNameDest( const MergeFileInfos& mfi ) - { if ( m_dirDestInternal.prettyAbsPath() == m_dirC.prettyAbsPath() ) return fullNameC(mfi); - else if ( m_dirDestInternal.prettyAbsPath() == m_dirB.prettyAbsPath() ) return fullNameB(mfi); - else return m_dirDestInternal.absoluteFilePath() + "/" + mfi.subPath(); - } - - FileAccess m_dirA; - FileAccess m_dirB; - FileAccess m_dirC; - FileAccess m_dirDest; - FileAccess m_dirDestInternal; - Options* m_pOptions; - - void calcDirStatus( bool bThreeDirs, const QModelIndex& mi, - int& nofFiles, int& nofDirs, int& nofEqualFiles, int& nofManualMerges ); - - void mergeContinue( bool bStart, bool bVerbose ); - - void prepareListView(ProgressProxy& pp); - void calcSuggestedOperation( const QModelIndex& mi, e_MergeOperation eDefaultOperation ); - void setAllMergeOperations( e_MergeOperation eDefaultOperation ); - friend class MergeFileInfos; - - bool canContinue(); - QModelIndex treeIterator( QModelIndex mi, bool bVisitChildren=true, bool bFindInvisible=false ); - void prepareMergeStart( const QModelIndex& miBegin, const QModelIndex& miEnd, bool bVerbose ); - bool executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge ); - - void scanDirectory( const QString& dirName, t_DirectoryList& dirList ); - void scanLocalDirectory( const QString& dirName, t_DirectoryList& dirList ); - bool fastFileComparison( FileAccess& fi1, FileAccess& fi2, - bool& bError, QString& status ); - void compareFilesAndCalcAges( MergeFileInfos& mfi ); - - void setMergeOperation( const QModelIndex& mi, e_MergeOperation eMergeOp, bool bRecursive = true ); - bool isDir( const QModelIndex& mi ); - QString getFileName( const QModelIndex& mi ); - - 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 ); - - t_DirectoryList m_dirListA; - t_DirectoryList m_dirListB; - t_DirectoryList m_dirListC; - - QString m_dirMergeStateFilename; - - class FileKey - { - public: - const FileAccess* m_pFA; - FileKey( const FileAccess& fa ) : m_pFA( &fa ){} - - int getParents( const FileAccess* pFA, const FileAccess* v[] ) const - { - int s = 0; - for(s=0; pFA->parent() != 0 ; pFA=pFA->parent(), ++s ) - v[s] = pFA ; - return s; - } - - // This is essentially the same as - // int r = filePath().compare( fa.filePath() ) - // if ( r<0 ) return true; - // if ( r==0 ) return m_col < fa.m_col; - // return false; - bool operator< ( const FileKey& fk ) const - { - const FileAccess* v1[100]; - const FileAccess* v2[100]; - int v1Size = getParents(m_pFA, v1); - int v2Size = getParents(fk.m_pFA, v2); - - for( int i=0; ifileName().compare( v2[v2Size-i-1]->fileName(), s_eCaseSensitivity ); - if ( r < 0 ) - return true; - else if ( r > 0 ) - return false; - } - - if ( v1Size < v2Size ) - return true; - return false; - } - }; - typedef QMap t_fileMergeMap; - t_fileMergeMap m_fileMergeMap; - - bool m_bFollowDirLinks; - bool m_bFollowFileLinks; - bool m_bSimulatedMergeStarted; - bool m_bRealMergeStarted; - bool m_bError; - bool m_bSyncMode; - bool m_bDirectoryMerge; // if true, then merge is the default operation, otherwise it's diff. - bool m_bCaseSensitive; - bool m_bUnfoldSubdirs; - bool m_bSkipDirStatus; - bool m_bScanning; // true while in init() - - KIconLoader* m_pIconLoader; - DirectoryMergeInfo* m_pDirectoryMergeInfo; - StatusInfo* m_pStatusInfo; - - typedef std::list< QModelIndex > MergeItemList; // linked list - MergeItemList m_mergeItemList; - MergeItemList::iterator m_currentIndexForOperation; - - QModelIndex m_selection1Index; - QModelIndex m_selection2Index; - QModelIndex m_selection3Index; - void selectItemAndColumn( const QModelIndex& mi, bool bContextMenu); - friend class DirMergeItem; - - QAction * m_pDirStartOperation; - QAction * m_pDirRunOperationForCurrentItem; - QAction * m_pDirCompareCurrent; - QAction * m_pDirMergeCurrent; - QAction * m_pDirRescan; - QAction * m_pDirChooseAEverywhere; - QAction * m_pDirChooseBEverywhere; - QAction * m_pDirChooseCEverywhere; - QAction * m_pDirAutoChoiceEverywhere; - QAction * m_pDirDoNothingEverywhere; - QAction * m_pDirFoldAll; - QAction * m_pDirUnfoldAll; - - KToggleAction* m_pDirShowIdenticalFiles; - KToggleAction* m_pDirShowDifferentFiles; - KToggleAction* m_pDirShowFilesOnlyInA; - KToggleAction* m_pDirShowFilesOnlyInB; - KToggleAction* m_pDirShowFilesOnlyInC; - - KToggleAction* m_pDirSynchronizeDirectories; - KToggleAction* m_pDirChooseNewerFiles; - - QAction * m_pDirCompareExplicit; - QAction * m_pDirMergeExplicit; - - QAction * m_pDirCurrentDoNothing; - QAction * m_pDirCurrentChooseA; - QAction * m_pDirCurrentChooseB; - QAction * m_pDirCurrentChooseC; - QAction * m_pDirCurrentMerge; - QAction * m_pDirCurrentDelete; - - QAction * m_pDirCurrentSyncDoNothing; - QAction * m_pDirCurrentSyncCopyAToB; - QAction * m_pDirCurrentSyncCopyBToA; - QAction * m_pDirCurrentSyncDeleteA; - QAction * m_pDirCurrentSyncDeleteB; - QAction * m_pDirCurrentSyncDeleteAAndB; - QAction * m_pDirCurrentSyncMergeToA; - QAction * m_pDirCurrentSyncMergeToB; - QAction * m_pDirCurrentSyncMergeToAAndB; - - QAction * m_pDirSaveMergeState; - QAction * m_pDirLoadMergeState; - - bool init( FileAccess& dirA, FileAccess& dirB, FileAccess& dirC, FileAccess& dirDest, bool bDirectoryMerge, bool bReload ); - void setOpStatus( const QModelIndex& mi, e_OperationStatus eOpStatus ) - { - if ( MergeFileInfos* pMFI = getMFI(mi) ) - { - pMFI->m_eOpStatus = eOpStatus; - emit dataChanged( mi, mi ); - } - } + public: + DirectoryMergeWindow* q; + Data(DirectoryMergeWindow* pDMW) + { + q = pDMW; + m_pOptions = 0; + m_pIconLoader = 0; + m_pDirectoryMergeInfo = 0; + m_bSimulatedMergeStarted = false; + m_bRealMergeStarted = false; + m_bError = false; + m_bSyncMode = false; + m_pStatusInfo = new StatusInfo(q); + m_pStatusInfo->hide(); + m_bScanning = false; + m_bCaseSensitive = true; + m_bUnfoldSubdirs = false; + m_bSkipDirStatus = false; + m_pRoot = new MergeFileInfos; + } + ~Data() + { + delete m_pRoot; + } + // Implement QAbstractItemModel + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + //Qt::ItemFlags flags ( const QModelIndex & index ) const + QModelIndex parent(const QModelIndex& index) const + { + MergeFileInfos* pMFI = getMFI(index); + if(pMFI == 0 || pMFI == m_pRoot || pMFI->m_pParent == m_pRoot) + return QModelIndex(); + else + { + MergeFileInfos* pParentsParent = pMFI->m_pParent->m_pParent; + return createIndex(pParentsParent->m_children.indexOf(pMFI->m_pParent), 0, pMFI->m_pParent); + } + } + int rowCount(const QModelIndex& parent = QModelIndex()) const + { + MergeFileInfos* pParentMFI = getMFI(parent); + if(pParentMFI != 0) + return pParentMFI->m_children.count(); + else + return m_pRoot->m_children.count(); + } + int columnCount(const QModelIndex& /*parent*/) const + { + return 10; + } + QModelIndex index(int row, int column, const QModelIndex& parent) const + { + MergeFileInfos* pParentMFI = getMFI(parent); + if(pParentMFI == 0 && row < m_pRoot->m_children.count()) + return createIndex(row, column, m_pRoot->m_children[row]); + else if(pParentMFI != 0 && row < pParentMFI->m_children.count()) + return createIndex(row, column, pParentMFI->m_children[row]); + else + return QModelIndex(); + } + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + void sort(int column, Qt::SortOrder order); + // private data and helper methods + MergeFileInfos* getMFI(const QModelIndex& mi) const + { + if(mi.isValid()) + return (MergeFileInfos*)mi.internalPointer(); + else + return 0; + } + MergeFileInfos* m_pRoot; + + QString fullNameA(const MergeFileInfos& mfi) + { + return mfi.existsInA() ? mfi.m_pFileInfoA->absoluteFilePath() : m_dirA.absoluteFilePath() + "/" + mfi.subPath(); + } + QString fullNameB(const MergeFileInfos& mfi) + { + return mfi.existsInB() ? mfi.m_pFileInfoB->absoluteFilePath() : m_dirB.absoluteFilePath() + "/" + mfi.subPath(); + } + QString fullNameC(const MergeFileInfos& mfi) + { + return mfi.existsInC() ? mfi.m_pFileInfoC->absoluteFilePath() : m_dirC.absoluteFilePath() + "/" + mfi.subPath(); + } + QString fullNameDest(const MergeFileInfos& mfi) + { + if(m_dirDestInternal.prettyAbsPath() == m_dirC.prettyAbsPath()) + return fullNameC(mfi); + else if(m_dirDestInternal.prettyAbsPath() == m_dirB.prettyAbsPath()) + return fullNameB(mfi); + else + return m_dirDestInternal.absoluteFilePath() + "/" + mfi.subPath(); + } + + FileAccess m_dirA; + FileAccess m_dirB; + FileAccess m_dirC; + FileAccess m_dirDest; + FileAccess m_dirDestInternal; + Options* m_pOptions; + + void calcDirStatus(bool bThreeDirs, const QModelIndex& mi, + int& nofFiles, int& nofDirs, int& nofEqualFiles, int& nofManualMerges); + + void mergeContinue(bool bStart, bool bVerbose); + + void prepareListView(ProgressProxy& pp); + void calcSuggestedOperation(const QModelIndex& mi, e_MergeOperation eDefaultOperation); + void setAllMergeOperations(e_MergeOperation eDefaultOperation); + friend class MergeFileInfos; + + bool canContinue(); + QModelIndex treeIterator(QModelIndex mi, bool bVisitChildren = true, bool bFindInvisible = false); + void prepareMergeStart(const QModelIndex& miBegin, const QModelIndex& miEnd, bool bVerbose); + bool executeMergeOperation(MergeFileInfos& mfi, bool& bSingleFileMerge); + + void scanDirectory(const QString& dirName, t_DirectoryList& dirList); + void scanLocalDirectory(const QString& dirName, t_DirectoryList& dirList); + bool fastFileComparison(FileAccess& fi1, FileAccess& fi2, + bool& bError, QString& status); + void compareFilesAndCalcAges(MergeFileInfos& mfi); + + void setMergeOperation(const QModelIndex& mi, e_MergeOperation eMergeOp, bool bRecursive = true); + bool isDir(const QModelIndex& mi); + QString getFileName(const QModelIndex& mi); + + 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); + + t_DirectoryList m_dirListA; + t_DirectoryList m_dirListB; + t_DirectoryList m_dirListC; + + QString m_dirMergeStateFilename; + + class FileKey + { + public: + const FileAccess* m_pFA; + FileKey(const FileAccess& fa) : m_pFA(&fa) {} + + int getParents(const FileAccess* pFA, const FileAccess* v[]) const + { + int s = 0; + for(s = 0; pFA->parent() != 0; pFA = pFA->parent(), ++s) + v[s] = pFA; + return s; + } + + // This is essentially the same as + // int r = filePath().compare( fa.filePath() ) + // if ( r<0 ) return true; + // if ( r==0 ) return m_col < fa.m_col; + // return false; + bool operator<(const FileKey& fk) const + { + const FileAccess* v1[100]; + const FileAccess* v2[100]; + int v1Size = getParents(m_pFA, v1); + int v2Size = getParents(fk.m_pFA, v2); + + for(int i = 0; i < v1Size && i < v2Size; ++i) + { + int r = v1[v1Size - i - 1]->fileName().compare(v2[v2Size - i - 1]->fileName(), s_eCaseSensitivity); + if(r < 0) + return true; + else if(r > 0) + return false; + } + + if(v1Size < v2Size) + return true; + return false; + } + }; + typedef QMap t_fileMergeMap; + t_fileMergeMap m_fileMergeMap; + + bool m_bFollowDirLinks; + bool m_bFollowFileLinks; + bool m_bSimulatedMergeStarted; + bool m_bRealMergeStarted; + bool m_bError; + bool m_bSyncMode; + bool m_bDirectoryMerge; // if true, then merge is the default operation, otherwise it's diff. + bool m_bCaseSensitive; + bool m_bUnfoldSubdirs; + bool m_bSkipDirStatus; + bool m_bScanning; // true while in init() + + KIconLoader* m_pIconLoader; + DirectoryMergeInfo* m_pDirectoryMergeInfo; + StatusInfo* m_pStatusInfo; + + typedef std::list MergeItemList; // linked list + MergeItemList m_mergeItemList; + MergeItemList::iterator m_currentIndexForOperation; + + QModelIndex m_selection1Index; + QModelIndex m_selection2Index; + QModelIndex m_selection3Index; + void selectItemAndColumn(const QModelIndex& mi, bool bContextMenu); + friend class DirMergeItem; + + QAction* m_pDirStartOperation; + QAction* m_pDirRunOperationForCurrentItem; + QAction* m_pDirCompareCurrent; + QAction* m_pDirMergeCurrent; + QAction* m_pDirRescan; + QAction* m_pDirChooseAEverywhere; + QAction* m_pDirChooseBEverywhere; + QAction* m_pDirChooseCEverywhere; + QAction* m_pDirAutoChoiceEverywhere; + QAction* m_pDirDoNothingEverywhere; + QAction* m_pDirFoldAll; + QAction* m_pDirUnfoldAll; + + KToggleAction* m_pDirShowIdenticalFiles; + KToggleAction* m_pDirShowDifferentFiles; + KToggleAction* m_pDirShowFilesOnlyInA; + KToggleAction* m_pDirShowFilesOnlyInB; + KToggleAction* m_pDirShowFilesOnlyInC; + + KToggleAction* m_pDirSynchronizeDirectories; + KToggleAction* m_pDirChooseNewerFiles; + + QAction* m_pDirCompareExplicit; + QAction* m_pDirMergeExplicit; + + QAction* m_pDirCurrentDoNothing; + QAction* m_pDirCurrentChooseA; + QAction* m_pDirCurrentChooseB; + QAction* m_pDirCurrentChooseC; + QAction* m_pDirCurrentMerge; + QAction* m_pDirCurrentDelete; + + QAction* m_pDirCurrentSyncDoNothing; + QAction* m_pDirCurrentSyncCopyAToB; + QAction* m_pDirCurrentSyncCopyBToA; + QAction* m_pDirCurrentSyncDeleteA; + QAction* m_pDirCurrentSyncDeleteB; + QAction* m_pDirCurrentSyncDeleteAAndB; + QAction* m_pDirCurrentSyncMergeToA; + QAction* m_pDirCurrentSyncMergeToB; + QAction* m_pDirCurrentSyncMergeToAAndB; + + QAction* m_pDirSaveMergeState; + QAction* m_pDirLoadMergeState; + + bool init(FileAccess& dirA, FileAccess& dirB, FileAccess& dirC, FileAccess& dirDest, bool bDirectoryMerge, bool bReload); + void setOpStatus(const QModelIndex& mi, e_OperationStatus eOpStatus) + { + if(MergeFileInfos* pMFI = getMFI(mi)) + { + pMFI->m_eOpStatus = eOpStatus; + emit dataChanged(mi, mi); + } + } }; -QVariant DirectoryMergeWindow::Data::data( const QModelIndex & index, int role ) const -{ - MergeFileInfos* pMFI = getMFI( index ); - if ( pMFI ) - { - if ( role == Qt::DisplayRole ) - { - switch ( index.column() ) - { - case s_NameCol: return QFileInfo(pMFI->subPath()).fileName(); - case s_ACol: return "A"; - case s_BCol: return "B"; - case s_CCol: return "C"; - //case s_OpCol: return i18n("Operation"); - //case s_OpStatusCol: return i18n("Status"); - case s_UnsolvedCol: return i18n("Unsolved"); - case s_SolvedCol: return i18n("Solved"); - case s_NonWhiteCol: return i18n("Nonwhite"); - case s_WhiteCol: return i18n("White"); - //default : return QVariant(); - } - - if ( s_OpCol == index.column() ) - { - bool bDir = pMFI->dirA() || pMFI->dirB() || pMFI->dirC(); - switch( pMFI->m_eMergeOperation ) +QVariant DirectoryMergeWindow::Data::data(const QModelIndex& index, int role) const +{ + MergeFileInfos* pMFI = getMFI(index); + if(pMFI) + { + if(role == Qt::DisplayRole) + { + switch(index.column()) + { + case s_NameCol: + return QFileInfo(pMFI->subPath()).fileName(); + case s_ACol: + return "A"; + case s_BCol: + return "B"; + case s_CCol: + return "C"; + //case s_OpCol: return i18n("Operation"); + //case s_OpStatusCol: return i18n("Status"); + case s_UnsolvedCol: + return i18n("Unsolved"); + case s_SolvedCol: + return i18n("Solved"); + case s_NonWhiteCol: + return i18n("Nonwhite"); + case s_WhiteCol: + return i18n("White"); + //default : return QVariant(); + } + + if(s_OpCol == index.column()) { - case eNoOperation: return ""; break; - case eCopyAToB: return i18n("Copy A to B"); break; - case eCopyBToA: return i18n("Copy B to A"); break; - case eDeleteA: return i18n("Delete A"); break; - case eDeleteB: return i18n("Delete B"); break; - case eDeleteAB: return i18n("Delete A & B"); break; - case eMergeToA: return i18n("Merge to A"); break; - case eMergeToB: return i18n("Merge to B"); break; - case eMergeToAB: return i18n("Merge to A & B"); break; - case eCopyAToDest: return "A"; break; - case eCopyBToDest: return "B"; break; - case eCopyCToDest: return "C"; break; - case eDeleteFromDest: return i18n("Delete (if exists)"); break; - case eMergeABCToDest: return bDir ? i18n("Merge") : i18n("Merge (manual)"); break; - case eMergeABToDest: return bDir ? i18n("Merge") : i18n("Merge (manual)"); break; - case eConflictingFileTypes: return i18n("Error: Conflicting File Types"); break; - case eChangedAndDeleted: return i18n("Error: Changed and Deleted"); break; - case eConflictingAges: return i18n("Error: Dates are equal but files are not."); break; - default: assert(false); break; - } - } - if ( s_OpStatusCol == index.column() ) - { - switch( pMFI->m_eOpStatus ) + bool bDir = pMFI->dirA() || pMFI->dirB() || pMFI->dirC(); + switch(pMFI->m_eMergeOperation) + { + case eNoOperation: + return ""; + break; + case eCopyAToB: + return i18n("Copy A to B"); + break; + case eCopyBToA: + return i18n("Copy B to A"); + break; + case eDeleteA: + return i18n("Delete A"); + break; + case eDeleteB: + return i18n("Delete B"); + break; + case eDeleteAB: + return i18n("Delete A & B"); + break; + case eMergeToA: + return i18n("Merge to A"); + break; + case eMergeToB: + return i18n("Merge to B"); + break; + case eMergeToAB: + return i18n("Merge to A & B"); + break; + case eCopyAToDest: + return "A"; + break; + case eCopyBToDest: + return "B"; + break; + case eCopyCToDest: + return "C"; + break; + case eDeleteFromDest: + return i18n("Delete (if exists)"); + break; + case eMergeABCToDest: + return bDir ? i18n("Merge") : i18n("Merge (manual)"); + break; + case eMergeABToDest: + return bDir ? i18n("Merge") : i18n("Merge (manual)"); + break; + case eConflictingFileTypes: + return i18n("Error: Conflicting File Types"); + break; + case eChangedAndDeleted: + return i18n("Error: Changed and Deleted"); + break; + case eConflictingAges: + return i18n("Error: Dates are equal but files are not."); + break; + default: + assert(false); + break; + } + } + if(s_OpStatusCol == index.column()) + { + switch(pMFI->m_eOpStatus) + { + case eOpStatusNone: + return ""; + case eOpStatusDone: + return i18n("Done"); + case eOpStatusError: + return i18n("Error"); + case eOpStatusSkipped: + return i18n("Skipped."); + case eOpStatusNotSaved: + return i18n("Not saved."); + case eOpStatusInProgress: + return i18n("In progress..."); + case eOpStatusToDo: + return i18n("To do."); + } + } + } + else if(role == Qt::DecorationRole) + { + if(s_NameCol == index.column()) + { + return getOnePixmap(eAgeEnd, pMFI->isLinkA() || pMFI->isLinkB() || pMFI->isLinkC(), + pMFI->dirA() || pMFI->dirB() || pMFI->dirC()); + } + + if(s_ACol == index.column()) { - case eOpStatusNone: return ""; - case eOpStatusDone: return i18n("Done"); - case eOpStatusError: return i18n("Error"); - case eOpStatusSkipped: return i18n("Skipped."); - case eOpStatusNotSaved:return i18n("Not saved."); - case eOpStatusInProgress: return i18n("In progress..."); - case eOpStatusToDo: return i18n("To do."); - } - } - } - else if ( role == Qt::DecorationRole ) - { - if ( s_NameCol == index.column() ) - { - return getOnePixmap( eAgeEnd, pMFI->isLinkA() || pMFI->isLinkB() || pMFI->isLinkC(), - pMFI->dirA() || pMFI->dirB() || pMFI->dirC() ); - } - - if ( s_ACol == index.column() ) - { - return getOnePixmap( pMFI->m_ageA, pMFI->isLinkA(), pMFI->dirA() ); - } - if ( s_BCol == index.column() ) - { - return getOnePixmap( pMFI->m_ageB, pMFI->isLinkB(), pMFI->dirB() ); - } - if ( s_CCol == index.column() ) - { - return getOnePixmap( pMFI->m_ageC, pMFI->isLinkC(), pMFI->dirC() ); - } - } - else if ( role == Qt::TextAlignmentRole ) - { - if ( s_UnsolvedCol == index.column() || s_SolvedCol == index.column() - || s_NonWhiteCol == index.column() || s_WhiteCol == index.column() ) - return Qt::AlignRight; - } - } - return QVariant(); -} - -QVariant DirectoryMergeWindow::Data::headerData ( int section, Qt::Orientation orientation, int role ) const -{ - if ( orientation == Qt::Horizontal && section>=0 && sectionm_ageA, pMFI->isLinkA(), pMFI->dirA()); + } + if(s_BCol == index.column()) + { + return getOnePixmap(pMFI->m_ageB, pMFI->isLinkB(), pMFI->dirB()); + } + if(s_CCol == index.column()) + { + return getOnePixmap(pMFI->m_ageC, pMFI->isLinkC(), pMFI->dirC()); + } + } + else if(role == Qt::TextAlignmentRole) + { + if(s_UnsolvedCol == index.column() || s_SolvedCol == index.column() || s_NonWhiteCol == index.column() || s_WhiteCol == index.column()) + return Qt::AlignRight; + } + } + return QVariant(); +} + +QVariant DirectoryMergeWindow::Data::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(orientation == Qt::Horizontal && section >= 0 && section < columnCount(QModelIndex()) && role == Qt::DisplayRole) + { + switch(section) + { + case s_NameCol: + return i18n("Name"); + case s_ACol: + return "A"; + case s_BCol: + return "B"; + case s_CCol: + return "C"; + case s_OpCol: + return i18n("Operation"); + case s_OpStatusCol: + return i18n("Status"); + case s_UnsolvedCol: + return i18n("Unsolved"); + case s_SolvedCol: + return i18n("Solved"); + case s_NonWhiteCol: + return i18n("Nonwhite"); + case s_WhiteCol: + return i18n("White"); + default: + return QVariant(); + } + } + return QVariant(); } // Previously Q3ListViewItem::paintCell(p,cg,column,width,align); class DirectoryMergeWindow::DirMergeItemDelegate : public QStyledItemDelegate { - DirectoryMergeWindow* m_pDMW; - DirectoryMergeWindow::Data* d; -public: - DirMergeItemDelegate(DirectoryMergeWindow* pParent) - : QStyledItemDelegate(pParent), m_pDMW(pParent), d(pParent->d) - { - } - void paint( QPainter * p, const QStyleOptionViewItem & option, const QModelIndex & index ) const - { - int column = index.column(); - if (column == s_ACol || column == s_BCol || column == s_CCol ) - { - QVariant value = index.data( Qt::DecorationRole ); - QPixmap icon; - if ( value.isValid() ) - { - if (value.type() == QVariant::Icon) - { - icon = qvariant_cast(value).pixmap(16,16); - //icon = qvariant_cast(value); - //decorationRect = QRect(QPoint(0, 0), icon.actualSize(option.decorationSize, iconMode, iconState)); - } - else - { - icon = qvariant_cast(value); - //decorationRect = QRect(QPoint(0, 0), option.decorationSize).intersected(pixmap.rect()); - } - } - - int x = option.rect.left(); - int y = option.rect.top(); - //QPixmap icon = value.value(); //pixmap(column); - if ( !icon.isNull() ) - { - int yOffset = (sizeHint(option,index).height() - icon.height()) / 2; - p->drawPixmap( x+2, y+yOffset, icon ); - - int i = index==d->m_selection1Index ? 1 : - index==d->m_selection2Index ? 2 : - index==d->m_selection3Index ? 3 : - 0 ; - if ( i!=0 ) + DirectoryMergeWindow* m_pDMW; + DirectoryMergeWindow::Data* d; + + public: + DirMergeItemDelegate(DirectoryMergeWindow* pParent) + : QStyledItemDelegate(pParent), m_pDMW(pParent), d(pParent->d) + { + } + void paint(QPainter* p, const QStyleOptionViewItem& option, const QModelIndex& index) const + { + int column = index.column(); + if(column == s_ACol || column == s_BCol || column == s_CCol) + { + QVariant value = index.data(Qt::DecorationRole); + QPixmap icon; + if(value.isValid()) { - Options* pOpts = d->m_pOptions; - QColor c ( i==1 ? pOpts->m_colorA : i==2 ? pOpts->m_colorB : pOpts->m_colorC ); - p->setPen( c );// highlight() ); - p->drawRect( x+2, y+yOffset, icon.width(), icon.height()); - p->setPen( QPen( c, 0, Qt::DotLine) ); - p->drawRect( x+1, y+yOffset-1, icon.width()+2, icon.height()+2); - p->setPen( Qt::white ); - QString s( QChar('A'+i-1) ); - p->drawText( x+2 + (icon.width() - p->fontMetrics().width(s))/2, - y+yOffset + (icon.height() + p->fontMetrics().ascent())/2-1, - s ); + if(value.type() == QVariant::Icon) + { + icon = qvariant_cast(value).pixmap(16, 16); + //icon = qvariant_cast(value); + //decorationRect = QRect(QPoint(0, 0), icon.actualSize(option.decorationSize, iconMode, iconState)); + } + else + { + icon = qvariant_cast(value); + //decorationRect = QRect(QPoint(0, 0), option.decorationSize).intersected(pixmap.rect()); + } } - else + + int x = option.rect.left(); + int y = option.rect.top(); + //QPixmap icon = value.value(); //pixmap(column); + if(!icon.isNull()) { - p->setPen( m_pDMW->palette().background().color() ); - p->drawRect( x+1, y+yOffset-1, icon.width()+2, icon.height()+2); + int yOffset = (sizeHint(option, index).height() - icon.height()) / 2; + p->drawPixmap(x + 2, y + yOffset, icon); + + int i = index == d->m_selection1Index ? 1 : index == d->m_selection2Index ? 2 : index == d->m_selection3Index ? 3 : 0; + if(i != 0) + { + Options* pOpts = d->m_pOptions; + QColor c(i == 1 ? pOpts->m_colorA : i == 2 ? pOpts->m_colorB : pOpts->m_colorC); + p->setPen(c); // highlight() ); + p->drawRect(x + 2, y + yOffset, icon.width(), icon.height()); + p->setPen(QPen(c, 0, Qt::DotLine)); + p->drawRect(x + 1, y + yOffset - 1, icon.width() + 2, icon.height() + 2); + p->setPen(Qt::white); + QString s(QChar('A' + i - 1)); + p->drawText(x + 2 + (icon.width() - p->fontMetrics().width(s)) / 2, + y + yOffset + (icon.height() + p->fontMetrics().ascent()) / 2 - 1, + s); + } + else + { + p->setPen(m_pDMW->palette().background().color()); + p->drawRect(x + 1, y + yOffset - 1, icon.width() + 2, icon.height() + 2); + } + return; } - return; - } - } - QStyleOptionViewItem option2 = option; - if ( column>=s_UnsolvedCol ) - { - option2.displayAlignment = Qt::AlignRight; - } - QStyledItemDelegate::paint( p, option2, index ); - } - QSize sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const - { - QSize sz = QStyledItemDelegate::sizeHint( option, index ); - return sz.expandedTo( QSize(0,18) ); - } + } + QStyleOptionViewItem option2 = option; + if(column >= s_UnsolvedCol) + { + option2.displayAlignment = Qt::AlignRight; + } + QStyledItemDelegate::paint(p, option2, index); + } + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const + { + QSize sz = QStyledItemDelegate::sizeHint(option, index); + return sz.expandedTo(QSize(0, 18)); + } }; - -DirectoryMergeWindow::DirectoryMergeWindow( QWidget* pParent, Options* pOptions, KIconLoader* pIconLoader ) - : QTreeView( pParent ) +DirectoryMergeWindow::DirectoryMergeWindow(QWidget* pParent, Options* pOptions, KIconLoader* pIconLoader) + : QTreeView(pParent) { - d = new Data(this); - setModel( d ); - setItemDelegate( new DirMergeItemDelegate(this) ); - connect(this, &DirectoryMergeWindow::doubleClicked, this, &DirectoryMergeWindow::onDoubleClick); - connect(this, &DirectoryMergeWindow::expanded, this, &DirectoryMergeWindow::onExpanded); + d = new Data(this); + setModel(d); + setItemDelegate(new DirMergeItemDelegate(this)); + connect(this, &DirectoryMergeWindow::doubleClicked, this, &DirectoryMergeWindow::onDoubleClick); + connect(this, &DirectoryMergeWindow::expanded, this, &DirectoryMergeWindow::onExpanded); - d->m_pOptions = pOptions; - d->m_pIconLoader = pIconLoader; + d->m_pOptions = pOptions; + d->m_pIconLoader = pIconLoader; - setSortingEnabled(true); + setSortingEnabled(true); } DirectoryMergeWindow::~DirectoryMergeWindow() { - delete d; + delete d; } -QString DirectoryMergeWindow::getDirNameA(){ return d->m_dirA.prettyAbsPath(); } -QString DirectoryMergeWindow::getDirNameB(){ return d->m_dirB.prettyAbsPath(); } -QString DirectoryMergeWindow::getDirNameC(){ return d->m_dirC.prettyAbsPath(); } -QString DirectoryMergeWindow::getDirNameDest(){ return d->m_dirDest.prettyAbsPath(); } -void DirectoryMergeWindow::setDirectoryMergeInfo(DirectoryMergeInfo* p){ d->m_pDirectoryMergeInfo=p; } +QString DirectoryMergeWindow::getDirNameA() { return d->m_dirA.prettyAbsPath(); } +QString DirectoryMergeWindow::getDirNameB() { return d->m_dirB.prettyAbsPath(); } +QString DirectoryMergeWindow::getDirNameC() { return d->m_dirC.prettyAbsPath(); } +QString DirectoryMergeWindow::getDirNameDest() { return d->m_dirDest.prettyAbsPath(); } +void DirectoryMergeWindow::setDirectoryMergeInfo(DirectoryMergeInfo* p) { d->m_pDirectoryMergeInfo = p; } bool DirectoryMergeWindow::isDirectoryMergeInProgress() { return d->m_bRealMergeStarted; } bool DirectoryMergeWindow::isSyncMode() { return d->m_bSyncMode; } bool DirectoryMergeWindow::isScanning() { return d->m_bScanning; } bool DirectoryMergeWindow::Data::fastFileComparison( - FileAccess& fi1, FileAccess& fi2, - bool& bError, QString& status ) -{ - ProgressProxy pp; - status = ""; - bool bEqual = false; - bError = true; - - if ( !m_bFollowFileLinks ) - { - if ( fi1.isSymLink() != fi2.isSymLink() ) - { - status = i18n("Mix of links and normal files."); - return bEqual; - } - else if ( fi1.isSymLink() && fi2.isSymLink() ) - { - bError = false; - bEqual = fi1.readLink() == fi2.readLink(); - status = i18n("Link: "); - return bEqual; - } - } - - if ( fi1.size()!=fi2.size() ) - { - bEqual = false; - status = i18n("Size. "); - return bEqual; - } - else if ( m_pOptions->m_bDmTrustSize ) - { - bEqual = true; - return bEqual; - } - - if ( m_pOptions->m_bDmTrustDate ) - { - bEqual = ( fi1.lastModified() == fi2.lastModified() && fi1.size()==fi2.size() ); - bError = false; - status = i18n("Date & Size: "); - return bEqual; - } - - if ( m_pOptions->m_bDmTrustDateFallbackToBinary ) - { - bEqual = ( fi1.lastModified() == fi2.lastModified() && fi1.size()==fi2.size() ); - if ( bEqual ) - { - bError = false; - status = i18n("Date & Size: "); - return bEqual; - } - } - - QString fileName1 = fi1.absoluteFilePath(); - QString fileName2 = fi2.absoluteFilePath(); - TempRemover tr1( fileName1, fi1 ); - if ( !tr1.success() ) - { - status = i18n("Creating temp copy of %1 failed.",fileName1); - return bEqual; - } - TempRemover tr2( fileName2, fi2 ); - if ( !tr2.success() ) - { - status = i18n("Creating temp copy of %1 failed.",fileName2); - return bEqual; - } - - std::vector buf1(100000); - std::vector buf2(buf1.size()); - - QFile file1( tr1.name() ); - - if ( ! file1.open(QIODevice::ReadOnly) ) - { - status = i18n("Opening %1 failed.",fileName1); - return bEqual; - } - - QFile file2( tr2.name() ); - - if ( ! file2.open(QIODevice::ReadOnly) ) - { - status = i18n("Opening %1 failed.",fileName2); - return bEqual; - } - - pp.setInformation( i18n("Comparing file..."), 0, false ); - typedef qint64 t_FileSize; - t_FileSize fullSize = file1.size(); - t_FileSize sizeLeft = fullSize; - - pp.setMaxNofSteps( fullSize / buf1.size() ); - - while( sizeLeft>0 && ! pp.wasCancelled() ) - { - int len = min2( sizeLeft, (t_FileSize)buf1.size() ); - if( len != file1.read( &buf1[0], len ) ) - { - status = i18n("Error reading from %1",fileName1); - return bEqual; - } - - if( len != file2.read( &buf2[0], len ) ) - { - status = i18n("Error reading from %1",fileName2); - return bEqual; - } - - if ( memcmp( &buf1[0], &buf2[0], len ) != 0 ) - { - bError = false; - return bEqual; - } - sizeLeft-=len; - //pp.setCurrent(double(fullSize-sizeLeft)/fullSize, false ); - pp.step(); - } - - // If the program really arrives here, then the files are really equal. - bError = false; - bEqual = true; - return bEqual; + FileAccess& fi1, FileAccess& fi2, + bool& bError, QString& status) +{ + ProgressProxy pp; + status = ""; + bool bEqual = false; + bError = true; + + if(!m_bFollowFileLinks) + { + if(fi1.isSymLink() != fi2.isSymLink()) + { + status = i18n("Mix of links and normal files."); + return bEqual; + } + else if(fi1.isSymLink() && fi2.isSymLink()) + { + bError = false; + bEqual = fi1.readLink() == fi2.readLink(); + status = i18n("Link: "); + return bEqual; + } + } + + if(fi1.size() != fi2.size()) + { + bEqual = false; + status = i18n("Size. "); + return bEqual; + } + else if(m_pOptions->m_bDmTrustSize) + { + bEqual = true; + return bEqual; + } + + if(m_pOptions->m_bDmTrustDate) + { + bEqual = (fi1.lastModified() == fi2.lastModified() && fi1.size() == fi2.size()); + bError = false; + status = i18n("Date & Size: "); + return bEqual; + } + + if(m_pOptions->m_bDmTrustDateFallbackToBinary) + { + bEqual = (fi1.lastModified() == fi2.lastModified() && fi1.size() == fi2.size()); + if(bEqual) + { + bError = false; + status = i18n("Date & Size: "); + return bEqual; + } + } + + QString fileName1 = fi1.absoluteFilePath(); + QString fileName2 = fi2.absoluteFilePath(); + TempRemover tr1(fileName1, fi1); + if(!tr1.success()) + { + status = i18n("Creating temp copy of %1 failed.", fileName1); + return bEqual; + } + TempRemover tr2(fileName2, fi2); + if(!tr2.success()) + { + status = i18n("Creating temp copy of %1 failed.", fileName2); + return bEqual; + } + + std::vector buf1(100000); + std::vector buf2(buf1.size()); + + QFile file1(tr1.name()); + + if(!file1.open(QIODevice::ReadOnly)) + { + status = i18n("Opening %1 failed.", fileName1); + return bEqual; + } + + QFile file2(tr2.name()); + + if(!file2.open(QIODevice::ReadOnly)) + { + status = i18n("Opening %1 failed.", fileName2); + return bEqual; + } + + pp.setInformation(i18n("Comparing file..."), 0, false); + typedef qint64 t_FileSize; + t_FileSize fullSize = file1.size(); + t_FileSize sizeLeft = fullSize; + + pp.setMaxNofSteps(fullSize / buf1.size()); + + while(sizeLeft > 0 && !pp.wasCancelled()) + { + int len = min2(sizeLeft, (t_FileSize)buf1.size()); + if(len != file1.read(&buf1[0], len)) + { + status = i18n("Error reading from %1", fileName1); + return bEqual; + } + + if(len != file2.read(&buf2[0], len)) + { + status = i18n("Error reading from %1", fileName2); + return bEqual; + } + + if(memcmp(&buf1[0], &buf2[0], len) != 0) + { + bError = false; + return bEqual; + } + sizeLeft -= len; + //pp.setCurrent(double(fullSize-sizeLeft)/fullSize, false ); + pp.step(); + } + + // If the program really arrives here, then the files are really equal. + bError = false; + bEqual = true; + return bEqual; } int DirectoryMergeWindow::totalColumnWidth() { - int w=0; - for (int i=0; im_dirA, d->m_dirB, d->m_dirC, d->m_dirDest, d->m_bDirectoryMerge, true ); - //fix file visibilities after reload or menu will be out of sync with display if changed from defaults. - updateFileVisibilities(); + init(d->m_dirA, d->m_dirB, d->m_dirC, d->m_dirDest, d->m_bDirectoryMerge, true); + //fix file visibilities after reload or menu will be out of sync with display if changed from defaults. + updateFileVisibilities(); } // Copy pm2 onto pm1, but preserve the alpha value from pm1 where pm2 is transparent. -static QPixmap pixCombiner( const QPixmap* pm1, const QPixmap* pm2 ) +static QPixmap pixCombiner(const QPixmap* pm1, const QPixmap* pm2) { - QImage img1 = pm1->toImage().convertToFormat(QImage::Format_ARGB32); - QImage img2 = pm2->toImage().convertToFormat(QImage::Format_ARGB32); + QImage img1 = pm1->toImage().convertToFormat(QImage::Format_ARGB32); + QImage img2 = pm2->toImage().convertToFormat(QImage::Format_ARGB32); - for (int y = 0; y < img1.height(); y++) - { - quint32 *line1 = reinterpret_cast(img1.scanLine(y)); - quint32 *line2 = reinterpret_cast(img2.scanLine(y)); - for (int x = 0; x < img1.width(); x++) - { - if ( qAlpha( line2[x] ) >0 ) - line1[x] = (line2[x] | 0xff000000); - } - } - return QPixmap::fromImage(img1); + for(int y = 0; y < img1.height(); y++) + { + quint32* line1 = reinterpret_cast(img1.scanLine(y)); + quint32* line2 = reinterpret_cast(img2.scanLine(y)); + for(int x = 0; x < img1.width(); x++) + { + if(qAlpha(line2[x]) > 0) + line1[x] = (line2[x] | 0xff000000); + } + } + return QPixmap::fromImage(img1); } // like pixCombiner but let the pm1 color shine through -static QPixmap pixCombiner2( const QPixmap* pm1, const QPixmap* pm2 ) -{ - QPixmap pix=*pm1; - QPainter p(&pix); - p.setOpacity(0.5); - p.drawPixmap( 0,0,*pm2 ); - p.end(); - - return pix; -} - -void DirectoryMergeWindow::Data::calcDirStatus( bool bThreeDirs, const QModelIndex& mi, - int& nofFiles, int& nofDirs, int& nofEqualFiles, int& nofManualMerges ) -{ - MergeFileInfos* pMFI = getMFI(mi); - if ( pMFI->dirA() || pMFI->dirB() || pMFI->dirC() ) - { - ++nofDirs; - } - else - { - ++nofFiles; - if ( pMFI->m_bEqualAB && (!bThreeDirs || pMFI->m_bEqualAC )) - { - ++nofEqualFiles; - } - else - { - if ( pMFI->m_eMergeOperation==eMergeABCToDest || pMFI->m_eMergeOperation==eMergeABToDest ) - ++nofManualMerges; - } - } - for( int childIdx=0; childIdxdirA() || pMFI->dirB() || pMFI->dirC()) + { + ++nofDirs; + } + else + { + ++nofFiles; + if(pMFI->m_bEqualAB && (!bThreeDirs || pMFI->m_bEqualAC)) + { + ++nofEqualFiles; + } + else + { + if(pMFI->m_eMergeOperation == eMergeABCToDest || pMFI->m_eMergeOperation == eMergeABToDest) + ++nofManualMerges; + } + } + for(int childIdx = 0; childIdx < rowCount(mi); ++childIdx) + calcDirStatus(bThreeDirs, index(childIdx, 0, mi), nofFiles, nofDirs, nofEqualFiles, nofManualMerges); +} + +struct t_ItemInfo { + bool bExpanded; + bool bOperationComplete; + QString status; + e_MergeOperation eMergeOperation; }; -bool DirectoryMergeWindow::init - ( - FileAccess& dirA, - FileAccess& dirB, - FileAccess& dirC, - FileAccess& dirDest, - bool bDirectoryMerge, - bool bReload - ) -{ - return d->init( dirA, dirB, dirC, dirDest, bDirectoryMerge, bReload ); -} - -bool DirectoryMergeWindow::Data::init - ( - FileAccess& dirA, - FileAccess& dirB, - FileAccess& dirC, - FileAccess& dirDest, - bool bDirectoryMerge, - bool bReload - ) -{ - if ( m_pOptions->m_bDmFullAnalysis ) - { - // A full analysis uses the same ressources that a normal text-diff/merge uses. - // So make sure that the user saves his data first. - bool bCanContinue=false; - emit q->checkIfCanContinue( &bCanContinue ); - if ( !bCanContinue ) - return false; - emit q->startDiffMerge("","","","","","","",0); // hide main window - } - - q->show(); - q->setUpdatesEnabled(true); - - std::map expandedDirsMap; - - if ( bReload ) - { - // Remember expanded items TODO - //QTreeWidgetItemIterator it( this ); - //while ( *it ) - //{ - // DirMergeItem* pDMI = static_cast( *it ); - // t_ItemInfo& ii = expandedDirsMap[ pDMI->m_pMFI->subPath() ]; - // ii.bExpanded = pDMI->isExpanded(); - // ii.bOperationComplete = pDMI->m_pMFI->m_bOperationComplete; - // ii.status = pDMI->text( s_OpStatusCol ); - // ii.eMergeOperation = pDMI->m_pMFI->m_eMergeOperation; - // ++it; - //} - } - - ProgressProxy pp; - m_bFollowDirLinks = m_pOptions->m_bDmFollowDirLinks; - m_bFollowFileLinks = m_pOptions->m_bDmFollowFileLinks; - m_bSimulatedMergeStarted=false; - m_bRealMergeStarted=false; - m_bError=false; - m_bDirectoryMerge = bDirectoryMerge; - m_selection1Index = QModelIndex(); - m_selection2Index = QModelIndex(); - m_selection3Index = QModelIndex(); - m_bCaseSensitive = m_pOptions->m_bDmCaseSensitiveFilenameComparison; - m_bUnfoldSubdirs = m_pOptions->m_bDmUnfoldSubdirs; - m_bSkipDirStatus = m_pOptions->m_bDmSkipDirStatus; - - - beginResetModel(); - m_pRoot->m_children.clear(); - m_mergeItemList.clear(); - endResetModel(); - - m_currentIndexForOperation = m_mergeItemList.end(); - - m_dirA = dirA; - m_dirB = dirB; - m_dirC = dirC; - m_dirDest = dirDest; - - if ( !bReload ) - { - m_pDirShowIdenticalFiles->setChecked(true); - m_pDirShowDifferentFiles->setChecked(true); - m_pDirShowFilesOnlyInA->setChecked(true); - m_pDirShowFilesOnlyInB->setChecked(true); - m_pDirShowFilesOnlyInC->setChecked(true); - } - - // Check if all input directories exist and are valid. The dest dir is not tested now. - // The test will happen only when we are going to write to it. - if ( !m_dirA.isDir() || !m_dirB.isDir() || - (m_dirC.isValid() && !m_dirC.isDir()) ) - { - QString text( i18n("Opening of directories failed:") ); - text += "\n\n"; - if ( !dirA.isDir() ) - { text += i18n("Dir A \"%1\" does not exist or is not a directory.\n",m_dirA.prettyAbsPath()); } - - if ( !dirB.isDir() ) - { text += i18n("Dir B \"%1\" does not exist or is not a directory.\n",m_dirB.prettyAbsPath()); } - - if ( m_dirC.isValid() && !m_dirC.isDir() ) - { text += i18n("Dir C \"%1\" does not exist or is not a directory.\n",m_dirC.prettyAbsPath()); } - - KMessageBox::sorry( q, 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(q, - i18n( "The destination directory must not be the same as A or B when " - "three directories are merged.\nCheck again before continuing."), - i18n("Parameter Warning")); - return false; - } - - m_bScanning = true; - emit q->statusBarMessage(i18n("Scanning directories...")); - - m_bSyncMode = m_pOptions->m_bDmSyncMode && !m_dirC.isValid() && !m_dirDest.isValid(); - - if ( m_dirDest.isValid() ) - m_dirDestInternal = m_dirDest; - else - m_dirDestInternal = m_dirC.isValid() ? m_dirC : m_dirB; - - QString origCurrentDirectory = QDir::currentPath(); - - m_fileMergeMap.clear(); - s_eCaseSensitivity = m_bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; - 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; - -//TODO setColumnWidthMode(s_UnsolvedCol, Q3ListView::Manual); -// setColumnWidthMode(s_SolvedCol, Q3ListView::Manual); -// setColumnWidthMode(s_WhiteCol, Q3ListView::Manual); -// setColumnWidthMode(s_NonWhiteCol, Q3ListView::Manual); - q->setColumnHidden( s_CCol, !m_dirC.isValid() ); - q->setColumnHidden( s_WhiteCol, !m_pOptions->m_bDmFullAnalysis ); - q->setColumnHidden( s_NonWhiteCol, !m_pOptions->m_bDmFullAnalysis ); - q->setColumnHidden( s_UnsolvedCol, !m_pOptions->m_bDmFullAnalysis ); - q->setColumnHidden( s_SolvedCol, !( m_pOptions->m_bDmFullAnalysis && m_dirC.isValid() ) ); - - bool bListDirSuccessA = true; - bool bListDirSuccessB = true; - bool bListDirSuccessC = true; - m_dirListA.clear(); - m_dirListB.clear(); - m_dirListC.clear(); - if ( m_dirA.isValid() ) - { - pp.setInformation(i18n("Reading Directory A")); - pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans); - ++currentScan; - - bListDirSuccessA = m_dirA.listDir( &m_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=m_dirListA.begin(); i!=m_dirListA.end();++i ) - { - MergeFileInfos& mfi = m_fileMergeMap[FileKey(*i)]; - //std::cout <filePath()<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=m_dirListB.begin(); i!=m_dirListB.end();++i ) - { - MergeFileInfos& mfi = m_fileMergeMap[FileKey(*i)]; - mfi.m_pFileInfoB = &(*i); - if ( mfi.m_pFileInfoA && mfi.m_pFileInfoA->fileName() == mfi.m_pFileInfoB->fileName() ) - mfi.m_pFileInfoB->setSharedName(mfi.m_pFileInfoA->fileName()); // Reduce memory by sharing the name. - } - } - - e_MergeOperation eDefaultMergeOp; - if ( m_dirC.isValid() ) - { - pp.setInformation(i18n("Reading Directory C")); - pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans); - ++currentScan; - - bListDirSuccessC = m_dirC.listDir( &m_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=m_dirListC.begin(); i!=m_dirListC.end();++i ) - { - MergeFileInfos& mfi = m_fileMergeMap[FileKey(*i)]; - mfi.m_pFileInfoC = &(*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( q, s ); - } - - if ( bContinue ) - { - prepareListView(pp); - - q->updateFileVisibilities(); - - for( int childIdx = 0; childIdxsortByColumn(0,Qt::AscendingOrder); - - for (int i=0;iresizeColumnToContents(i); - - // Try to improve the view a little bit. - QWidget* pParent = q->parentWidget(); - QSplitter* pSplitter = static_cast(pParent); - if (pSplitter!=0) - { - QList sizes = pSplitter->sizes(); - int total = sizes[0] + sizes[1]; - if ( total < 10 ) - total = 100; - sizes[0]=total*6/10; - sizes[1]=total - sizes[0]; - pSplitter->setSizes( sizes ); - } - - QDir::setCurrent(origCurrentDirectory); - - m_bScanning = false; - emit q->statusBarMessage(i18n("Ready.")); - - if ( bContinue && !m_bSkipDirStatus ) - { - // Generate a status report - int nofFiles=0; - int nofDirs=0; - int nofEqualFiles=0; - int nofManualMerges=0; -//TODO - for( int childIdx = 0; childIdx0 ) - //{ - // topLevelItem(0)->setSelected(true); - // setCurrentItem( topLevelItem(0) ); - //} - } - - if ( bReload ) - { - // Remember expanded items - //TODO - //QTreeWidgetItemIterator it( this ); - //while ( *it ) - //{ - // DirMergeItem* pDMI = static_cast( *it ); - // std::map::iterator i = expandedDirsMap.find( pDMI->m_pMFI->subPath() ); - // if ( i!=expandedDirsMap.end() ) - // { - // t_ItemInfo& ii = i->second; - // pDMI->setExpanded( ii.bExpanded ); - // //pDMI->m_pMFI->setMergeOperation( ii.eMergeOperation, false ); unsafe, might have changed - // pDMI->m_pMFI->m_bOperationComplete = ii.bOperationComplete; - // pDMI->setText( s_OpStatusCol, ii.status ); - // } - // ++it; - //} - } - else if (m_bUnfoldSubdirs) - { - m_pDirUnfoldAll->trigger(); - } - - return true; +bool DirectoryMergeWindow::init( + FileAccess& dirA, + FileAccess& dirB, + FileAccess& dirC, + FileAccess& dirDest, + bool bDirectoryMerge, + bool bReload) +{ + return d->init(dirA, dirB, dirC, dirDest, bDirectoryMerge, bReload); +} + +bool DirectoryMergeWindow::Data::init( + FileAccess& dirA, + FileAccess& dirB, + FileAccess& dirC, + FileAccess& dirDest, + bool bDirectoryMerge, + bool bReload) +{ + if(m_pOptions->m_bDmFullAnalysis) + { + // A full analysis uses the same ressources that a normal text-diff/merge uses. + // So make sure that the user saves his data first. + bool bCanContinue = false; + emit q->checkIfCanContinue(&bCanContinue); + if(!bCanContinue) + return false; + emit q->startDiffMerge("", "", "", "", "", "", "", 0); // hide main window + } + + q->show(); + q->setUpdatesEnabled(true); + + std::map expandedDirsMap; + + if(bReload) + { + // Remember expanded items TODO + //QTreeWidgetItemIterator it( this ); + //while ( *it ) + //{ + // DirMergeItem* pDMI = static_cast( *it ); + // t_ItemInfo& ii = expandedDirsMap[ pDMI->m_pMFI->subPath() ]; + // ii.bExpanded = pDMI->isExpanded(); + // ii.bOperationComplete = pDMI->m_pMFI->m_bOperationComplete; + // ii.status = pDMI->text( s_OpStatusCol ); + // ii.eMergeOperation = pDMI->m_pMFI->m_eMergeOperation; + // ++it; + //} + } + + ProgressProxy pp; + m_bFollowDirLinks = m_pOptions->m_bDmFollowDirLinks; + m_bFollowFileLinks = m_pOptions->m_bDmFollowFileLinks; + m_bSimulatedMergeStarted = false; + m_bRealMergeStarted = false; + m_bError = false; + m_bDirectoryMerge = bDirectoryMerge; + m_selection1Index = QModelIndex(); + m_selection2Index = QModelIndex(); + m_selection3Index = QModelIndex(); + m_bCaseSensitive = m_pOptions->m_bDmCaseSensitiveFilenameComparison; + m_bUnfoldSubdirs = m_pOptions->m_bDmUnfoldSubdirs; + m_bSkipDirStatus = m_pOptions->m_bDmSkipDirStatus; + + beginResetModel(); + m_pRoot->m_children.clear(); + m_mergeItemList.clear(); + endResetModel(); + + m_currentIndexForOperation = m_mergeItemList.end(); + + m_dirA = dirA; + m_dirB = dirB; + m_dirC = dirC; + m_dirDest = dirDest; + + if(!bReload) + { + m_pDirShowIdenticalFiles->setChecked(true); + m_pDirShowDifferentFiles->setChecked(true); + m_pDirShowFilesOnlyInA->setChecked(true); + m_pDirShowFilesOnlyInB->setChecked(true); + m_pDirShowFilesOnlyInC->setChecked(true); + } + + // Check if all input directories exist and are valid. The dest dir is not tested now. + // The test will happen only when we are going to write to it. + if(!m_dirA.isDir() || !m_dirB.isDir() || + (m_dirC.isValid() && !m_dirC.isDir())) + { + QString text(i18n("Opening of directories failed:")); + text += "\n\n"; + if(!dirA.isDir()) + { + text += i18n("Dir A \"%1\" does not exist or is not a directory.\n", m_dirA.prettyAbsPath()); + } + + if(!dirB.isDir()) + { + text += i18n("Dir B \"%1\" does not exist or is not a directory.\n", m_dirB.prettyAbsPath()); + } + + if(m_dirC.isValid() && !m_dirC.isDir()) + { + text += i18n("Dir C \"%1\" does not exist or is not a directory.\n", m_dirC.prettyAbsPath()); + } + + KMessageBox::sorry(q, 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(q, + i18n("The destination directory must not be the same as A or B when " + "three directories are merged.\nCheck again before continuing."), + i18n("Parameter Warning")); + return false; + } + + m_bScanning = true; + emit q->statusBarMessage(i18n("Scanning directories...")); + + m_bSyncMode = m_pOptions->m_bDmSyncMode && !m_dirC.isValid() && !m_dirDest.isValid(); + + if(m_dirDest.isValid()) + m_dirDestInternal = m_dirDest; + else + m_dirDestInternal = m_dirC.isValid() ? m_dirC : m_dirB; + + QString origCurrentDirectory = QDir::currentPath(); + + m_fileMergeMap.clear(); + s_eCaseSensitivity = m_bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; + 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; + + //TODO setColumnWidthMode(s_UnsolvedCol, Q3ListView::Manual); + // setColumnWidthMode(s_SolvedCol, Q3ListView::Manual); + // setColumnWidthMode(s_WhiteCol, Q3ListView::Manual); + // setColumnWidthMode(s_NonWhiteCol, Q3ListView::Manual); + q->setColumnHidden(s_CCol, !m_dirC.isValid()); + q->setColumnHidden(s_WhiteCol, !m_pOptions->m_bDmFullAnalysis); + q->setColumnHidden(s_NonWhiteCol, !m_pOptions->m_bDmFullAnalysis); + q->setColumnHidden(s_UnsolvedCol, !m_pOptions->m_bDmFullAnalysis); + q->setColumnHidden(s_SolvedCol, !(m_pOptions->m_bDmFullAnalysis && m_dirC.isValid())); + + bool bListDirSuccessA = true; + bool bListDirSuccessB = true; + bool bListDirSuccessC = true; + m_dirListA.clear(); + m_dirListB.clear(); + m_dirListC.clear(); + if(m_dirA.isValid()) + { + pp.setInformation(i18n("Reading Directory A")); + pp.setSubRangeTransformation(currentScan / nofScans, (currentScan + 1) / nofScans); + ++currentScan; + + bListDirSuccessA = m_dirA.listDir(&m_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 = m_dirListA.begin(); i != m_dirListA.end(); ++i) + { + MergeFileInfos& mfi = m_fileMergeMap[FileKey(*i)]; + //std::cout <filePath()<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 = m_dirListB.begin(); i != m_dirListB.end(); ++i) + { + MergeFileInfos& mfi = m_fileMergeMap[FileKey(*i)]; + mfi.m_pFileInfoB = &(*i); + if(mfi.m_pFileInfoA && mfi.m_pFileInfoA->fileName() == mfi.m_pFileInfoB->fileName()) + mfi.m_pFileInfoB->setSharedName(mfi.m_pFileInfoA->fileName()); // Reduce memory by sharing the name. + } + } + + e_MergeOperation eDefaultMergeOp; + if(m_dirC.isValid()) + { + pp.setInformation(i18n("Reading Directory C")); + pp.setSubRangeTransformation(currentScan / nofScans, (currentScan + 1) / nofScans); + ++currentScan; + + bListDirSuccessC = m_dirC.listDir(&m_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 = m_dirListC.begin(); i != m_dirListC.end(); ++i) + { + MergeFileInfos& mfi = m_fileMergeMap[FileKey(*i)]; + mfi.m_pFileInfoC = &(*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(q, s); + } + + if(bContinue) + { + prepareListView(pp); + + q->updateFileVisibilities(); + + for(int childIdx = 0; childIdx < rowCount(); ++childIdx) + { + QModelIndex mi = index(childIdx, 0, QModelIndex()); + calcSuggestedOperation(mi, eDefaultMergeOp); + } + } + + q->sortByColumn(0, Qt::AscendingOrder); + + for(int i = 0; i < columnCount(QModelIndex()); ++i) + q->resizeColumnToContents(i); + + // Try to improve the view a little bit. + QWidget* pParent = q->parentWidget(); + QSplitter* pSplitter = static_cast(pParent); + if(pSplitter != 0) + { + QList sizes = pSplitter->sizes(); + int total = sizes[0] + sizes[1]; + if(total < 10) + total = 100; + sizes[0] = total * 6 / 10; + sizes[1] = total - sizes[0]; + pSplitter->setSizes(sizes); + } + + QDir::setCurrent(origCurrentDirectory); + + m_bScanning = false; + emit q->statusBarMessage(i18n("Ready.")); + + if(bContinue && !m_bSkipDirStatus) + { + // Generate a status report + int nofFiles = 0; + int nofDirs = 0; + int nofEqualFiles = 0; + int nofManualMerges = 0; + //TODO + for(int childIdx = 0; childIdx < rowCount(); ++childIdx) + calcDirStatus(m_dirC.isValid(), index(childIdx, 0, QModelIndex()), + 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(q, s); + // + //TODO + //if ( topLevelItemCount()>0 ) + //{ + // topLevelItem(0)->setSelected(true); + // setCurrentItem( topLevelItem(0) ); + //} + } + + if(bReload) + { + // Remember expanded items + //TODO + //QTreeWidgetItemIterator it( this ); + //while ( *it ) + //{ + // DirMergeItem* pDMI = static_cast( *it ); + // std::map::iterator i = expandedDirsMap.find( pDMI->m_pMFI->subPath() ); + // if ( i!=expandedDirsMap.end() ) + // { + // t_ItemInfo& ii = i->second; + // pDMI->setExpanded( ii.bExpanded ); + // //pDMI->m_pMFI->setMergeOperation( ii.eMergeOperation, false ); unsafe, might have changed + // pDMI->m_pMFI->m_bOperationComplete = ii.bOperationComplete; + // pDMI->setText( s_OpStatusCol, ii.status ); + // } + // ++it; + //} + } + else if(m_bUnfoldSubdirs) + { + m_pDirUnfoldAll->trigger(); + } + + return true; } void DirectoryMergeWindow::onExpanded() { - resizeColumnToContents(s_NameCol); + resizeColumnToContents(s_NameCol); } +void DirectoryMergeWindow::slotChooseAEverywhere() { d->setAllMergeOperations(eCopyAToDest); } -void DirectoryMergeWindow::slotChooseAEverywhere(){ d->setAllMergeOperations( eCopyAToDest ); } +void DirectoryMergeWindow::slotChooseBEverywhere() { d->setAllMergeOperations(eCopyBToDest); } -void DirectoryMergeWindow::slotChooseBEverywhere(){ d->setAllMergeOperations( eCopyBToDest ); } - -void DirectoryMergeWindow::slotChooseCEverywhere(){ d->setAllMergeOperations( eCopyCToDest ); } +void DirectoryMergeWindow::slotChooseCEverywhere() { d->setAllMergeOperations(eCopyCToDest); } void DirectoryMergeWindow::slotAutoChooseEverywhere() { - e_MergeOperation eDefaultMergeOp = d->m_dirC.isValid() ? eMergeABCToDest : - d->m_bSyncMode ? eMergeToAB : eMergeABToDest; - d->setAllMergeOperations(eDefaultMergeOp ); + e_MergeOperation eDefaultMergeOp = d->m_dirC.isValid() ? eMergeABCToDest : d->m_bSyncMode ? eMergeToAB : eMergeABToDest; + d->setAllMergeOperations(eDefaultMergeOp); } -void DirectoryMergeWindow::slotNoOpEverywhere(){ d->setAllMergeOperations(eNoOperation); } +void DirectoryMergeWindow::slotNoOpEverywhere() { d->setAllMergeOperations(eNoOperation); } void DirectoryMergeWindow::slotFoldAllSubdirs() { - collapseAll(); + collapseAll(); } void DirectoryMergeWindow::slotUnfoldAllSubdirs() { - expandAll(); + expandAll(); } // Merge current item (merge mode) -void DirectoryMergeWindow::slotCurrentDoNothing() { d->setMergeOperation(currentIndex(), eNoOperation ); } -void DirectoryMergeWindow::slotCurrentChooseA() { d->setMergeOperation(currentIndex(), d->m_bSyncMode ? eCopyAToB : eCopyAToDest ); } -void DirectoryMergeWindow::slotCurrentChooseB() { d->setMergeOperation(currentIndex(), d->m_bSyncMode ? eCopyBToA : eCopyBToDest ); } -void DirectoryMergeWindow::slotCurrentChooseC() { d->setMergeOperation(currentIndex(), eCopyCToDest ); } +void DirectoryMergeWindow::slotCurrentDoNothing() { d->setMergeOperation(currentIndex(), eNoOperation); } +void DirectoryMergeWindow::slotCurrentChooseA() { d->setMergeOperation(currentIndex(), d->m_bSyncMode ? eCopyAToB : eCopyAToDest); } +void DirectoryMergeWindow::slotCurrentChooseB() { d->setMergeOperation(currentIndex(), d->m_bSyncMode ? eCopyBToA : eCopyBToDest); } +void DirectoryMergeWindow::slotCurrentChooseC() { d->setMergeOperation(currentIndex(), eCopyCToDest); } void DirectoryMergeWindow::slotCurrentMerge() { - bool bThreeDirs = d->m_dirC.isValid(); - d->setMergeOperation(currentIndex(), bThreeDirs ? eMergeABCToDest : eMergeABToDest ); + bool bThreeDirs = d->m_dirC.isValid(); + d->setMergeOperation(currentIndex(), bThreeDirs ? eMergeABCToDest : eMergeABToDest); } -void DirectoryMergeWindow::slotCurrentDelete() { d->setMergeOperation(currentIndex(), eDeleteFromDest ); } +void DirectoryMergeWindow::slotCurrentDelete() { d->setMergeOperation(currentIndex(), eDeleteFromDest); } // Sync current item -void DirectoryMergeWindow::slotCurrentCopyAToB() { d->setMergeOperation(currentIndex(), eCopyAToB ); } -void DirectoryMergeWindow::slotCurrentCopyBToA() { d->setMergeOperation(currentIndex(), eCopyBToA ); } -void DirectoryMergeWindow::slotCurrentDeleteA() { d->setMergeOperation(currentIndex(), eDeleteA ); } -void DirectoryMergeWindow::slotCurrentDeleteB() { d->setMergeOperation(currentIndex(), eDeleteB ); } -void DirectoryMergeWindow::slotCurrentDeleteAAndB() { d->setMergeOperation(currentIndex(), eDeleteAB ); } -void DirectoryMergeWindow::slotCurrentMergeToA() { d->setMergeOperation(currentIndex(), eMergeToA ); } -void DirectoryMergeWindow::slotCurrentMergeToB() { d->setMergeOperation(currentIndex(), eMergeToB ); } -void DirectoryMergeWindow::slotCurrentMergeToAAndB() { d->setMergeOperation(currentIndex(), eMergeToAB ); } - - -void DirectoryMergeWindow::keyPressEvent( QKeyEvent* e ) -{ - if ( (e->QInputEvent::modifiers() & Qt::ControlModifier)!=0 ) - { - bool bThreeDirs = d->m_dirC.isValid(); - - MergeFileInfos* pMFI = d->getMFI( currentIndex() ); - - if ( pMFI==0 ) - return; - bool bMergeMode = bThreeDirs || !d->m_bSyncMode; - bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI); - - if ( bMergeMode ) - { - switch(e->key()) - { - case Qt::Key_1: if(pMFI->existsInA()){ slotCurrentChooseA(); } return; - case Qt::Key_2: if(pMFI->existsInB()){ slotCurrentChooseB(); } return; - case Qt::Key_3: if(pMFI->existsInC()){ slotCurrentChooseC(); } return; - case Qt::Key_Space: slotCurrentDoNothing(); return; - case Qt::Key_4: if ( !bFTConflict ) { slotCurrentMerge(); } return; - case Qt::Key_Delete: slotCurrentDelete(); return; - default: break; - } - } - else - { - switch(e->key()) - { - case Qt::Key_1: if(pMFI->existsInA()){ slotCurrentCopyAToB(); } return; - case Qt::Key_2: if(pMFI->existsInB()){ slotCurrentCopyBToA(); } return; - case Qt::Key_Space: slotCurrentDoNothing(); return; - case Qt::Key_4: if ( !bFTConflict ) { slotCurrentMergeToAAndB(); } return; - case Qt::Key_Delete: if( pMFI->existsInA() && pMFI->existsInB() ) slotCurrentDeleteAAndB(); - else if( pMFI->existsInA() ) slotCurrentDeleteA(); - else if( pMFI->existsInB() ) slotCurrentDeleteB(); - return; - default: break; - } - } - } - else if ( e->key()==Qt::Key_Return || e->key()==Qt::Key_Enter ) - { - onDoubleClick( currentIndex() ); - return; - } - - QTreeView::keyPressEvent(e); +void DirectoryMergeWindow::slotCurrentCopyAToB() { d->setMergeOperation(currentIndex(), eCopyAToB); } +void DirectoryMergeWindow::slotCurrentCopyBToA() { d->setMergeOperation(currentIndex(), eCopyBToA); } +void DirectoryMergeWindow::slotCurrentDeleteA() { d->setMergeOperation(currentIndex(), eDeleteA); } +void DirectoryMergeWindow::slotCurrentDeleteB() { d->setMergeOperation(currentIndex(), eDeleteB); } +void DirectoryMergeWindow::slotCurrentDeleteAAndB() { d->setMergeOperation(currentIndex(), eDeleteAB); } +void DirectoryMergeWindow::slotCurrentMergeToA() { d->setMergeOperation(currentIndex(), eMergeToA); } +void DirectoryMergeWindow::slotCurrentMergeToB() { d->setMergeOperation(currentIndex(), eMergeToB); } +void DirectoryMergeWindow::slotCurrentMergeToAAndB() { d->setMergeOperation(currentIndex(), eMergeToAB); } + +void DirectoryMergeWindow::keyPressEvent(QKeyEvent* e) +{ + if((e->QInputEvent::modifiers() & Qt::ControlModifier) != 0) + { + bool bThreeDirs = d->m_dirC.isValid(); + + MergeFileInfos* pMFI = d->getMFI(currentIndex()); + + if(pMFI == 0) + return; + bool bMergeMode = bThreeDirs || !d->m_bSyncMode; + bool bFTConflict = pMFI == 0 ? false : conflictingFileTypes(*pMFI); + + if(bMergeMode) + { + switch(e->key()) + { + case Qt::Key_1: + if(pMFI->existsInA()) { + slotCurrentChooseA(); + } + return; + case Qt::Key_2: + if(pMFI->existsInB()) { + slotCurrentChooseB(); + } + return; + case Qt::Key_3: + if(pMFI->existsInC()) { + slotCurrentChooseC(); + } + return; + case Qt::Key_Space: + slotCurrentDoNothing(); + return; + case Qt::Key_4: + if(!bFTConflict) { + slotCurrentMerge(); + } + return; + case Qt::Key_Delete: + slotCurrentDelete(); + return; + default: + break; + } + } + else + { + switch(e->key()) + { + case Qt::Key_1: + if(pMFI->existsInA()) { + slotCurrentCopyAToB(); + } + return; + case Qt::Key_2: + if(pMFI->existsInB()) { + slotCurrentCopyBToA(); + } + return; + case Qt::Key_Space: + slotCurrentDoNothing(); + return; + case Qt::Key_4: + if(!bFTConflict) { + slotCurrentMergeToAAndB(); + } + return; + case Qt::Key_Delete: + if(pMFI->existsInA() && pMFI->existsInB()) + slotCurrentDeleteAAndB(); + else if(pMFI->existsInA()) + slotCurrentDeleteA(); + else if(pMFI->existsInB()) + slotCurrentDeleteB(); + return; + default: + break; + } + } + } + else if(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) + { + onDoubleClick(currentIndex()); + return; + } + + QTreeView::keyPressEvent(e); } void DirectoryMergeWindow::focusInEvent(QFocusEvent*) { - updateAvailabilities(); + updateAvailabilities(); } void DirectoryMergeWindow::focusOutEvent(QFocusEvent*) { - updateAvailabilities(); -} - -void DirectoryMergeWindow::Data::setAllMergeOperations( e_MergeOperation eDefaultOperation ) -{ - if ( KMessageBox::Yes == KMessageBox::warningYesNo(q, - i18n("This affects all merge operations."), - i18n("Changing All Merge Operations"), - KStandardGuiItem::cont(), - KStandardGuiItem::cancel() ) ) - { - for( int i=0; i dateMap; - - if( mfi.existsInA() ) - { - dateMap[ mfi.m_pFileInfoA->lastModified() ] = 0; - } - if( mfi.existsInB() ) - { - dateMap[ mfi.m_pFileInfoB->lastModified() ] = 1; - } - if( mfi.existsInC() ) - { - dateMap[ mfi.m_pFileInfoC->lastModified() ] = 2; - } - - if ( m_pOptions->m_bDmFullAnalysis ) - { - if( (mfi.existsInA() && mfi.dirA()) || (mfi.existsInB() && mfi.dirB()) || (mfi.existsInC() && mfi.dirC()) ) - { - // If any input is a directory, don't start any comparison. - mfi.m_bEqualAB=mfi.existsInA() && mfi.existsInB(); - mfi.m_bEqualAC=mfi.existsInA() && mfi.existsInC(); - mfi.m_bEqualBC=mfi.existsInB() && mfi.existsInC(); - } - else - { - emit q->startDiffMerge( - mfi.existsInA() ? mfi.m_pFileInfoA->absoluteFilePath() : QString(""), - mfi.existsInB() ? mfi.m_pFileInfoB->absoluteFilePath() : QString(""), - mfi.existsInC() ? mfi.m_pFileInfoC->absoluteFilePath() : QString(""), - "", - "","","",&mfi.m_totalDiffStatus - ); - int nofNonwhiteConflicts = mfi.m_totalDiffStatus.nofUnsolvedConflicts + - mfi.m_totalDiffStatus.nofSolvedConflicts - mfi.m_totalDiffStatus.nofWhitespaceConflicts; - - if (m_pOptions->m_bDmWhiteSpaceEqual && nofNonwhiteConflicts == 0) - { + updateAvailabilities(); +} + +void DirectoryMergeWindow::Data::setAllMergeOperations(e_MergeOperation eDefaultOperation) +{ + if(KMessageBox::Yes == KMessageBox::warningYesNo(q, + i18n("This affects all merge operations."), + i18n("Changing All Merge Operations"), + KStandardGuiItem::cont(), + KStandardGuiItem::cancel())) + { + for(int i = 0; i < rowCount(); ++i) + { + calcSuggestedOperation(index(i, 0, QModelIndex()), eDefaultOperation); + } + } +} + +void DirectoryMergeWindow::Data::compareFilesAndCalcAges(MergeFileInfos& mfi) +{ + std::map dateMap; + + if(mfi.existsInA()) + { + dateMap[mfi.m_pFileInfoA->lastModified()] = 0; + } + if(mfi.existsInB()) + { + dateMap[mfi.m_pFileInfoB->lastModified()] = 1; + } + if(mfi.existsInC()) + { + dateMap[mfi.m_pFileInfoC->lastModified()] = 2; + } + + if(m_pOptions->m_bDmFullAnalysis) + { + if((mfi.existsInA() && mfi.dirA()) || (mfi.existsInB() && mfi.dirB()) || (mfi.existsInC() && mfi.dirC())) + { + // If any input is a directory, don't start any comparison. mfi.m_bEqualAB = mfi.existsInA() && mfi.existsInB(); mfi.m_bEqualAC = mfi.existsInA() && mfi.existsInC(); mfi.m_bEqualBC = mfi.existsInB() && mfi.existsInC(); - } - else - { - mfi.m_bEqualAB = mfi.m_totalDiffStatus.bBinaryAEqB; - mfi.m_bEqualBC = mfi.m_totalDiffStatus.bBinaryBEqC; - mfi.m_bEqualAC = mfi.m_totalDiffStatus.bBinaryAEqC; - } - } - } - else - { - bool bError; - QString eqStatus; - if( mfi.existsInA() && mfi.existsInB() ) - { - if( mfi.dirA() ) mfi.m_bEqualAB=true; - else mfi.m_bEqualAB = fastFileComparison( *mfi.m_pFileInfoA, *mfi.m_pFileInfoB, bError, eqStatus ); - } - if( mfi.existsInA() && mfi.existsInC() ) - { - if( mfi.dirA() ) mfi.m_bEqualAC=true; - else mfi.m_bEqualAC = fastFileComparison( *mfi.m_pFileInfoA, *mfi.m_pFileInfoC, bError, eqStatus ); - } - if( mfi.existsInB() && mfi.existsInC() ) - { - if (mfi.m_bEqualAB && mfi.m_bEqualAC) - mfi.m_bEqualBC = true; - else - { - if( mfi.dirB() ) mfi.m_bEqualBC=true; - else mfi.m_bEqualBC = fastFileComparison( *mfi.m_pFileInfoB, *mfi.m_pFileInfoC, bError, eqStatus ); - } - } - } - - if (mfi.isLinkA()!=mfi.isLinkB()) mfi.m_bEqualAB=false; - if (mfi.isLinkA()!=mfi.isLinkC()) mfi.m_bEqualAC=false; - if (mfi.isLinkB()!=mfi.isLinkC()) mfi.m_bEqualBC=false; - - if (mfi.dirA()!=mfi.dirB()) mfi.m_bEqualAB=false; - if (mfi.dirA()!=mfi.dirC()) mfi.m_bEqualAC=false; - if (mfi.dirB()!=mfi.dirC()) 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.existsInC() && mfi.m_ageC==eNotThere ) - { - mfi.m_ageC = (e_Age)age; ++age; - mfi.m_bConflictingAges = true; - } - if ( mfi.existsInB() && mfi.m_ageB==eNotThere ) - { - mfi.m_ageB = (e_Age)age; ++age; - mfi.m_bConflictingAges = true; - } - if ( mfi.existsInA() && 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; - } + } + else + { + emit q->startDiffMerge( + mfi.existsInA() ? mfi.m_pFileInfoA->absoluteFilePath() : QString(""), + mfi.existsInB() ? mfi.m_pFileInfoB->absoluteFilePath() : QString(""), + mfi.existsInC() ? mfi.m_pFileInfoC->absoluteFilePath() : QString(""), + "", + "", "", "", &mfi.m_totalDiffStatus); + int nofNonwhiteConflicts = mfi.m_totalDiffStatus.nofUnsolvedConflicts + + mfi.m_totalDiffStatus.nofSolvedConflicts - mfi.m_totalDiffStatus.nofWhitespaceConflicts; + + if(m_pOptions->m_bDmWhiteSpaceEqual && nofNonwhiteConflicts == 0) + { + mfi.m_bEqualAB = mfi.existsInA() && mfi.existsInB(); + mfi.m_bEqualAC = mfi.existsInA() && mfi.existsInC(); + mfi.m_bEqualBC = mfi.existsInB() && mfi.existsInC(); + } + else + { + mfi.m_bEqualAB = mfi.m_totalDiffStatus.bBinaryAEqB; + mfi.m_bEqualBC = mfi.m_totalDiffStatus.bBinaryBEqC; + mfi.m_bEqualAC = mfi.m_totalDiffStatus.bBinaryAEqC; + } + } + } + else + { + bool bError; + QString eqStatus; + if(mfi.existsInA() && mfi.existsInB()) + { + if(mfi.dirA()) + mfi.m_bEqualAB = true; + else + mfi.m_bEqualAB = fastFileComparison(*mfi.m_pFileInfoA, *mfi.m_pFileInfoB, bError, eqStatus); + } + if(mfi.existsInA() && mfi.existsInC()) + { + if(mfi.dirA()) + mfi.m_bEqualAC = true; + else + mfi.m_bEqualAC = fastFileComparison(*mfi.m_pFileInfoA, *mfi.m_pFileInfoC, bError, eqStatus); + } + if(mfi.existsInB() && mfi.existsInC()) + { + if(mfi.m_bEqualAB && mfi.m_bEqualAC) + mfi.m_bEqualBC = true; + else + { + if(mfi.dirB()) + mfi.m_bEqualBC = true; + else + mfi.m_bEqualBC = fastFileComparison(*mfi.m_pFileInfoB, *mfi.m_pFileInfoC, bError, eqStatus); + } + } + } + + if(mfi.isLinkA() != mfi.isLinkB()) mfi.m_bEqualAB = false; + if(mfi.isLinkA() != mfi.isLinkC()) mfi.m_bEqualAC = false; + if(mfi.isLinkB() != mfi.isLinkC()) mfi.m_bEqualBC = false; + + if(mfi.dirA() != mfi.dirB()) mfi.m_bEqualAB = false; + if(mfi.dirA() != mfi.dirC()) mfi.m_bEqualAC = false; + if(mfi.dirB() != mfi.dirC()) 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.existsInC() && mfi.m_ageC == eNotThere) + { + mfi.m_ageC = (e_Age)age; + ++age; + mfi.m_bConflictingAges = true; + } + if(mfi.existsInB() && mfi.m_ageB == eNotThere) + { + mfi.m_ageB = (e_Age)age; + ++age; + mfi.m_bConflictingAges = true; + } + if(mfi.existsInA() && mfi.m_ageA == eNotThere) + { + mfi.m_ageA = (e_Age)age; + ++age; + mfi.m_bConflictingAges = true; + } + + if(mfi.m_ageA != eOld && mfi.m_ageB != eOld && mfi.m_ageC != eOld) + { + if(mfi.m_ageA == eMiddle) mfi.m_ageA = eOld; + if(mfi.m_ageB == eMiddle) mfi.m_ageB = eOld; + if(mfi.m_ageC == eMiddle) mfi.m_ageC = eOld; + } } static QPixmap* s_pm_dir; static QPixmap* s_pm_file; static QPixmap* pmNotThere; static QPixmap* pmNew; static QPixmap* pmOld; static QPixmap* pmMiddle; static QPixmap* pmLink; static QPixmap* pmDirLink; static QPixmap* pmFileLink; static QPixmap* pmNewLink; static QPixmap* pmOldLink; static QPixmap* pmMiddleLink; static QPixmap* pmNewDir; static QPixmap* pmMiddleDir; static QPixmap* pmOldDir; static QPixmap* pmNewDirLink; static QPixmap* pmMiddleDirLink; static QPixmap* pmOldDirLink; - static QPixmap colorToPixmap(QColor c) { - QPixmap pm(16,16); - QPainter p(&pm); - p.setPen( Qt::black ); - p.setBrush( c ); - p.drawRect(0,0,pm.width(),pm.height()); - return pm; -} - -static void initPixmaps( QColor newest, QColor oldest, QColor middle, QColor notThere ) -{ - if (pmNew==0) - { - pmNotThere = new QPixmap; - pmNew = new QPixmap; - pmOld = new QPixmap; - pmMiddle = new QPixmap; - - #include "xpm/link_arrow.xpm" - pmLink = new QPixmap(link_arrow); - - pmDirLink = new QPixmap; - pmFileLink = new QPixmap; - - pmNewLink = new QPixmap; - pmOldLink = new QPixmap; - pmMiddleLink = new QPixmap; - - pmNewDir = new QPixmap; - pmMiddleDir = new QPixmap; - pmOldDir = new QPixmap; - - pmNewDirLink = new QPixmap; - pmMiddleDirLink = new QPixmap; - pmOldDirLink = new QPixmap; - } - - - *pmNotThere = colorToPixmap(notThere); - *pmNew = colorToPixmap(newest); - *pmOld = colorToPixmap(oldest); - *pmMiddle = colorToPixmap(middle); - - *pmDirLink = pixCombiner( s_pm_dir, pmLink); - *pmFileLink = pixCombiner( s_pm_file, pmLink ); - - *pmNewLink = pixCombiner( pmNew, pmLink); - *pmOldLink = pixCombiner( pmOld, pmLink); - *pmMiddleLink = pixCombiner( pmMiddle, pmLink); - - *pmNewDir = pixCombiner2( pmNew, s_pm_dir); - *pmMiddleDir = pixCombiner2( pmMiddle, s_pm_dir); - *pmOldDir = pixCombiner2( pmOld, s_pm_dir); - - *pmNewDirLink = pixCombiner( pmNewDir, pmLink); - *pmMiddleDirLink = pixCombiner( pmMiddleDir, pmLink); - *pmOldDirLink = pixCombiner( pmOldDir, pmLink); -} - -static QPixmap getOnePixmap( e_Age eAge, bool bLink, bool bDir ) -{ - static QPixmap* ageToPm[]= { pmNew, pmMiddle, pmOld, pmNotThere, s_pm_file }; - static QPixmap* ageToPmLink[]= { pmNewLink, pmMiddleLink, pmOldLink, pmNotThere, pmFileLink }; - static QPixmap* ageToPmDir[]= { pmNewDir, pmMiddleDir, pmOldDir, pmNotThere, s_pm_dir }; - static QPixmap* ageToPmDirLink[]={ pmNewDirLink, pmMiddleDirLink, pmOldDirLink, pmNotThere, pmDirLink }; - - QPixmap** ppPm = bDir ? ( bLink ? ageToPmDirLink : ageToPmDir ): - ( bLink ? ageToPmLink : ageToPm ); - - return *ppPm[eAge]; -} - -static void setPixmaps( MergeFileInfos& mfi, bool ) -{ - if ( mfi.dirA() || mfi.dirB() || mfi.dirC() ) - { - mfi.m_ageA=eNotThere; - mfi.m_ageB=eNotThere; - mfi.m_ageC=eNotThere; - int age = eNew; - if ( mfi.existsInC() ) - { - 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.existsInB() && mfi.m_ageB==eNotThere ) - { - mfi.m_ageB = (e_Age)age; - if (mfi.m_bEqualAB) mfi.m_ageA = (e_Age)age; - ++age; - } - if ( mfi.existsInA() && 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; - } - } + QPixmap pm(16, 16); + QPainter p(&pm); + p.setPen(Qt::black); + p.setBrush(c); + p.drawRect(0, 0, pm.width(), pm.height()); + return pm; +} + +static void initPixmaps(QColor newest, QColor oldest, QColor middle, QColor notThere) +{ + if(pmNew == 0) + { + pmNotThere = new QPixmap; + pmNew = new QPixmap; + pmOld = new QPixmap; + pmMiddle = new QPixmap; + +#include "xpm/link_arrow.xpm" + pmLink = new QPixmap(link_arrow); + + pmDirLink = new QPixmap; + pmFileLink = new QPixmap; + + pmNewLink = new QPixmap; + pmOldLink = new QPixmap; + pmMiddleLink = new QPixmap; + + pmNewDir = new QPixmap; + pmMiddleDir = new QPixmap; + pmOldDir = new QPixmap; + + pmNewDirLink = new QPixmap; + pmMiddleDirLink = new QPixmap; + pmOldDirLink = new QPixmap; + } + + *pmNotThere = colorToPixmap(notThere); + *pmNew = colorToPixmap(newest); + *pmOld = colorToPixmap(oldest); + *pmMiddle = colorToPixmap(middle); + + *pmDirLink = pixCombiner(s_pm_dir, pmLink); + *pmFileLink = pixCombiner(s_pm_file, pmLink); + + *pmNewLink = pixCombiner(pmNew, pmLink); + *pmOldLink = pixCombiner(pmOld, pmLink); + *pmMiddleLink = pixCombiner(pmMiddle, pmLink); + + *pmNewDir = pixCombiner2(pmNew, s_pm_dir); + *pmMiddleDir = pixCombiner2(pmMiddle, s_pm_dir); + *pmOldDir = pixCombiner2(pmOld, s_pm_dir); + + *pmNewDirLink = pixCombiner(pmNewDir, pmLink); + *pmMiddleDirLink = pixCombiner(pmMiddleDir, pmLink); + *pmOldDirLink = pixCombiner(pmOldDir, pmLink); +} + +static QPixmap getOnePixmap(e_Age eAge, bool bLink, bool bDir) +{ + static QPixmap* ageToPm[] = {pmNew, pmMiddle, pmOld, pmNotThere, s_pm_file}; + static QPixmap* ageToPmLink[] = {pmNewLink, pmMiddleLink, pmOldLink, pmNotThere, pmFileLink}; + static QPixmap* ageToPmDir[] = {pmNewDir, pmMiddleDir, pmOldDir, pmNotThere, s_pm_dir}; + static QPixmap* ageToPmDirLink[] = {pmNewDirLink, pmMiddleDirLink, pmOldDirLink, pmNotThere, pmDirLink}; + + QPixmap** ppPm = bDir ? (bLink ? ageToPmDirLink : ageToPmDir) : (bLink ? ageToPmLink : ageToPm); + + return *ppPm[eAge]; +} + +static void setPixmaps(MergeFileInfos& mfi, bool) +{ + if(mfi.dirA() || mfi.dirB() || mfi.dirC()) + { + mfi.m_ageA = eNotThere; + mfi.m_ageB = eNotThere; + mfi.m_ageC = eNotThere; + int age = eNew; + if(mfi.existsInC()) + { + 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.existsInB() && mfi.m_ageB == eNotThere) + { + mfi.m_ageB = (e_Age)age; + if(mfi.m_bEqualAB) mfi.m_ageA = (e_Age)age; + ++age; + } + if(mfi.existsInA() && 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; + } + } } static QModelIndex nextSibling(const QModelIndex& mi) { - QModelIndex miParent = mi.parent(); - int currentIdx = mi.row(); - if ( currentIdx+1 < mi.model()->rowCount(miParent) ) - return mi.model()->index(mi.row()+1,0,miParent); // next child of parent - return QModelIndex(); + QModelIndex miParent = mi.parent(); + int currentIdx = mi.row(); + if(currentIdx + 1 < mi.model()->rowCount(miParent)) + return mi.model()->index(mi.row() + 1, 0, miParent); // next child of parent + return QModelIndex(); } // Iterate through the complete tree. Start by specifying QListView::firstChild(). -QModelIndex DirectoryMergeWindow::Data::treeIterator( QModelIndex mi, bool bVisitChildren, bool bFindInvisible ) -{ - if( mi.isValid() ) - { - do - { - if ( bVisitChildren && mi.model()->rowCount(mi) != 0 ) - mi = mi.model()->index(0,0,mi); - else - { - QModelIndex miNextSibling = nextSibling(mi); - if ( miNextSibling.isValid() ) - mi = miNextSibling; +QModelIndex DirectoryMergeWindow::Data::treeIterator(QModelIndex mi, bool bVisitChildren, bool bFindInvisible) +{ + if(mi.isValid()) + { + do + { + if(bVisitChildren && mi.model()->rowCount(mi) != 0) + mi = mi.model()->index(0, 0, mi); else { - mi = mi.parent(); - while ( mi.isValid() ) - { - QModelIndex miNextSibling = nextSibling(mi); - if( miNextSibling.isValid() ) - { - mi = miNextSibling; - break; - } - else - { - mi = mi.parent(); - } - } - } - } - } - while( mi.isValid() && q->isRowHidden(mi.row(),mi.parent()) && !bFindInvisible ); - } - return mi; -} - -void DirectoryMergeWindow::Data::prepareListView( ProgressProxy& pp ) -{ - static bool bFirstTime = true; - if (bFirstTime) - { - #include "xpm/file.xpm" - #include "xpm/folder.xpm" - // FIXME specify correct icon loader group - s_pm_dir = new QPixmap( m_pIconLoader->loadIcon("folder", KIconLoader::NoGroup, KIconLoader::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; - } - -//TODO clear(); - initPixmaps( m_pOptions->m_newestFileColor, m_pOptions->m_oldestFileColor, - m_pOptions->m_midAgeFileColor, m_pOptions->m_missingFileColor ); - - q->setRootIsDecorated( true ); - - bool bCheckC = m_dirC.isValid(); - - t_fileMergeMap::iterator j; - int nrOfFiles = m_fileMergeMap.size(); - int currentIdx = 1; - QTime t; - t.start(); - pp.setMaxNofSteps(nrOfFiles); - for( j=m_fileMergeMap.begin(); j!=m_fileMergeMap.end(); ++j ) - { - MergeFileInfos& mfi = j.value(); - - // const QString& fileName = j->first; - const QString& fileName = mfi.subPath(); - - pp.setInformation( - i18n("Processing ") + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles) - +"\n" + fileName, currentIdx, false ); - if ( pp.wasCancelled() ) break; - ++currentIdx; - - // The comparisons and calculations for each file take place here. - compareFilesAndCalcAges( mfi ); - - // Get dirname from fileName: Search for "/" from end: - int pos = fileName.lastIndexOf('/'); - 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 - { - m_pRoot->m_children.push_back(&mfi); //new DirMergeItem( this, filePart, &mfi ); - mfi.m_pParent = m_pRoot; - } - else - { - FileAccess* pFA = mfi.m_pFileInfoA ? mfi.m_pFileInfoA : mfi.m_pFileInfoB ? mfi.m_pFileInfoB : mfi.m_pFileInfoC; - MergeFileInfos& dirMfi = pFA->parent() ? m_fileMergeMap[FileKey(*pFA->parent())] : *m_pRoot; // parent - - dirMfi.m_children.push_back(&mfi);//new DirMergeItem( dirMfi.m_pDMI, filePart, &mfi ); - mfi.m_pParent = &dirMfi; - - // // Equality for parent dirs is set in updateFileVisibilities() - } - - setPixmaps( mfi, bCheckC ); - } - beginResetModel(); - endResetModel(); + QModelIndex miNextSibling = nextSibling(mi); + if(miNextSibling.isValid()) + mi = miNextSibling; + else + { + mi = mi.parent(); + while(mi.isValid()) + { + QModelIndex miNextSibling = nextSibling(mi); + if(miNextSibling.isValid()) + { + mi = miNextSibling; + break; + } + else + { + mi = mi.parent(); + } + } + } + } + } while(mi.isValid() && q->isRowHidden(mi.row(), mi.parent()) && !bFindInvisible); + } + return mi; +} + +void DirectoryMergeWindow::Data::prepareListView(ProgressProxy& pp) +{ + static bool bFirstTime = true; + if(bFirstTime) + { +#include "xpm/file.xpm" +#include "xpm/folder.xpm" + // FIXME specify correct icon loader group + s_pm_dir = new QPixmap(m_pIconLoader->loadIcon("folder", KIconLoader::NoGroup, KIconLoader::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; + } + + //TODO clear(); + initPixmaps(m_pOptions->m_newestFileColor, m_pOptions->m_oldestFileColor, + m_pOptions->m_midAgeFileColor, m_pOptions->m_missingFileColor); + + q->setRootIsDecorated(true); + + bool bCheckC = m_dirC.isValid(); + + t_fileMergeMap::iterator j; + int nrOfFiles = m_fileMergeMap.size(); + int currentIdx = 1; + QTime t; + t.start(); + pp.setMaxNofSteps(nrOfFiles); + for(j = m_fileMergeMap.begin(); j != m_fileMergeMap.end(); ++j) + { + MergeFileInfos& mfi = j.value(); + + // const QString& fileName = j->first; + const QString& fileName = mfi.subPath(); + + pp.setInformation( + i18n("Processing ") + QString::number(currentIdx) + " / " + QString::number(nrOfFiles) + "\n" + fileName, currentIdx, false); + if(pp.wasCancelled()) break; + ++currentIdx; + + // The comparisons and calculations for each file take place here. + compareFilesAndCalcAges(mfi); + + // Get dirname from fileName: Search for "/" from end: + int pos = fileName.lastIndexOf('/'); + 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 + { + m_pRoot->m_children.push_back(&mfi); //new DirMergeItem( this, filePart, &mfi ); + mfi.m_pParent = m_pRoot; + } + else + { + FileAccess* pFA = mfi.m_pFileInfoA ? mfi.m_pFileInfoA : mfi.m_pFileInfoB ? mfi.m_pFileInfoB : mfi.m_pFileInfoC; + MergeFileInfos& dirMfi = pFA->parent() ? m_fileMergeMap[FileKey(*pFA->parent())] : *m_pRoot; // parent + + dirMfi.m_children.push_back(&mfi); //new DirMergeItem( dirMfi.m_pDMI, filePart, &mfi ); + mfi.m_pParent = &dirMfi; + + // // Equality for parent dirs is set in updateFileVisibilities() + } + + setPixmaps(mfi, bCheckC); + } + beginResetModel(); + endResetModel(); } static bool conflictingFileTypes(MergeFileInfos& mfi) { - // Now check if file/dir-types fit. - if ( mfi.isLinkA() || mfi.isLinkB() || mfi.isLinkC() ) - { - if ( (mfi.existsInA() && ! mfi.isLinkA()) || - (mfi.existsInB() && ! mfi.isLinkB()) || - (mfi.existsInC() && ! mfi.isLinkC()) ) - { - return true; - } - } - - if ( mfi.dirA() || mfi.dirB() || mfi.dirC() ) - { - if ( (mfi.existsInA() && ! mfi.dirA()) || - (mfi.existsInB() && ! mfi.dirB()) || - (mfi.existsInC() && ! mfi.dirC()) ) - { - return true; - } - } - return false; -} - -void DirectoryMergeWindow::Data::calcSuggestedOperation( const QModelIndex& mi, e_MergeOperation eDefaultMergeOp ) -{ - MergeFileInfos* pMFI = getMFI(mi); - if ( pMFI==0 ) - return; - MergeFileInfos& mfi = *pMFI; - bool bCheckC = m_dirC.isValid(); - bool bCopyNewer = m_pOptions->m_bDmCopyNewer; - bool bOtherDest = !( (m_dirDestInternal.absoluteFilePath() == m_dirA.absoluteFilePath()) || + // Now check if file/dir-types fit. + if(mfi.isLinkA() || mfi.isLinkB() || mfi.isLinkC()) + { + if((mfi.existsInA() && !mfi.isLinkA()) || + (mfi.existsInB() && !mfi.isLinkB()) || + (mfi.existsInC() && !mfi.isLinkC())) + { + return true; + } + } + + if(mfi.dirA() || mfi.dirB() || mfi.dirC()) + { + if((mfi.existsInA() && !mfi.dirA()) || + (mfi.existsInB() && !mfi.dirB()) || + (mfi.existsInC() && !mfi.dirC())) + { + return true; + } + } + return false; +} + +void DirectoryMergeWindow::Data::calcSuggestedOperation(const QModelIndex& mi, e_MergeOperation eDefaultMergeOp) +{ + MergeFileInfos* pMFI = getMFI(mi); + if(pMFI == 0) + return; + MergeFileInfos& mfi = *pMFI; + bool bCheckC = m_dirC.isValid(); + bool bCopyNewer = m_pOptions->m_bDmCopyNewer; + bool bOtherDest = !((m_dirDestInternal.absoluteFilePath() == m_dirA.absoluteFilePath()) || (m_dirDestInternal.absoluteFilePath() == m_dirB.absoluteFilePath()) || - (bCheckC && m_dirDestInternal.absoluteFilePath() == m_dirC.absoluteFilePath()) ); - - - 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 ) - { - setMergeOperation( mi, bOtherDest ? eCopyBToDest : eNoOperation ); - } - else if ( mfi.existsInA() && mfi.existsInB() ) - { - if ( !bCopyNewer || mfi.dirA() ) - setMergeOperation( mi, eDefaultMergeOp ); - else if ( bCopyNewer && mfi.m_bConflictingAges ) + (bCheckC && m_dirDestInternal.absoluteFilePath() == m_dirC.absoluteFilePath())); + + 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) { - setMergeOperation( mi, eConflictingAges ); + setMergeOperation(mi, bOtherDest ? eCopyBToDest : eNoOperation); } - else + else if(mfi.existsInA() && mfi.existsInB()) { - if ( mfi.m_ageA == eNew ) - setMergeOperation( mi, eDefaultMergeOp == eMergeToAB ? eCopyAToB : eCopyAToDest ); - else - setMergeOperation( mi, eDefaultMergeOp == eMergeToAB ? eCopyBToA : eCopyBToDest ); - } - } - else if ( !mfi.existsInA() && mfi.existsInB() ) - { - if ( eDefaultMergeOp==eMergeABToDest ) setMergeOperation( mi, eCopyBToDest ); - else if ( eDefaultMergeOp==eMergeToB ) setMergeOperation( mi, eNoOperation ); - else setMergeOperation( mi, eCopyBToA ); - } - else if ( mfi.existsInA() && !mfi.existsInB() ) - { - if ( eDefaultMergeOp==eMergeABToDest ) setMergeOperation( mi, eCopyAToDest ); - else if ( eDefaultMergeOp==eMergeToA ) setMergeOperation( mi, eNoOperation ); - else setMergeOperation( mi, eCopyAToB ); - } - else //if ( !mfi.existsInA() && !mfi.existsInB() ) - { - setMergeOperation( mi, eNoOperation ); assert(false); - } - } - else - { - if ( mfi.m_bEqualAB && mfi.m_bEqualAC ) - { - setMergeOperation( mi, bOtherDest ? eCopyCToDest : eNoOperation ); - } - else if ( mfi.existsInA() && mfi.existsInB() && mfi.existsInC()) - { - if ( mfi.m_bEqualAB ) - setMergeOperation( mi, eCopyCToDest ); - else if ( mfi.m_bEqualAC ) - setMergeOperation( mi, eCopyBToDest ); - else if ( mfi.m_bEqualBC ) - setMergeOperation( mi, eCopyCToDest ); - else - setMergeOperation( mi, eMergeABCToDest ); - } - else if ( mfi.existsInA() && mfi.existsInB() && !mfi.existsInC() ) - { - if ( mfi.m_bEqualAB ) - setMergeOperation( mi, eDeleteFromDest ); - else - setMergeOperation( mi, eChangedAndDeleted ); - } - else if ( mfi.existsInA() && !mfi.existsInB() && mfi.existsInC() ) - { - if ( mfi.m_bEqualAC ) - setMergeOperation( mi, eDeleteFromDest ); - else - setMergeOperation( mi, eChangedAndDeleted ); - } - else if ( !mfi.existsInA() && mfi.existsInB() && mfi.existsInC() ) - { - if ( mfi.m_bEqualBC ) - setMergeOperation( mi, eCopyCToDest ); - else - setMergeOperation( mi, eMergeABCToDest ); - } - else if ( !mfi.existsInA() && !mfi.existsInB() && mfi.existsInC() ) - { - setMergeOperation( mi, eCopyCToDest ); - } - else if ( !mfi.existsInA() && mfi.existsInB() && !mfi.existsInC() ) - { - setMergeOperation( mi, eCopyBToDest ); - } - else if ( mfi.existsInA() && !mfi.existsInB() && !mfi.existsInC()) - { - setMergeOperation( mi, eDeleteFromDest ); - } - else //if ( !mfi.existsInA() && !mfi.existsInB() && !mfi.existsInC() ) - { - setMergeOperation( mi, eNoOperation ); assert(false); - } - } - - // Now check if file/dir-types fit. - if ( conflictingFileTypes(mfi) ) - { - setMergeOperation( mi, eConflictingFileTypes ); - } - } - else - { - e_MergeOperation eMO = eDefaultMergeOp; - switch ( eDefaultMergeOp ) - { - case eConflictingFileTypes: - case eChangedAndDeleted: - case eConflictingAges: - case eDeleteA: - case eDeleteB: - case eDeleteAB: - case eDeleteFromDest: - case eNoOperation: break; - case eCopyAToB: if ( !mfi.existsInA() ) { eMO = eDeleteB; } break; - case eCopyBToA: if ( !mfi.existsInB() ) { eMO = eDeleteA; } break; - case eCopyAToDest: if ( !mfi.existsInA() ) { eMO = eDeleteFromDest; } break; - case eCopyBToDest: if ( !mfi.existsInB() ) { eMO = eDeleteFromDest; } break; - case eCopyCToDest: if ( !mfi.existsInC() ) { eMO = eDeleteFromDest; } break; - - case eMergeToA: - case eMergeToB: - case eMergeToAB: - case eMergeABCToDest: - case eMergeABToDest: - default: - assert(false); - } - setMergeOperation( mi, eMO ); - } -} - -void DirectoryMergeWindow::onDoubleClick( const QModelIndex& mi ) -{ - if ( ! mi.isValid() ) - return; - - d->m_bSimulatedMergeStarted = false; - if ( d->m_bDirectoryMerge ) - mergeCurrentFile(); - else - compareCurrentFile(); -} - -void DirectoryMergeWindow::currentChanged ( const QModelIndex & current, const QModelIndex & previous ) -{ - QTreeView::currentChanged( current, previous ); - MergeFileInfos* pMFI = d->getMFI( current ); - if ( pMFI==0 ) - return; - - d->m_pDirectoryMergeInfo->setInfo( d->m_dirA, d->m_dirB, d->m_dirC, d->m_dirDestInternal, *pMFI ); -} - -void DirectoryMergeWindow::mousePressEvent( QMouseEvent* e ) -{ - QTreeView::mousePressEvent(e); - QModelIndex mi = indexAt( e->pos() ); - int c = mi.column(); - QPoint p = e->globalPos(); - MergeFileInfos* pMFI = d->getMFI( mi ); - if ( pMFI==0 ) - return; - MergeFileInfos& mfi = *pMFI; - - if ( c==s_OpCol ) - { - bool bThreeDirs = d->m_dirC.isValid(); - - QMenu m(this); - if ( bThreeDirs ) - { - m.addAction( d->m_pDirCurrentDoNothing ); - int count=0; - if ( mfi.existsInA() ) { m.addAction( d->m_pDirCurrentChooseA ); ++count; } - if ( mfi.existsInB() ) { m.addAction( d->m_pDirCurrentChooseB ); ++count; } - if ( mfi.existsInC() ) { m.addAction( d->m_pDirCurrentChooseC ); ++count; } - if ( !conflictingFileTypes(mfi) && count>1 ) m.addAction( d->m_pDirCurrentMerge ); - m.addAction( d->m_pDirCurrentDelete ); - } - else if ( d->m_bSyncMode ) - { - m.addAction( d->m_pDirCurrentSyncDoNothing ); - if ( mfi.existsInA() ) m.addAction( d->m_pDirCurrentSyncCopyAToB ); - if ( mfi.existsInB() ) m.addAction( d->m_pDirCurrentSyncCopyBToA ); - if ( mfi.existsInA() ) m.addAction( d->m_pDirCurrentSyncDeleteA ); - if ( mfi.existsInB() ) m.addAction( d->m_pDirCurrentSyncDeleteB ); - if ( mfi.existsInA() && mfi.existsInB() ) - { - m.addAction( d->m_pDirCurrentSyncDeleteAAndB ); - if ( !conflictingFileTypes(mfi)) + if(!bCopyNewer || mfi.dirA()) + setMergeOperation(mi, eDefaultMergeOp); + else if(bCopyNewer && mfi.m_bConflictingAges) + { + setMergeOperation(mi, eConflictingAges); + } + else + { + if(mfi.m_ageA == eNew) + setMergeOperation(mi, eDefaultMergeOp == eMergeToAB ? eCopyAToB : eCopyAToDest); + else + setMergeOperation(mi, eDefaultMergeOp == eMergeToAB ? eCopyBToA : eCopyBToDest); + } + } + else if(!mfi.existsInA() && mfi.existsInB()) + { + if(eDefaultMergeOp == eMergeABToDest) + setMergeOperation(mi, eCopyBToDest); + else if(eDefaultMergeOp == eMergeToB) + setMergeOperation(mi, eNoOperation); + else + setMergeOperation(mi, eCopyBToA); + } + else if(mfi.existsInA() && !mfi.existsInB()) + { + if(eDefaultMergeOp == eMergeABToDest) + setMergeOperation(mi, eCopyAToDest); + else if(eDefaultMergeOp == eMergeToA) + setMergeOperation(mi, eNoOperation); + else + setMergeOperation(mi, eCopyAToB); + } + else //if ( !mfi.existsInA() && !mfi.existsInB() ) + { + setMergeOperation(mi, eNoOperation); + assert(false); + } + } + else + { + if(mfi.m_bEqualAB && mfi.m_bEqualAC) + { + setMergeOperation(mi, bOtherDest ? eCopyCToDest : eNoOperation); + } + else if(mfi.existsInA() && mfi.existsInB() && mfi.existsInC()) + { + if(mfi.m_bEqualAB) + setMergeOperation(mi, eCopyCToDest); + else if(mfi.m_bEqualAC) + setMergeOperation(mi, eCopyBToDest); + else if(mfi.m_bEqualBC) + setMergeOperation(mi, eCopyCToDest); + else + setMergeOperation(mi, eMergeABCToDest); + } + else if(mfi.existsInA() && mfi.existsInB() && !mfi.existsInC()) { - m.addAction( d->m_pDirCurrentSyncMergeToA ); - m.addAction( d->m_pDirCurrentSyncMergeToB ); - m.addAction( d->m_pDirCurrentSyncMergeToAAndB ); - } - } - } - else - { - m.addAction( d->m_pDirCurrentDoNothing ); - if ( mfi.existsInA() ) { m.addAction( d->m_pDirCurrentChooseA ); } - if ( mfi.existsInB() ) { m.addAction( d->m_pDirCurrentChooseB ); } - if ( !conflictingFileTypes(mfi) && mfi.existsInA() && mfi.existsInB() ) m.addAction( d->m_pDirCurrentMerge ); - m.addAction( d->m_pDirCurrentDelete ); - } - - m.exec( p ); - } - else if ( c == s_ACol || c==s_BCol || c==s_CCol ) - { - QString itemPath; - if ( c == s_ACol && mfi.existsInA() ){ itemPath = d->fullNameA(mfi); } - else if ( c == s_BCol && mfi.existsInB() ){ itemPath = d->fullNameB(mfi); } - else if ( c == s_CCol && mfi.existsInC() ){ itemPath = d->fullNameC(mfi); } - - if (!itemPath.isEmpty()) - { - d->selectItemAndColumn( mi, e->button()==Qt::RightButton ); - } - } + if(mfi.m_bEqualAB) + setMergeOperation(mi, eDeleteFromDest); + else + setMergeOperation(mi, eChangedAndDeleted); + } + else if(mfi.existsInA() && !mfi.existsInB() && mfi.existsInC()) + { + if(mfi.m_bEqualAC) + setMergeOperation(mi, eDeleteFromDest); + else + setMergeOperation(mi, eChangedAndDeleted); + } + else if(!mfi.existsInA() && mfi.existsInB() && mfi.existsInC()) + { + if(mfi.m_bEqualBC) + setMergeOperation(mi, eCopyCToDest); + else + setMergeOperation(mi, eMergeABCToDest); + } + else if(!mfi.existsInA() && !mfi.existsInB() && mfi.existsInC()) + { + setMergeOperation(mi, eCopyCToDest); + } + else if(!mfi.existsInA() && mfi.existsInB() && !mfi.existsInC()) + { + setMergeOperation(mi, eCopyBToDest); + } + else if(mfi.existsInA() && !mfi.existsInB() && !mfi.existsInC()) + { + setMergeOperation(mi, eDeleteFromDest); + } + else //if ( !mfi.existsInA() && !mfi.existsInB() && !mfi.existsInC() ) + { + setMergeOperation(mi, eNoOperation); + assert(false); + } + } + + // Now check if file/dir-types fit. + if(conflictingFileTypes(mfi)) + { + setMergeOperation(mi, eConflictingFileTypes); + } + } + else + { + e_MergeOperation eMO = eDefaultMergeOp; + switch(eDefaultMergeOp) + { + case eConflictingFileTypes: + case eChangedAndDeleted: + case eConflictingAges: + case eDeleteA: + case eDeleteB: + case eDeleteAB: + case eDeleteFromDest: + case eNoOperation: + break; + case eCopyAToB: + if(!mfi.existsInA()) { + eMO = eDeleteB; + } + break; + case eCopyBToA: + if(!mfi.existsInB()) { + eMO = eDeleteA; + } + break; + case eCopyAToDest: + if(!mfi.existsInA()) { + eMO = eDeleteFromDest; + } + break; + case eCopyBToDest: + if(!mfi.existsInB()) { + eMO = eDeleteFromDest; + } + break; + case eCopyCToDest: + if(!mfi.existsInC()) { + eMO = eDeleteFromDest; + } + break; + + case eMergeToA: + case eMergeToB: + case eMergeToAB: + case eMergeABCToDest: + case eMergeABToDest: + default: + assert(false); + } + setMergeOperation(mi, eMO); + } +} + +void DirectoryMergeWindow::onDoubleClick(const QModelIndex& mi) +{ + if(!mi.isValid()) + return; + + d->m_bSimulatedMergeStarted = false; + if(d->m_bDirectoryMerge) + mergeCurrentFile(); + else + compareCurrentFile(); +} + +void DirectoryMergeWindow::currentChanged(const QModelIndex& current, const QModelIndex& previous) +{ + QTreeView::currentChanged(current, previous); + MergeFileInfos* pMFI = d->getMFI(current); + if(pMFI == 0) + return; + + d->m_pDirectoryMergeInfo->setInfo(d->m_dirA, d->m_dirB, d->m_dirC, d->m_dirDestInternal, *pMFI); +} + +void DirectoryMergeWindow::mousePressEvent(QMouseEvent* e) +{ + QTreeView::mousePressEvent(e); + QModelIndex mi = indexAt(e->pos()); + int c = mi.column(); + QPoint p = e->globalPos(); + MergeFileInfos* pMFI = d->getMFI(mi); + if(pMFI == 0) + return; + MergeFileInfos& mfi = *pMFI; + + if(c == s_OpCol) + { + bool bThreeDirs = d->m_dirC.isValid(); + + QMenu m(this); + if(bThreeDirs) + { + m.addAction(d->m_pDirCurrentDoNothing); + int count = 0; + if(mfi.existsInA()) { + m.addAction(d->m_pDirCurrentChooseA); + ++count; + } + if(mfi.existsInB()) { + m.addAction(d->m_pDirCurrentChooseB); + ++count; + } + if(mfi.existsInC()) { + m.addAction(d->m_pDirCurrentChooseC); + ++count; + } + if(!conflictingFileTypes(mfi) && count > 1) m.addAction(d->m_pDirCurrentMerge); + m.addAction(d->m_pDirCurrentDelete); + } + else if(d->m_bSyncMode) + { + m.addAction(d->m_pDirCurrentSyncDoNothing); + if(mfi.existsInA()) m.addAction(d->m_pDirCurrentSyncCopyAToB); + if(mfi.existsInB()) m.addAction(d->m_pDirCurrentSyncCopyBToA); + if(mfi.existsInA()) m.addAction(d->m_pDirCurrentSyncDeleteA); + if(mfi.existsInB()) m.addAction(d->m_pDirCurrentSyncDeleteB); + if(mfi.existsInA() && mfi.existsInB()) + { + m.addAction(d->m_pDirCurrentSyncDeleteAAndB); + if(!conflictingFileTypes(mfi)) + { + m.addAction(d->m_pDirCurrentSyncMergeToA); + m.addAction(d->m_pDirCurrentSyncMergeToB); + m.addAction(d->m_pDirCurrentSyncMergeToAAndB); + } + } + } + else + { + m.addAction(d->m_pDirCurrentDoNothing); + if(mfi.existsInA()) { + m.addAction(d->m_pDirCurrentChooseA); + } + if(mfi.existsInB()) { + m.addAction(d->m_pDirCurrentChooseB); + } + if(!conflictingFileTypes(mfi) && mfi.existsInA() && mfi.existsInB()) m.addAction(d->m_pDirCurrentMerge); + m.addAction(d->m_pDirCurrentDelete); + } + + m.exec(p); + } + else if(c == s_ACol || c == s_BCol || c == s_CCol) + { + QString itemPath; + if(c == s_ACol && mfi.existsInA()) { + itemPath = d->fullNameA(mfi); + } + else if(c == s_BCol && mfi.existsInB()) + { + itemPath = d->fullNameB(mfi); + } + else if(c == s_CCol && mfi.existsInC()) + { + itemPath = d->fullNameC(mfi); + } + + if(!itemPath.isEmpty()) + { + d->selectItemAndColumn(mi, e->button() == Qt::RightButton); + } + } } void DirectoryMergeWindow::contextMenuEvent(QContextMenuEvent* e) { - QModelIndex mi = indexAt( e->pos() ); - int c = mi.column(); - QPoint p = e->globalPos(); - - MergeFileInfos* pMFI = d->getMFI(mi); - if (pMFI==0) - return; - if ( c == s_ACol || c==s_BCol || c==s_CCol ) - { - QString itemPath; - if ( c == s_ACol && pMFI->existsInA() ){ itemPath = d->fullNameA(*pMFI); } - else if ( c == s_BCol && pMFI->existsInB() ){ itemPath = d->fullNameB(*pMFI); } - else if ( c == s_CCol && pMFI->existsInC() ){ itemPath = d->fullNameC(*pMFI); } - - if (!itemPath.isEmpty()) - { - d->selectItemAndColumn(mi, true); - QMenu m(this); - m.addAction( d->m_pDirCompareExplicit ); - m.addAction( d->m_pDirMergeExplicit ); + QModelIndex mi = indexAt(e->pos()); + int c = mi.column(); + QPoint p = e->globalPos(); + + MergeFileInfos* pMFI = d->getMFI(mi); + if(pMFI == 0) + return; + if(c == s_ACol || c == s_BCol || c == s_CCol) + { + QString itemPath; + if(c == s_ACol && pMFI->existsInA()) { + itemPath = d->fullNameA(*pMFI); + } + else if(c == s_BCol && pMFI->existsInB()) + { + itemPath = d->fullNameB(*pMFI); + } + else if(c == s_CCol && pMFI->existsInC()) + { + itemPath = d->fullNameC(*pMFI); + } + + if(!itemPath.isEmpty()) + { + d->selectItemAndColumn(mi, true); + QMenu m(this); + m.addAction(d->m_pDirCompareExplicit); + m.addAction(d->m_pDirMergeExplicit); #ifndef _WIN32 - m.exec( p ); + m.exec(p); #else - void showShellContextMenu( const QString&, QPoint, QWidget*, QMenu* ); - showShellContextMenu( itemPath, p, this, &m ); + void showShellContextMenu(const QString&, QPoint, QWidget*, QMenu*); + showShellContextMenu(itemPath, p, this, &m); #endif - } - } + } + } } -QString DirectoryMergeWindow::Data::getFileName( const QModelIndex& mi ) +QString DirectoryMergeWindow::Data::getFileName(const QModelIndex& mi) { - MergeFileInfos* pMFI = getMFI( mi ); - if ( pMFI != 0 ) - { - return mi.column() == s_ACol ? pMFI->m_pFileInfoA->absoluteFilePath() : - mi.column() == s_BCol ? pMFI->m_pFileInfoB->absoluteFilePath() : - mi.column() == s_CCol ? pMFI->m_pFileInfoC->absoluteFilePath() : - QString(""); - } - return ""; + MergeFileInfos* pMFI = getMFI(mi); + if(pMFI != 0) + { + return mi.column() == s_ACol ? pMFI->m_pFileInfoA->absoluteFilePath() : mi.column() == s_BCol ? pMFI->m_pFileInfoB->absoluteFilePath() : mi.column() == s_CCol ? pMFI->m_pFileInfoC->absoluteFilePath() : QString(""); + } + return ""; } -bool DirectoryMergeWindow::Data::isDir( const QModelIndex& mi ) +bool DirectoryMergeWindow::Data::isDir(const QModelIndex& mi) { - MergeFileInfos* pMFI = getMFI( mi ); - if ( pMFI != 0 ) - { - return mi.column() == s_ACol ? pMFI->dirA() : - mi.column() == s_BCol ? pMFI->dirB() : - pMFI->dirC(); - } - return false; + MergeFileInfos* pMFI = getMFI(mi); + if(pMFI != 0) + { + return mi.column() == s_ACol ? pMFI->dirA() : mi.column() == s_BCol ? pMFI->dirB() : pMFI->dirC(); + } + return false; } - void DirectoryMergeWindow::Data::selectItemAndColumn(const QModelIndex& mi, bool bContextMenu) { - if ( bContextMenu && ( mi==m_selection1Index || mi==m_selection2Index || mi==m_selection3Index ) ) - return; - - QModelIndex old1=m_selection1Index; - QModelIndex old2=m_selection2Index; - QModelIndex old3=m_selection3Index; - - bool bReset = false; - - if ( m_selection1Index.isValid() ) - { - if (isDir( m_selection1Index )!=isDir( mi )) - bReset = true; - } - - if ( bReset || m_selection3Index.isValid() || mi==m_selection1Index || mi==m_selection2Index || mi==m_selection3Index ) - { - // restart - m_selection1Index = QModelIndex(); - m_selection2Index = QModelIndex(); - m_selection3Index = QModelIndex(); - } - else if ( !m_selection1Index.isValid() ) - { - m_selection1Index = mi; - m_selection2Index = QModelIndex(); - m_selection3Index = QModelIndex(); - } - else if ( !m_selection2Index.isValid() ) - { - m_selection2Index = mi; - m_selection3Index = QModelIndex(); - } - else if ( !m_selection3Index.isValid() ) - { - m_selection3Index = mi; - } - if (old1.isValid()) dataChanged( old1, old1 ); - if (old2.isValid()) dataChanged( old2, old2 ); - if (old3.isValid()) dataChanged( old3, old3 ); - if (m_selection1Index.isValid()) dataChanged( m_selection1Index, m_selection1Index ); - if (m_selection2Index.isValid()) dataChanged( m_selection2Index, m_selection2Index ); - if (m_selection3Index.isValid()) dataChanged( m_selection3Index, m_selection3Index ); - emit q->updateAvailabilities(); + if(bContextMenu && (mi == m_selection1Index || mi == m_selection2Index || mi == m_selection3Index)) + return; + + QModelIndex old1 = m_selection1Index; + QModelIndex old2 = m_selection2Index; + QModelIndex old3 = m_selection3Index; + + bool bReset = false; + + if(m_selection1Index.isValid()) + { + if(isDir(m_selection1Index) != isDir(mi)) + bReset = true; + } + + if(bReset || m_selection3Index.isValid() || mi == m_selection1Index || mi == m_selection2Index || mi == m_selection3Index) + { + // restart + m_selection1Index = QModelIndex(); + m_selection2Index = QModelIndex(); + m_selection3Index = QModelIndex(); + } + else if(!m_selection1Index.isValid()) + { + m_selection1Index = mi; + m_selection2Index = QModelIndex(); + m_selection3Index = QModelIndex(); + } + else if(!m_selection2Index.isValid()) + { + m_selection2Index = mi; + m_selection3Index = QModelIndex(); + } + else if(!m_selection3Index.isValid()) + { + m_selection3Index = mi; + } + if(old1.isValid()) dataChanged(old1, old1); + if(old2.isValid()) dataChanged(old2, old2); + if(old3.isValid()) dataChanged(old3, old3); + if(m_selection1Index.isValid()) dataChanged(m_selection1Index, m_selection1Index); + if(m_selection2Index.isValid()) dataChanged(m_selection2Index, m_selection2Index); + if(m_selection3Index.isValid()) dataChanged(m_selection3Index, m_selection3Index); + emit q->updateAvailabilities(); } //TODO //void DirMergeItem::init(MergeFileInfos* pMFI) //{ // pMFI->m_pDMI = this; // m_pMFI = pMFI; // TotalDiffStatus& tds = pMFI->m_totalDiffStatus; // if ( m_pMFI->dirA() || m_pMFI->dirB() || m_pMFI->dirC() ) // { // } // else // { // setText( s_UnsolvedCol, QString::number( tds.nofUnsolvedConflicts ) ); // setText( s_SolvedCol, QString::number( tds.nofSolvedConflicts ) ); // setText( s_NonWhiteCol, QString::number( tds.nofUnsolvedConflicts + tds.nofSolvedConflicts - tds.nofWhitespaceConflicts ) ); // setText( s_WhiteCol, QString::number( tds.nofWhitespaceConflicts ) ); // } // setSizeHint( s_ACol, QSize(17,17) ); // Iconsize // setSizeHint( s_BCol, QSize(17,17) ); // Iconsize // setSizeHint( s_CCol, QSize(17,17) ); // Iconsize //} class MfiCompare { - Qt::SortOrder mOrder; - - public: - MfiCompare( Qt::SortOrder order ) { + Qt::SortOrder mOrder; + + public: + MfiCompare(Qt::SortOrder order) + { mOrder = order; - } - bool operator()( MergeFileInfos* pMFI1, MergeFileInfos* pMFI2 ) - { - bool bDir1 = pMFI1->dirA() || pMFI1->dirB() || pMFI1->dirC(); - bool bDir2 = pMFI2->dirA() || pMFI2->dirB() || pMFI2->dirC(); - if( bDir1 == bDir2 ) { - if( mOrder == Qt::AscendingOrder) - { - return pMFI1->fileName().compare( pMFI2->fileName(), Qt::CaseInsensitive ) < 0; - } - else{ - return pMFI1->fileName().compare( pMFI2->fileName(), Qt::CaseInsensitive ) > 0; - } + } + bool operator()(MergeFileInfos* pMFI1, MergeFileInfos* pMFI2) + { + bool bDir1 = pMFI1->dirA() || pMFI1->dirB() || pMFI1->dirC(); + bool bDir2 = pMFI2->dirA() || pMFI2->dirB() || pMFI2->dirC(); + if(bDir1 == bDir2) { + if(mOrder == Qt::AscendingOrder) + { + return pMFI1->fileName().compare(pMFI2->fileName(), Qt::CaseInsensitive) < 0; } else - return bDir1; + { + return pMFI1->fileName().compare(pMFI2->fileName(), Qt::CaseInsensitive) > 0; + } } + else + return bDir1; + } }; -static void sortHelper( MergeFileInfos* pMFI, Qt::SortOrder order ) +static void sortHelper(MergeFileInfos* pMFI, Qt::SortOrder order) { - std::sort( pMFI->m_children.begin(), pMFI->m_children.end(), MfiCompare( order ) ); + std::sort(pMFI->m_children.begin(), pMFI->m_children.end(), MfiCompare(order)); - for( int i=0; im_children.count(); ++i ) - sortHelper( pMFI->m_children[i], order ); + for(int i = 0; i < pMFI->m_children.count(); ++i) + sortHelper(pMFI->m_children[i], order); } -void DirectoryMergeWindow::Data::sort( int column, Qt::SortOrder order ) +void DirectoryMergeWindow::Data::sort(int column, Qt::SortOrder order) { Q_UNUSED(column); beginResetModel(); - sortHelper( m_pRoot, order ); + sortHelper(m_pRoot, order); endResetModel(); } // //DirMergeItem::~DirMergeItem() //{ // m_pMFI->m_pDMI = 0; //} -void DirectoryMergeWindow::Data::setMergeOperation( const QModelIndex& mi, e_MergeOperation eMOp, bool bRecursive ) +void DirectoryMergeWindow::Data::setMergeOperation(const QModelIndex& mi, e_MergeOperation eMOp, bool bRecursive) { - MergeFileInfos* pMFI = getMFI( mi ); - if ( pMFI == 0 ) - return; + MergeFileInfos* pMFI = getMFI(mi); + if(pMFI == 0) + return; - MergeFileInfos& mfi = *pMFI; + MergeFileInfos& mfi = *pMFI; - if ( eMOp != mfi.m_eMergeOperation ) - { - mfi.m_bOperationComplete = false; - setOpStatus( mi, eOpStatusNone ); - } + if(eMOp != mfi.m_eMergeOperation) + { + mfi.m_bOperationComplete = false; + setOpStatus(mi, eOpStatusNone); + } - mfi.m_eMergeOperation = eMOp; - if ( bRecursive ) - { - e_MergeOperation eChildrenMergeOp = mfi.m_eMergeOperation; - if ( eChildrenMergeOp == eConflictingFileTypes ) eChildrenMergeOp = eMergeABCToDest; - for( int childIdx=0; childIdxcanContinue()) return; + if(!d->canContinue()) return; - if ( d->m_bRealMergeStarted ) - { - KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible")); - return; - } + if(d->m_bRealMergeStarted) + { + KMessageBox::sorry(this, i18n("This operation is currently not possible."), i18n("Operation Not Possible")); + return; + } - if ( MergeFileInfos* pMFI = d->getMFI(currentIndex()) ) - { - if ( !(pMFI->dirA() || pMFI->dirB() || pMFI->dirC()) ) - { - emit startDiffMerge( - pMFI->existsInA() ? pMFI->m_pFileInfoA->absoluteFilePath() : QString(""), - pMFI->existsInB() ? pMFI->m_pFileInfoB->absoluteFilePath() : QString(""), - pMFI->existsInC() ? pMFI->m_pFileInfoC->absoluteFilePath() : QString(""), - "", - "","","",0 - ); - } - } - emit updateAvailabilities(); + if(MergeFileInfos* pMFI = d->getMFI(currentIndex())) + { + if(!(pMFI->dirA() || pMFI->dirB() || pMFI->dirC())) + { + emit startDiffMerge( + pMFI->existsInA() ? pMFI->m_pFileInfoA->absoluteFilePath() : QString(""), + pMFI->existsInB() ? pMFI->m_pFileInfoB->absoluteFilePath() : QString(""), + pMFI->existsInC() ? pMFI->m_pFileInfoC->absoluteFilePath() : QString(""), + "", + "", "", "", 0); + } + } + emit updateAvailabilities(); } - void DirectoryMergeWindow::slotCompareExplicitlySelectedFiles() { - if ( ! d->isDir(d->m_selection1Index) && !d->canContinue() ) return; + if(!d->isDir(d->m_selection1Index) && !d->canContinue()) return; - if ( d->m_bRealMergeStarted ) - { - KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible")); - return; - } + if(d->m_bRealMergeStarted) + { + KMessageBox::sorry(this, i18n("This operation is currently not possible."), i18n("Operation Not Possible")); + return; + } - emit startDiffMerge( - d->getFileName( d->m_selection1Index ), - d->getFileName( d->m_selection2Index ), - d->getFileName( d->m_selection3Index ), - "", - "","","",0 - ); - d->m_selection1Index=QModelIndex(); - d->m_selection2Index=QModelIndex(); - d->m_selection3Index=QModelIndex(); + emit startDiffMerge( + d->getFileName(d->m_selection1Index), + d->getFileName(d->m_selection2Index), + d->getFileName(d->m_selection3Index), + "", + "", "", "", 0); + d->m_selection1Index = QModelIndex(); + d->m_selection2Index = QModelIndex(); + d->m_selection3Index = QModelIndex(); - emit updateAvailabilities(); - update(); + emit updateAvailabilities(); + update(); } void DirectoryMergeWindow::slotMergeExplicitlySelectedFiles() { - if ( ! d->isDir(d->m_selection1Index) && !d->canContinue() ) return; + if(!d->isDir(d->m_selection1Index) && !d->canContinue()) return; - if ( d->m_bRealMergeStarted ) - { - KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible")); - return; - } + if(d->m_bRealMergeStarted) + { + KMessageBox::sorry(this, i18n("This operation is currently not possible."), i18n("Operation Not Possible")); + return; + } - QString fn1 = d->getFileName( d->m_selection1Index ); - QString fn2 = d->getFileName( d->m_selection2Index ); - QString fn3 = d->getFileName( d->m_selection3Index ); + QString fn1 = d->getFileName(d->m_selection1Index); + QString fn2 = d->getFileName(d->m_selection2Index); + QString fn3 = d->getFileName(d->m_selection3Index); - emit startDiffMerge( fn1, fn2, fn3, - fn3.isEmpty() ? fn2 : fn3, - "","","",0 - ); - d->m_selection1Index=QModelIndex(); - d->m_selection2Index=QModelIndex(); - d->m_selection3Index=QModelIndex(); + emit startDiffMerge(fn1, fn2, fn3, + fn3.isEmpty() ? fn2 : fn3, + "", "", "", 0); + d->m_selection1Index = QModelIndex(); + d->m_selection2Index = QModelIndex(); + d->m_selection3Index = QModelIndex(); - emit updateAvailabilities(); - update(); + emit updateAvailabilities(); + update(); } bool DirectoryMergeWindow::isFileSelected() { - if ( MergeFileInfos* pMFI = d->getMFI(currentIndex()) ) - { - return ! (pMFI->dirA() || pMFI->dirB() || pMFI->dirC() || conflictingFileTypes(*pMFI) ); - } - return false; + if(MergeFileInfos* pMFI = d->getMFI(currentIndex())) + { + return !(pMFI->dirA() || pMFI->dirB() || pMFI->dirC() || conflictingFileTypes(*pMFI)); + } + return false; } void DirectoryMergeWindow::mergeResultSaved(const QString& fileName) { - QModelIndex mi = (d->m_mergeItemList.empty() || d->m_currentIndexForOperation==d->m_mergeItemList.end() ) - ? QModelIndex() - : *d->m_currentIndexForOperation; - - MergeFileInfos* pMFI = d->getMFI(mi); - if ( pMFI==0 ) - { - // This can happen if the same file is saved and modified and saved again. Nothing to do then. - return; - } - if ( fileName == d->fullNameDest(*pMFI) ) - { - MergeFileInfos& mfi = *pMFI; - if ( mfi.m_eMergeOperation==eMergeToAB ) - { - bool bSuccess = d->copyFLD( d->fullNameB(mfi), d->fullNameA(mfi) ); - if (!bSuccess) - { - KMessageBox::error(this, i18n("An error occurred while copying.\n"), i18n("Error") ); - d->m_pStatusInfo->setWindowTitle(i18n("Merge Error")); - d->m_pStatusInfo->exec(); - //if ( m_pStatusInfo->firstChild()!=0 ) - // m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() ); - d->m_bError = true; - d->setOpStatus( mi, eOpStatusError ); - mfi.m_eMergeOperation = eCopyBToA; - return; - } - } - d->setOpStatus( mi, eOpStatusDone ); - pMFI->m_bOperationComplete = true; - if ( d->m_mergeItemList.size()==1 ) - { - d->m_mergeItemList.clear(); - d->m_bRealMergeStarted=false; - } - } + QModelIndex mi = (d->m_mergeItemList.empty() || d->m_currentIndexForOperation == d->m_mergeItemList.end()) + ? QModelIndex() + : *d->m_currentIndexForOperation; + + MergeFileInfos* pMFI = d->getMFI(mi); + if(pMFI == 0) + { + // This can happen if the same file is saved and modified and saved again. Nothing to do then. + return; + } + if(fileName == d->fullNameDest(*pMFI)) + { + MergeFileInfos& mfi = *pMFI; + if(mfi.m_eMergeOperation == eMergeToAB) + { + bool bSuccess = d->copyFLD(d->fullNameB(mfi), d->fullNameA(mfi)); + if(!bSuccess) + { + KMessageBox::error(this, i18n("An error occurred while copying.\n"), i18n("Error")); + d->m_pStatusInfo->setWindowTitle(i18n("Merge Error")); + d->m_pStatusInfo->exec(); + //if ( m_pStatusInfo->firstChild()!=0 ) + // m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() ); + d->m_bError = true; + d->setOpStatus(mi, eOpStatusError); + mfi.m_eMergeOperation = eCopyBToA; + return; + } + } + d->setOpStatus(mi, eOpStatusDone); + pMFI->m_bOperationComplete = true; + if(d->m_mergeItemList.size() == 1) + { + d->m_mergeItemList.clear(); + d->m_bRealMergeStarted = false; + } + } - emit updateAvailabilities(); + emit updateAvailabilities(); } bool DirectoryMergeWindow::Data::canContinue() { - bool bCanContinue=false; - q->checkIfCanContinue( &bCanContinue ); - if ( bCanContinue && !m_bError ) - { - QModelIndex mi = (m_mergeItemList.empty() || m_currentIndexForOperation==m_mergeItemList.end() ) ? QModelIndex() : *m_currentIndexForOperation; - MergeFileInfos* pMFI = getMFI(mi); - if ( pMFI && ! pMFI->m_bOperationComplete ) - { - setOpStatus( mi, eOpStatusNotSaved ); - pMFI->m_bOperationComplete = true; - if ( m_mergeItemList.size()==1 ) - { - m_mergeItemList.clear(); - m_bRealMergeStarted=false; - } - } - } - return bCanContinue; -} - -bool DirectoryMergeWindow::Data::executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge ) -{ - bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles; - // First decide destname - QString destName; - switch( mfi.m_eMergeOperation ) - { - case eNoOperation: break; - case eDeleteAB: break; - case eMergeToAB: // let the user save in B. In mergeResultSaved() the file will be copied to A. - case eMergeToB: - case eDeleteB: - case eCopyAToB: destName = fullNameB(mfi); break; - case eMergeToA: - case eDeleteA: - case eCopyBToA: destName = fullNameA(mfi); break; - case eMergeABToDest: - case eMergeABCToDest: - case eCopyAToDest: - case eCopyBToDest: - case eCopyCToDest: - case eDeleteFromDest: destName = fullNameDest(mfi); break; - default: - KMessageBox::error( q, i18n("Unknown merge operation. (This must never happen!)"), i18n("Error") ); - assert(false); - } - - bool bSuccess = false; - bSingleFileMerge = false; - switch( mfi.m_eMergeOperation ) - { - case eNoOperation: bSuccess = true; break; - case eCopyAToDest: - case eCopyAToB: bSuccess = copyFLD( fullNameA(mfi), destName ); break; - case eCopyBToDest: - case eCopyBToA: bSuccess = copyFLD( fullNameB(mfi), destName ); break; - case eCopyCToDest: bSuccess = copyFLD( fullNameC(mfi), destName ); break; - case eDeleteFromDest: - case eDeleteA: - case eDeleteB: bSuccess = deleteFLD( destName, bCreateBackups ); break; - case eDeleteAB: bSuccess = deleteFLD( fullNameA(mfi), bCreateBackups ) && - deleteFLD( fullNameB(mfi), bCreateBackups ); break; - case eMergeABToDest: - case eMergeToA: - case eMergeToAB: - case eMergeToB: bSuccess = mergeFLD( fullNameA(mfi), fullNameB(mfi), "", - destName, bSingleFileMerge ); - break; - case eMergeABCToDest:bSuccess = mergeFLD( - mfi.existsInA() ? fullNameA(mfi) : QString(""), - mfi.existsInB() ? fullNameB(mfi) : QString(""), - mfi.existsInC() ? fullNameC(mfi) : QString(""), - destName, bSingleFileMerge ); - break; - default: - KMessageBox::error( q, i18n("Unknown merge operation."), i18n("Error") ); - assert(false); - } - - return bSuccess; + bool bCanContinue = false; + q->checkIfCanContinue(&bCanContinue); + if(bCanContinue && !m_bError) + { + QModelIndex mi = (m_mergeItemList.empty() || m_currentIndexForOperation == m_mergeItemList.end()) ? QModelIndex() : *m_currentIndexForOperation; + MergeFileInfos* pMFI = getMFI(mi); + if(pMFI && !pMFI->m_bOperationComplete) + { + setOpStatus(mi, eOpStatusNotSaved); + pMFI->m_bOperationComplete = true; + if(m_mergeItemList.size() == 1) + { + m_mergeItemList.clear(); + m_bRealMergeStarted = false; + } + } + } + return bCanContinue; +} + +bool DirectoryMergeWindow::Data::executeMergeOperation(MergeFileInfos& mfi, bool& bSingleFileMerge) +{ + bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles; + // First decide destname + QString destName; + switch(mfi.m_eMergeOperation) + { + case eNoOperation: + break; + case eDeleteAB: + break; + case eMergeToAB: // let the user save in B. In mergeResultSaved() the file will be copied to A. + case eMergeToB: + case eDeleteB: + case eCopyAToB: + destName = fullNameB(mfi); + break; + case eMergeToA: + case eDeleteA: + case eCopyBToA: + destName = fullNameA(mfi); + break; + case eMergeABToDest: + case eMergeABCToDest: + case eCopyAToDest: + case eCopyBToDest: + case eCopyCToDest: + case eDeleteFromDest: + destName = fullNameDest(mfi); + break; + default: + KMessageBox::error(q, i18n("Unknown merge operation. (This must never happen!)"), i18n("Error")); + assert(false); + } + + bool bSuccess = false; + bSingleFileMerge = false; + switch(mfi.m_eMergeOperation) + { + case eNoOperation: + bSuccess = true; + break; + case eCopyAToDest: + case eCopyAToB: + bSuccess = copyFLD(fullNameA(mfi), destName); + break; + case eCopyBToDest: + case eCopyBToA: + bSuccess = copyFLD(fullNameB(mfi), destName); + break; + case eCopyCToDest: + bSuccess = copyFLD(fullNameC(mfi), destName); + break; + case eDeleteFromDest: + case eDeleteA: + case eDeleteB: + bSuccess = deleteFLD(destName, bCreateBackups); + break; + case eDeleteAB: + bSuccess = deleteFLD(fullNameA(mfi), bCreateBackups) && + deleteFLD(fullNameB(mfi), bCreateBackups); + break; + case eMergeABToDest: + case eMergeToA: + case eMergeToAB: + case eMergeToB: + bSuccess = mergeFLD(fullNameA(mfi), fullNameB(mfi), "", + destName, bSingleFileMerge); + break; + case eMergeABCToDest: + bSuccess = mergeFLD( + mfi.existsInA() ? fullNameA(mfi) : QString(""), + mfi.existsInB() ? fullNameB(mfi) : QString(""), + mfi.existsInC() ? fullNameC(mfi) : QString(""), + destName, bSingleFileMerge); + break; + default: + KMessageBox::error(q, i18n("Unknown merge operation."), i18n("Error")); + assert(false); + } + + return bSuccess; } - // Check if the merge can start, and prepare the m_mergeItemList which then contains all // items that must be merged. -void DirectoryMergeWindow::Data::prepareMergeStart( const QModelIndex& miBegin, const QModelIndex& miEnd, bool bVerbose ) -{ - if ( bVerbose ) - { - int status = KMessageBox::warningYesNoCancel(q, - i18n("The merge is about to begin.\n\n" - "Choose \"Do it\" if you have read the instructions and know what you are doing.\n" - "Choosing \"Simulate it\" will tell you what would happen.\n\n" - "Be aware that this program still has beta status " - "and there is NO WARRANTY whatsoever! Make backups of your vital data!"), - i18n("Starting Merge"), - KGuiItem( i18n("Do It") ), - KGuiItem( i18n("Simulate It") ) ); - if (status==KMessageBox::Yes) m_bRealMergeStarted = true; - else if (status==KMessageBox::No ) m_bSimulatedMergeStarted = true; - else return; - } - else - { - m_bRealMergeStarted = true; - } - - m_mergeItemList.clear(); - if ( !miBegin.isValid() ) - return; - - for( QModelIndex mi = miBegin; mi!=miEnd; mi = treeIterator( mi ) ) - { - MergeFileInfos* pMFI = getMFI( mi ); - if ( pMFI && ! pMFI->m_bOperationComplete ) - { - m_mergeItemList.push_back(mi); - QString errorText; - if (pMFI->m_eMergeOperation == eConflictingFileTypes ) - { - errorText = i18n("The highlighted item has a different type in the different directories. Select what to do."); - } - if (pMFI->m_eMergeOperation == eConflictingAges ) - { - errorText = i18n("The modification dates of the file are equal but the files are not. Select what to do."); - } - if (pMFI->m_eMergeOperation == eChangedAndDeleted ) - { - errorText = i18n("The highlighted item was changed in one directory and deleted in the other. Select what to do."); - } - if ( !errorText.isEmpty() ) - { - q->scrollTo( mi, QAbstractItemView::EnsureVisible ); - q->setCurrentIndex( mi ); - KMessageBox::error(q, errorText, i18n("Error")); - m_mergeItemList.clear(); - m_bRealMergeStarted=false; +void DirectoryMergeWindow::Data::prepareMergeStart(const QModelIndex& miBegin, const QModelIndex& miEnd, bool bVerbose) +{ + if(bVerbose) + { + int status = KMessageBox::warningYesNoCancel(q, + i18n("The merge is about to begin.\n\n" + "Choose \"Do it\" if you have read the instructions and know what you are doing.\n" + "Choosing \"Simulate it\" will tell you what would happen.\n\n" + "Be aware that this program still has beta status " + "and there is NO WARRANTY whatsoever! Make backups of your vital data!"), + i18n("Starting Merge"), + KGuiItem(i18n("Do It")), + KGuiItem(i18n("Simulate It"))); + if(status == KMessageBox::Yes) + m_bRealMergeStarted = true; + else if(status == KMessageBox::No) + m_bSimulatedMergeStarted = true; + else return; - } - } - } + } + else + { + m_bRealMergeStarted = true; + } + + m_mergeItemList.clear(); + if(!miBegin.isValid()) + return; + + for(QModelIndex mi = miBegin; mi != miEnd; mi = treeIterator(mi)) + { + MergeFileInfos* pMFI = getMFI(mi); + if(pMFI && !pMFI->m_bOperationComplete) + { + m_mergeItemList.push_back(mi); + QString errorText; + if(pMFI->m_eMergeOperation == eConflictingFileTypes) + { + errorText = i18n("The highlighted item has a different type in the different directories. Select what to do."); + } + if(pMFI->m_eMergeOperation == eConflictingAges) + { + errorText = i18n("The modification dates of the file are equal but the files are not. Select what to do."); + } + if(pMFI->m_eMergeOperation == eChangedAndDeleted) + { + errorText = i18n("The highlighted item was changed in one directory and deleted in the other. Select what to do."); + } + if(!errorText.isEmpty()) + { + q->scrollTo(mi, QAbstractItemView::EnsureVisible); + q->setCurrentIndex(mi); + KMessageBox::error(q, errorText, i18n("Error")); + m_mergeItemList.clear(); + m_bRealMergeStarted = false; + return; + } + } + } - m_currentIndexForOperation = m_mergeItemList.begin(); - return; + m_currentIndexForOperation = m_mergeItemList.begin(); + return; } void DirectoryMergeWindow::slotRunOperationForCurrentItem() { - if ( ! d->canContinue() ) return; + if(!d->canContinue()) return; - bool bVerbose = false; - if ( d->m_mergeItemList.empty() ) - { - QModelIndex miBegin = currentIndex(); - QModelIndex miEnd = d->treeIterator(miBegin,false,false); // find next visible sibling (no children) + bool bVerbose = false; + if(d->m_mergeItemList.empty()) + { + QModelIndex miBegin = currentIndex(); + QModelIndex miEnd = d->treeIterator(miBegin, false, false); // find next visible sibling (no children) - d->prepareMergeStart( miBegin, miEnd, bVerbose ); - d->mergeContinue(true, bVerbose); - } - else - d->mergeContinue(false, bVerbose); + d->prepareMergeStart(miBegin, miEnd, bVerbose); + d->mergeContinue(true, bVerbose); + } + else + d->mergeContinue(false, bVerbose); } void DirectoryMergeWindow::slotRunOperationForAllItems() { - if ( ! d->canContinue() ) return; + if(!d->canContinue()) return; - bool bVerbose = true; - if ( d->m_mergeItemList.empty() ) - { - QModelIndex miBegin = d->rowCount()>0 ? d->index(0,0,QModelIndex()) : QModelIndex(); + bool bVerbose = true; + if(d->m_mergeItemList.empty()) + { + QModelIndex miBegin = d->rowCount() > 0 ? d->index(0, 0, QModelIndex()) : QModelIndex(); - d->prepareMergeStart( miBegin, QModelIndex(), bVerbose ); - d->mergeContinue(true, bVerbose); - } - else - d->mergeContinue(false, bVerbose); + d->prepareMergeStart(miBegin, QModelIndex(), bVerbose); + d->mergeContinue(true, bVerbose); + } + else + d->mergeContinue(false, bVerbose); } void DirectoryMergeWindow::mergeCurrentFile() { - if (!d->canContinue()) return; - - if ( d->m_bRealMergeStarted ) - { - KMessageBox::sorry(this,i18n("This operation is currently not possible because directory merge is currently running."),i18n("Operation Not Possible")); - return; - } - - if ( isFileSelected() ) - { - MergeFileInfos* pMFI = d->getMFI( currentIndex() ); - if ( pMFI != 0 ) - { - MergeFileInfos& mfi = *pMFI; - d->m_mergeItemList.clear(); - d->m_mergeItemList.push_back( currentIndex() ); - d->m_currentIndexForOperation = d->m_mergeItemList.begin(); - bool bDummy=false; - d->mergeFLD( - mfi.existsInA() ? mfi.m_pFileInfoA->absoluteFilePath() : QString(""), - mfi.existsInB() ? mfi.m_pFileInfoB->absoluteFilePath() : QString(""), - mfi.existsInC() ? mfi.m_pFileInfoC->absoluteFilePath() : QString(""), - d->fullNameDest(mfi), - bDummy - ); - } - } - emit updateAvailabilities(); -} + if(!d->canContinue()) return; + if(d->m_bRealMergeStarted) + { + KMessageBox::sorry(this, i18n("This operation is currently not possible because directory merge is currently running."), i18n("Operation Not Possible")); + return; + } + + if(isFileSelected()) + { + MergeFileInfos* pMFI = d->getMFI(currentIndex()); + if(pMFI != 0) + { + MergeFileInfos& mfi = *pMFI; + d->m_mergeItemList.clear(); + d->m_mergeItemList.push_back(currentIndex()); + d->m_currentIndexForOperation = d->m_mergeItemList.begin(); + bool bDummy = false; + d->mergeFLD( + mfi.existsInA() ? mfi.m_pFileInfoA->absoluteFilePath() : QString(""), + mfi.existsInB() ? mfi.m_pFileInfoB->absoluteFilePath() : QString(""), + mfi.existsInC() ? mfi.m_pFileInfoC->absoluteFilePath() : QString(""), + d->fullNameDest(mfi), + bDummy); + } + } + emit updateAvailabilities(); +} // When bStart is true then m_currentIndexForOperation must still be processed. // When bVerbose is true then a messagebox will tell when the merge is complete. void DirectoryMergeWindow::Data::mergeContinue(bool bStart, bool bVerbose) { - ProgressProxy pp; - if ( m_mergeItemList.empty() ) - return; - - int nrOfItems = 0; - int nrOfCompletedItems = 0; - int nrOfCompletedSimItems = 0; - - // Count the number of completed items (for the progress bar). - for( MergeItemList::iterator i = m_mergeItemList.begin(); i!=m_mergeItemList.end(); ++i ) - { - MergeFileInfos* pMFI = getMFI( *i ); - ++nrOfItems; - if ( pMFI->m_bOperationComplete ) - ++nrOfCompletedItems; - if ( pMFI->m_bSimOpComplete ) - ++nrOfCompletedSimItems; - } - - m_pStatusInfo->hide(); - m_pStatusInfo->clear(); - - QModelIndex miCurrent = m_currentIndexForOperation==m_mergeItemList.end() ? QModelIndex() : *m_currentIndexForOperation; - - bool bContinueWithCurrentItem = bStart; // true for first item, else false - bool bSkipItem = false; - if ( !bStart && m_bError && miCurrent.isValid() ) - { - int status = KMessageBox::warningYesNoCancel(q, - i18n("There was an error in the last step.\n" - "Do you want to continue with the item that caused the error or do you want to skip this item?"), - i18n("Continue merge after an error"), - KGuiItem( i18n("Continue With Last Item") ), - KGuiItem( i18n("Skip Item") ) ); - if (status==KMessageBox::Yes) bContinueWithCurrentItem = true; - else if (status==KMessageBox::No ) bSkipItem = true; - else return; - m_bError = false; - } - - pp.setMaxNofSteps( nrOfItems ); - - bool bSuccess = true; - bool bSingleFileMerge = false; - bool bSim = m_bSimulatedMergeStarted; - while( bSuccess ) - { - MergeFileInfos* pMFI = getMFI(miCurrent); - if ( pMFI==0 ) - { - m_mergeItemList.clear(); - m_bRealMergeStarted=false; - break; - } - - if ( pMFI!=0 && !bContinueWithCurrentItem ) - { - if ( bSim ) - { - if( rowCount(miCurrent)==0 ) + ProgressProxy pp; + if(m_mergeItemList.empty()) + return; + + int nrOfItems = 0; + int nrOfCompletedItems = 0; + int nrOfCompletedSimItems = 0; + + // Count the number of completed items (for the progress bar). + for(MergeItemList::iterator i = m_mergeItemList.begin(); i != m_mergeItemList.end(); ++i) + { + MergeFileInfos* pMFI = getMFI(*i); + ++nrOfItems; + if(pMFI->m_bOperationComplete) + ++nrOfCompletedItems; + if(pMFI->m_bSimOpComplete) + ++nrOfCompletedSimItems; + } + + m_pStatusInfo->hide(); + m_pStatusInfo->clear(); + + QModelIndex miCurrent = m_currentIndexForOperation == m_mergeItemList.end() ? QModelIndex() : *m_currentIndexForOperation; + + bool bContinueWithCurrentItem = bStart; // true for first item, else false + bool bSkipItem = false; + if(!bStart && m_bError && miCurrent.isValid()) + { + int status = KMessageBox::warningYesNoCancel(q, + i18n("There was an error in the last step.\n" + "Do you want to continue with the item that caused the error or do you want to skip this item?"), + i18n("Continue merge after an error"), + KGuiItem(i18n("Continue With Last Item")), + KGuiItem(i18n("Skip Item"))); + if(status == KMessageBox::Yes) + bContinueWithCurrentItem = true; + else if(status == KMessageBox::No) + bSkipItem = true; + else + return; + m_bError = false; + } + + pp.setMaxNofSteps(nrOfItems); + + bool bSuccess = true; + bool bSingleFileMerge = false; + bool bSim = m_bSimulatedMergeStarted; + while(bSuccess) + { + MergeFileInfos* pMFI = getMFI(miCurrent); + if(pMFI == 0) + { + m_mergeItemList.clear(); + m_bRealMergeStarted = false; + break; + } + + if(pMFI != 0 && !bContinueWithCurrentItem) + { + if(bSim) { - pMFI->m_bSimOpComplete = true; + if(rowCount(miCurrent) == 0) + { + pMFI->m_bSimOpComplete = true; + } } - } - else - { - if( rowCount( miCurrent )==0 ) + else { - if( !pMFI->m_bOperationComplete ) - { - setOpStatus( miCurrent, bSkipItem ? eOpStatusSkipped : eOpStatusDone ); - pMFI->m_bOperationComplete = true; - bSkipItem = false; - } + if(rowCount(miCurrent) == 0) + { + if(!pMFI->m_bOperationComplete) + { + setOpStatus(miCurrent, bSkipItem ? eOpStatusSkipped : eOpStatusDone); + pMFI->m_bOperationComplete = true; + bSkipItem = false; + } + } + else + { + setOpStatus(miCurrent, eOpStatusInProgress); + } } - else + } + + if(!bContinueWithCurrentItem) + { + // Depth first + QModelIndex miPrev = miCurrent; + ++m_currentIndexForOperation; + miCurrent = m_currentIndexForOperation == m_mergeItemList.end() ? QModelIndex() : *m_currentIndexForOperation; + if((!miCurrent.isValid() || miCurrent.parent() != miPrev.parent()) && miPrev.parent().isValid()) { - setOpStatus( miCurrent, eOpStatusInProgress ); - } - } - } - - if ( ! bContinueWithCurrentItem ) - { - // Depth first - QModelIndex miPrev = miCurrent; - ++m_currentIndexForOperation; - miCurrent = m_currentIndexForOperation==m_mergeItemList.end() ? QModelIndex() : *m_currentIndexForOperation; - if ( (!miCurrent.isValid() || miCurrent.parent()!=miPrev.parent()) && miPrev.parent().isValid() ) - { - // Check if the parent may be set to "Done" - QModelIndex miParent = miPrev.parent(); - bool bDone = true; - while ( bDone && miParent.isValid() ) + // Check if the parent may be set to "Done" + QModelIndex miParent = miPrev.parent(); + bool bDone = true; + while(bDone && miParent.isValid()) + { + for(int childIdx = 0; childIdx < rowCount(miParent); ++childIdx) + { + MergeFileInfos* pMFI = getMFI(index(childIdx, 0, miParent)); + if((!bSim && !pMFI->m_bOperationComplete) || (bSim && pMFI->m_bSimOpComplete)) + { + bDone = false; + break; + } + } + if(bDone) + { + MergeFileInfos* pMFI = getMFI(miParent); + if(bSim) + pMFI->m_bSimOpComplete = bDone; + else + { + setOpStatus(miParent, eOpStatusDone); + pMFI->m_bOperationComplete = bDone; + } + } + miParent = miParent.parent(); + } + } + } + + if(!miCurrent.isValid()) // end? + { + if(m_bRealMergeStarted) { - for( int childIdx = 0; childIdxm_bOperationComplete) || (bSim && pMFI->m_bSimOpComplete) ) - { - bDone=false; - break; - } - } - if ( bDone ) - { - MergeFileInfos* pMFI = getMFI(miParent); - if (bSim) - pMFI->m_bSimOpComplete = bDone; - else - { - setOpStatus( miParent, eOpStatusDone ); - pMFI->m_bOperationComplete = bDone; - } - } - miParent = miParent.parent(); - } - } - } - - if ( !miCurrent.isValid() ) // end? - { - if ( m_bRealMergeStarted ) - { - if (bVerbose) + if(bVerbose) + { + KMessageBox::information(q, i18n("Merge operation complete."), i18n("Merge Complete")); + } + m_bRealMergeStarted = false; + m_pStatusInfo->setWindowTitle(i18n("Merge Complete")); + } + if(m_bSimulatedMergeStarted) { - KMessageBox::information( q, i18n("Merge operation complete."), i18n("Merge Complete") ); + m_bSimulatedMergeStarted = false; + QModelIndex mi = rowCount() > 0 ? index(0, 0, QModelIndex()) : QModelIndex(); + for(; mi.isValid(); mi = treeIterator(mi)) + { + getMFI(mi)->m_bSimOpComplete = false; + } + m_pStatusInfo->setWindowTitle(i18n("Simulated merge complete: Check if you agree with the proposed operations.")); + m_pStatusInfo->exec(); } + m_mergeItemList.clear(); m_bRealMergeStarted = false; - m_pStatusInfo->setWindowTitle(i18n("Merge Complete")); - } - if ( m_bSimulatedMergeStarted ) - { - m_bSimulatedMergeStarted = false; - QModelIndex mi = rowCount()>0 ? index(0,0,QModelIndex()) : QModelIndex(); - for( ; mi.isValid(); mi=treeIterator(mi) ) + return; + } + + MergeFileInfos& mfi = *getMFI(miCurrent); + + pp.setInformation(mfi.subPath(), + bSim ? nrOfCompletedSimItems : nrOfCompletedItems, + false // bRedrawUpdate + ); + + bSuccess = executeMergeOperation(mfi, bSingleFileMerge); // Here the real operation happens. + + if(bSuccess) + { + if(bSim) + ++nrOfCompletedSimItems; + else + ++nrOfCompletedItems; + bContinueWithCurrentItem = false; + } + + if(pp.wasCancelled()) + break; + } // end while + + //g_pProgressDialog->hide(); + + q->setCurrentIndex(miCurrent); + q->scrollTo(miCurrent, EnsureVisible); + if(!bSuccess && !bSingleFileMerge) + { + KMessageBox::error(q, i18n("An error occurred. Press OK to see detailed information.\n"), i18n("Error")); + m_pStatusInfo->setWindowTitle(i18n("Merge Error")); + m_pStatusInfo->exec(); + //if ( m_pStatusInfo->firstChild()!=0 ) + // m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() ); + m_bError = true; + + setOpStatus(miCurrent, eOpStatusError); + } + else + { + m_bError = false; + } + emit q->updateAvailabilities(); + + if(m_currentIndexForOperation == m_mergeItemList.end()) + { + m_mergeItemList.clear(); + m_bRealMergeStarted = false; + } +} + +bool DirectoryMergeWindow::Data::deleteFLD(const QString& name, bool bCreateBackup) +{ + FileAccess fi(name, true); + if(!fi.exists()) + return true; + + if(bCreateBackup) + { + bool bSuccess = renameFLD(name, name + ".orig"); + if(!bSuccess) + { + m_pStatusInfo->addText(i18n("Error: While deleting %1: Creating backup failed.", name)); + return false; + } + } + else + { + if(fi.isDir() && !fi.isSymLink()) + m_pStatusInfo->addText(i18n("delete directory recursively( %1 )", name)); + else + m_pStatusInfo->addText(i18n("delete( %1 )", name)); + + if(m_bSimulatedMergeStarted) + { + return true; + } + + if(fi.isDir() && !fi.isSymLink()) // recursive directory delete only for real dirs, not symlinks + { + t_DirectoryList dirList; + bool bSuccess = fi.listDir(&dirList, false, true, "*", "", "", false, false); // not recursive, find hidden files + + if(!bSuccess) + { + // No Permission to read directory or other error. + m_pStatusInfo->addText(i18n("Error: delete dir operation failed while trying to read the directory.")); + return false; + } + + t_DirectoryList::iterator it; // create list iterator + + for(it = dirList.begin(); it != dirList.end(); ++it) // for each file... { - getMFI( mi )->m_bSimOpComplete = false; - } - m_pStatusInfo->setWindowTitle(i18n("Simulated merge complete: Check if you agree with the proposed operations.")); - m_pStatusInfo->exec(); - } - m_mergeItemList.clear(); - m_bRealMergeStarted=false; - return; - } - - MergeFileInfos& mfi = *getMFI(miCurrent); - - pp.setInformation( mfi.subPath(), - bSim ? nrOfCompletedSimItems : nrOfCompletedItems, - false // bRedrawUpdate - ); - - bSuccess = executeMergeOperation( mfi, bSingleFileMerge ); // Here the real operation happens. - - if ( bSuccess ) - { - if(bSim) ++nrOfCompletedSimItems; - else ++nrOfCompletedItems; - bContinueWithCurrentItem = false; - } - - if( pp.wasCancelled() ) - break; - } // end while - - //g_pProgressDialog->hide(); - - q->setCurrentIndex( miCurrent ); - q->scrollTo( miCurrent, EnsureVisible ); - if ( !bSuccess && !bSingleFileMerge ) - { - KMessageBox::error(q, i18n("An error occurred. Press OK to see detailed information.\n"), i18n("Error") ); - m_pStatusInfo->setWindowTitle(i18n("Merge Error")); - m_pStatusInfo->exec(); - //if ( m_pStatusInfo->firstChild()!=0 ) - // m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() ); - m_bError = true; - - setOpStatus( miCurrent, eOpStatusError ); - } - else - { - m_bError = false; - } - emit q->updateAvailabilities(); - - if ( m_currentIndexForOperation==m_mergeItemList.end() ) - { - m_mergeItemList.clear(); - m_bRealMergeStarted=false; - } -} - -bool DirectoryMergeWindow::Data::deleteFLD( const QString& name, bool bCreateBackup ) -{ - FileAccess fi(name, true); - if ( !fi.exists() ) - return true; - - if ( bCreateBackup ) - { - bool bSuccess = renameFLD( name, name+".orig" ); - if (!bSuccess) - { - m_pStatusInfo->addText( i18n("Error: While deleting %1: Creating backup failed.",name) ); - return false; - } - } - else - { - if ( fi.isDir() && !fi.isSymLink() ) - m_pStatusInfo->addText(i18n("delete directory recursively( %1 )",name)); - else - m_pStatusInfo->addText(i18n("delete( %1 )",name)); - - if ( m_bSimulatedMergeStarted ) - { - return true; - } - - if ( fi.isDir() && !fi.isSymLink() )// recursive directory delete only for real dirs, not symlinks - { - t_DirectoryList dirList; - bool bSuccess = fi.listDir( &dirList, false, true, "*", "", "", false, false ); // not recursive, find hidden files - - if ( !bSuccess ) - { - // No Permission to read directory or other error. - m_pStatusInfo->addText( i18n("Error: delete dir operation failed while trying to read the directory.") ); - return false; - } - - t_DirectoryList::iterator it; // create list iterator - - for ( it=dirList.begin(); it!=dirList.end(); ++it ) // for each file... - { - FileAccess& fi2 = *it; - if ( fi2.fileName() == "." || fi2.fileName()==".." ) - continue; - bSuccess = deleteFLD( fi2.absoluteFilePath(), false ); - if (!bSuccess) break; - } - if (bSuccess) - { - bSuccess = FileAccess::removeDir( name ); - if ( !bSuccess ) + FileAccess& fi2 = *it; + if(fi2.fileName() == "." || fi2.fileName() == "..") + continue; + bSuccess = deleteFLD(fi2.absoluteFilePath(), false); + if(!bSuccess) break; + } + if(bSuccess) { - m_pStatusInfo->addText( i18n("Error: rmdir( %1 ) operation failed.",name)); - return false; - } - } - } - else - { - bool bSuccess = FileAccess::removeFile( name ); - if ( !bSuccess ) - { - m_pStatusInfo->addText( i18n("Error: delete operation failed.") ); + bSuccess = FileAccess::removeDir(name); + if(!bSuccess) + { + m_pStatusInfo->addText(i18n("Error: rmdir( %1 ) operation failed.", name)); + return false; + } + } + } + else + { + bool bSuccess = FileAccess::removeFile(name); + if(!bSuccess) + { + m_pStatusInfo->addText(i18n("Error: delete operation failed.")); + return false; + } + } + } + return true; +} + +bool DirectoryMergeWindow::Data::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.lastIndexOf('/'); + if(pos > 0) + { + QString parentName = nameDest.left(pos); + bool bSuccess = makeDir(parentName, true /*quiet*/); + if(!bSuccess) return false; - } - } - } - return true; -} - -bool DirectoryMergeWindow::Data::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.lastIndexOf('/'); - if ( pos>0 ) - { - QString parentName = nameDest.left(pos); - bool bSuccess = makeDir(parentName, true /*quiet*/); - if (!bSuccess) - return false; - } - - m_pStatusInfo->addText(i18n("manual merge( %1, %2, %3 -> %4)",nameA,nameB,nameC,nameDest)); - if ( m_bSimulatedMergeStarted ) - { - m_pStatusInfo->addText(i18n(" Note: After a manual merge the user should continue by pressing F7.") ); - return true; - } - - bSingleFileMerge = true; - setOpStatus(*m_currentIndexForOperation, eOpStatusInProgress ); - q->scrollTo( *m_currentIndexForOperation, EnsureVisible ); - - emit q->startDiffMerge( nameA, nameB, nameC, nameDest, "","","",0 ); - - return false; -} - -bool DirectoryMergeWindow::Data::copyFLD( const QString& srcName, const QString& destName ) -{ - if ( srcName == destName ) - return true; - - FileAccess fi( srcName ); - FileAccess faDest(destName, true); - if ( faDest.exists() && !( fi.isDir() && faDest.isDir() && (fi.isSymLink()==faDest.isSymLink())) ) - { - bool bSuccess = deleteFLD( destName, m_pOptions->m_bDmCreateBakFiles ); - if ( !bSuccess ) - { - m_pStatusInfo->addText(i18n("Error: copy( %1 -> %2 ) failed." - "Deleting existing destination failed.",srcName,destName)); - return false; - } - } - - - if ( fi.isSymLink() && ((fi.isDir() && !m_bFollowDirLinks) || (!fi.isDir() && !m_bFollowFileLinks)) ) - { - m_pStatusInfo->addText(i18n("copyLink( %1 -> %2 )",srcName,destName)); + } + + m_pStatusInfo->addText(i18n("manual merge( %1, %2, %3 -> %4)", nameA, nameB, nameC, nameDest)); + if(m_bSimulatedMergeStarted) + { + m_pStatusInfo->addText(i18n(" Note: After a manual merge the user should continue by pressing F7.")); + return true; + } + + bSingleFileMerge = true; + setOpStatus(*m_currentIndexForOperation, eOpStatusInProgress); + q->scrollTo(*m_currentIndexForOperation, EnsureVisible); + + emit q->startDiffMerge(nameA, nameB, nameC, nameDest, "", "", "", 0); + + return false; +} + +bool DirectoryMergeWindow::Data::copyFLD(const QString& srcName, const QString& destName) +{ + if(srcName == destName) + return true; + + FileAccess fi(srcName); + FileAccess faDest(destName, true); + if(faDest.exists() && !(fi.isDir() && faDest.isDir() && (fi.isSymLink() == faDest.isSymLink()))) + { + bool bSuccess = deleteFLD(destName, m_pOptions->m_bDmCreateBakFiles); + if(!bSuccess) + { + m_pStatusInfo->addText(i18n("Error: copy( %1 -> %2 ) failed." + "Deleting existing destination failed.", + srcName, destName)); + return false; + } + } + + if(fi.isSymLink() && ((fi.isDir() && !m_bFollowDirLinks) || (!fi.isDir() && !m_bFollowFileLinks))) + { + m_pStatusInfo->addText(i18n("copyLink( %1 -> %2 )", srcName, destName)); #if defined(_WIN32) || defined(Q_OS_OS2) - // What are links? +// What are links? #else - if ( m_bSimulatedMergeStarted ) - { - return true; - } - FileAccess destFi(destName); - if ( !destFi.isLocal() || !fi.isLocal() ) - { - m_pStatusInfo->addText(i18n("Error: copyLink failed: Remote links are not yet supported.")); - return false; - } - QString linkTarget = fi.readLink(); - bool bSuccess = FileAccess::symLink( linkTarget, destName ); - if (!bSuccess) - m_pStatusInfo->addText(i18n("Error: copyLink failed.")); - return bSuccess; + if(m_bSimulatedMergeStarted) + { + return true; + } + FileAccess destFi(destName); + if(!destFi.isLocal() || !fi.isLocal()) + { + m_pStatusInfo->addText(i18n("Error: copyLink failed: Remote links are not yet supported.")); + return false; + } + QString linkTarget = fi.readLink(); + bool bSuccess = FileAccess::symLink(linkTarget, destName); + if(!bSuccess) + m_pStatusInfo->addText(i18n("Error: copyLink failed.")); + return bSuccess; #endif - } - - if ( fi.isDir() ) - { - if ( faDest.exists() ) - return true; - else - { - bool bSuccess = makeDir( destName ); - return bSuccess; - } - } - - int pos=destName.lastIndexOf('/'); - if ( pos>0 ) - { - QString parentName = destName.left(pos); - bool bSuccess = makeDir(parentName, true /*quiet*/); - if (!bSuccess) - return false; - } - - m_pStatusInfo->addText(i18n("copy( %1 -> %2 )",srcName,destName)); - - if ( m_bSimulatedMergeStarted ) - { - return true; - } - - FileAccess faSrc ( srcName ); - bool bSuccess = faSrc.copyFile( destName ); - if (! bSuccess ) m_pStatusInfo->addText( faSrc.getStatusText() ); - return bSuccess; + } + + if(fi.isDir()) + { + if(faDest.exists()) + return true; + else + { + bool bSuccess = makeDir(destName); + return bSuccess; + } + } + + int pos = destName.lastIndexOf('/'); + if(pos > 0) + { + QString parentName = destName.left(pos); + bool bSuccess = makeDir(parentName, true /*quiet*/); + if(!bSuccess) + return false; + } + + m_pStatusInfo->addText(i18n("copy( %1 -> %2 )", 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::Data::renameFLD( const QString& srcName, const QString& destName ) -{ - if ( srcName == destName ) - return true; - - if ( FileAccess(destName, true).exists() ) - { - bool bSuccess = deleteFLD( destName, false /*no backup*/ ); - if (!bSuccess) - { - m_pStatusInfo->addText( i18n("Error during rename( %1 -> %2 ): " - "Cannot delete existing destination." ,srcName,destName)); - return false; - } - } - - m_pStatusInfo->addText(i18n("rename( %1 -> %2 )",srcName,destName)); - if ( m_bSimulatedMergeStarted ) - { - return true; - } - - bool bSuccess = FileAccess( srcName ).rename( destName ); - if (!bSuccess) - { - m_pStatusInfo->addText( i18n("Error: Rename failed.") ); - return false; - } - - return true; -} - -bool DirectoryMergeWindow::Data::makeDir( const QString& name, bool bQuiet ) -{ - FileAccess fi(name, true); - if( fi.exists() && fi.isDir() ) - return true; - - if( fi.exists() && !fi.isDir() ) - { - bool bSuccess = deleteFLD( name, true ); - if (!bSuccess) - { - m_pStatusInfo->addText( i18n("Error during makeDir of %1. " - "Cannot delete existing file." ,name)); - return false; - } - } - - int pos=name.lastIndexOf('/'); - if ( pos>0 ) - { - QString parentName = name.left(pos); - bool bSuccess = makeDir(parentName,true); - if (!bSuccess) - return false; - } - - if ( ! bQuiet ) - m_pStatusInfo->addText(i18n("makeDir( %1 )",name)); - - if ( m_bSimulatedMergeStarted ) - { - return true; - } - - bool bSuccess = FileAccess::makeDir( name ); - if ( bSuccess == false ) - { - m_pStatusInfo->addText( i18n("Error while creating directory.") ); - return false; - } - return true; -} - - -DirectoryMergeInfo::DirectoryMergeInfo( QWidget* pParent ) -: QFrame(pParent) -{ - QVBoxLayout *topLayout = new QVBoxLayout( this ); - topLayout->setMargin(0); - - QGridLayout *grid = new QGridLayout(); - topLayout->addLayout(grid); - grid->setColumnStretch(1,10); - - int line=0; - - m_pA = new QLabel("A",this); grid->addWidget( m_pA,line, 0 ); - m_pInfoA = new QLabel(this); grid->addWidget( m_pInfoA,line,1 ); ++line; - m_pB = new QLabel("B",this); grid->addWidget( m_pB,line, 0 ); - m_pInfoB = new QLabel(this); grid->addWidget( m_pInfoB,line,1 ); ++line; - m_pC = new QLabel("C",this); grid->addWidget( m_pC,line, 0 ); - m_pInfoC = new QLabel(this); grid->addWidget( m_pInfoC,line,1 ); ++line; - m_pDest = new QLabel(i18n("Dest"),this); grid->addWidget( m_pDest,line, 0 ); - m_pInfoDest = new QLabel(this); grid->addWidget( m_pInfoDest,line,1 ); ++line; - - m_pInfoList = new QTreeWidget(this); topLayout->addWidget( m_pInfoList ); - m_pInfoList->setHeaderLabels( QStringList() << i18n("Dir") << i18n("Type") << i18n("Size") - << i18n("Attr") << i18n("Last Modification") << i18n("Link-Destination") ); - setMinimumSize( 100,100 ); - - m_pInfoList->installEventFilter(this); - m_pInfoList->setRootIsDecorated( false ); -} - -bool DirectoryMergeInfo::eventFilter(QObject*o, QEvent* e) -{ - if ( e->type()==QEvent::FocusIn && o==m_pInfoList ) - emit gotFocus(); - return false; -} - -static void addListViewItem( QTreeWidget* pListView, const QString& dir, - const QString& basePath, FileAccess* fi ) -{ - if ( basePath.isEmpty() ) - { - return; - } - else - { - if ( fi!=0 && fi->exists() ) - { - QString dateString = fi->lastModified().toString("yyyy-MM-dd hh:mm:ss"); - - new QTreeWidgetItem( - pListView, - QStringList() << dir << - QString( fi->isDir() ? i18n("Dir") : i18n("File") ) + (fi->isSymLink() ? "-Link" : "") << - QString::number(fi->size()) << - QString(fi->isReadable() ? "r" : " ") + (fi->isWritable()?"w" : " ") +bool DirectoryMergeWindow::Data::renameFLD(const QString& srcName, const QString& destName) +{ + if(srcName == destName) + return true; + + if(FileAccess(destName, true).exists()) + { + bool bSuccess = deleteFLD(destName, false /*no backup*/); + if(!bSuccess) + { + m_pStatusInfo->addText(i18n("Error during rename( %1 -> %2 ): " + "Cannot delete existing destination.", + srcName, destName)); + return false; + } + } + + m_pStatusInfo->addText(i18n("rename( %1 -> %2 )", srcName, destName)); + if(m_bSimulatedMergeStarted) + { + return true; + } + + bool bSuccess = FileAccess(srcName).rename(destName); + if(!bSuccess) + { + m_pStatusInfo->addText(i18n("Error: Rename failed.")); + return false; + } + + return true; +} + +bool DirectoryMergeWindow::Data::makeDir(const QString& name, bool bQuiet) +{ + FileAccess fi(name, true); + if(fi.exists() && fi.isDir()) + return true; + + if(fi.exists() && !fi.isDir()) + { + bool bSuccess = deleteFLD(name, true); + if(!bSuccess) + { + m_pStatusInfo->addText(i18n("Error during makeDir of %1. " + "Cannot delete existing file.", + name)); + return false; + } + } + + int pos = name.lastIndexOf('/'); + if(pos > 0) + { + QString parentName = name.left(pos); + bool bSuccess = makeDir(parentName, true); + if(!bSuccess) + return false; + } + + if(!bQuiet) + m_pStatusInfo->addText(i18n("makeDir( %1 )", name)); + + if(m_bSimulatedMergeStarted) + { + return true; + } + + bool bSuccess = FileAccess::makeDir(name); + if(bSuccess == false) + { + m_pStatusInfo->addText(i18n("Error while creating directory.")); + return false; + } + return true; +} + +DirectoryMergeInfo::DirectoryMergeInfo(QWidget* pParent) + : QFrame(pParent) +{ + QVBoxLayout* topLayout = new QVBoxLayout(this); + topLayout->setMargin(0); + + QGridLayout* grid = new QGridLayout(); + topLayout->addLayout(grid); + grid->setColumnStretch(1, 10); + + int line = 0; + + m_pA = new QLabel("A", this); + grid->addWidget(m_pA, line, 0); + m_pInfoA = new QLabel(this); + grid->addWidget(m_pInfoA, line, 1); + ++line; + m_pB = new QLabel("B", this); + grid->addWidget(m_pB, line, 0); + m_pInfoB = new QLabel(this); + grid->addWidget(m_pInfoB, line, 1); + ++line; + m_pC = new QLabel("C", this); + grid->addWidget(m_pC, line, 0); + m_pInfoC = new QLabel(this); + grid->addWidget(m_pInfoC, line, 1); + ++line; + m_pDest = new QLabel(i18n("Dest"), this); + grid->addWidget(m_pDest, line, 0); + m_pInfoDest = new QLabel(this); + grid->addWidget(m_pInfoDest, line, 1); + ++line; + + m_pInfoList = new QTreeWidget(this); + topLayout->addWidget(m_pInfoList); + m_pInfoList->setHeaderLabels(QStringList() << i18n("Dir") << i18n("Type") << i18n("Size") + << i18n("Attr") << i18n("Last Modification") << i18n("Link-Destination")); + setMinimumSize(100, 100); + + m_pInfoList->installEventFilter(this); + m_pInfoList->setRootIsDecorated(false); +} + +bool DirectoryMergeInfo::eventFilter(QObject* o, QEvent* e) +{ + if(e->type() == QEvent::FocusIn && o == m_pInfoList) + emit gotFocus(); + return false; +} + +static void addListViewItem(QTreeWidget* pListView, const QString& dir, + const QString& basePath, FileAccess* fi) +{ + if(basePath.isEmpty()) + { + return; + } + else + { + if(fi != 0 && fi->exists()) + { + QString dateString = fi->lastModified().toString("yyyy-MM-dd hh:mm:ss"); + + new QTreeWidgetItem( + pListView, + QStringList() << dir << QString(fi->isDir() ? i18n("Dir") : i18n("File")) + (fi->isSymLink() ? "-Link" : "") << QString::number(fi->size()) << QString(fi->isReadable() ? "r" : " ") + (fi->isWritable() ? "w" : " ") #ifdef _WIN32 - /*Future: Use GetFileAttributes()*/ << + /*Future: Use GetFileAttributes()*/ + << #else - + (fi->isExecutable()?"x" : " ") << + + (fi->isExecutable() ? "x" : " ") + << #endif - dateString << - QString(fi->isSymLink() ? (" -> " + fi->readLink()) : QString("")) - ); - } - else - { - new QTreeWidgetItem( - pListView, - QStringList() << dir << - i18n("not available") << - "" << - "" << - "" << - "" - ); - } - } + dateString << QString(fi->isSymLink() ? (" -> " + fi->readLink()) : QString(""))); + } + else + { + new QTreeWidgetItem( + pListView, + QStringList() << dir << i18n("not available") << "" + << "" + << "" + << ""); + } + } } void DirectoryMergeInfo::setInfo( - const FileAccess& dirA, - const FileAccess& dirB, - const FileAccess& dirC, - const FileAccess& dirDest, - MergeFileInfos& mfi ) -{ - bool bHideDest = false; - if ( dirA.absoluteFilePath()==dirDest.absoluteFilePath() ) - { - m_pA->setText( i18n("A (Dest): ") ); bHideDest=true; - } - else - m_pA->setText( !dirC.isValid() ? QString("A: ") : i18n("A (Base): ")); - - m_pInfoA->setText( dirA.prettyAbsPath() ); - - if ( dirB.absoluteFilePath()==dirDest.absoluteFilePath() ) - { - m_pB->setText( i18n("B (Dest): ") ); bHideDest=true; - } - else - m_pB->setText( "B: " ); - m_pInfoB->setText( dirB.prettyAbsPath() ); - - if ( dirC.absoluteFilePath()==dirDest.absoluteFilePath() ) - { - m_pC->setText( i18n("C (Dest): ") ); bHideDest=true; - } - else - m_pC->setText( "C: " ); - m_pInfoC->setText( dirC.prettyAbsPath() ); - - m_pDest->setText( i18n("Dest: ") ); m_pInfoDest->setText( dirDest.prettyAbsPath() ); - - if (!dirC.isValid()) { m_pC->hide(); m_pInfoC->hide(); } - else { m_pC->show(); m_pInfoC->show(); } - - if (!dirDest.isValid()||bHideDest) { m_pDest->hide(); m_pInfoDest->hide(); } - else { m_pDest->show(); m_pInfoDest->show(); } - - m_pInfoList->clear(); - addListViewItem( m_pInfoList, "A", dirA.prettyAbsPath(), mfi.m_pFileInfoA ); - addListViewItem( m_pInfoList, "B", dirB.prettyAbsPath(), mfi.m_pFileInfoB ); - addListViewItem( m_pInfoList, "C", dirC.prettyAbsPath(), mfi.m_pFileInfoC ); - if (!bHideDest) - { - FileAccess fiDest( dirDest.prettyAbsPath() + "/" + mfi.subPath(), true ); - addListViewItem( m_pInfoList, i18n("Dest"), dirDest.prettyAbsPath(), &fiDest ); - } - for (int i=0;icolumnCount();++i) - m_pInfoList->resizeColumnToContents ( i ); -} - -QTextStream& operator<<( QTextStream& ts, MergeFileInfos& mfi ) -{ - ts << "{\n"; - ValueMap vm; - vm.writeEntry( "SubPath", mfi.subPath() ); - vm.writeEntry( "ExistsInA", mfi.existsInA() ); - vm.writeEntry( "ExistsInB", mfi.existsInB() ); - vm.writeEntry( "ExistsInC", mfi.existsInC() ); - vm.writeEntry( "EqualAB", mfi.m_bEqualAB ); - vm.writeEntry( "EqualAC", mfi.m_bEqualAC ); - vm.writeEntry( "EqualBC", mfi.m_bEqualBC ); - //DirMergeItem* m_pDMI; - //MergeFileInfos* m_pParent; - vm.writeEntry( "MergeOperation", (int) mfi.m_eMergeOperation ); - vm.writeEntry( "DirA", mfi.dirA() ); - vm.writeEntry( "DirB", mfi.dirB() ); - vm.writeEntry( "DirC", mfi.dirC() ); - vm.writeEntry( "LinkA", mfi.isLinkA() ); - vm.writeEntry( "LinkB", mfi.isLinkB() ); - vm.writeEntry( "LinkC", mfi.isLinkC() ); - vm.writeEntry( "OperationComplete", mfi.m_bOperationComplete ); - //bool m_bSimOpComplete ); - - vm.writeEntry( "AgeA", (int) mfi.m_ageA ); - vm.writeEntry( "AgeB", (int) mfi.m_ageB ); - vm.writeEntry( "AgeC", (int) mfi.m_ageC ); - vm.writeEntry( "ConflictingAges", mfi.m_bConflictingAges ); // Equal age but files are not! - - //FileAccess m_fileInfoA; - //FileAccess m_fileInfoB; - //FileAccess m_fileInfoC; - - //TotalDiffStatus m_totalDiffStatus; - - vm.save(ts); - - ts << "}\n"; - - return ts; + const FileAccess& dirA, + const FileAccess& dirB, + const FileAccess& dirC, + const FileAccess& dirDest, + MergeFileInfos& mfi) +{ + bool bHideDest = false; + if(dirA.absoluteFilePath() == dirDest.absoluteFilePath()) + { + m_pA->setText(i18n("A (Dest): ")); + bHideDest = true; + } + else + m_pA->setText(!dirC.isValid() ? QString("A: ") : i18n("A (Base): ")); + + m_pInfoA->setText(dirA.prettyAbsPath()); + + if(dirB.absoluteFilePath() == dirDest.absoluteFilePath()) + { + m_pB->setText(i18n("B (Dest): ")); + bHideDest = true; + } + else + m_pB->setText("B: "); + m_pInfoB->setText(dirB.prettyAbsPath()); + + if(dirC.absoluteFilePath() == dirDest.absoluteFilePath()) + { + m_pC->setText(i18n("C (Dest): ")); + bHideDest = true; + } + else + m_pC->setText("C: "); + m_pInfoC->setText(dirC.prettyAbsPath()); + + m_pDest->setText(i18n("Dest: ")); + m_pInfoDest->setText(dirDest.prettyAbsPath()); + + if(!dirC.isValid()) { + m_pC->hide(); + m_pInfoC->hide(); + } + else + { + m_pC->show(); + m_pInfoC->show(); + } + + if(!dirDest.isValid() || bHideDest) { + m_pDest->hide(); + m_pInfoDest->hide(); + } + else + { + m_pDest->show(); + m_pInfoDest->show(); + } + + m_pInfoList->clear(); + addListViewItem(m_pInfoList, "A", dirA.prettyAbsPath(), mfi.m_pFileInfoA); + addListViewItem(m_pInfoList, "B", dirB.prettyAbsPath(), mfi.m_pFileInfoB); + addListViewItem(m_pInfoList, "C", dirC.prettyAbsPath(), mfi.m_pFileInfoC); + if(!bHideDest) + { + FileAccess fiDest(dirDest.prettyAbsPath() + "/" + mfi.subPath(), true); + addListViewItem(m_pInfoList, i18n("Dest"), dirDest.prettyAbsPath(), &fiDest); + } + for(int i = 0; i < m_pInfoList->columnCount(); ++i) + m_pInfoList->resizeColumnToContents(i); +} + +QTextStream& operator<<(QTextStream& ts, MergeFileInfos& mfi) +{ + ts << "{\n"; + ValueMap vm; + vm.writeEntry("SubPath", mfi.subPath()); + vm.writeEntry("ExistsInA", mfi.existsInA()); + vm.writeEntry("ExistsInB", mfi.existsInB()); + vm.writeEntry("ExistsInC", mfi.existsInC()); + vm.writeEntry("EqualAB", mfi.m_bEqualAB); + vm.writeEntry("EqualAC", mfi.m_bEqualAC); + vm.writeEntry("EqualBC", mfi.m_bEqualBC); + //DirMergeItem* m_pDMI; + //MergeFileInfos* m_pParent; + vm.writeEntry("MergeOperation", (int)mfi.m_eMergeOperation); + vm.writeEntry("DirA", mfi.dirA()); + vm.writeEntry("DirB", mfi.dirB()); + vm.writeEntry("DirC", mfi.dirC()); + vm.writeEntry("LinkA", mfi.isLinkA()); + vm.writeEntry("LinkB", mfi.isLinkB()); + vm.writeEntry("LinkC", mfi.isLinkC()); + vm.writeEntry("OperationComplete", mfi.m_bOperationComplete); + //bool m_bSimOpComplete ); + + vm.writeEntry("AgeA", (int)mfi.m_ageA); + vm.writeEntry("AgeB", (int)mfi.m_ageB); + vm.writeEntry("AgeC", (int)mfi.m_ageC); + vm.writeEntry("ConflictingAges", mfi.m_bConflictingAges); // Equal age but files are not! + + //FileAccess m_fileInfoA; + //FileAccess m_fileInfoB; + //FileAccess m_fileInfoC; + + //TotalDiffStatus m_totalDiffStatus; + + vm.save(ts); + + ts << "}\n"; + + return ts; } void DirectoryMergeWindow::slotSaveMergeState() { - //slotStatusMsg(i18n("Saving Directory Merge State ...")); - - //QString s = KFileDialog::getSaveUrl( QDir::currentPath(), 0, this, i18n("Save As...") ).url(); - QString s = QFileDialog::getSaveFileName(this, i18n("Save Directory Merge State As...") , QDir::currentPath(), 0); - if(!s.isEmpty()) - { - d->m_dirMergeStateFilename = s; - + //slotStatusMsg(i18n("Saving Directory Merge State ...")); - QFile file(d->m_dirMergeStateFilename); - bool bSuccess = file.open( QIODevice::WriteOnly ); - if ( bSuccess ) - { - QTextStream ts( &file ); + //QString s = KFileDialog::getSaveUrl( QDir::currentPath(), 0, this, i18n("Save As...") ).url(); + QString s = QFileDialog::getSaveFileName(this, i18n("Save Directory Merge State As..."), QDir::currentPath(), 0); + if(!s.isEmpty()) + { + d->m_dirMergeStateFilename = s; - QModelIndex mi( d->index(0,0,QModelIndex()) ); - while ( mi.isValid() ) { - MergeFileInfos* pMFI = d->getMFI(mi); - ts << *pMFI; - mi = d->treeIterator(mi,true,true); - } - } - } + QFile file(d->m_dirMergeStateFilename); + bool bSuccess = file.open(QIODevice::WriteOnly); + if(bSuccess) + { + QTextStream ts(&file); - //slotStatusMsg(i18n("Ready.")); + QModelIndex mi(d->index(0, 0, QModelIndex())); + while(mi.isValid()) { + MergeFileInfos* pMFI = d->getMFI(mi); + ts << *pMFI; + mi = d->treeIterator(mi, true, true); + } + } + } + //slotStatusMsg(i18n("Ready.")); } void DirectoryMergeWindow::slotLoadMergeState() { } void DirectoryMergeWindow::updateFileVisibilities() { - bool bShowIdentical = d->m_pDirShowIdenticalFiles->isChecked(); - bool bShowDifferent = d->m_pDirShowDifferentFiles->isChecked(); - bool bShowOnlyInA = d->m_pDirShowFilesOnlyInA->isChecked(); - bool bShowOnlyInB = d->m_pDirShowFilesOnlyInB->isChecked(); - bool bShowOnlyInC = d->m_pDirShowFilesOnlyInC->isChecked(); - bool bThreeDirs = d->m_dirC.isValid(); - d->m_selection1Index = QModelIndex(); - d->m_selection2Index = QModelIndex(); - d->m_selection3Index = QModelIndex(); - - // in first run set all dirs to equal and determine if they are not equal. - // on second run don't change the equal-status anymore; it is needed to - // set the visibility (when bShowIdentical is false). - for( int loop=0; loop<2; ++loop ) - { - QModelIndex mi = d->rowCount()>0 ? d->index(0,0,QModelIndex()) : QModelIndex(); - while( mi.isValid() ) - { - MergeFileInfos* pMFI = d->getMFI(mi); - bool bDir = pMFI->dirA() || pMFI->dirB() || pMFI->dirC(); - if ( loop==0 && bDir ) - { - bool bChange = false; - if ( !pMFI->m_bEqualAB && pMFI->dirA() == pMFI->dirB() && pMFI->isLinkA()== pMFI->isLinkB() ) - { - pMFI->m_bEqualAB = true; - bChange=true; - } - if ( !pMFI->m_bEqualBC && pMFI->dirC() == pMFI->dirB() && pMFI->isLinkC()== pMFI->isLinkB() ) - { - pMFI->m_bEqualBC = true; - bChange=true; - } - if ( !pMFI->m_bEqualAC && pMFI->dirA() == pMFI->dirC() && pMFI->isLinkA()== pMFI->isLinkC() ) - { - pMFI->m_bEqualAC = true; - bChange=true; - } - - if ( bChange ) - setPixmaps( *pMFI, bThreeDirs ); - } - bool bExistsEverywhere = pMFI->existsInA() && pMFI->existsInB() && (pMFI->existsInC() || !bThreeDirs); - int existCount = int(pMFI->existsInA()) + int(pMFI->existsInB()) + int(pMFI->existsInC()); - bool bVisible = - ( bShowIdentical && bExistsEverywhere && pMFI->m_bEqualAB && (pMFI->m_bEqualAC || !bThreeDirs) ) - || ( (bShowDifferent||bDir) && existCount>=2 && (!pMFI->m_bEqualAB || !(pMFI->m_bEqualAC || !bThreeDirs))) - || ( bShowOnlyInA && pMFI->existsInA() && !pMFI->existsInB() && !pMFI->existsInC() ) - || ( bShowOnlyInB && !pMFI->existsInA() && pMFI->existsInB() && !pMFI->existsInC() ) - || ( bShowOnlyInC && !pMFI->existsInA() && !pMFI->existsInB() && pMFI->existsInC() ); - - QString fileName = pMFI->fileName(); - bVisible = bVisible && ( - (bDir && ! wildcardMultiMatch( d->m_pOptions->m_DmDirAntiPattern, fileName, d->m_bCaseSensitive )) - || (wildcardMultiMatch( d->m_pOptions->m_DmFilePattern, fileName, d->m_bCaseSensitive ) - && !wildcardMultiMatch( d->m_pOptions->m_DmFileAntiPattern, fileName, d->m_bCaseSensitive )) ); - - setRowHidden(mi.row(),mi.parent(),!bVisible); - - bool bEqual = bThreeDirs ? pMFI->m_bEqualAB && pMFI->m_bEqualAC : pMFI->m_bEqualAB; - if ( !bEqual && bVisible && loop==0 ) // Set all parents to "not equal" - { - MergeFileInfos* p2 = pMFI->m_pParent; - while(p2!=0) + bool bShowIdentical = d->m_pDirShowIdenticalFiles->isChecked(); + bool bShowDifferent = d->m_pDirShowDifferentFiles->isChecked(); + bool bShowOnlyInA = d->m_pDirShowFilesOnlyInA->isChecked(); + bool bShowOnlyInB = d->m_pDirShowFilesOnlyInB->isChecked(); + bool bShowOnlyInC = d->m_pDirShowFilesOnlyInC->isChecked(); + bool bThreeDirs = d->m_dirC.isValid(); + d->m_selection1Index = QModelIndex(); + d->m_selection2Index = QModelIndex(); + d->m_selection3Index = QModelIndex(); + + // in first run set all dirs to equal and determine if they are not equal. + // on second run don't change the equal-status anymore; it is needed to + // set the visibility (when bShowIdentical is false). + for(int loop = 0; loop < 2; ++loop) + { + QModelIndex mi = d->rowCount() > 0 ? d->index(0, 0, QModelIndex()) : QModelIndex(); + while(mi.isValid()) + { + MergeFileInfos* pMFI = d->getMFI(mi); + bool bDir = pMFI->dirA() || pMFI->dirB() || pMFI->dirC(); + if(loop == 0 && bDir) { - bool bChange = false; - if ( !pMFI->m_bEqualAB && p2->m_bEqualAB ){ p2->m_bEqualAB = false; bChange=true; } - if ( !pMFI->m_bEqualAC && p2->m_bEqualAC ){ p2->m_bEqualAC = false; bChange=true; } - if ( !pMFI->m_bEqualBC && p2->m_bEqualBC ){ p2->m_bEqualBC = false; bChange=true; } + bool bChange = false; + if(!pMFI->m_bEqualAB && pMFI->dirA() == pMFI->dirB() && pMFI->isLinkA() == pMFI->isLinkB()) + { + pMFI->m_bEqualAB = true; + bChange = true; + } + if(!pMFI->m_bEqualBC && pMFI->dirC() == pMFI->dirB() && pMFI->isLinkC() == pMFI->isLinkB()) + { + pMFI->m_bEqualBC = true; + bChange = true; + } + if(!pMFI->m_bEqualAC && pMFI->dirA() == pMFI->dirC() && pMFI->isLinkA() == pMFI->isLinkC()) + { + pMFI->m_bEqualAC = true; + bChange = true; + } + + if(bChange) + setPixmaps(*pMFI, bThreeDirs); + } + bool bExistsEverywhere = pMFI->existsInA() && pMFI->existsInB() && (pMFI->existsInC() || !bThreeDirs); + int existCount = int(pMFI->existsInA()) + int(pMFI->existsInB()) + int(pMFI->existsInC()); + bool bVisible = + (bShowIdentical && bExistsEverywhere && pMFI->m_bEqualAB && (pMFI->m_bEqualAC || !bThreeDirs)) || ((bShowDifferent || bDir) && existCount >= 2 && (!pMFI->m_bEqualAB || !(pMFI->m_bEqualAC || !bThreeDirs))) || (bShowOnlyInA && pMFI->existsInA() && !pMFI->existsInB() && !pMFI->existsInC()) || (bShowOnlyInB && !pMFI->existsInA() && pMFI->existsInB() && !pMFI->existsInC()) || (bShowOnlyInC && !pMFI->existsInA() && !pMFI->existsInB() && pMFI->existsInC()); - if ( bChange ) - setPixmaps( *p2, bThreeDirs ); - else - break; + QString fileName = pMFI->fileName(); + bVisible = bVisible && ((bDir && !wildcardMultiMatch(d->m_pOptions->m_DmDirAntiPattern, fileName, d->m_bCaseSensitive)) || (wildcardMultiMatch(d->m_pOptions->m_DmFilePattern, fileName, d->m_bCaseSensitive) && !wildcardMultiMatch(d->m_pOptions->m_DmFileAntiPattern, fileName, d->m_bCaseSensitive))); - p2 = p2->m_pParent; + setRowHidden(mi.row(), mi.parent(), !bVisible); + + bool bEqual = bThreeDirs ? pMFI->m_bEqualAB && pMFI->m_bEqualAC : pMFI->m_bEqualAB; + if(!bEqual && bVisible && loop == 0) // Set all parents to "not equal" + { + MergeFileInfos* p2 = pMFI->m_pParent; + while(p2 != 0) + { + bool bChange = false; + if(!pMFI->m_bEqualAB && p2->m_bEqualAB) { + p2->m_bEqualAB = false; + bChange = true; + } + if(!pMFI->m_bEqualAC && p2->m_bEqualAC) { + p2->m_bEqualAC = false; + bChange = true; + } + if(!pMFI->m_bEqualBC && p2->m_bEqualBC) { + p2->m_bEqualBC = false; + bChange = true; + } + + if(bChange) + setPixmaps(*p2, bThreeDirs); + else + break; + + p2 = p2->m_pParent; + } } - } - mi = d->treeIterator( mi, true, true ); - } - } + mi = d->treeIterator(mi, true, true); + } + } } -void DirectoryMergeWindow::slotShowIdenticalFiles() { - d->m_pOptions->m_bDmShowIdenticalFiles=d->m_pDirShowIdenticalFiles->isChecked(); - updateFileVisibilities(); +void DirectoryMergeWindow::slotShowIdenticalFiles() +{ + d->m_pOptions->m_bDmShowIdenticalFiles = d->m_pDirShowIdenticalFiles->isChecked(); + updateFileVisibilities(); } void DirectoryMergeWindow::slotShowDifferentFiles() { updateFileVisibilities(); } -void DirectoryMergeWindow::slotShowFilesOnlyInA() { updateFileVisibilities(); } -void DirectoryMergeWindow::slotShowFilesOnlyInB() { updateFileVisibilities(); } -void DirectoryMergeWindow::slotShowFilesOnlyInC() { updateFileVisibilities(); } +void DirectoryMergeWindow::slotShowFilesOnlyInA() { updateFileVisibilities(); } +void DirectoryMergeWindow::slotShowFilesOnlyInB() { updateFileVisibilities(); } +void DirectoryMergeWindow::slotShowFilesOnlyInC() { updateFileVisibilities(); } -void DirectoryMergeWindow::slotSynchronizeDirectories() { } -void DirectoryMergeWindow::slotChooseNewerFiles() { } +void DirectoryMergeWindow::slotSynchronizeDirectories() {} +void DirectoryMergeWindow::slotChooseNewerFiles() {} -void DirectoryMergeWindow::initDirectoryMergeActions( QObject* pKDiff3App, KActionCollection* ac ) +void DirectoryMergeWindow::initDirectoryMergeActions(QObject* pKDiff3App, KActionCollection* ac) { -#include "xpm/startmerge.xpm" #include "xpm/showequalfiles.xpm" #include "xpm/showfilesonlyina.xpm" #include "xpm/showfilesonlyinb.xpm" #include "xpm/showfilesonlyinc.xpm" - DirectoryMergeWindow* p = this; - - d->m_pDirStartOperation = KDiff3::createAction< QAction >(i18n("Start/Continue Directory Merge"), QKeySequence( Qt::Key_F7 ), p, SLOT(slotRunOperationForAllItems()), ac, "dir_start_operation"); - d->m_pDirRunOperationForCurrentItem = KDiff3::createAction< QAction >(i18n("Run Operation for Current Item"), QKeySequence( Qt::Key_F6 ), p, SLOT(slotRunOperationForCurrentItem()), ac, "dir_run_operation_for_current_item"); - d->m_pDirCompareCurrent = KDiff3::createAction< QAction >(i18n("Compare Selected File"), p, SLOT(compareCurrentFile()), ac, "dir_compare_current"); - d->m_pDirMergeCurrent = KDiff3::createAction< QAction >(i18n("Merge Current File"), QIcon(QPixmap(startmerge)), i18n("Merge\nFile"), pKDiff3App, SLOT(slotMergeCurrentFile()), ac, "merge_current"); - d->m_pDirFoldAll = KDiff3::createAction< QAction >(i18n("Fold All Subdirs"), p, SLOT(collapseAll()), ac, "dir_fold_all"); - d->m_pDirUnfoldAll = KDiff3::createAction< QAction >(i18n("Unfold All Subdirs"), p, SLOT(expandAll()), ac, "dir_unfold_all"); - d->m_pDirRescan = KDiff3::createAction< QAction >(i18n("Rescan"), QKeySequence( Qt::SHIFT+Qt::Key_F5 ), p, SLOT(reload()), ac, "dir_rescan"); - d->m_pDirSaveMergeState = 0; //KDiff3::createAction< QAction >(i18n("Save Directory Merge State ..."), 0, p, SLOT(slotSaveMergeState()), ac, "dir_save_merge_state"); - d->m_pDirLoadMergeState = 0; //KDiff3::createAction< QAction >(i18n("Load Directory Merge State ..."), 0, p, SLOT(slotLoadMergeState()), ac, "dir_load_merge_state"); - d->m_pDirChooseAEverywhere = KDiff3::createAction< QAction >(i18n("Choose A for All Items"), p, SLOT(slotChooseAEverywhere()), ac, "dir_choose_a_everywhere"); - d->m_pDirChooseBEverywhere = KDiff3::createAction< QAction >(i18n("Choose B for All Items"), p, SLOT(slotChooseBEverywhere()), ac, "dir_choose_b_everywhere"); - d->m_pDirChooseCEverywhere = KDiff3::createAction< QAction >(i18n("Choose C for All Items"), p, SLOT(slotChooseCEverywhere()), ac, "dir_choose_c_everywhere"); - d->m_pDirAutoChoiceEverywhere = KDiff3::createAction< QAction >(i18n("Auto-Choose Operation for All Items"), p, SLOT(slotAutoChooseEverywhere()), ac, "dir_autochoose_everywhere"); - d->m_pDirDoNothingEverywhere = KDiff3::createAction< QAction >(i18n("No Operation for All Items"), p, SLOT(slotNoOpEverywhere()), ac, "dir_nothing_everywhere"); - -// d->m_pDirSynchronizeDirectories = KDiff3::createAction< KToggleAction >(i18n("Synchronize Directories"), 0, this, SLOT(slotSynchronizeDirectories()), ac, "dir_synchronize_directories"); -// d->m_pDirChooseNewerFiles = KDiff3::createAction< KToggleAction >(i18n("Copy Newer Files Instead of Merging"), 0, this, SLOT(slotChooseNewerFiles()), ac, "dir_choose_newer_files"); - - d->m_pDirShowIdenticalFiles = KDiff3::createAction< KToggleAction >(i18n("Show Identical Files"), QIcon(QPixmap(showequalfiles)), i18n("Identical\nFiles"), this, SLOT(slotShowIdenticalFiles()), ac, "dir_show_identical_files"); - d->m_pDirShowDifferentFiles = KDiff3::createAction< KToggleAction >(i18n("Show Different Files"), this, SLOT(slotShowDifferentFiles()), ac, "dir_show_different_files"); - d->m_pDirShowFilesOnlyInA = KDiff3::createAction< KToggleAction >(i18n("Show Files only in A"), QIcon(QPixmap(showfilesonlyina)), i18n("Files\nonly in A"), this, SLOT(slotShowFilesOnlyInA()), ac, "dir_show_files_only_in_a"); - d->m_pDirShowFilesOnlyInB = KDiff3::createAction< KToggleAction >(i18n("Show Files only in B"), QIcon(QPixmap(showfilesonlyinb)), i18n("Files\nonly in B"), this, SLOT(slotShowFilesOnlyInB()), ac, "dir_show_files_only_in_b"); - d->m_pDirShowFilesOnlyInC = KDiff3::createAction< KToggleAction >(i18n("Show Files only in C"), QIcon(QPixmap(showfilesonlyinc)), i18n("Files\nonly in C"), this, SLOT(slotShowFilesOnlyInC()), ac, "dir_show_files_only_in_c"); - - d->m_pDirShowIdenticalFiles->setChecked( d->m_pOptions->m_bDmShowIdenticalFiles ); - - d->m_pDirCompareExplicit = KDiff3::createAction< QAction >(i18n("Compare Explicitly Selected Files"), p, SLOT(slotCompareExplicitlySelectedFiles()), ac, "dir_compare_explicitly_selected_files"); - d->m_pDirMergeExplicit = KDiff3::createAction< QAction >(i18n("Merge Explicitly Selected Files"), p, SLOT(slotMergeExplicitlySelectedFiles()), ac, "dir_merge_explicitly_selected_files"); - - d->m_pDirCurrentDoNothing = KDiff3::createAction< QAction >(i18n("Do Nothing"), p, SLOT(slotCurrentDoNothing()), ac, "dir_current_do_nothing"); - d->m_pDirCurrentChooseA = KDiff3::createAction< QAction >(i18n("A"), p, SLOT(slotCurrentChooseA()), ac, "dir_current_choose_a"); - d->m_pDirCurrentChooseB = KDiff3::createAction< QAction >(i18n("B"), p, SLOT(slotCurrentChooseB()), ac, "dir_current_choose_b"); - d->m_pDirCurrentChooseC = KDiff3::createAction< QAction >(i18n("C"), p, SLOT(slotCurrentChooseC()), ac, "dir_current_choose_c"); - d->m_pDirCurrentMerge = KDiff3::createAction< QAction >(i18n("Merge"), p, SLOT(slotCurrentMerge()), ac, "dir_current_merge"); - d->m_pDirCurrentDelete = KDiff3::createAction< QAction >(i18n("Delete (if exists)"), p, SLOT(slotCurrentDelete()), ac, "dir_current_delete"); - - d->m_pDirCurrentSyncDoNothing = KDiff3::createAction< QAction >(i18n("Do Nothing"), p, SLOT(slotCurrentDoNothing()), ac, "dir_current_sync_do_nothing"); - d->m_pDirCurrentSyncCopyAToB = KDiff3::createAction< QAction >(i18n("Copy A to B"), p, SLOT(slotCurrentCopyAToB()), ac, "dir_current_sync_copy_a_to_b" ); - d->m_pDirCurrentSyncCopyBToA = KDiff3::createAction< QAction >(i18n("Copy B to A"), p, SLOT(slotCurrentCopyBToA()), ac, "dir_current_sync_copy_b_to_a" ); - d->m_pDirCurrentSyncDeleteA = KDiff3::createAction< QAction >(i18n("Delete A"), p, SLOT(slotCurrentDeleteA()), ac,"dir_current_sync_delete_a"); - d->m_pDirCurrentSyncDeleteB = KDiff3::createAction< QAction >(i18n("Delete B"), p, SLOT(slotCurrentDeleteB()), ac,"dir_current_sync_delete_b"); - d->m_pDirCurrentSyncDeleteAAndB = KDiff3::createAction< QAction >(i18n("Delete A && B"), p, SLOT(slotCurrentDeleteAAndB()), ac,"dir_current_sync_delete_a_and_b"); - d->m_pDirCurrentSyncMergeToA = KDiff3::createAction< QAction >(i18n("Merge to A"), p, SLOT(slotCurrentMergeToA()), ac,"dir_current_sync_merge_to_a"); - d->m_pDirCurrentSyncMergeToB = KDiff3::createAction< QAction >(i18n("Merge to B"), p, SLOT(slotCurrentMergeToB()), ac,"dir_current_sync_merge_to_b"); - d->m_pDirCurrentSyncMergeToAAndB = KDiff3::createAction< QAction >(i18n("Merge to A && B"), p, SLOT(slotCurrentMergeToAAndB()), ac,"dir_current_sync_merge_to_a_and_b"); -} - - -void DirectoryMergeWindow::updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible, - KToggleAction* chooseA, KToggleAction* chooseB, KToggleAction* chooseC ) -{ - d->m_pDirStartOperation->setEnabled( bDirCompare ); - d->m_pDirRunOperationForCurrentItem->setEnabled( bDirCompare ); - d->m_pDirFoldAll->setEnabled( bDirCompare ); - d->m_pDirUnfoldAll->setEnabled( bDirCompare ); - - d->m_pDirCompareCurrent->setEnabled( bDirCompare && isVisible() && isFileSelected() ); - - d->m_pDirMergeCurrent->setEnabled( (bDirCompare && isVisible() && isFileSelected()) - || bDiffWindowVisible ); - - d->m_pDirRescan->setEnabled( bDirCompare ); - - d->m_pDirAutoChoiceEverywhere->setEnabled( bDirCompare && isVisible() ); - d->m_pDirDoNothingEverywhere->setEnabled( bDirCompare && isVisible() ); - d->m_pDirChooseAEverywhere->setEnabled( bDirCompare && isVisible() ); - d->m_pDirChooseBEverywhere->setEnabled( bDirCompare && isVisible() ); - d->m_pDirChooseCEverywhere->setEnabled( bDirCompare && isVisible() ); - - bool bThreeDirs = d->m_dirC.isValid(); - - MergeFileInfos* pMFI = d->getMFI( currentIndex() ); - - bool bItemActive = bDirCompare && isVisible() && pMFI!=0;// && hasFocus(); - bool bMergeMode = bThreeDirs || !d->m_bSyncMode; - bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI); - - bool bDirWindowHasFocus = isVisible() && hasFocus(); - - d->m_pDirShowIdenticalFiles->setEnabled( bDirCompare && isVisible() ); - d->m_pDirShowDifferentFiles->setEnabled( bDirCompare && isVisible() ); - d->m_pDirShowFilesOnlyInA->setEnabled( bDirCompare && isVisible() ); - d->m_pDirShowFilesOnlyInB->setEnabled( bDirCompare && isVisible() ); - d->m_pDirShowFilesOnlyInC->setEnabled( bDirCompare && isVisible() && bThreeDirs ); - - d->m_pDirCompareExplicit->setEnabled( bDirCompare && isVisible() && d->m_selection2Index.isValid() ); - d->m_pDirMergeExplicit->setEnabled( bDirCompare && isVisible() && d->m_selection2Index.isValid() ); - - d->m_pDirCurrentDoNothing->setEnabled( bItemActive && bMergeMode ); - d->m_pDirCurrentChooseA->setEnabled( bItemActive && bMergeMode && pMFI->existsInA() ); - d->m_pDirCurrentChooseB->setEnabled( bItemActive && bMergeMode && pMFI->existsInB() ); - d->m_pDirCurrentChooseC->setEnabled( bItemActive && bMergeMode && pMFI->existsInC() ); - d->m_pDirCurrentMerge->setEnabled( bItemActive && bMergeMode && !bFTConflict ); - d->m_pDirCurrentDelete->setEnabled( bItemActive && bMergeMode ); - if ( bDirWindowHasFocus ) - { - chooseA->setEnabled( bItemActive && pMFI->existsInA() ); - chooseB->setEnabled( bItemActive && pMFI->existsInB() ); - chooseC->setEnabled( bItemActive && pMFI->existsInC() ); - chooseA->setChecked( false ); - chooseB->setChecked( false ); - chooseC->setChecked( false ); - } - - d->m_pDirCurrentSyncDoNothing->setEnabled( bItemActive && !bMergeMode ); - d->m_pDirCurrentSyncCopyAToB->setEnabled( bItemActive && !bMergeMode && pMFI->existsInA() ); - d->m_pDirCurrentSyncCopyBToA->setEnabled( bItemActive && !bMergeMode && pMFI->existsInB() ); - d->m_pDirCurrentSyncDeleteA->setEnabled( bItemActive && !bMergeMode && pMFI->existsInA() ); - d->m_pDirCurrentSyncDeleteB->setEnabled( bItemActive && !bMergeMode && pMFI->existsInB() ); - d->m_pDirCurrentSyncDeleteAAndB->setEnabled( bItemActive && !bMergeMode && pMFI->existsInA() && pMFI->existsInB() ); - d->m_pDirCurrentSyncMergeToA->setEnabled( bItemActive && !bMergeMode && !bFTConflict ); - d->m_pDirCurrentSyncMergeToB->setEnabled( bItemActive && !bMergeMode && !bFTConflict ); - d->m_pDirCurrentSyncMergeToAAndB->setEnabled( bItemActive && !bMergeMode && !bFTConflict ); +#include "xpm/startmerge.xpm" + DirectoryMergeWindow* p = this; + + d->m_pDirStartOperation = KDiff3::createAction(i18n("Start/Continue Directory Merge"), QKeySequence(Qt::Key_F7), p, SLOT(slotRunOperationForAllItems()), ac, "dir_start_operation"); + d->m_pDirRunOperationForCurrentItem = KDiff3::createAction(i18n("Run Operation for Current Item"), QKeySequence(Qt::Key_F6), p, SLOT(slotRunOperationForCurrentItem()), ac, "dir_run_operation_for_current_item"); + d->m_pDirCompareCurrent = KDiff3::createAction(i18n("Compare Selected File"), p, SLOT(compareCurrentFile()), ac, "dir_compare_current"); + d->m_pDirMergeCurrent = KDiff3::createAction(i18n("Merge Current File"), QIcon(QPixmap(startmerge)), i18n("Merge\nFile"), pKDiff3App, SLOT(slotMergeCurrentFile()), ac, "merge_current"); + d->m_pDirFoldAll = KDiff3::createAction(i18n("Fold All Subdirs"), p, SLOT(collapseAll()), ac, "dir_fold_all"); + d->m_pDirUnfoldAll = KDiff3::createAction(i18n("Unfold All Subdirs"), p, SLOT(expandAll()), ac, "dir_unfold_all"); + d->m_pDirRescan = KDiff3::createAction(i18n("Rescan"), QKeySequence(Qt::SHIFT + Qt::Key_F5), p, SLOT(reload()), ac, "dir_rescan"); + d->m_pDirSaveMergeState = 0; //KDiff3::createAction< QAction >(i18n("Save Directory Merge State ..."), 0, p, SLOT(slotSaveMergeState()), ac, "dir_save_merge_state"); + d->m_pDirLoadMergeState = 0; //KDiff3::createAction< QAction >(i18n("Load Directory Merge State ..."), 0, p, SLOT(slotLoadMergeState()), ac, "dir_load_merge_state"); + d->m_pDirChooseAEverywhere = KDiff3::createAction(i18n("Choose A for All Items"), p, SLOT(slotChooseAEverywhere()), ac, "dir_choose_a_everywhere"); + d->m_pDirChooseBEverywhere = KDiff3::createAction(i18n("Choose B for All Items"), p, SLOT(slotChooseBEverywhere()), ac, "dir_choose_b_everywhere"); + d->m_pDirChooseCEverywhere = KDiff3::createAction(i18n("Choose C for All Items"), p, SLOT(slotChooseCEverywhere()), ac, "dir_choose_c_everywhere"); + d->m_pDirAutoChoiceEverywhere = KDiff3::createAction(i18n("Auto-Choose Operation for All Items"), p, SLOT(slotAutoChooseEverywhere()), ac, "dir_autochoose_everywhere"); + d->m_pDirDoNothingEverywhere = KDiff3::createAction(i18n("No Operation for All Items"), p, SLOT(slotNoOpEverywhere()), ac, "dir_nothing_everywhere"); + + // d->m_pDirSynchronizeDirectories = KDiff3::createAction< KToggleAction >(i18n("Synchronize Directories"), 0, this, SLOT(slotSynchronizeDirectories()), ac, "dir_synchronize_directories"); + // d->m_pDirChooseNewerFiles = KDiff3::createAction< KToggleAction >(i18n("Copy Newer Files Instead of Merging"), 0, this, SLOT(slotChooseNewerFiles()), ac, "dir_choose_newer_files"); + + d->m_pDirShowIdenticalFiles = KDiff3::createAction(i18n("Show Identical Files"), QIcon(QPixmap(showequalfiles)), i18n("Identical\nFiles"), this, SLOT(slotShowIdenticalFiles()), ac, "dir_show_identical_files"); + d->m_pDirShowDifferentFiles = KDiff3::createAction(i18n("Show Different Files"), this, SLOT(slotShowDifferentFiles()), ac, "dir_show_different_files"); + d->m_pDirShowFilesOnlyInA = KDiff3::createAction(i18n("Show Files only in A"), QIcon(QPixmap(showfilesonlyina)), i18n("Files\nonly in A"), this, SLOT(slotShowFilesOnlyInA()), ac, "dir_show_files_only_in_a"); + d->m_pDirShowFilesOnlyInB = KDiff3::createAction(i18n("Show Files only in B"), QIcon(QPixmap(showfilesonlyinb)), i18n("Files\nonly in B"), this, SLOT(slotShowFilesOnlyInB()), ac, "dir_show_files_only_in_b"); + d->m_pDirShowFilesOnlyInC = KDiff3::createAction(i18n("Show Files only in C"), QIcon(QPixmap(showfilesonlyinc)), i18n("Files\nonly in C"), this, SLOT(slotShowFilesOnlyInC()), ac, "dir_show_files_only_in_c"); + + d->m_pDirShowIdenticalFiles->setChecked(d->m_pOptions->m_bDmShowIdenticalFiles); + + d->m_pDirCompareExplicit = KDiff3::createAction(i18n("Compare Explicitly Selected Files"), p, SLOT(slotCompareExplicitlySelectedFiles()), ac, "dir_compare_explicitly_selected_files"); + d->m_pDirMergeExplicit = KDiff3::createAction(i18n("Merge Explicitly Selected Files"), p, SLOT(slotMergeExplicitlySelectedFiles()), ac, "dir_merge_explicitly_selected_files"); + + d->m_pDirCurrentDoNothing = KDiff3::createAction(i18n("Do Nothing"), p, SLOT(slotCurrentDoNothing()), ac, "dir_current_do_nothing"); + d->m_pDirCurrentChooseA = KDiff3::createAction(i18n("A"), p, SLOT(slotCurrentChooseA()), ac, "dir_current_choose_a"); + d->m_pDirCurrentChooseB = KDiff3::createAction(i18n("B"), p, SLOT(slotCurrentChooseB()), ac, "dir_current_choose_b"); + d->m_pDirCurrentChooseC = KDiff3::createAction(i18n("C"), p, SLOT(slotCurrentChooseC()), ac, "dir_current_choose_c"); + d->m_pDirCurrentMerge = KDiff3::createAction(i18n("Merge"), p, SLOT(slotCurrentMerge()), ac, "dir_current_merge"); + d->m_pDirCurrentDelete = KDiff3::createAction(i18n("Delete (if exists)"), p, SLOT(slotCurrentDelete()), ac, "dir_current_delete"); + + d->m_pDirCurrentSyncDoNothing = KDiff3::createAction(i18n("Do Nothing"), p, SLOT(slotCurrentDoNothing()), ac, "dir_current_sync_do_nothing"); + d->m_pDirCurrentSyncCopyAToB = KDiff3::createAction(i18n("Copy A to B"), p, SLOT(slotCurrentCopyAToB()), ac, "dir_current_sync_copy_a_to_b"); + d->m_pDirCurrentSyncCopyBToA = KDiff3::createAction(i18n("Copy B to A"), p, SLOT(slotCurrentCopyBToA()), ac, "dir_current_sync_copy_b_to_a"); + d->m_pDirCurrentSyncDeleteA = KDiff3::createAction(i18n("Delete A"), p, SLOT(slotCurrentDeleteA()), ac, "dir_current_sync_delete_a"); + d->m_pDirCurrentSyncDeleteB = KDiff3::createAction(i18n("Delete B"), p, SLOT(slotCurrentDeleteB()), ac, "dir_current_sync_delete_b"); + d->m_pDirCurrentSyncDeleteAAndB = KDiff3::createAction(i18n("Delete A && B"), p, SLOT(slotCurrentDeleteAAndB()), ac, "dir_current_sync_delete_a_and_b"); + d->m_pDirCurrentSyncMergeToA = KDiff3::createAction(i18n("Merge to A"), p, SLOT(slotCurrentMergeToA()), ac, "dir_current_sync_merge_to_a"); + d->m_pDirCurrentSyncMergeToB = KDiff3::createAction(i18n("Merge to B"), p, SLOT(slotCurrentMergeToB()), ac, "dir_current_sync_merge_to_b"); + d->m_pDirCurrentSyncMergeToAAndB = KDiff3::createAction(i18n("Merge to A && B"), p, SLOT(slotCurrentMergeToAAndB()), ac, "dir_current_sync_merge_to_a_and_b"); +} + +void DirectoryMergeWindow::updateAvailabilities(bool bDirCompare, bool bDiffWindowVisible, + KToggleAction* chooseA, KToggleAction* chooseB, KToggleAction* chooseC) +{ + d->m_pDirStartOperation->setEnabled(bDirCompare); + d->m_pDirRunOperationForCurrentItem->setEnabled(bDirCompare); + d->m_pDirFoldAll->setEnabled(bDirCompare); + d->m_pDirUnfoldAll->setEnabled(bDirCompare); + + d->m_pDirCompareCurrent->setEnabled(bDirCompare && isVisible() && isFileSelected()); + + d->m_pDirMergeCurrent->setEnabled((bDirCompare && isVisible() && isFileSelected()) || bDiffWindowVisible); + + d->m_pDirRescan->setEnabled(bDirCompare); + + d->m_pDirAutoChoiceEverywhere->setEnabled(bDirCompare && isVisible()); + d->m_pDirDoNothingEverywhere->setEnabled(bDirCompare && isVisible()); + d->m_pDirChooseAEverywhere->setEnabled(bDirCompare && isVisible()); + d->m_pDirChooseBEverywhere->setEnabled(bDirCompare && isVisible()); + d->m_pDirChooseCEverywhere->setEnabled(bDirCompare && isVisible()); + + bool bThreeDirs = d->m_dirC.isValid(); + + MergeFileInfos* pMFI = d->getMFI(currentIndex()); + + bool bItemActive = bDirCompare && isVisible() && pMFI != 0; // && hasFocus(); + bool bMergeMode = bThreeDirs || !d->m_bSyncMode; + bool bFTConflict = pMFI == 0 ? false : conflictingFileTypes(*pMFI); + + bool bDirWindowHasFocus = isVisible() && hasFocus(); + + d->m_pDirShowIdenticalFiles->setEnabled(bDirCompare && isVisible()); + d->m_pDirShowDifferentFiles->setEnabled(bDirCompare && isVisible()); + d->m_pDirShowFilesOnlyInA->setEnabled(bDirCompare && isVisible()); + d->m_pDirShowFilesOnlyInB->setEnabled(bDirCompare && isVisible()); + d->m_pDirShowFilesOnlyInC->setEnabled(bDirCompare && isVisible() && bThreeDirs); + + d->m_pDirCompareExplicit->setEnabled(bDirCompare && isVisible() && d->m_selection2Index.isValid()); + d->m_pDirMergeExplicit->setEnabled(bDirCompare && isVisible() && d->m_selection2Index.isValid()); + + d->m_pDirCurrentDoNothing->setEnabled(bItemActive && bMergeMode); + d->m_pDirCurrentChooseA->setEnabled(bItemActive && bMergeMode && pMFI->existsInA()); + d->m_pDirCurrentChooseB->setEnabled(bItemActive && bMergeMode && pMFI->existsInB()); + d->m_pDirCurrentChooseC->setEnabled(bItemActive && bMergeMode && pMFI->existsInC()); + d->m_pDirCurrentMerge->setEnabled(bItemActive && bMergeMode && !bFTConflict); + d->m_pDirCurrentDelete->setEnabled(bItemActive && bMergeMode); + if(bDirWindowHasFocus) + { + chooseA->setEnabled(bItemActive && pMFI->existsInA()); + chooseB->setEnabled(bItemActive && pMFI->existsInB()); + chooseC->setEnabled(bItemActive && pMFI->existsInC()); + chooseA->setChecked(false); + chooseB->setChecked(false); + chooseC->setChecked(false); + } + + d->m_pDirCurrentSyncDoNothing->setEnabled(bItemActive && !bMergeMode); + d->m_pDirCurrentSyncCopyAToB->setEnabled(bItemActive && !bMergeMode && pMFI->existsInA()); + d->m_pDirCurrentSyncCopyBToA->setEnabled(bItemActive && !bMergeMode && pMFI->existsInB()); + d->m_pDirCurrentSyncDeleteA->setEnabled(bItemActive && !bMergeMode && pMFI->existsInA()); + d->m_pDirCurrentSyncDeleteB->setEnabled(bItemActive && !bMergeMode && pMFI->existsInB()); + d->m_pDirCurrentSyncDeleteAAndB->setEnabled(bItemActive && !bMergeMode && pMFI->existsInA() && pMFI->existsInB()); + d->m_pDirCurrentSyncMergeToA->setEnabled(bItemActive && !bMergeMode && !bFTConflict); + d->m_pDirCurrentSyncMergeToB->setEnabled(bItemActive && !bMergeMode && !bFTConflict); + d->m_pDirCurrentSyncMergeToAAndB->setEnabled(bItemActive && !bMergeMode && !bFTConflict); } - //#include "directorymergewindow.moc" diff --git a/src/fileaccess.cpp b/src/fileaccess.cpp index fe6155d..20233a2 100644 --- a/src/fileaccess.cpp +++ b/src/fileaccess.cpp @@ -1,1788 +1,1784 @@ /*************************************************************************** * Copyright (C) 2003-2011 by Joachim Eibl * * joachim.eibl at gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "fileaccess.h" -#include "progress.h" #include "common.h" +#include "progress.h" #include -#include -#include #include +#include #include +#include -#include #include +#include +#include +#include #include +#include #include -#include #include -#include #include -#include -#include #include +#include #ifdef _WIN32 -#include #include -#include #include +#include +#include #else -#include // Needed for creating symbolic links via symlink(). +#include // Needed for creating symbolic links via symlink(). #include #endif - class FileAccess::Data { -public: - Data() - { - reset(); - } - void reset() - { - m_url = QUrl(); - m_bValidData = false; - m_name = QString(); - //m_creationTime = QDateTime(); - //m_accessTime = QDateTime(); - m_bReadable = false; - m_bExecutable = false; - m_linkTarget = ""; - //m_fileType = -1; - m_bLocal = true; - m_pParent = 0; - } - - QUrl m_url; - bool m_bLocal; - bool m_bValidData; - - //QDateTime m_accessTime; - //QDateTime m_creationTime; - bool m_bReadable; - bool m_bExecutable; - //long m_fileType; // for testing only - FileAccess* m_pParent; - - QString m_linkTarget; - //QString m_user; - //QString m_group; - QString m_name; - QString m_localCopy; - QString m_statusText; // Might contain an error string, when the last operation didn't succeed. -}; + public: + Data() + { + reset(); + } + void reset() + { + m_url = QUrl(); + m_bValidData = false; + m_name = QString(); + //m_creationTime = QDateTime(); + //m_accessTime = QDateTime(); + m_bReadable = false; + m_bExecutable = false; + m_linkTarget = ""; + //m_fileType = -1; + m_bLocal = true; + m_pParent = 0; + } + QUrl m_url; + bool m_bLocal; + bool m_bValidData; + + //QDateTime m_accessTime; + //QDateTime m_creationTime; + bool m_bReadable; + bool m_bExecutable; + //long m_fileType; // for testing only + FileAccess* m_pParent; + + QString m_linkTarget; + //QString m_user; + //QString m_group; + QString m_name; + QString m_localCopy; + QString m_statusText; // Might contain an error string, when the last operation didn't succeed. +}; -FileAccess::FileAccess( const QString& name, bool bWantToWrite ) +FileAccess::FileAccess(const QString& name, bool bWantToWrite) { - m_pData = 0; - m_bUseData = false; - setFile( name, bWantToWrite ); + m_pData = 0; + m_bUseData = false; + setFile(name, bWantToWrite); } FileAccess::FileAccess() { - m_bUseData = false; - m_bExists = false; - m_bFile = false; - m_bDir = false; - m_bSymLink = false; - m_bWritable = false; - m_bHidden = false; - m_pParent = 0; - m_size = 0; + m_bUseData = false; + m_bExists = false; + m_bFile = false; + m_bDir = false; + m_bSymLink = false; + m_bWritable = false; + m_bHidden = false; + m_pParent = 0; + m_size = 0; } FileAccess::FileAccess(const FileAccess& other) { - m_pData = 0; - m_bUseData = false; - *this = other; + m_pData = 0; + m_bUseData = false; + *this = other; } void FileAccess::createData() { - if ( d() == 0 ) - { - FileAccess* pParent = m_pParent; // backup because in union with m_pData - m_pData = new Data(); - m_bUseData = true; - m_pData->m_pParent = pParent; - } + if(d() == 0) + { + FileAccess* pParent = m_pParent; // backup because in union with m_pData + m_pData = new Data(); + m_bUseData = true; + m_pData->m_pParent = pParent; + } } const FileAccess& FileAccess::operator=(const FileAccess& other) { - m_size = other.m_size; - m_filePath = other.m_filePath; - m_modificationTime = other.m_modificationTime; - m_bSymLink = other.m_bSymLink; - m_bFile = other.m_bFile; - m_bDir = other.m_bDir; - m_bExists = other.m_bExists; - m_bWritable = other.m_bWritable; - m_bHidden = other.m_bHidden; - - if ( other.m_bUseData ) - { - createData(); - *m_pData = *other.m_pData; - } - else - { - if ( m_bUseData ) - { - delete m_pData; - } - m_bUseData = false; - m_pParent = other.parent(); // should be 0 anyway - } - return *this; + m_size = other.m_size; + m_filePath = other.m_filePath; + m_modificationTime = other.m_modificationTime; + m_bSymLink = other.m_bSymLink; + m_bFile = other.m_bFile; + m_bDir = other.m_bDir; + m_bExists = other.m_bExists; + m_bWritable = other.m_bWritable; + m_bHidden = other.m_bHidden; + + if(other.m_bUseData) + { + createData(); + *m_pData = *other.m_pData; + } + else + { + if(m_bUseData) + { + delete m_pData; + } + m_bUseData = false; + m_pParent = other.parent(); // should be 0 anyway + } + return *this; } FileAccess::~FileAccess() { - if ( m_bUseData ) - { - if( ! d()->m_localCopy.isEmpty() ) - { - removeTempFile( d()->m_localCopy ); - } - delete m_pData; - } + if(m_bUseData) + { + if(!d()->m_localCopy.isEmpty()) + { + removeTempFile(d()->m_localCopy); + } + delete m_pData; + } } -static QString nicePath( const QFileInfo& fi ) +static QString nicePath(const QFileInfo& fi) { - QString fp = fi.filePath(); - if ( fp.length()>2 && fp[0] == '.' && fp[1] == '/' ) - { - return fp.mid(2); - } - return fp; + QString fp = fi.filePath(); + if(fp.length() > 2 && fp[0] == '.' && fp[1] == '/') + { + return fp.mid(2); + } + return fp; } // Two kinds of optimization are applied here: // 1. Speed: don't ask for data as long as it is not needed or cheap to get. // When opening a file it is early enough to ask for details. // 2. Memory usage: Don't store data that is not needed, and avoid redundancy. // For recursive directory trees don't store the full path if a parent is available. // Store urls only if files are not local. -void FileAccess::setFile( const QFileInfo& fi, FileAccess* pParent ) +void FileAccess::setFile(const QFileInfo& fi, FileAccess* pParent) { - m_filePath = pParent == 0 ? fi.absoluteFilePath() : - nicePath( fi.filePath() ); // remove "./" at start + m_filePath = pParent == 0 ? fi.absoluteFilePath() : nicePath(fi.filePath()); // remove "./" at start - m_bSymLink = fi.isSymLink(); - if ( m_bSymLink || (!m_bExists && m_filePath.contains("@@") ) ) - { - createData(); - } + m_bSymLink = fi.isSymLink(); + if(m_bSymLink || (!m_bExists && m_filePath.contains("@@"))) + { + createData(); + } - if ( m_bUseData ) - d()->m_pParent = pParent; - else - m_pParent = pParent; - - if ( parent() || d() ) // if a parent is specified then we arrive here because of listing a directory - { - m_bFile = fi.isFile(); - m_bDir = fi.isDir(); - m_bExists = fi.exists(); - m_size = fi.size(); - m_modificationTime = fi.lastModified(); - m_bHidden = fi.isHidden(); + if(m_bUseData) + d()->m_pParent = pParent; + else + m_pParent = pParent; + + if(parent() || d()) // if a parent is specified then we arrive here because of listing a directory + { + m_bFile = fi.isFile(); + m_bDir = fi.isDir(); + m_bExists = fi.exists(); + m_size = fi.size(); + m_modificationTime = fi.lastModified(); + m_bHidden = fi.isHidden(); #if defined(Q_WS_WIN) - m_bWritable = pParent == 0 || fi.isWritable(); // in certain situations this might become a problem though + m_bWritable = pParent == 0 || fi.isWritable(); // in certain situations this might become a problem though #else - m_bWritable = fi.isWritable(); + m_bWritable = fi.isWritable(); #endif - } - - if ( d() != 0 ) - { + } + + if(d() != 0) + { #if defined(Q_WS_WIN) - // On some windows machines in a network this takes very long. - // and it's not so important anyway. - d()->m_bReadable = true; - d()->m_bExecutable = false; + // On some windows machines in a network this takes very long. + // and it's not so important anyway. + d()->m_bReadable = true; + d()->m_bExecutable = false; #else - d()->m_bReadable = fi.isReadable(); - d()->m_bExecutable = fi.isExecutable(); + d()->m_bReadable = fi.isReadable(); + d()->m_bExecutable = fi.isExecutable(); #endif - //d()->m_creationTime = fi.created(); - //d()->m_modificationTime = fi.lastModified(); - //d()->m_accessTime = fi.lastRead(); - d()->m_name = fi.fileName(); - if ( m_bSymLink ) - { + //d()->m_creationTime = fi.created(); + //d()->m_modificationTime = fi.lastModified(); + //d()->m_accessTime = fi.lastRead(); + d()->m_name = fi.fileName(); + if(m_bSymLink) + { #ifdef _WIN32 - d()->m_linkTarget = fi.readLink(); -#else - // TODO: Update for Qt5. - // Unfortunately Qt4 readLink always returns an absolute path, even if the link is relative - char s[PATH_MAX+1]; - int len = readlink(QFile::encodeName(fi.absoluteFilePath()).constData(), s, PATH_MAX); - if ( len>0 ) - { - s[len] = '\0'; - d()->m_linkTarget = QFile::decodeName(s); - } - else - { d()->m_linkTarget = fi.readLink(); - } +#else + // TODO: Update for Qt5. + // Unfortunately Qt4 readLink always returns an absolute path, even if the link is relative + char s[PATH_MAX + 1]; + int len = readlink(QFile::encodeName(fi.absoluteFilePath()).constData(), s, PATH_MAX); + if(len > 0) + { + s[len] = '\0'; + d()->m_linkTarget = QFile::decodeName(s); + } + else + { + d()->m_linkTarget = fi.readLink(); + } #endif - } - d()->m_bLocal = true; - d()->m_bValidData = true; - d()->m_url = QUrl::fromLocalFile( fi.filePath() ); - if ( d()->m_url.isRelative() ) - { - d()->m_url.setPath( absoluteFilePath() ); - } - - if ( !m_bExists && absoluteFilePath().contains("@@") ) - { - // Try reading a clearcase file - d()->m_localCopy = FileAccess::tempFileName(); - QString cmd = "cleartool get -to \"" + d()->m_localCopy + "\" \"" + absoluteFilePath() + "\""; - QProcess process; - process.start( cmd ); - process.waitForFinished(-1); - //::system( cmd.local8Bit() ); - QFile::setPermissions( d()->m_localCopy, QFile::ReadUser | QFile::WriteUser ); // Clearcase creates a write protected file, allow delete. - - QFileInfo fi( d()->m_localCopy ); + } + d()->m_bLocal = true; + d()->m_bValidData = true; + d()->m_url = QUrl::fromLocalFile(fi.filePath()); + if(d()->m_url.isRelative()) + { + d()->m_url.setPath(absoluteFilePath()); + } + + if(!m_bExists && absoluteFilePath().contains("@@")) + { + // Try reading a clearcase file + d()->m_localCopy = FileAccess::tempFileName(); + QString cmd = "cleartool get -to \"" + d()->m_localCopy + "\" \"" + absoluteFilePath() + "\""; + QProcess process; + process.start(cmd); + process.waitForFinished(-1); + //::system( cmd.local8Bit() ); + QFile::setPermissions(d()->m_localCopy, QFile::ReadUser | QFile::WriteUser); // Clearcase creates a write protected file, allow delete. + + QFileInfo fi(d()->m_localCopy); #if defined(Q_WS_WIN) - d()->m_bReadable = true;//fi.isReadable(); - m_bWritable = true;//fi.isWritable(); - d()->m_bExecutable = false;//fi.isExecutable(); + d()->m_bReadable = true; //fi.isReadable(); + m_bWritable = true; //fi.isWritable(); + d()->m_bExecutable = false; //fi.isExecutable(); #else - d()->m_bReadable = fi.isReadable(); - d()->m_bExecutable = fi.isExecutable(); + d()->m_bReadable = fi.isReadable(); + d()->m_bExecutable = fi.isExecutable(); #endif - //d()->m_creationTime = fi.created(); - //d()->m_accessTime = fi.lastRead(); - m_bExists = fi.exists(); - m_size = fi.size(); - } - } + //d()->m_creationTime = fi.created(); + //d()->m_accessTime = fi.lastRead(); + m_bExists = fi.exists(); + m_size = fi.size(); + } + } } -void FileAccess::setFile( const QString& name, bool bWantToWrite ) +void FileAccess::setFile(const QString& name, bool bWantToWrite) { - m_bExists = false; - m_bFile = false; - m_bDir = false; - m_bSymLink = false; - m_size = 0; - m_modificationTime = QDateTime(); + m_bExists = false; + m_bFile = false; + m_bDir = false; + m_bSymLink = false; + m_size = 0; + m_modificationTime = QDateTime(); - if ( d()!=0 ) - { - d()->reset(); - d()->m_pParent = 0; - } - else - m_pParent = 0; + if(d() != 0) + { + d()->reset(); + d()->m_pParent = 0; + } + else + m_pParent = 0; - // 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() ) - { - QUrl url = QUrl::fromUserInput(name, QString(), QUrl::AssumeLocalFile); - - // FileAccess tries to detect if the given name is an URL or a local file. - // This is a problem if the filename looks like an URL (i.e. contains a colon ':'). - // e.g. "file:f.txt" is a valid filename. - // Most of the time it is sufficient to check if the file exists locally. - // 2 Problems remain: - // 1. When the local file exists and the remote location is wanted nevertheless. (unlikely) - // 2. When the local file doesn't exist and should be written to. - - bool bExistsLocal = QDir().exists(name); - if ( url.isLocalFile() || url.isRelative() || !url.isValid() || bExistsLocal ) // assuming that invalid means relative - { - QString localName = name; + // 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()) + { + QUrl url = QUrl::fromUserInput(name, QString(), QUrl::AssumeLocalFile); + + // FileAccess tries to detect if the given name is an URL or a local file. + // This is a problem if the filename looks like an URL (i.e. contains a colon ':'). + // e.g. "file:f.txt" is a valid filename. + // Most of the time it is sufficient to check if the file exists locally. + // 2 Problems remain: + // 1. When the local file exists and the remote location is wanted nevertheless. (unlikely) + // 2. When the local file doesn't exist and should be written to. + + bool bExistsLocal = QDir().exists(name); + if(url.isLocalFile() || url.isRelative() || !url.isValid() || bExistsLocal) // assuming that invalid means relative + { + QString localName = name; #if defined(Q_WS_WIN) - if ( localName.startsWith("/tmp/") ) - { - // git on Cygwin will put files in /tmp - // A workaround for the a native kdiff3 binary to find them... - - QString cygwinBin = getenv("CYGWIN_BIN"); - if ( !cygwinBin.isEmpty() ) + if(localName.startsWith("/tmp/")) { - localName = QString("%1\\..%2").arg(cygwinBin).arg(name); + // git on Cygwin will put files in /tmp + // A workaround for the a native kdiff3 binary to find them... + + QString cygwinBin = getenv("CYGWIN_BIN"); + if(!cygwinBin.isEmpty()) + { + localName = QString("%1\\..%2").arg(cygwinBin).arg(name); + } } - } #endif - if ( !bExistsLocal && url.isLocalFile() && name.left(5).toLower()=="file:" ) - { - localName = url.path(); // I want the path without preceding "file:" - } - - QFileInfo fi( localName ); - setFile( fi, 0 ); - } - else - { - createData(); - d()->m_url = url; - d()->m_name = d()->m_url.fileName(); - d()->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_filePath = name; - d()->m_bValidData = true; // After running stat() the variables are initialised - // and valid even if the file doesn't exist and the stat - // query failed. - } - } + if(!bExistsLocal && url.isLocalFile() && name.left(5).toLower() == "file:") + { + localName = url.path(); // I want the path without preceding "file:" + } + + QFileInfo fi(localName); + setFile(fi, 0); + } + else + { + createData(); + d()->m_url = url; + d()->m_name = d()->m_url.fileName(); + d()->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_filePath = name; + d()->m_bValidData = true; // After running stat() the variables are initialised + // and valid even if the file doesn't exist and the stat + // query failed. + } + } } -void FileAccess::addPath( const QString& txt ) +void FileAccess::addPath(const QString& txt) { - if ( d()!=0 && d()->m_url.isValid() ) - { - QUrl url = d()->m_url.adjusted(QUrl::StripTrailingSlash); - d()->m_url.setPath(url.path()+'/'+txt ); - setFile( d()->m_url.url() ); // reinitialise - } - else - { - QString slash = (txt.isEmpty() || txt[0]=='/') ? "" : "/"; - setFile( absoluteFilePath() + slash + txt ); - } + if(d() != 0 && d()->m_url.isValid()) + { + QUrl url = d()->m_url.adjusted(QUrl::StripTrailingSlash); + d()->m_url.setPath(url.path() + '/' + txt); + setFile(d()->m_url.url()); // reinitialise + } + else + { + QString slash = (txt.isEmpty() || txt[0] == '/') ? "" : "/"; + setFile(absoluteFilePath() + slash + txt); + } } /* Filetype: S_IFMT 0170000 bitmask for the file type bitfields S_IFSOCK 0140000 socket S_IFLNK 0120000 symbolic link S_IFREG 0100000 regular file S_IFBLK 0060000 block device S_IFDIR 0040000 directory S_IFCHR 0020000 character device S_IFIFO 0010000 fifo S_ISUID 0004000 set UID bit S_ISGID 0002000 set GID bit (see below) S_ISVTX 0001000 sticky bit (see below) Access: S_IRWXU 00700 mask for file owner permissions S_IRUSR 00400 owner has read permission S_IWUSR 00200 owner has write permission S_IXUSR 00100 owner has execute permission S_IRWXG 00070 mask for group permissions S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 mask for permissions for others (not in group) S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permisson S_IXOTH 00001 others have execute permission */ //TODO: Change this to kf5/kde auto test #ifdef KREPLACEMENTS_H -void FileAccess::setUdsEntry( const KIO::UDSEntry& ){} // not needed if KDE is not available +void FileAccess::setUdsEntry(const KIO::UDSEntry&) +{ +} // not needed if KDE is not available #else -void FileAccess::setUdsEntry( const KIO::UDSEntry& e ) +void FileAccess::setUdsEntry(const KIO::UDSEntry& e) { - long acc = 0; - long fileType = 0; - QVector< uint > fields = e.fields(); - for( QVector< uint >::ConstIterator ei=fields.constBegin(); ei!=fields.constEnd(); ++ei ) - { - uint f = *ei; - switch( f ) - { - case KIO::UDSEntry::UDS_SIZE : m_size = e.numberValue(f); break; - //case KIO::UDSEntry::UDS_USER : d()->m_user = e.stringValue(f); break; - //case KIO::UDSEntry::UDS_GROUP : d()->m_group = e.stringValue(f); break; - case KIO::UDSEntry::UDS_NAME : m_filePath = e.stringValue(f); break; // During listDir the relative path is given here. - case KIO::UDSEntry::UDS_MODIFICATION_TIME : m_modificationTime.setTime_t( e.numberValue(f) ); break; - //case KIO::UDSEntry::UDS_ACCESS_TIME : d()->m_accessTime.setTime_t( e.numberValue(f) ); break; - //case KIO::UDSEntry::UDS_CREATION_TIME : d()->m_creationTime.setTime_t( e.numberValue(f) ); break; - case KIO::UDSEntry::UDS_LINK_DEST : d()->m_linkTarget = e.stringValue(f); break; - case KIO::UDSEntry::UDS_ACCESS : - { + long acc = 0; + long fileType = 0; + QVector fields = e.fields(); + for(QVector::ConstIterator ei = fields.constBegin(); ei != fields.constEnd(); ++ei) + { + uint f = *ei; + switch(f) + { + case KIO::UDSEntry::UDS_SIZE: + m_size = e.numberValue(f); + break; + //case KIO::UDSEntry::UDS_USER : d()->m_user = e.stringValue(f); break; + //case KIO::UDSEntry::UDS_GROUP : d()->m_group = e.stringValue(f); break; + case KIO::UDSEntry::UDS_NAME: + m_filePath = e.stringValue(f); + break; // During listDir the relative path is given here. + case KIO::UDSEntry::UDS_MODIFICATION_TIME: + m_modificationTime.setTime_t(e.numberValue(f)); + break; + //case KIO::UDSEntry::UDS_ACCESS_TIME : d()->m_accessTime.setTime_t( e.numberValue(f) ); break; + //case KIO::UDSEntry::UDS_CREATION_TIME : d()->m_creationTime.setTime_t( e.numberValue(f) ); break; + case KIO::UDSEntry::UDS_LINK_DEST: + d()->m_linkTarget = e.stringValue(f); + break; + case KIO::UDSEntry::UDS_ACCESS: + { acc = e.numberValue(f); - d()->m_bReadable = (acc & S_IRUSR)!=0; - m_bWritable = (acc & S_IWUSR)!=0; - d()->m_bExecutable = (acc & S_IXUSR)!=0; + d()->m_bReadable = (acc & S_IRUSR) != 0; + m_bWritable = (acc & S_IWUSR) != 0; + d()->m_bExecutable = (acc & S_IXUSR) != 0; break; - } - case KIO::UDSEntry::UDS_FILE_TYPE : - { + } + case KIO::UDSEntry::UDS_FILE_TYPE: + { fileType = e.numberValue(f); - 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_bDir = (fileType & S_IFMT) == S_IFDIR; + m_bFile = (fileType & S_IFMT) == S_IFREG; + m_bSymLink = (fileType & S_IFMT) == S_IFLNK; + m_bExists = fileType != 0; //d()->m_fileType = fileType; break; - } - - case KIO::UDSEntry::UDS_URL : // m_url = QUrlFix( e.stringValue(f) ); - break; - case KIO::UDSEntry::UDS_MIME_TYPE : break; - case KIO::UDSEntry::UDS_GUESSED_MIME_TYPE : break; - case KIO::UDSEntry::UDS_XML_PROPERTIES : break; - default: break; - } - } + } - m_bExists = acc!=0 || fileType!=0; + case KIO::UDSEntry::UDS_URL: // m_url = QUrlFix( e.stringValue(f) ); + break; + case KIO::UDSEntry::UDS_MIME_TYPE: + break; + case KIO::UDSEntry::UDS_GUESSED_MIME_TYPE: + break; + case KIO::UDSEntry::UDS_XML_PROPERTIES: + break; + default: + break; + } + } - d()->m_bLocal = false; - d()->m_bValidData = true; - m_bSymLink = !d()->m_linkTarget.isEmpty(); - if ( d()->m_name.isEmpty() ) - { - int pos = m_filePath.lastIndexOf('/') + 1; - d()->m_name = m_filePath.mid( pos ); - } - m_bHidden = d()->m_name[0]=='.'; + m_bExists = acc != 0 || fileType != 0; + + d()->m_bLocal = false; + d()->m_bValidData = true; + m_bSymLink = !d()->m_linkTarget.isEmpty(); + if(d()->m_name.isEmpty()) + { + int pos = m_filePath.lastIndexOf('/') + 1; + d()->m_name = m_filePath.mid(pos); + } + m_bHidden = d()->m_name[0] == '.'; } #endif - -bool FileAccess::isValid() const -{ - return d()==0 ? !m_filePath.isEmpty() : d()->m_bValidData; +bool FileAccess::isValid() const +{ + return d() == 0 ? !m_filePath.isEmpty() : d()->m_bValidData; } -bool FileAccess::isFile() const +bool FileAccess::isFile() const { - if ( parent() || d() ) - return m_bFile; - else - return QFileInfo( absoluteFilePath() ).isFile(); + if(parent() || d()) + return m_bFile; + else + return QFileInfo(absoluteFilePath()).isFile(); } -bool FileAccess::isDir() const -{ - if ( parent() || d() ) - return m_bDir; - else - return QFileInfo( absoluteFilePath() ).isDir(); +bool FileAccess::isDir() const +{ + if(parent() || d()) + return m_bDir; + else + return QFileInfo(absoluteFilePath()).isDir(); } -bool FileAccess::isSymLink() const -{ - return m_bSymLink; +bool FileAccess::isSymLink() const +{ + return m_bSymLink; } -bool FileAccess::exists() const -{ - if ( parent() || d()) - return m_bExists; - else - return QFileInfo::exists(absoluteFilePath()); +bool FileAccess::exists() const +{ + if(parent() || d()) + return m_bExists; + else + return QFileInfo::exists(absoluteFilePath()); } -qint64 FileAccess::size() const +qint64 FileAccess::size() const { - if ( parent() || d()) - return m_size; - else - return QFileInfo( absoluteFilePath() ).size(); + if(parent() || d()) + return m_size; + else + return QFileInfo(absoluteFilePath()).size(); } QUrl FileAccess::url() const -{ - if ( d()!=0 ) - return d()->m_url; - else - { - QUrl url = QUrl::fromLocalFile( m_filePath ); - if ( url.isRelative() ) - { - url.setPath( absoluteFilePath() ); - } - return url; - } +{ + if(d() != 0) + return d()->m_url; + else + { + QUrl url = QUrl::fromLocalFile(m_filePath); + if(url.isRelative()) + { + url.setPath(absoluteFilePath()); + } + return url; + } } -bool FileAccess::isLocal() const -{ - return d()==0 || d()->m_bLocal; +bool FileAccess::isLocal() const +{ + return d() == 0 || d()->m_bLocal; } -bool FileAccess::isReadable() const +bool FileAccess::isReadable() const { #if defined(Q_WS_WIN) - // On some windows machines in a network this takes very long to find out and it's not so important anyway. - return true; + // On some windows machines in a network this takes very long to find out and it's not so important anyway. + return true; #else - if ( d()!=0 ) - return d()->m_bReadable; - else - return QFileInfo( absoluteFilePath() ).isReadable(); + if(d() != 0) + return d()->m_bReadable; + else + return QFileInfo(absoluteFilePath()).isReadable(); #endif } -bool FileAccess::isWritable() const +bool FileAccess::isWritable() const { - if ( parent() || d()) - return m_bWritable; - else - return QFileInfo( absoluteFilePath() ).isWritable(); + if(parent() || d()) + return m_bWritable; + else + return QFileInfo(absoluteFilePath()).isWritable(); } -bool FileAccess::isExecutable() const +bool FileAccess::isExecutable() const { #if defined(Q_WS_WIN) - // On some windows machines in a network this takes very long to find out and it's not so important anyway. - return true; + // On some windows machines in a network this takes very long to find out and it's not so important anyway. + return true; #else - if ( d()!=0 ) - return d()->m_bExecutable; - else - return QFileInfo( absoluteFilePath() ).isExecutable(); + if(d() != 0) + return d()->m_bExecutable; + else + return QFileInfo(absoluteFilePath()).isExecutable(); #endif } -bool FileAccess::isHidden() const -{ - if ( parent() || d() ) - return m_bHidden; - else - return QFileInfo( absoluteFilePath() ).isHidden(); +bool FileAccess::isHidden() const +{ + if(parent() || d()) + return m_bHidden; + else + return QFileInfo(absoluteFilePath()).isHidden(); } -QString FileAccess::readLink() const +QString FileAccess::readLink() const { - if ( d()!=0 ) - return d()->m_linkTarget; - else - return QString(); + if(d() != 0) + return d()->m_linkTarget; + else + return QString(); } QString FileAccess::absoluteFilePath() const { - if ( parent() != 0 ) - return parent()->absoluteFilePath() + "/" + m_filePath; - else - { - if ( m_filePath.isEmpty() ) - return QString(); - - if ( ! isLocal() ) - return m_filePath; // return complete url - - QFileInfo fi( m_filePath ); - if ( fi.isAbsolute() ) - return m_filePath; - else - return fi.absoluteFilePath(); // Probably never reached - } -} // Full abs path + if(parent() != 0) + return parent()->absoluteFilePath() + "/" + m_filePath; + else + { + if(m_filePath.isEmpty()) + return QString(); + + if(!isLocal()) + return m_filePath; // return complete url + + QFileInfo fi(m_filePath); + if(fi.isAbsolute()) + return m_filePath; + else + return fi.absoluteFilePath(); // Probably never reached + } +} // Full abs path // Just the name-part of the path, without parent directories QString FileAccess::fileName() const { - if ( d()!=0 ) - return d()->m_name; - else if ( parent() ) - return m_filePath; - else - return QFileInfo( m_filePath ).fileName(); + if(d() != 0) + return d()->m_name; + else if(parent()) + return m_filePath; + else + return QFileInfo(m_filePath).fileName(); } void FileAccess::setSharedName(const QString& name) { - if ( name == m_filePath ) - m_filePath = name; // reduce memory because string is only used once. + if(name == m_filePath) + m_filePath = name; // reduce memory because string is only used once. } -QString FileAccess::filePath() const -{ - if ( parent() && parent()->parent() ) - return parent()->filePath() + "/" + m_filePath; - else - return m_filePath; // The path-string that was used during construction +QString FileAccess::filePath() const +{ + if(parent() && parent()->parent()) + return parent()->filePath() + "/" + m_filePath; + else + return m_filePath; // The path-string that was used during construction } FileAccess* FileAccess::parent() const { - if ( m_bUseData ) - return d()->m_pParent; - else - return m_pParent; + if(m_bUseData) + return d()->m_pParent; + else + return m_pParent; } FileAccess::Data* FileAccess::d() { - if ( m_bUseData ) - return m_pData; - else - return 0; + if(m_bUseData) + return m_pData; + else + return 0; } const FileAccess::Data* FileAccess::d() const { - if ( m_bUseData ) - return m_pData; - else - return 0; + if(m_bUseData) + return m_pData; + else + return 0; } -QString FileAccess::prettyAbsPath() const +QString FileAccess::prettyAbsPath() const { - return isLocal() ? absoluteFilePath() : d()->m_url.toDisplayString(); + return isLocal() ? absoluteFilePath() : d()->m_url.toDisplayString(); } /* QDateTime FileAccess::created() const { if ( d()!=0 ) { if ( isLocal() && d()->m_creationTime.isNull() ) const_cast(this)->d()->m_creationTime = QFileInfo( absoluteFilePath() ).created(); return ( d()->m_creationTime.isValid() ? d()->m_creationTime : lastModified() ); } else { QDateTime created = QFileInfo( absoluteFilePath() ).created(); return created.isValid() ? created : lastModified(); } } */ QDateTime FileAccess::lastModified() const { - if ( isLocal() && m_modificationTime.isNull() ) - const_cast(this)->m_modificationTime = QFileInfo( absoluteFilePath() ).lastModified(); - return m_modificationTime; + if(isLocal() && m_modificationTime.isNull()) + const_cast(this)->m_modificationTime = QFileInfo(absoluteFilePath()).lastModified(); + return m_modificationTime; } /* QDateTime FileAccess::lastRead() const { QDateTime accessTime = d()!=0 ? d()->m_accessTime : QFileInfo( absoluteFilePath() ).lastRead(); return ( accessTime.isValid() ? accessTime : lastModified() ); } */ -static bool interruptableReadFile( QFile& f, void* pDestBuffer, unsigned long maxLength ) +static bool interruptableReadFile(QFile& f, void* pDestBuffer, unsigned long maxLength) { - ProgressProxy pp; - const unsigned long maxChunkSize = 100000; - unsigned long i=0; - pp.setMaxNofSteps( maxLength / maxChunkSize + 1 ); - while( im_localCopy.isEmpty() ) - { - QFile f( d()->m_localCopy ); - if ( f.open( QIODevice::ReadOnly ) ) - return interruptableReadFile(f, pDestBuffer, maxLength);// maxLength == f.read( (char*)pDestBuffer, maxLength ); - } - else if (isLocal()) - { - QFile f( absoluteFilePath() ); + if(d() != 0 && !d()->m_localCopy.isEmpty()) + { + QFile f(d()->m_localCopy); + if(f.open(QIODevice::ReadOnly)) + return interruptableReadFile(f, pDestBuffer, maxLength); // maxLength == f.read( (char*)pDestBuffer, maxLength ); + } + else if(isLocal()) + { + QFile f(absoluteFilePath()); - if ( f.open( QIODevice::ReadOnly ) ) - return interruptableReadFile(f, pDestBuffer, maxLength); //maxLength == f.read( (char*)pDestBuffer, maxLength ); - } - else - { - FileAccessJobHandler jh( this ); - return jh.get( pDestBuffer, maxLength ); - } - return false; + if(f.open(QIODevice::ReadOnly)) + return interruptableReadFile(f, pDestBuffer, maxLength); //maxLength == f.read( (char*)pDestBuffer, maxLength ); + } + else + { + FileAccessJobHandler jh(this); + return jh.get(pDestBuffer, maxLength); + } + return false; } -bool FileAccess::writeFile( const void* pSrcBuffer, unsigned long length ) +bool FileAccess::writeFile(const void* pSrcBuffer, unsigned long length) { - ProgressProxy pp; - if ( isLocal() ) - { - QFile f( absoluteFilePath() ); - if ( f.open( QIODevice::WriteOnly ) ) - { - const unsigned long maxChunkSize = 100000; - pp.setMaxNofSteps( length / maxChunkSize + 1 ); - unsigned long i=0; - while( im_localCopy = localCopy; - return m_size; - } - else - { - return 0; - } - } - else - return size(); + if(!isLocal() && m_size == 0) + { + // 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(); + d()->m_localCopy = localCopy; + return m_size; + } + else + { + return 0; + } + } + else + return size(); } QString FileAccess::getStatusText() { - return d()==0 ? QString() : d()->m_statusText; + return d() == 0 ? QString() : d()->m_statusText; } -void FileAccess::setStatusText( const QString& s ) +void FileAccess::setStatusText(const QString& s) { - if ( ! s.isEmpty() || d() != 0 ) - { - createData(); - d()->m_statusText = s; - } + if(!s.isEmpty() || d() != 0) + { + createData(); + d()->m_statusText = s; + } } -QString FileAccess::cleanPath( const QString& path ) // static +QString FileAccess::cleanPath(const QString& path) // static { - QUrl url = QUrl::fromUserInput(path, QString(""), QUrl::AssumeLocalFile); - if ( url.isLocalFile() || ! url.isValid() ) - { - return QDir().cleanPath( path ); - } - else - { - return path; - } + QUrl url = QUrl::fromUserInput(path, QString(""), QUrl::AssumeLocalFile); + if(url.isLocalFile() || !url.isValid()) + { + return QDir().cleanPath(path); + } + else + { + return path; + } } -bool FileAccess::createBackup( const QString& bakExtension ) +bool FileAccess::createBackup(const QString& bakExtension) { - if ( exists() ) - { - createData(); - setFile( absoluteFilePath() ); // make sure Data is initialized - // First rename the existing file to the bak-file. If a bak-file file exists, delete that. - QString bakName = absoluteFilePath() + bakExtension; - FileAccess bakFile( bakName, true /*bWantToWrite*/ ); - if ( bakFile.exists() ) - { - bool bSuccess = bakFile.removeFile(); - if ( !bSuccess ) - { - setStatusText( i18n("While trying to make a backup, deleting an older backup failed. \nFilename: ") + bakName ); + if(exists()) + { + createData(); + setFile(absoluteFilePath()); // make sure Data is initialized + // First rename the existing file to the bak-file. If a bak-file file exists, delete that. + QString bakName = absoluteFilePath() + bakExtension; + FileAccess bakFile(bakName, true /*bWantToWrite*/); + if(bakFile.exists()) + { + bool bSuccess = bakFile.removeFile(); + if(!bSuccess) + { + setStatusText(i18n("While trying to make a backup, deleting an older backup failed. \nFilename: ") + bakName); + return false; + } + } + bool bSuccess = rename(bakName); + if(!bSuccess) + { + setStatusText(i18n("While trying to make a backup, renaming failed. \nFilenames: ") + + absoluteFilePath() + " -> " + bakName); return false; - } - } - bool bSuccess = rename( bakName ); - if (!bSuccess) - { - setStatusText( i18n("While trying to make a backup, renaming failed. \nFilenames: ") + - absoluteFilePath() + " -> " + bakName ); - return false; - } - } - return true; + } + } + return true; } -FileAccessJobHandler::FileAccessJobHandler( FileAccess* pFileAccess ) +FileAccessJobHandler::FileAccessJobHandler(FileAccess* pFileAccess) { - m_pFileAccess = pFileAccess; - m_bSuccess = false; + m_pFileAccess = pFileAccess; + m_bSuccess = false; } -bool FileAccessJobHandler::stat( int detail, bool bWantToWrite ) +bool FileAccessJobHandler::stat(int detail, bool bWantToWrite) { - m_bSuccess = false; - m_pFileAccess->setStatusText( QString() ); - KIO::StatJob* pStatJob = KIO::stat( m_pFileAccess->url(), - bWantToWrite ? KIO::StatJob::DestinationSide : KIO::StatJob::SourceSide, - detail, KIO::HideProgressInfo ); + m_bSuccess = false; + m_pFileAccess->setStatusText(QString()); + KIO::StatJob* pStatJob = KIO::stat(m_pFileAccess->url(), + bWantToWrite ? KIO::StatJob::DestinationSide : KIO::StatJob::SourceSide, + detail, KIO::HideProgressInfo); - connect(pStatJob, &KIO::StatJob::result, this, &FileAccessJobHandler::slotStatResult); + connect(pStatJob, &KIO::StatJob::result, this, &FileAccessJobHandler::slotStatResult); - ProgressProxy::enterEventLoop( pStatJob, i18n("Getting file status: %1",m_pFileAccess->prettyAbsPath()) ); + ProgressProxy::enterEventLoop(pStatJob, i18n("Getting file status: %1", m_pFileAccess->prettyAbsPath())); - return m_bSuccess; + return m_bSuccess; } void FileAccessJobHandler::slotStatResult(KJob* pJob) { - if ( pJob->error() ) - { - //pJob->uiDelegate()->showErrorMessage(); - m_pFileAccess->m_bExists = false; - m_bSuccess = true; - } - else - { - m_bSuccess = true; + if(pJob->error()) + { + //pJob->uiDelegate()->showErrorMessage(); + m_pFileAccess->m_bExists = false; + m_bSuccess = true; + } + else + { + m_bSuccess = true; - m_pFileAccess->d()->m_bValidData = true; - const KIO::UDSEntry e = static_cast(pJob)->statResult(); + m_pFileAccess->d()->m_bValidData = true; + const KIO::UDSEntry e = static_cast(pJob)->statResult(); - m_pFileAccess->setUdsEntry( e ); - } + m_pFileAccess->setUdsEntry(e); + } - ProgressProxy::exitEventLoop(); + ProgressProxy::exitEventLoop(); } - -bool FileAccessJobHandler::get(void* pDestBuffer, long maxLength ) +bool FileAccessJobHandler::get(void* pDestBuffer, long maxLength) { - ProgressProxyExtender pp; // Implicitly used in slotPercent() - if ( maxLength>0 && !pp.wasCancelled() ) - { - KIO::TransferJob* pJob = KIO::get( m_pFileAccess->url(), KIO::NoReload ); - m_transferredBytes = 0; - m_pTransferBuffer = (char*)pDestBuffer; - m_maxLength = maxLength; - m_bSuccess = false; - m_pFileAccess->setStatusText( QString() ); - - connect(pJob, &KIO::TransferJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); - connect(pJob, &KIO::TransferJob::data, this, &FileAccessJobHandler::slotGetData); - connect(pJob, SIGNAL(percent(KJob*,unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); - - ProgressProxy::enterEventLoop( pJob, i18n("Reading file: %1",m_pFileAccess->prettyAbsPath()) ); - return m_bSuccess; - } - else - return true; + ProgressProxyExtender pp; // Implicitly used in slotPercent() + if(maxLength > 0 && !pp.wasCancelled()) + { + KIO::TransferJob* pJob = KIO::get(m_pFileAccess->url(), KIO::NoReload); + m_transferredBytes = 0; + m_pTransferBuffer = (char*)pDestBuffer; + m_maxLength = maxLength; + m_bSuccess = false; + m_pFileAccess->setStatusText(QString()); + + connect(pJob, &KIO::TransferJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); + connect(pJob, &KIO::TransferJob::data, this, &FileAccessJobHandler::slotGetData); + connect(pJob, SIGNAL(percent(KJob*, unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); + + ProgressProxy::enterEventLoop(pJob, i18n("Reading file: %1", m_pFileAccess->prettyAbsPath())); + return m_bSuccess; + } + else + return true; } -void FileAccessJobHandler::slotGetData( KJob* pJob, const QByteArray& newData ) +void FileAccessJobHandler::slotGetData(KJob* pJob, const QByteArray& newData) { - if ( pJob->error() ) - { - pJob->uiDelegate()->showErrorMessage(); - } - else - { - qint64 length = min2( qint64(newData.size()), m_maxLength - m_transferredBytes ); - ::memcpy( m_pTransferBuffer + m_transferredBytes, newData.data(), newData.size() ); - m_transferredBytes += length; - } + if(pJob->error()) + { + pJob->uiDelegate()->showErrorMessage(); + } + else + { + qint64 length = min2(qint64(newData.size()), m_maxLength - m_transferredBytes); + ::memcpy(m_pTransferBuffer + m_transferredBytes, newData.data(), newData.size()); + m_transferredBytes += length; + } } -bool FileAccessJobHandler::put(const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume, int permissions ) +bool FileAccessJobHandler::put(const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume, int permissions) { - ProgressProxyExtender pp; // Implicitly used in slotPercent() - if ( maxLength>0 ) - { - KIO::TransferJob* pJob = KIO::put( m_pFileAccess->url(), permissions, - KIO::HideProgressInfo | (bOverwrite ? KIO::Overwrite : KIO::DefaultFlags) | (bResume ? KIO::Resume : KIO::DefaultFlags) ); - m_transferredBytes = 0; - m_pTransferBuffer = (char*)pSrcBuffer; - m_maxLength = maxLength; - m_bSuccess = false; - m_pFileAccess->setStatusText( QString() ); - - connect(pJob, &KIO::TransferJob::result, this, &FileAccessJobHandler::slotPutJobResult); - connect(pJob, &KIO::TransferJob::dataReq, this, &FileAccessJobHandler::slotPutData); - connect( pJob, SIGNAL(percent(KJob*,unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); - - ProgressProxy::enterEventLoop( pJob, i18n("Writing file: %1",m_pFileAccess->prettyAbsPath()) ); - return m_bSuccess; - } - else - return true; + ProgressProxyExtender pp; // Implicitly used in slotPercent() + if(maxLength > 0) + { + KIO::TransferJob* pJob = KIO::put(m_pFileAccess->url(), permissions, + KIO::HideProgressInfo | (bOverwrite ? KIO::Overwrite : KIO::DefaultFlags) | (bResume ? KIO::Resume : KIO::DefaultFlags)); + m_transferredBytes = 0; + m_pTransferBuffer = (char*)pSrcBuffer; + m_maxLength = maxLength; + m_bSuccess = false; + m_pFileAccess->setStatusText(QString()); + + connect(pJob, &KIO::TransferJob::result, this, &FileAccessJobHandler::slotPutJobResult); + connect(pJob, &KIO::TransferJob::dataReq, this, &FileAccessJobHandler::slotPutData); + connect(pJob, SIGNAL(percent(KJob*, unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); + + ProgressProxy::enterEventLoop(pJob, i18n("Writing file: %1", m_pFileAccess->prettyAbsPath())); + return m_bSuccess; + } + else + return true; } -void FileAccessJobHandler::slotPutData( KIO::Job* pJob, QByteArray& data ) +void FileAccessJobHandler::slotPutData(KIO::Job* pJob, QByteArray& data) { - if ( pJob->error() ) - { - pJob->uiDelegate()->showErrorMessage(); - } - else - { - qint64 maxChunkSize = 100000; - qint64 length = min2( maxChunkSize, m_maxLength - m_transferredBytes ); - data.resize( length ); - if ( data.size()==length ) - { - if ( length>0 ) - { - ::memcpy( data.data(), m_pTransferBuffer + m_transferredBytes, data.size() ); - m_transferredBytes += length; - } - } - else - { - KMessageBox::error( ProgressProxy::getDialog(), i18n("Out of memory") ); - data.resize(0); - m_bSuccess = false; - } - } + if(pJob->error()) + { + pJob->uiDelegate()->showErrorMessage(); + } + else + { + qint64 maxChunkSize = 100000; + qint64 length = min2(maxChunkSize, m_maxLength - m_transferredBytes); + data.resize(length); + if(data.size() == length) + { + if(length > 0) + { + ::memcpy(data.data(), m_pTransferBuffer + m_transferredBytes, data.size()); + m_transferredBytes += length; + } + } + else + { + KMessageBox::error(ProgressProxy::getDialog(), i18n("Out of memory")); + data.resize(0); + m_bSuccess = false; + } + } } void FileAccessJobHandler::slotPutJobResult(KJob* pJob) { - if ( pJob->error() ) - { - pJob->uiDelegate()->showErrorMessage(); - } - else - { - m_bSuccess = (m_transferredBytes == m_maxLength); // Special success condition - } - ProgressProxy::exitEventLoop(); // Close the dialog, return from exec() + if(pJob->error()) + { + pJob->uiDelegate()->showErrorMessage(); + } + else + { + m_bSuccess = (m_transferredBytes == m_maxLength); // Special success condition + } + ProgressProxy::exitEventLoop(); // Close the dialog, return from exec() } -bool FileAccessJobHandler::mkDir( const QString& dirName ) +bool FileAccessJobHandler::mkDir(const QString& dirName) { - QUrl dirURL = QUrl::fromUserInput(dirName, QString(""), QUrl::AssumeLocalFile); - if ( dirName.isEmpty() ) - return false; - else if ( dirURL.isLocalFile() || dirURL.isRelative() ) - { - return QDir().mkdir( dirURL.path() ); - } - else - { - m_bSuccess = false; - KIO::SimpleJob* pJob = KIO::mkdir( dirURL ); - connect(pJob, &KIO::SimpleJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); + QUrl dirURL = QUrl::fromUserInput(dirName, QString(""), QUrl::AssumeLocalFile); + if(dirName.isEmpty()) + return false; + else if(dirURL.isLocalFile() || dirURL.isRelative()) + { + return QDir().mkdir(dirURL.path()); + } + else + { + m_bSuccess = false; + KIO::SimpleJob* pJob = KIO::mkdir(dirURL); + connect(pJob, &KIO::SimpleJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); - ProgressProxy::enterEventLoop( pJob, i18n("Making directory: %1", dirName) ); - return m_bSuccess; - } + ProgressProxy::enterEventLoop(pJob, i18n("Making directory: %1", dirName)); + return m_bSuccess; + } } -bool FileAccessJobHandler::rmDir( const QString& dirName ) +bool FileAccessJobHandler::rmDir(const QString& dirName) { - QUrl dirURL = QUrl::fromUserInput(dirName, QString(""), QUrl::AssumeLocalFile); - 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, &KIO::SimpleJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); + QUrl dirURL = QUrl::fromUserInput(dirName, QString(""), QUrl::AssumeLocalFile); + 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, &KIO::SimpleJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); - ProgressProxy::enterEventLoop(pJob, i18n("Removing directory: %1",dirName)); - return m_bSuccess; - } + ProgressProxy::enterEventLoop(pJob, i18n("Removing directory: %1", dirName)); + return m_bSuccess; + } } -bool FileAccessJobHandler::removeFile( const QUrl& fileName ) +bool FileAccessJobHandler::removeFile(const QUrl& fileName) { - if ( fileName.isEmpty() ) - return false; - else - { - m_bSuccess = false; - KIO::SimpleJob* pJob = KIO::file_delete( fileName, KIO::HideProgressInfo ); - connect(pJob, &KIO::SimpleJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); + if(fileName.isEmpty()) + return false; + else + { + m_bSuccess = false; + KIO::SimpleJob* pJob = KIO::file_delete(fileName, KIO::HideProgressInfo); + connect(pJob, &KIO::SimpleJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); - ProgressProxy::enterEventLoop( pJob, i18n("Removing file: %1",fileName.toDisplayString()) ); - return m_bSuccess; - } + ProgressProxy::enterEventLoop(pJob, i18n("Removing file: %1", fileName.toDisplayString())); + return m_bSuccess; + } } -bool FileAccessJobHandler::symLink( const QUrl& linkTarget, const QUrl& linkLocation ) +bool FileAccessJobHandler::symLink(const QUrl& linkTarget, const QUrl& linkLocation) { - if ( linkTarget.isEmpty() || linkLocation.isEmpty() ) - return false; - else - { - m_bSuccess = false; - KIO::CopyJob* pJob = KIO::link( linkTarget, linkLocation, KIO::HideProgressInfo ); - connect(pJob, &KIO::CopyJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); + if(linkTarget.isEmpty() || linkLocation.isEmpty()) + return false; + else + { + m_bSuccess = false; + KIO::CopyJob* pJob = KIO::link(linkTarget, linkLocation, KIO::HideProgressInfo); + connect(pJob, &KIO::CopyJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); - ProgressProxy::enterEventLoop( pJob, - i18n("Creating symbolic link: %1 -> %2",linkLocation.toDisplayString(),linkTarget.toDisplayString()) ); - return m_bSuccess; - } + ProgressProxy::enterEventLoop(pJob, + i18n("Creating symbolic link: %1 -> %2", linkLocation.toDisplayString(), linkTarget.toDisplayString())); + return m_bSuccess; + } } -bool FileAccessJobHandler::rename( const QString& dest ) +bool FileAccessJobHandler::rename(const QString& dest) { - if ( dest.isEmpty() ) - return false; + if(dest.isEmpty()) + return false; - QUrl kurl = QUrl::fromUserInput(dest, QString(""), QUrl::AssumeLocalFile); - if ( kurl.isRelative() ) - kurl = QUrl::fromUserInput(QDir().absoluteFilePath(dest), QString(""), QUrl::AssumeLocalFile); // assuming that invalid means relative + QUrl kurl = QUrl::fromUserInput(dest, QString(""), QUrl::AssumeLocalFile); + if(kurl.isRelative()) + kurl = QUrl::fromUserInput(QDir().absoluteFilePath(dest), QString(""), QUrl::AssumeLocalFile); // assuming that invalid means relative - if ( m_pFileAccess->isLocal() && kurl.isLocalFile() ) - { - return QDir().rename( m_pFileAccess->absoluteFilePath(), kurl.path() ); - } - else - { - ProgressProxyExtender pp; - int permissions=-1; - m_bSuccess = false; - KIO::FileCopyJob* pJob = KIO::file_move( m_pFileAccess->url(), kurl, permissions, KIO::HideProgressInfo ); - connect(pJob, &KIO::FileCopyJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); - connect(pJob, SIGNAL(percent(KJob*,unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); - - ProgressProxy::enterEventLoop( pJob, - i18n("Renaming file: %1 -> %2",m_pFileAccess->prettyAbsPath(),dest) ); - return m_bSuccess; - } + if(m_pFileAccess->isLocal() && kurl.isLocalFile()) + { + return QDir().rename(m_pFileAccess->absoluteFilePath(), kurl.path()); + } + else + { + ProgressProxyExtender pp; + int permissions = -1; + m_bSuccess = false; + KIO::FileCopyJob* pJob = KIO::file_move(m_pFileAccess->url(), kurl, permissions, KIO::HideProgressInfo); + connect(pJob, &KIO::FileCopyJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); + connect(pJob, SIGNAL(percent(KJob*, unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); + + ProgressProxy::enterEventLoop(pJob, + i18n("Renaming file: %1 -> %2", m_pFileAccess->prettyAbsPath(), dest)); + return m_bSuccess; + } } void FileAccessJobHandler::slotSimpleJobResult(KJob* pJob) { - if ( pJob->error() ) - { - pJob->uiDelegate()->showErrorMessage(); - } - else - { - m_bSuccess = true; - } - ProgressProxy::exitEventLoop(); // Close the dialog, return from exec() + if(pJob->error()) + { + pJob->uiDelegate()->showErrorMessage(); + } + else + { + m_bSuccess = true; + } + ProgressProxy::exitEventLoop(); // Close the dialog, return from exec() } - // Copy local or remote files. -bool FileAccessJobHandler::copyFile( const QString& dest ) +bool FileAccessJobHandler::copyFile(const QString& dest) { - ProgressProxyExtender pp; - QUrl destUrl = QUrl::fromUserInput(dest, QString(""), QUrl::AssumeLocalFile); - m_pFileAccess->setStatusText( QString() ); - if ( ! m_pFileAccess->isLocal() || !destUrl.isLocalFile() ) // if either url is nonlocal - { - 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->url(), destUrl, permissions, KIO::HideProgressInfo ); - connect(pJob, &KIO::FileCopyJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); - connect(pJob, SIGNAL(percent(KJob*,unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); - ProgressProxy::enterEventLoop( pJob, - i18n("Copying file: %1 -> %2",m_pFileAccess->prettyAbsPath(),dest) ); - - return m_bSuccess; - // Note that the KIO-slave preserves the original date, if this is supported. - } + ProgressProxyExtender pp; + QUrl destUrl = QUrl::fromUserInput(dest, QString(""), QUrl::AssumeLocalFile); + m_pFileAccess->setStatusText(QString()); + if(!m_pFileAccess->isLocal() || !destUrl.isLocalFile()) // if either url is nonlocal + { + 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->url(), destUrl, permissions, KIO::HideProgressInfo); + connect(pJob, &KIO::FileCopyJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); + connect(pJob, SIGNAL(percent(KJob*, unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); + ProgressProxy::enterEventLoop(pJob, + i18n("Copying file: %1 -> %2", m_pFileAccess->prettyAbsPath(), dest)); + + return m_bSuccess; + // Note that the KIO-slave preserves the original date, if this is supported. + } - // Both files are local: - QString srcName = m_pFileAccess->absoluteFilePath(); - QString destName = dest; - QFile srcFile( srcName ); - QFile destFile( destName ); - bool bReadSuccess = srcFile.open( QIODevice::ReadOnly ); - if ( bReadSuccess == false ) - { - m_pFileAccess->setStatusText( i18n("Error during file copy operation: Opening file for reading failed. Filename: %1",srcName) ); - return false; - } - bool bWriteSuccess = destFile.open( QIODevice::WriteOnly ); - if ( bWriteSuccess == false ) - { - m_pFileAccess->setStatusText( i18n("Error during file copy operation: Opening file for writing failed. Filename: %1",destName) ); - return false; - } + // Both files are local: + QString srcName = m_pFileAccess->absoluteFilePath(); + QString destName = dest; + QFile srcFile(srcName); + QFile destFile(destName); + bool bReadSuccess = srcFile.open(QIODevice::ReadOnly); + if(bReadSuccess == false) + { + m_pFileAccess->setStatusText(i18n("Error during file copy operation: Opening file for reading failed. Filename: %1", srcName)); + return false; + } + bool bWriteSuccess = destFile.open(QIODevice::WriteOnly); + if(bWriteSuccess == false) + { + m_pFileAccess->setStatusText(i18n("Error during file copy operation: Opening file for writing failed. Filename: %1", destName)); + return false; + } - std::vector buffer(100000); - qint64 bufSize = buffer.size(); - qint64 srcSize = srcFile.size(); - while ( srcSize > 0 && !pp.wasCancelled() ) - { - qint64 readSize = srcFile.read( &buffer[0], min2( srcSize, bufSize ) ); - if ( readSize==-1 || readSize==0 ) - { - m_pFileAccess->setStatusText( i18n("Error during file copy operation: Reading failed. Filename: %1",srcName) ); - return false; - } - srcSize -= readSize; - while ( readSize > 0 ) - { - qint64 writeSize = destFile.write( &buffer[0], readSize ); - if ( writeSize==-1 || writeSize==0 ) - { - m_pFileAccess->setStatusText( i18n("Error during file copy operation: Writing failed. Filename: %1",destName) ); + std::vector buffer(100000); + qint64 bufSize = buffer.size(); + qint64 srcSize = srcFile.size(); + while(srcSize > 0 && !pp.wasCancelled()) + { + qint64 readSize = srcFile.read(&buffer[0], min2(srcSize, bufSize)); + if(readSize == -1 || readSize == 0) + { + m_pFileAccess->setStatusText(i18n("Error during file copy operation: Reading failed. Filename: %1", srcName)); return false; - } - readSize -= writeSize; - } - destFile.flush(); - pp.setCurrent( (double)(srcFile.size()-srcSize)/srcFile.size(), false ); - } - srcFile.close(); - destFile.close(); + } + srcSize -= readSize; + while(readSize > 0) + { + qint64 writeSize = destFile.write(&buffer[0], readSize); + if(writeSize == -1 || writeSize == 0) + { + m_pFileAccess->setStatusText(i18n("Error during file copy operation: Writing failed. Filename: %1", destName)); + return false; + } + readSize -= writeSize; + } + destFile.flush(); + pp.setCurrent((double)(srcFile.size() - srcSize) / srcFile.size(), false); + } + srcFile.close(); + destFile.close(); - // Update the times of the destFile +// Update the times of the destFile #ifdef _WIN32 - struct _stat srcFileStatus; - int statResult = ::_stat( srcName.toLocal8Bit().constData(), &srcFileStatus ); - if (statResult==0) - { - _utimbuf destTimes; - destTimes.actime = srcFileStatus.st_atime;/* time of last access */ - destTimes.modtime = srcFileStatus.st_mtime;/* time of last modification */ + struct _stat srcFileStatus; + int statResult = ::_stat(srcName.toLocal8Bit().constData(), &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.toLocal8Bit().constData(), &destTimes ); - _chmod ( destName.toLocal8Bit().constData(), srcFileStatus.st_mode ); - } + _utime(destName.toLocal8Bit().constData(), &destTimes); + _chmod(destName.toLocal8Bit().constData(), srcFileStatus.st_mode); + } #else - struct stat srcFileStatus; - int statResult = ::stat( srcName.toLocal8Bit().constData(), &srcFileStatus ); - if (statResult==0) - { - utimbuf destTimes; - destTimes.actime = srcFileStatus.st_atime;/* time of last access */ - destTimes.modtime = srcFileStatus.st_mtime;/* time of last modification */ + struct stat srcFileStatus; + int statResult = ::stat(srcName.toLocal8Bit().constData(), &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.toLocal8Bit().constData(), &destTimes ); - chmod ( destName.toLocal8Bit().constData(), srcFileStatus.st_mode ); - } + utime(destName.toLocal8Bit().constData(), &destTimes); + chmod(destName.toLocal8Bit().constData(), srcFileStatus.st_mode); + } #endif - return true; + return true; } -bool wildcardMultiMatch( const QString& wildcard, const QString& testString, bool bCaseSensitive ) +bool wildcardMultiMatch(const QString& wildcard, const QString& testString, bool bCaseSensitive) { - static QHash s_patternMap; + static QHash s_patternMap; - QStringList sl = wildcard.split( ";" ); + QStringList sl = wildcard.split(";"); - for ( QStringList::Iterator it = sl.begin(); it != sl.end(); ++it ) - { - QHash::iterator patIt = s_patternMap.find( *it ); - if ( patIt == s_patternMap.end() ) - { - QRegExp pattern( *it, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard ); - patIt = s_patternMap.insert( *it, pattern ); - } - - if ( patIt.value().exactMatch( testString ) ) - return true; - } + for(QStringList::Iterator it = sl.begin(); it != sl.end(); ++it) + { + QHash::iterator patIt = s_patternMap.find(*it); + if(patIt == s_patternMap.end()) + { + QRegExp pattern(*it, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); + patIt = s_patternMap.insert(*it, pattern); + } - return false; -} + if(patIt.value().exactMatch(testString)) + return true; + } + return false; +} // class CvsIgnoreList from Cervisia cvsdir.cpp // Copyright (C) 1999-2002 Bernd Gehrmann // with elements from class StringMatcher // Copyright (c) 2003 Andre Woebbeking // Modifications for KDiff3 by Joachim Eibl class CvsIgnoreList { -public: - CvsIgnoreList(){} - void init(FileAccess& dir, bool bUseLocalCvsIgnore ); - bool matches(const QString& fileName, bool bCaseSensitive ) const; + public: + CvsIgnoreList() {} + void init(FileAccess& dir, bool bUseLocalCvsIgnore); + bool matches(const QString& fileName, bool bCaseSensitive) const; -private: + 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 ) +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 _$* *$"; + 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::homePath() + "/.cvsignore"); - addEntriesFromString(QString::fromLocal8Bit(::getenv("CVSIGNORE"))); + addEntriesFromString(QString::fromLatin1(ignorestr)); + addEntriesFromFile(QDir::homePath() + "/.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(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) { - if( pos==size || buf[pos]==' ' || buf[pos]=='\t' || buf[pos]=='\n' || buf[pos]=='\r' ) - { - if (pos>pos1) - { - addEntry( QString::fromLatin1( &buf[pos1], pos-pos1 ) ); - } - ++pos1; - } + file.readFile(buf, size); + int pos1 = 0; + for(int pos = 0; pos <= size; ++pos) + { + if(pos == size || buf[pos] == ' ' || buf[pos] == '\t' || buf[pos] == '\n' || buf[pos] == '\r') + { + if(pos > pos1) + { + addEntry(QString::fromLatin1(&buf[pos1], pos - pos1)); + } + ++pos1; + } + } + delete[] buf; } - delete[] buf; - } - } - } + } + } } - void CvsIgnoreList::addEntriesFromString(const QString& str) { int posLast(0); int pos; - while ((pos = str.indexOf(' ', posLast)) >= 0) + while((pos = str.indexOf(' ', posLast)) >= 0) { - if (pos > posLast) + if(pos > posLast) addEntry(str.mid(posLast, pos - posLast)); posLast = pos + 1; } - if (posLast < static_cast(str.length())) + if(posLast < static_cast(str.length())) addEntry(str.mid(posLast)); } - -void CvsIgnoreList::addEntriesFromFile(const QString &name) +void CvsIgnoreList::addEntriesFromFile(const QString& name) { QFile file(name); - if( file.open(QIODevice::ReadOnly) ) + if(file.open(QIODevice::ReadOnly)) { QTextStream stream(&file); - while( !stream.atEnd() ) + while(!stream.atEnd()) { addEntriesFromString(stream.readLine()); } } } void CvsIgnoreList::addEntry(const QString& pattern) { - if (pattern != QString("!")) - { - if (pattern.isEmpty()) return; - - // The general match is general but slow. - // Special tests for '*' and '?' at the beginning or end of a pattern - // allow fast checks. - - // Count number of '*' and '?' - unsigned int nofMetaCharacters = 0; - - const QChar* pos; - pos = pattern.unicode(); - const QChar* posEnd; - posEnd=pos + pattern.length(); - while (pos < posEnd) - { - if( *pos==QChar('*') || *pos==QChar('?') ) ++nofMetaCharacters; - ++pos; - } - - if ( nofMetaCharacters==0 ) - { - m_exactPatterns.append(pattern); - } - else if ( nofMetaCharacters==1 ) - { - if ( pattern.at(0) == QChar('*') ) - { - m_endPatterns.append( pattern.right( pattern.length() - 1) ); - } - else if (pattern.at(pattern.length() - 1) == QChar('*')) - { - m_startPatterns.append( pattern.left( pattern.length() - 1) ); - } - else - { + if(pattern != QString("!")) + { + if(pattern.isEmpty()) return; + + // The general match is general but slow. + // Special tests for '*' and '?' at the beginning or end of a pattern + // allow fast checks. + + // Count number of '*' and '?' + unsigned int nofMetaCharacters = 0; + + const QChar* pos; + pos = pattern.unicode(); + const QChar* posEnd; + posEnd = pos + pattern.length(); + while(pos < posEnd) + { + if(*pos == QChar('*') || *pos == QChar('?')) ++nofMetaCharacters; + ++pos; + } + + if(nofMetaCharacters == 0) + { + m_exactPatterns.append(pattern); + } + else if(nofMetaCharacters == 1) + { + if(pattern.at(0) == QChar('*')) + { + m_endPatterns.append(pattern.right(pattern.length() - 1)); + } + else if(pattern.at(pattern.length() - 1) == QChar('*')) + { + m_startPatterns.append(pattern.left(pattern.length() - 1)); + } + else + { + m_generalPatterns.append(pattern.toLocal8Bit()); + } + } + else + { m_generalPatterns.append(pattern.toLocal8Bit()); - } - } - else - { - m_generalPatterns.append(pattern.toLocal8Bit()); - } - } - else - { - m_exactPatterns.clear(); - m_startPatterns.clear(); - m_endPatterns.clear(); - m_generalPatterns.clear(); - } + } + } + else + { + m_exactPatterns.clear(); + m_startPatterns.clear(); + m_endPatterns.clear(); + m_generalPatterns.clear(); + } } -bool CvsIgnoreList::matches(const QString& text, bool bCaseSensitive ) const +bool CvsIgnoreList::matches(const QString& text, bool bCaseSensitive) const { - if ( m_exactPatterns.indexOf(text) >=0 ) + if(m_exactPatterns.indexOf(text) >= 0) { return true; } QStringList::ConstIterator it; QStringList::ConstIterator itEnd; - for ( it=m_startPatterns.begin(), itEnd=m_startPatterns.end(); it != itEnd; ++it) + for(it = m_startPatterns.begin(), itEnd = m_startPatterns.end(); it != itEnd; ++it) { - if (text.startsWith(*it)) + if(text.startsWith(*it)) { return true; } } - for ( it = m_endPatterns.begin(), itEnd=m_endPatterns.end(); it != itEnd; ++it) + for(it = m_endPatterns.begin(), itEnd = m_endPatterns.end(); it != itEnd; ++it) { - if (text.mid( text.length() - (*it).length() )==*it) //(text.endsWith(*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, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); + if(pattern.exactMatch(text)) + return true; + } - for ( it = m_generalPatterns.begin(); it != m_generalPatterns.end(); ++it ) - { - QRegExp pattern( *it, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard ); - if ( pattern.exactMatch( text ) ) - return true; - } - - return false; + return false; } -static bool cvsIgnoreExists( t_DirectoryList* pDirList ) +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; + 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 ) +bool FileAccessJobHandler::listDir(t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden, const QString& filePattern, + const QString& fileAntiPattern, const QString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore) { - ProgressProxyExtender pp; - m_pDirList = pDirList; - m_pDirList->clear(); - m_bFindHidden = bFindHidden; - m_bRecursive = bRecursive; - m_bFollowDirLinks = bFollowDirLinks; // Only relevant if bRecursive==true. - m_fileAntiPattern = fileAntiPattern; - m_filePattern = filePattern; - m_dirAntiPattern = dirAntiPattern; + ProgressProxyExtender pp; + m_pDirList = pDirList; + m_pDirList->clear(); + m_bFindHidden = bFindHidden; + m_bRecursive = bRecursive; + m_bFollowDirLinks = bFollowDirLinks; // Only relevant if bRecursive==true. + m_fileAntiPattern = fileAntiPattern; + m_filePattern = filePattern; + m_dirAntiPattern = dirAntiPattern; - if ( pp.wasCancelled() ) - return true; // Cancelled is not an error. + if(pp.wasCancelled()) + return true; // Cancelled is not an error. - pp.setInformation( i18n("Reading directory: ") + m_pFileAccess->absoluteFilePath(), 0, false ); + pp.setInformation(i18n("Reading directory: ") + m_pFileAccess->absoluteFilePath(), 0, false); - if( m_pFileAccess->isLocal() ) - { - QString currentPath = QDir::currentPath(); - m_bSuccess = QDir::setCurrent( m_pFileAccess->absoluteFilePath() ); - if ( m_bSuccess ) - { + if(m_pFileAccess->isLocal()) + { + QString currentPath = QDir::currentPath(); + m_bSuccess = QDir::setCurrent(m_pFileAccess->absoluteFilePath()); + if(m_bSuccess) + { #ifndef _WIN32 - m_bSuccess = true; - QDir dir( "." ); + m_bSuccess = true; + QDir dir("."); - dir.setSorting( QDir::Name | QDir::DirsFirst ); - dir.setFilter( QDir::Files | QDir::Dirs | /* from KDE3 QDir::TypeMaskDirs | */ QDir::Hidden | QDir::System ); + dir.setSorting(QDir::Name | QDir::DirsFirst); + dir.setFilter(QDir::Files | QDir::Dirs | /* from KDE3 QDir::TypeMaskDirs | */ QDir::Hidden | QDir::System); - QFileInfoList fiList = dir.entryInfoList(); - if ( fiList.isEmpty() ) - { - // No Permission to read directory or other error. - m_bSuccess = false; - } - else - { - foreach ( const QFileInfo &fi, fiList ) // for each file... + QFileInfoList fiList = dir.entryInfoList(); + if(fiList.isEmpty()) { - if ( fi.fileName() == "." || fi.fileName()==".." ) - continue; - - FileAccess fa; - fa.setFile( fi, m_pFileAccess ); - pDirList->push_back( fa ); + // No Permission to read directory or other error. + m_bSuccess = false; + } + else + { + foreach(const QFileInfo& fi, fiList) // for each file... + { + if(fi.fileName() == "." || fi.fileName() == "..") + continue; + + FileAccess fa; + fa.setFile(fi, m_pFileAccess); + pDirList->push_back(fa); + } } - } #else - QString pattern ="*.*"; - WIN32_FIND_DATA findData; + QString pattern = "*.*"; + WIN32_FIND_DATA findData; - Qt::HANDLE searchHandle = FindFirstFileW( (const wchar_t*)pattern.utf16(), &findData ); + Qt::HANDLE searchHandle = FindFirstFileW((const wchar_t*)pattern.utf16(), &findData); - if ( searchHandle != INVALID_HANDLE_VALUE ) - { - QString absPath = m_pFileAccess->absoluteFilePath(); - QString relPath = m_pFileAccess->filePath(); - bool bFirst=true; - while( ! pp.wasCancelled() ) + if(searchHandle != INVALID_HANDLE_VALUE) { - if (!bFirst) - { - if ( ! FindNextFileW(searchHandle,&findData) ) - break; - } - bFirst = false; - FileAccess fa; - - fa.m_filePath = QString::fromUtf16((const ushort*)findData.cFileName); - if ( fa.m_filePath!="." && fa.m_filePath!=".." ) - { - fa.m_size = ( qint64( findData.nFileSizeHigh ) << 32 ) + findData.nFileSizeLow; - - FILETIME ft; - SYSTEMTIME t; - FileTimeToLocalFileTime( &findData.ftLastWriteTime, &ft ); FileTimeToSystemTime(&ft,&t); - fa.m_modificationTime = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) ); - //FileTimeToLocalFileTime( &findData.ftLastAccessTime, &ft ); FileTimeToSystemTime(&ft,&t); - //fa.m_accessTime = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) ); - //FileTimeToLocalFileTime( &findData.ftCreationTime, &ft ); FileTimeToSystemTime(&ft,&t); - //fa.m_creationTime = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) ); - - int a = findData.dwFileAttributes; - fa.m_bWritable = ( a & FILE_ATTRIBUTE_READONLY) == 0; - fa.m_bDir = ( a & FILE_ATTRIBUTE_DIRECTORY ) != 0; - fa.m_bFile = !fa.m_bDir; - fa.m_bHidden = ( a & FILE_ATTRIBUTE_HIDDEN) != 0; - - //fa.m_bExecutable = false; // Useless on windows - fa.m_bExists = true; - //fa.m_bReadable = true; - //fa.m_bLocal = true; - //fa.m_bValidData = true; - fa.m_bSymLink = false; - //fa.m_fileType = 0; - - - //fa.m_filePath = fa.m_name; - //fa.m_absoluteFilePath = absPath + "/" + fa.m_name; - //fa.m_url.setPath( fa.m_absoluteFilePath ); - if ( fa.d() ) - fa.m_pData->m_pParent = m_pFileAccess; - else - fa.m_pParent = m_pFileAccess; - pDirList->push_back( fa ); - } + QString absPath = m_pFileAccess->absoluteFilePath(); + QString relPath = m_pFileAccess->filePath(); + bool bFirst = true; + while(!pp.wasCancelled()) + { + if(!bFirst) + { + if(!FindNextFileW(searchHandle, &findData)) + break; + } + bFirst = false; + FileAccess fa; + + fa.m_filePath = QString::fromUtf16((const ushort*)findData.cFileName); + if(fa.m_filePath != "." && fa.m_filePath != "..") + { + fa.m_size = (qint64(findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; + + FILETIME ft; + SYSTEMTIME t; + FileTimeToLocalFileTime(&findData.ftLastWriteTime, &ft); + FileTimeToSystemTime(&ft, &t); + fa.m_modificationTime = QDateTime(QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond)); + //FileTimeToLocalFileTime( &findData.ftLastAccessTime, &ft ); FileTimeToSystemTime(&ft,&t); + //fa.m_accessTime = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) ); + //FileTimeToLocalFileTime( &findData.ftCreationTime, &ft ); FileTimeToSystemTime(&ft,&t); + //fa.m_creationTime = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) ); + + int a = findData.dwFileAttributes; + fa.m_bWritable = (a & FILE_ATTRIBUTE_READONLY) == 0; + fa.m_bDir = (a & FILE_ATTRIBUTE_DIRECTORY) != 0; + fa.m_bFile = !fa.m_bDir; + fa.m_bHidden = (a & FILE_ATTRIBUTE_HIDDEN) != 0; + + //fa.m_bExecutable = false; // Useless on windows + fa.m_bExists = true; + //fa.m_bReadable = true; + //fa.m_bLocal = true; + //fa.m_bValidData = true; + fa.m_bSymLink = false; + //fa.m_fileType = 0; + + //fa.m_filePath = fa.m_name; + //fa.m_absoluteFilePath = absPath + "/" + fa.m_name; + //fa.m_url.setPath( fa.m_absoluteFilePath ); + if(fa.d()) + fa.m_pData->m_pParent = m_pFileAccess; + else + fa.m_pParent = m_pFileAccess; + pDirList->push_back(fa); + } + } + FindClose(searchHandle); + } + else + { + QDir::setCurrent(currentPath); // restore current path + return false; } - FindClose( searchHandle ); - } - else - { - QDir::setCurrent( currentPath ); // restore current path - return false; - } #endif - } - QDir::setCurrent( currentPath ); // restore current path - } - else - { - KIO::ListJob* pListJob=0; - pListJob = KIO::listDir( m_pFileAccess->url(), KIO::HideProgressInfo, true /*bFindHidden*/ ); + } + QDir::setCurrent(currentPath); // restore current path + } + else + { + KIO::ListJob* pListJob = 0; + pListJob = KIO::listDir(m_pFileAccess->url(), KIO::HideProgressInfo, true /*bFindHidden*/); - m_bSuccess = false; - if ( pListJob!=0 ) - { - connect(pListJob, &KIO::ListJob::entries, this, &FileAccessJobHandler::slotListDirProcessNewEntries); - connect(pListJob, &KIO::ListJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); + m_bSuccess = false; + if(pListJob != 0) + { + connect(pListJob, &KIO::ListJob::entries, this, &FileAccessJobHandler::slotListDirProcessNewEntries); + connect(pListJob, &KIO::ListJob::result, this, &FileAccessJobHandler::slotSimpleJobResult); - connect(pListJob, &KIO::ListJob::infoMessage, &pp, &ProgressProxyExtender::slotListDirInfoMessage); + connect(pListJob, &KIO::ListJob::infoMessage, &pp, &ProgressProxyExtender::slotListDirInfoMessage); - // This line makes the transfer via fish unreliable.:-( - //connect( pListJob, SIGNAL(percent(KJob*,unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); + // This line makes the transfer via fish unreliable.:-( + //connect( pListJob, SIGNAL(percent(KJob*,unsigned long)), &pp, SLOT(slotPercent(KJob*, unsigned long))); - ProgressProxy::enterEventLoop( pListJob, - i18n("Listing directory: %1",m_pFileAccess->prettyAbsPath()) ); - } - } + ProgressProxy::enterEventLoop(pListJob, + i18n("Listing directory: %1", m_pFileAccess->prettyAbsPath())); + } + } - CvsIgnoreList cvsIgnoreList; - if ( bUseCvsIgnore ) - { - cvsIgnoreList.init( *m_pFileAccess, cvsIgnoreExists(pDirList) ); - } + CvsIgnoreList cvsIgnoreList; + if(bUseCvsIgnore) + { + cvsIgnoreList.init(*m_pFileAccess, cvsIgnoreExists(pDirList)); + } #if defined(_WIN32) || defined(Q_OS_OS2) - bool bCaseSensitive = false; + bool bCaseSensitive = false; #else - bool bCaseSensitive = true; + bool bCaseSensitive = true; #endif - // Now remove all entries that don't match: - t_DirectoryList::iterator i; - for( i = pDirList->begin(); i!=pDirList->end(); ) - { - t_DirectoryList::iterator i2=i; - ++i2; - QString fn = i->fileName(); - if ( (!bFindHidden && i->isHidden() ) - || - (i->isFile() && - ( !wildcardMultiMatch( filePattern, fn, bCaseSensitive ) || - wildcardMultiMatch( fileAntiPattern, fn, bCaseSensitive ) ) ) - || - (i->isDir() && wildcardMultiMatch( dirAntiPattern, fn, bCaseSensitive ) ) - || - cvsIgnoreList.matches( fn, bCaseSensitive ) - ) - { - // Remove it - pDirList->erase( i ); - i = i2; - } - else - { - ++i; - } - } + // 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, fn, bCaseSensitive) || + wildcardMultiMatch(fileAntiPattern, fn, bCaseSensitive))) || + (i->isDir() && wildcardMultiMatch(dirAntiPattern, fn, bCaseSensitive)) || + cvsIgnoreList.matches(fn, bCaseSensitive)) + { + // Remove it + pDirList->erase(i); + i = i2; + } + else + { + ++i; + } + } - if ( bRecursive ) - { - t_DirectoryList subDirsList; - - t_DirectoryList::iterator i; - for( i = m_pDirList->begin(); i!=m_pDirList->end(); ++i ) - { - if ( i->isDir() && (!i->isSymLink() || m_bFollowDirLinks)) - { - t_DirectoryList dirList; - i->listDir( &dirList, bRecursive, bFindHidden, - filePattern, fileAntiPattern, dirAntiPattern, bFollowDirLinks, bUseCvsIgnore ); - - t_DirectoryList::iterator j; - for( j = dirList.begin(); j!=dirList.end(); ++j ) + 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)) { - if ( j->parent()==0 ) - j->m_filePath = i->fileName() + "/" + j->m_filePath; + 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) + { + if(j->parent() == 0) + j->m_filePath = i->fileName() + "/" + j->m_filePath; + } + + // append data onto the main list + subDirsList.splice(subDirsList.end(), dirList); } + } - // append data onto the main list - subDirsList.splice( subDirsList.end(), dirList ); - } - } - - m_pDirList->splice( m_pDirList->end(), subDirsList ); - } + m_pDirList->splice(m_pDirList->end(), subDirsList); + } - return m_bSuccess; + return m_bSuccess; } - -void FileAccessJobHandler::slotListDirProcessNewEntries( KIO::Job*, const KIO::UDSEntryList& l ) +void FileAccessJobHandler::slotListDirProcessNewEntries(KIO::Job*, const KIO::UDSEntryList& l) { - //This function is called for non-local urls. Don't use QUrl::fromLocalFile here as it does not handle these. - QUrl parentUrl = QUrl::fromUserInput( m_pFileAccess->absoluteFilePath(), QString(""), QUrl::AssumeLocalFile); + //This function is called for non-local urls. Don't use QUrl::fromLocalFile here as it does not handle these. + QUrl parentUrl = QUrl::fromUserInput(m_pFileAccess->absoluteFilePath(), QString(""), QUrl::AssumeLocalFile); - KIO::UDSEntryList::ConstIterator i; - for ( i=l.begin(); i!=l.end(); ++i ) - { - const KIO::UDSEntry& e = *i; - FileAccess fa; - fa.createData(); - fa.m_pData->m_pParent = m_pFileAccess; - fa.setUdsEntry( e ); - - if ( fa.fileName() != "." && fa.fileName() != ".." ) - { - fa.d()->m_url = parentUrl; - QUrl url = fa.d()->m_url.adjusted(QUrl::StripTrailingSlash); - fa.d()->m_url.setPath(url.path() + "/" + fa.fileName() ); - //fa.d()->m_absoluteFilePath = fa.url().url(); - m_pDirList->push_back( fa ); - } - } + KIO::UDSEntryList::ConstIterator i; + for(i = l.begin(); i != l.end(); ++i) + { + const KIO::UDSEntry& e = *i; + FileAccess fa; + fa.createData(); + fa.m_pData->m_pParent = m_pFileAccess; + fa.setUdsEntry(e); + + if(fa.fileName() != "." && fa.fileName() != "..") + { + fa.d()->m_url = parentUrl; + QUrl url = fa.d()->m_url.adjusted(QUrl::StripTrailingSlash); + fa.d()->m_url.setPath(url.path() + "/" + fa.fileName()); + //fa.d()->m_absoluteFilePath = fa.url().url(); + m_pDirList->push_back(fa); + } + } } -void ProgressProxyExtender::slotListDirInfoMessage( KJob*, const QString& msg ) +void ProgressProxyExtender::slotListDirInfoMessage(KJob*, const QString& msg) { - setInformation( msg, 0 ); + setInformation(msg, 0); } -void ProgressProxyExtender::slotPercent( KJob*, unsigned long percent ) +void ProgressProxyExtender::slotPercent(KJob*, unsigned long percent) { - setCurrent( percent ); + setCurrent(percent); } - //#include "fileaccess.moc" diff --git a/src/gnudiff_analyze.cpp b/src/gnudiff_analyze.cpp index ac27bb0..3544ce6 100644 --- a/src/gnudiff_analyze.cpp +++ b/src/gnudiff_analyze.cpp @@ -1,869 +1,859 @@ /* Analyze file differences for GNU DIFF. Modified for KDiff3 by Joachim Eibl 2003. The original file was part of GNU DIFF. Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002 Free Software Foundation, Inc. GNU DIFF is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU DIFF is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. */ /* The basic algorithm is described in: "An O(ND) Difference Algorithm and its Variations", Eugene Myers, Algorithmica Vol. 1 No. 2, 1986, pp. 251-266; see especially section 4.2, which describes the variation used below. Unless the --minimal option is specified, this code uses the TOO_EXPENSIVE heuristic, by Paul Eggert, to limit the cost to O(N**1.5 log N) at the price of producing suboptimal output for large inputs with many differences. The basic algorithm was independently discovered as described in: "Algorithms for Approximate String Matching", E. Ukkonen, Information and Control Vol. 64, 1985, pp. 100-118. */ #define GDIFF_MAIN #include "gnudiff_diff.h" //#include #include -static lin *xvec, *yvec; /* Vectors being compared. */ -static lin *fdiag; /* Vector, indexed by diagonal, containing +static lin *xvec, *yvec; /* Vectors being compared. */ +static lin *fdiag; /* Vector, indexed by diagonal, containing 1 + the X coordinate of the point furthest along the given diagonal in the forward search of the edit matrix. */ -static lin *bdiag; /* Vector, indexed by diagonal, containing +static lin *bdiag; /* Vector, indexed by diagonal, containing the X coordinate of the point furthest along the given diagonal in the backward search of the edit matrix. */ -static lin too_expensive; /* Edit scripts longer than this are too +static lin too_expensive; /* Edit scripts longer than this are too expensive to compute. */ -#define SNAKE_LIMIT 20 /* Snakes bigger than this are considered `big'. */ +#define SNAKE_LIMIT 20 /* Snakes bigger than this are considered `big'. */ - -struct partition -{ - lin xmid, ymid; /* Midpoints of this partition. */ - bool lo_minimal; /* Nonzero if low half will be analyzed minimally. */ - bool hi_minimal; /* Likewise for high half. */ +struct partition { + lin xmid, ymid; /* Midpoints of this partition. */ + bool lo_minimal; /* Nonzero if low half will be analyzed minimally. */ + bool hi_minimal; /* Likewise for high half. */ }; /* Find the midpoint of the shortest edit script for a specified portion of the two files. Scan from the beginnings of the files, and simultaneously from the ends, doing a breadth-first search through the space of edit-sequence. When the two searches meet, we have found the midpoint of the shortest edit sequence. If FIND_MINIMAL is nonzero, find the minimal edit script regardless of expense. Otherwise, if the search is too expensive, use heuristics to stop the search and report a suboptimal answer. Set PART->(xmid,ymid) to the midpoint (XMID,YMID). The diagonal number XMID - YMID equals the number of inserted lines minus the number of deleted lines (counting only lines before the midpoint). Return the approximate edit cost; this is the total number of lines inserted or deleted (counting only lines before the midpoint), unless a heuristic is used to terminate the search prematurely. Set PART->lo_minimal to true iff the minimal edit script for the left half of the partition is known; similarly for PART->hi_minimal. This function assumes that the first lines of the specified portions of the two files do not match, and likewise that the last lines do not match. The caller must trim matching lines from the beginning and end of the portions it is going to specify. If we return the "wrong" partitions, the worst this can do is cause suboptimal diff output. It cannot cause incorrect diff output. */ -lin -GnuDiff::diag (lin xoff, lin xlim, lin yoff, lin ylim, bool find_minimal, - struct partition *part) +lin GnuDiff::diag(lin xoff, lin xlim, lin yoff, lin ylim, bool find_minimal, + struct partition *part) { - lin *const fd = fdiag; /* Give the compiler a chance. */ - lin *const bd = bdiag; /* Additional help for the compiler. */ - lin const *const xv = xvec; /* Still more help for the compiler. */ - lin const *const yv = yvec; /* And more and more . . . */ - lin const dmin = xoff - ylim; /* Minimum valid diagonal. */ - lin const dmax = xlim - yoff; /* Maximum valid diagonal. */ - lin const fmid = xoff - yoff; /* Center diagonal of top-down search. */ - lin const bmid = xlim - ylim; /* Center diagonal of bottom-up search. */ - lin fmin = fmid, fmax = fmid; /* Limits of top-down search. */ - lin bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */ - lin c; /* Cost. */ - bool odd = (fmid - bmid) & 1; /* True if southeast corner is on an odd + lin *const fd = fdiag; /* Give the compiler a chance. */ + lin *const bd = bdiag; /* Additional help for the compiler. */ + lin const *const xv = xvec; /* Still more help for the compiler. */ + lin const *const yv = yvec; /* And more and more . . . */ + lin const dmin = xoff - ylim; /* Minimum valid diagonal. */ + lin const dmax = xlim - yoff; /* Maximum valid diagonal. */ + lin const fmid = xoff - yoff; /* Center diagonal of top-down search. */ + lin const bmid = xlim - ylim; /* Center diagonal of bottom-up search. */ + lin fmin = fmid, fmax = fmid; /* Limits of top-down search. */ + lin bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */ + lin c; /* Cost. */ + bool odd = (fmid - bmid) & 1; /* True if southeast corner is on an odd diagonal with respect to the northwest. */ - fd[fmid] = xoff; - bd[bmid] = xlim; + fd[fmid] = xoff; + bd[bmid] = xlim; - for (c = 1;; ++c) + for(c = 1;; ++c) { - lin d; /* Active diagonal. */ - bool big_snake = 0; + lin d; /* Active diagonal. */ + bool big_snake = 0; - /* Extend the top-down search by an edit step in each diagonal. */ - fmin > dmin ? fd[--fmin - 1] = -1 : ++fmin; - fmax < dmax ? fd[++fmax + 1] = -1 : --fmax; - for (d = fmax; d >= fmin; d -= 2) - { - lin x, y, oldx, tlo = fd[d - 1], thi = fd[d + 1]; - - if (tlo >= thi) - x = tlo + 1; - else - x = thi; - oldx = x; - y = x - d; - while (x < xlim && y < ylim && xv[x] == yv[y]) - ++x, ++y; - if (x - oldx > SNAKE_LIMIT) - big_snake = 1; - fd[d] = x; - if (odd && bmin <= d && d <= bmax && bd[d] <= x) + /* Extend the top-down search by an edit step in each diagonal. */ + fmin > dmin ? fd[--fmin - 1] = -1 : ++fmin; + fmax < dmax ? fd[++fmax + 1] = -1 : --fmax; + for(d = fmax; d >= fmin; d -= 2) { - part->xmid = x; - part->ymid = y; - part->lo_minimal = part->hi_minimal = 1; - return 2 * c - 1; + lin x, y, oldx, tlo = fd[d - 1], thi = fd[d + 1]; + + if(tlo >= thi) + x = tlo + 1; + else + x = thi; + oldx = x; + y = x - d; + while(x < xlim && y < ylim && xv[x] == yv[y]) + ++x, ++y; + if(x - oldx > SNAKE_LIMIT) + big_snake = 1; + fd[d] = x; + if(odd && bmin <= d && d <= bmax && bd[d] <= x) + { + part->xmid = x; + part->ymid = y; + part->lo_minimal = part->hi_minimal = 1; + return 2 * c - 1; + } } - } - - /* Similarly extend the bottom-up search. */ - bmin > dmin ? bd[--bmin - 1] = LIN_MAX : ++bmin; - bmax < dmax ? bd[++bmax + 1] = LIN_MAX : --bmax; - for (d = bmax; d >= bmin; d -= 2) - { - lin x, y, oldx, tlo = bd[d - 1], thi = bd[d + 1]; - if (tlo < thi) - x = tlo; - else - x = thi - 1; - oldx = x; - y = x - d; - while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) - --x, --y; - if (oldx - x > SNAKE_LIMIT) - big_snake = 1; - bd[d] = x; - if (!odd && fmin <= d && d <= fmax && x <= fd[d]) + /* Similarly extend the bottom-up search. */ + bmin > dmin ? bd[--bmin - 1] = LIN_MAX : ++bmin; + bmax < dmax ? bd[++bmax + 1] = LIN_MAX : --bmax; + for(d = bmax; d >= bmin; d -= 2) { - part->xmid = x; - part->ymid = y; - part->lo_minimal = part->hi_minimal = 1; - return 2 * c; + lin x, y, oldx, tlo = bd[d - 1], thi = bd[d + 1]; + + if(tlo < thi) + x = tlo; + else + x = thi - 1; + oldx = x; + y = x - d; + while(x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) + --x, --y; + if(oldx - x > SNAKE_LIMIT) + big_snake = 1; + bd[d] = x; + if(!odd && fmin <= d && d <= fmax && x <= fd[d]) + { + part->xmid = x; + part->ymid = y; + part->lo_minimal = part->hi_minimal = 1; + return 2 * c; + } } - } - if (find_minimal) - continue; + if(find_minimal) + continue; - /* Heuristic: check occasionally for a diagonal that has made + /* Heuristic: check occasionally for a diagonal that has made lots of progress compared with the edit distance. If we have any such, find the one that has made the most progress and return it as if it had succeeded. With this heuristic, for files with a constant small density of changes, the algorithm is linear in the file size. */ - if (200 < c && big_snake && speed_large_files) - { - lin best; - - best = 0; - for (d = fmax; d >= fmin; d -= 2) + if(200 < c && big_snake && speed_large_files) { - lin dd = d - fmid; - lin x = fd[d]; - lin y = x - d; - lin v = (x - xoff) * 2 - dd; - if (v > 12 * (c + (dd < 0 ? -dd : dd))) - { - if (v > best - && xoff + SNAKE_LIMIT <= x && x < xlim - && yoff + SNAKE_LIMIT <= y && y < ylim) + lin best; + + best = 0; + for(d = fmax; d >= fmin; d -= 2) { - /* We have a good enough best diagonal; + lin dd = d - fmid; + lin x = fd[d]; + lin y = x - d; + lin v = (x - xoff) * 2 - dd; + if(v > 12 * (c + (dd < 0 ? -dd : dd))) + { + if(v > best && xoff + SNAKE_LIMIT <= x && x < xlim && yoff + SNAKE_LIMIT <= y && y < ylim) + { + /* We have a good enough best diagonal; now insist that it end with a significant snake. */ - int k; - - for (k = 1; xv[x - k] == yv[y - k]; k++) - if (k == SNAKE_LIMIT) - { - best = v; - part->xmid = x; - part->ymid = y; - break; - } + int k; + + for(k = 1; xv[x - k] == yv[y - k]; k++) + if(k == SNAKE_LIMIT) + { + best = v; + part->xmid = x; + part->ymid = y; + break; + } + } + } + } + if(best > 0) + { + part->lo_minimal = 1; + part->hi_minimal = 0; + return 2 * c - 1; } - } - } - if (best > 0) - { - part->lo_minimal = 1; - part->hi_minimal = 0; - return 2 * c - 1; - } - best = 0; - for (d = bmax; d >= bmin; d -= 2) - { - lin dd = d - bmid; - lin x = bd[d]; - lin y = x - d; - lin v = (xlim - x) * 2 + dd; - if (v > 12 * (c + (dd < 0 ? -dd : dd))) - { - if (v > best - && xoff < x && x <= xlim - SNAKE_LIMIT - && yoff < y && y <= ylim - SNAKE_LIMIT) + best = 0; + for(d = bmax; d >= bmin; d -= 2) { - /* We have a good enough best diagonal; + lin dd = d - bmid; + lin x = bd[d]; + lin y = x - d; + lin v = (xlim - x) * 2 + dd; + if(v > 12 * (c + (dd < 0 ? -dd : dd))) + { + if(v > best && xoff < x && x <= xlim - SNAKE_LIMIT && yoff < y && y <= ylim - SNAKE_LIMIT) + { + /* We have a good enough best diagonal; now insist that it end with a significant snake. */ - int k; - - for (k = 0; xv[x + k] == yv[y + k]; k++) - if (k == SNAKE_LIMIT - 1) - { - best = v; - part->xmid = x; - part->ymid = y; - break; - } + int k; + + for(k = 0; xv[x + k] == yv[y + k]; k++) + if(k == SNAKE_LIMIT - 1) + { + best = v; + part->xmid = x; + part->ymid = y; + break; + } + } + } + } + if(best > 0) + { + part->lo_minimal = 0; + part->hi_minimal = 1; + return 2 * c - 1; } } - } - if (best > 0) - { - part->lo_minimal = 0; - part->hi_minimal = 1; - return 2 * c - 1; - } - } - /* Heuristic: if we've gone well beyond the call of duty, + /* Heuristic: if we've gone well beyond the call of duty, give up and report halfway between our best results so far. */ - if (c >= too_expensive) - { - lin fxybest, fxbest; - lin bxybest, bxbest; + if(c >= too_expensive) + { + lin fxybest, fxbest; + lin bxybest, bxbest; - fxbest = bxbest = 0; /* Pacify `gcc -Wall'. */ + fxbest = bxbest = 0; /* Pacify `gcc -Wall'. */ - /* Find forward diagonal that maximizes X + Y. */ - fxybest = -1; - for (d = fmax; d >= fmin; d -= 2) - { - lin x = MIN (fd[d], xlim); - lin y = x - d; - if (ylim < y) - x = ylim + d, y = ylim; - if (fxybest < x + y) - { - fxybest = x + y; - fxbest = x; - } - } + /* Find forward diagonal that maximizes X + Y. */ + fxybest = -1; + for(d = fmax; d >= fmin; d -= 2) + { + lin x = MIN(fd[d], xlim); + lin y = x - d; + if(ylim < y) + x = ylim + d, y = ylim; + if(fxybest < x + y) + { + fxybest = x + y; + fxbest = x; + } + } - /* Find backward diagonal that minimizes X + Y. */ - bxybest = LIN_MAX; - for (d = bmax; d >= bmin; d -= 2) - { - lin x = MAX (xoff, bd[d]); - lin y = x - d; - if (y < yoff) - x = yoff + d, y = yoff; - if (x + y < bxybest) - { - bxybest = x + y; - bxbest = x; - } - } + /* Find backward diagonal that minimizes X + Y. */ + bxybest = LIN_MAX; + for(d = bmax; d >= bmin; d -= 2) + { + lin x = MAX(xoff, bd[d]); + lin y = x - d; + if(y < yoff) + x = yoff + d, y = yoff; + if(x + y < bxybest) + { + bxybest = x + y; + bxbest = x; + } + } - /* Use the better of the two diagonals. */ - if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff)) - { - part->xmid = fxbest; - part->ymid = fxybest - fxbest; - part->lo_minimal = 1; - part->hi_minimal = 0; - } - else - { - part->xmid = bxbest; - part->ymid = bxybest - bxbest; - part->lo_minimal = 0; - part->hi_minimal = 1; + /* Use the better of the two diagonals. */ + if((xlim + ylim) - bxybest < fxybest - (xoff + yoff)) + { + part->xmid = fxbest; + part->ymid = fxybest - fxbest; + part->lo_minimal = 1; + part->hi_minimal = 0; + } + else + { + part->xmid = bxbest; + part->ymid = bxybest - bxbest; + part->lo_minimal = 0; + part->hi_minimal = 1; + } + return 2 * c - 1; } - return 2 * c - 1; - } } } - + /* Compare in detail contiguous subsequences of the two files which are known, as a whole, to match each other. The results are recorded in the vectors files[N].changed, by storing 1 in the element for each line that is an insertion or deletion. The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1. Note that XLIM, YLIM are exclusive bounds. All line numbers are origin-0 and discarded lines are not counted. If FIND_MINIMAL, find a minimal difference no matter how expensive it is. */ -void GnuDiff::compareseq (lin xoff, lin xlim, lin yoff, lin ylim, bool find_minimal) +void GnuDiff::compareseq(lin xoff, lin xlim, lin yoff, lin ylim, bool find_minimal) { - lin * const xv = xvec; /* Help the compiler. */ - lin * const yv = yvec; - - /* Slide down the bottom initial diagonal. */ - while (xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff]) - ++xoff, ++yoff; - /* Slide up the top initial diagonal. */ - while (xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1]) - --xlim, --ylim; - - /* Handle simple cases. */ - if (xoff == xlim) - while (yoff < ylim) - files[1].changed[files[1].realindexes[yoff++]] = 1; - else if (yoff == ylim) - while (xoff < xlim) - files[0].changed[files[0].realindexes[xoff++]] = 1; - else + lin *const xv = xvec; /* Help the compiler. */ + lin *const yv = yvec; + + /* Slide down the bottom initial diagonal. */ + while(xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff]) + ++xoff, ++yoff; + /* Slide up the top initial diagonal. */ + while(xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1]) + --xlim, --ylim; + + /* Handle simple cases. */ + if(xoff == xlim) + while(yoff < ylim) + files[1].changed[files[1].realindexes[yoff++]] = 1; + else if(yoff == ylim) + while(xoff < xlim) + files[0].changed[files[0].realindexes[xoff++]] = 1; + else { - lin c; - struct partition part; + lin c; + struct partition part; - /* Find a point of correspondence in the middle of the files. */ + /* Find a point of correspondence in the middle of the files. */ - c = diag (xoff, xlim, yoff, ylim, find_minimal, &part); + c = diag(xoff, xlim, yoff, ylim, find_minimal, &part); - if (c == 1) - { - /* This should be impossible, because it implies that + if(c == 1) + { + /* This should be impossible, because it implies that one of the two subsequences is empty, and that case was handled above without calling `diag'. Let's verify that this is true. */ - abort (); + abort(); #if 0 /* The two subsequences differ by a single insert or delete; record it and we are done. */ if (part.xmid - part.ymid < xoff - yoff) files[1].changed[files[1].realindexes[part.ymid - 1]] = 1; else files[0].changed[files[0].realindexes[part.xmid]] = 1; #endif - } - else - { - /* Use the partitions to split this problem into subproblems. */ - compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal); - compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal); - } + } + else + { + /* Use the partitions to split this problem into subproblems. */ + compareseq(xoff, part.xmid, yoff, part.ymid, part.lo_minimal); + compareseq(part.xmid, xlim, part.ymid, ylim, part.hi_minimal); + } } } - + /* Discard lines from one file that have no matches in the other file. A line which is discarded will not be considered by the actual comparison algorithm; it will be as if that line were not in the file. The file's `realindexes' table maps virtual line numbers (which don't count the discarded lines) into real line numbers; this is how the actual comparison algorithm produces results that are comprehensible when the discarded lines are counted. When we discard a line, we also mark it as a deletion or insertion so that it will be printed in the output. */ -void GnuDiff::discard_confusing_lines (struct file_data filevec[]) +void GnuDiff::discard_confusing_lines(struct file_data filevec[]) { - int f; - lin i; - char *discarded[2]; - lin *equiv_count[2]; - lin *p; - - /* Allocate our results. */ - p = (lin*)xmalloc ((filevec[0].buffered_lines + filevec[1].buffered_lines) - * (2 * sizeof *p)); - for (f = 0; f < 2; f++) + int f; + lin i; + char *discarded[2]; + lin *equiv_count[2]; + lin *p; + + /* Allocate our results. */ + p = (lin *)xmalloc((filevec[0].buffered_lines + filevec[1].buffered_lines) * (2 * sizeof *p)); + for(f = 0; f < 2; f++) { - filevec[f].undiscarded = p; p += filevec[f].buffered_lines; - filevec[f].realindexes = p; p += filevec[f].buffered_lines; + filevec[f].undiscarded = p; + p += filevec[f].buffered_lines; + filevec[f].realindexes = p; + p += filevec[f].buffered_lines; } - /* Set up equiv_count[F][I] as the number of lines in file F + /* Set up equiv_count[F][I] as the number of lines in file F that fall in equivalence class I. */ - p = (lin*)zalloc (filevec[0].equiv_max * (2 * sizeof *p)); - equiv_count[0] = p; - equiv_count[1] = p + filevec[0].equiv_max; + p = (lin *)zalloc(filevec[0].equiv_max * (2 * sizeof *p)); + equiv_count[0] = p; + equiv_count[1] = p + filevec[0].equiv_max; - for (i = 0; i < filevec[0].buffered_lines; ++i) - ++equiv_count[0][filevec[0].equivs[i]]; - for (i = 0; i < filevec[1].buffered_lines; ++i) - ++equiv_count[1][filevec[1].equivs[i]]; + for(i = 0; i < filevec[0].buffered_lines; ++i) + ++equiv_count[0][filevec[0].equivs[i]]; + for(i = 0; i < filevec[1].buffered_lines; ++i) + ++equiv_count[1][filevec[1].equivs[i]]; - /* Set up tables of which lines are going to be discarded. */ + /* Set up tables of which lines are going to be discarded. */ - discarded[0] = (char*)zalloc (filevec[0].buffered_lines - + filevec[1].buffered_lines); - discarded[1] = discarded[0] + filevec[0].buffered_lines; + discarded[0] = (char *)zalloc(filevec[0].buffered_lines + filevec[1].buffered_lines); + discarded[1] = discarded[0] + filevec[0].buffered_lines; - /* Mark to be discarded each line that matches no line of the other file. + /* Mark to be discarded each line that matches no line of the other file. If a line matches many lines, mark it as provisionally discardable. */ - for (f = 0; f < 2; f++) + for(f = 0; f < 2; f++) { - size_t end = filevec[f].buffered_lines; - char *discards = discarded[f]; - lin *counts = equiv_count[1 - f]; - lin *equivs = filevec[f].equivs; - size_t many = 5; - size_t tem = end / 64; - - /* Multiply MANY by approximate square root of number of lines. + size_t end = filevec[f].buffered_lines; + char *discards = discarded[f]; + lin *counts = equiv_count[1 - f]; + lin *equivs = filevec[f].equivs; + size_t many = 5; + size_t tem = end / 64; + + /* Multiply MANY by approximate square root of number of lines. That is the threshold for provisionally discardable lines. */ - while ((tem = tem >> 2) > 0) - many *= 2; + while((tem = tem >> 2) > 0) + many *= 2; - for (i = 0; i < (lin)end; i++) - { - lin nmatch; - if (equivs[i] == 0) - continue; - nmatch = counts[equivs[i]]; - if (nmatch == 0) - discards[i] = 1; - else if (nmatch > (lin)many) - discards[i] = 2; - } + for(i = 0; i < (lin)end; i++) + { + lin nmatch; + if(equivs[i] == 0) + continue; + nmatch = counts[equivs[i]]; + if(nmatch == 0) + discards[i] = 1; + else if(nmatch > (lin)many) + discards[i] = 2; + } } - /* Don't really discard the provisional lines except when they occur + /* Don't really discard the provisional lines except when they occur in a run of discardables, with nonprovisionals at the beginning and end. */ - for (f = 0; f < 2; f++) + for(f = 0; f < 2; f++) { - lin end = filevec[f].buffered_lines; - char *discards = discarded[f]; + lin end = filevec[f].buffered_lines; + char *discards = discarded[f]; - for (i = 0; i < end; i++) - { - /* Cancel provisional discards not in middle of run of discards. */ - if (discards[i] == 2) - discards[i] = 0; - else if (discards[i] != 0) + for(i = 0; i < end; i++) { - /* We have found a nonprovisional discard. */ - lin j; - lin length; - lin provisional = 0; + /* Cancel provisional discards not in middle of run of discards. */ + if(discards[i] == 2) + discards[i] = 0; + else if(discards[i] != 0) + { + /* We have found a nonprovisional discard. */ + lin j; + lin length; + lin provisional = 0; - /* Find end of this run of discardable lines. + /* Find end of this run of discardable lines. Count how many are provisionally discardable. */ - for (j = i; j < end; j++) - { - if (discards[j] == 0) - break; - if (discards[j] == 2) - ++provisional; - } - - /* Cancel provisional discards at end, and shrink the run. */ - while (j > i && discards[j - 1] == 2) - discards[--j] = 0, --provisional; - - /* Now we have the length of a run of discardable lines + for(j = i; j < end; j++) + { + if(discards[j] == 0) + break; + if(discards[j] == 2) + ++provisional; + } + + /* Cancel provisional discards at end, and shrink the run. */ + while(j > i && discards[j - 1] == 2) + discards[--j] = 0, --provisional; + + /* Now we have the length of a run of discardable lines whose first and last are not provisional. */ - length = j - i; + length = j - i; - /* If 1/4 of the lines in the run are provisional, + /* If 1/4 of the lines in the run are provisional, cancel discarding of all provisional lines in the run. */ - if (provisional * 4 > length) - { - while (j > i) - if (discards[--j] == 2) - discards[j] = 0; - } - else - { - lin consec; - lin minimum = 1; - lin tem = length >> 2; - - /* MINIMUM is approximate square root of LENGTH/4. + if(provisional * 4 > length) + { + while(j > i) + if(discards[--j] == 2) + discards[j] = 0; + } + else + { + lin consec; + lin minimum = 1; + lin tem = length >> 2; + + /* MINIMUM is approximate square root of LENGTH/4. A subrun of two or more provisionals can stand when LENGTH is at least 16. A subrun of 4 or more can stand when LENGTH >= 64. */ - while (0 < (tem >>= 2)) - minimum <<= 1; - minimum++; + while(0 < (tem >>= 2)) + minimum <<= 1; + minimum++; - /* Cancel any subrun of MINIMUM or more provisionals + /* Cancel any subrun of MINIMUM or more provisionals within the larger run. */ - for (j = 0, consec = 0; j < length; j++) - if (discards[i + j] != 2) - consec = 0; - else if (minimum == ++consec) - /* Back up to start of subrun, to cancel it all. */ - j -= consec; - else if (minimum < consec) - discards[i + j] = 0; - - /* Scan from beginning of run + for(j = 0, consec = 0; j < length; j++) + if(discards[i + j] != 2) + consec = 0; + else if(minimum == ++consec) + /* Back up to start of subrun, to cancel it all. */ + j -= consec; + else if(minimum < consec) + discards[i + j] = 0; + + /* Scan from beginning of run until we find 3 or more nonprovisionals in a row or until the first nonprovisional at least 8 lines in. Until that point, cancel any provisionals. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i + j] == 1) - break; - if (discards[i + j] == 2) - consec = 0, discards[i + j] = 0; - else if (discards[i + j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; - } - - /* I advances to the last line of the run. */ - i += length - 1; - - /* Same thing, from end. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i - j] == 1) - break; - if (discards[i - j] == 2) - consec = 0, discards[i - j] = 0; - else if (discards[i - j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; + for(j = 0, consec = 0; j < length; j++) + { + if(j >= 8 && discards[i + j] == 1) + break; + if(discards[i + j] == 2) + consec = 0, discards[i + j] = 0; + else if(discards[i + j] == 0) + consec = 0; + else + consec++; + if(consec == 3) + break; + } + + /* I advances to the last line of the run. */ + i += length - 1; + + /* Same thing, from end. */ + for(j = 0, consec = 0; j < length; j++) + { + if(j >= 8 && discards[i - j] == 1) + break; + if(discards[i - j] == 2) + consec = 0, discards[i - j] = 0; + else if(discards[i - j] == 0) + consec = 0; + else + consec++; + if(consec == 3) + break; + } + } } } - } - } } - /* Actually discard the lines. */ - for (f = 0; f < 2; f++) + /* Actually discard the lines. */ + for(f = 0; f < 2; f++) { - char *discards = discarded[f]; - lin end = filevec[f].buffered_lines; - lin j = 0; - for (i = 0; i < end; ++i) - if (minimal || discards[i] == 0) - { - filevec[f].undiscarded[j] = filevec[f].equivs[i]; - filevec[f].realindexes[j++] = i; - } - else - filevec[f].changed[i] = 1; - filevec[f].nondiscarded_lines = j; + char *discards = discarded[f]; + lin end = filevec[f].buffered_lines; + lin j = 0; + for(i = 0; i < end; ++i) + if(minimal || discards[i] == 0) + { + filevec[f].undiscarded[j] = filevec[f].equivs[i]; + filevec[f].realindexes[j++] = i; + } + else + filevec[f].changed[i] = 1; + filevec[f].nondiscarded_lines = j; } - free (discarded[0]); - free (equiv_count[0]); + free(discarded[0]); + free(equiv_count[0]); } - + /* Adjust inserts/deletes of identical lines to join changes as much as possible. We do something when a run of changed lines include a line at one end and have an excluded, identical line at the other. We are free to choose which identical line is included. `compareseq' usually chooses the one at the beginning, but usually it is cleaner to consider the following identical line to be the "change". */ -void GnuDiff::shift_boundaries (struct file_data filevec[]) +void GnuDiff::shift_boundaries(struct file_data filevec[]) { - int f; + int f; - for (f = 0; f < 2; f++) + for(f = 0; f < 2; f++) { - bool *changed = filevec[f].changed; - bool const *other_changed = filevec[1 - f].changed; - lin const *equivs = filevec[f].equivs; - lin i = 0; - lin j = 0; - lin i_end = filevec[f].buffered_lines; - - while (1) - { - lin runlength, start, corresponding; + bool *changed = filevec[f].changed; + bool const *other_changed = filevec[1 - f].changed; + lin const *equivs = filevec[f].equivs; + lin i = 0; + lin j = 0; + lin i_end = filevec[f].buffered_lines; + + while(1) + { + lin runlength, start, corresponding; - /* Scan forwards to find beginning of another run of changes. + /* Scan forwards to find beginning of another run of changes. Also keep track of the corresponding point in the other file. */ - while (i < i_end && !changed[i]) - { - while (other_changed[j++]) - continue; - i++; - } + while(i < i_end && !changed[i]) + { + while(other_changed[j++]) + continue; + i++; + } - if (i == i_end) - break; + if(i == i_end) + break; - start = i; + start = i; - /* Find the end of this run of changes. */ + /* Find the end of this run of changes. */ - while (changed[++i]) - continue; - while (other_changed[j]) - j++; + while(changed[++i]) + continue; + while(other_changed[j]) + j++; - do - { - /* Record the length of this run of changes, so that + do + { + /* Record the length of this run of changes, so that we can later determine whether the run has grown. */ - runlength = i - start; + runlength = i - start; - /* Move the changed region back, so long as the + /* Move the changed region back, so long as the previous unchanged line matches the last changed one. This merges with previous changed regions. */ - while (start && equivs[start - 1] == equivs[i - 1]) - { - changed[--start] = 1; - changed[--i] = 0; - while (changed[start - 1]) - start--; - while (other_changed[--j]) - continue; - } - - /* Set CORRESPONDING to the end of the changed run, at the last + while(start && equivs[start - 1] == equivs[i - 1]) + { + changed[--start] = 1; + changed[--i] = 0; + while(changed[start - 1]) + start--; + while(other_changed[--j]) + continue; + } + + /* Set CORRESPONDING to the end of the changed run, at the last point where it corresponds to a changed run in the other file. CORRESPONDING == I_END means no such point has been found. */ - corresponding = other_changed[j - 1] ? i : i_end; + corresponding = other_changed[j - 1] ? i : i_end; - /* Move the changed region forward, so long as the + /* Move the changed region forward, so long as the first changed line matches the following unchanged one. This merges with following changed regions. Do this second, so that if there are no merges, the changed region is moved forward as far as possible. */ - while (i != i_end && equivs[start] == equivs[i]) - { - changed[start++] = 0; - changed[i++] = 1; - while (changed[i]) - i++; - while (other_changed[++j]) - corresponding = i; - } - } - while (runlength != i - start); - - /* If possible, move the fully-merged run of changes + while(i != i_end && equivs[start] == equivs[i]) + { + changed[start++] = 0; + changed[i++] = 1; + while(changed[i]) + i++; + while(other_changed[++j]) + corresponding = i; + } + } while(runlength != i - start); + + /* If possible, move the fully-merged run of changes back to a corresponding run in the other file. */ - while (corresponding < i) - { - changed[--start] = 1; - changed[--i] = 0; - while (other_changed[--j]) - continue; + while(corresponding < i) + { + changed[--start] = 1; + changed[--i] = 0; + while(other_changed[--j]) + continue; + } } } - } } - + /* Cons an additional entry onto the front of an edit script OLD. LINE0 and LINE1 are the first affected lines in the two files (origin 0). DELETED is the number of lines deleted here from file 0. INSERTED is the number of lines inserted here in file 1. If DELETED is 0 then LINE0 is the number of the line before which the insertion was done; vice versa for INSERTED and LINE1. */ -GnuDiff::change* GnuDiff::add_change (lin line0, lin line1, lin deleted, lin inserted, struct change *old) +GnuDiff::change *GnuDiff::add_change(lin line0, lin line1, lin deleted, lin inserted, struct change *old) { - struct change *newChange = (change*) xmalloc (sizeof *newChange); - - newChange->line0 = line0; - newChange->line1 = line1; - newChange->inserted = inserted; - newChange->deleted = deleted; - newChange->link = old; - return newChange; + struct change *newChange = (change *)xmalloc(sizeof *newChange); + + newChange->line0 = line0; + newChange->line1 = line1; + newChange->inserted = inserted; + newChange->deleted = deleted; + newChange->link = old; + return newChange; } /* Scan the tables of which lines are inserted and deleted, producing an edit script in reverse order. */ -GnuDiff::change* GnuDiff::build_reverse_script (struct file_data const filevec[]) +GnuDiff::change *GnuDiff::build_reverse_script(struct file_data const filevec[]) { - struct change *script = 0; - bool *changed0 = filevec[0].changed; - bool *changed1 = filevec[1].changed; - lin len0 = filevec[0].buffered_lines; - lin len1 = filevec[1].buffered_lines; + struct change *script = 0; + bool *changed0 = filevec[0].changed; + bool *changed1 = filevec[1].changed; + lin len0 = filevec[0].buffered_lines; + lin len1 = filevec[1].buffered_lines; - /* Note that changedN[len0] does exist, and is 0. */ + /* Note that changedN[len0] does exist, and is 0. */ - lin i0 = 0, i1 = 0; + lin i0 = 0, i1 = 0; - while (i0 < len0 || i1 < len1) - { - if (changed0[i0] | changed1[i1]) + while(i0 < len0 || i1 < len1) { - lin line0 = i0, line1 = i1; + if(changed0[i0] | changed1[i1]) + { + lin line0 = i0, line1 = i1; - /* Find # lines changed here in each file. */ - while (changed0[i0]) ++i0; - while (changed1[i1]) ++i1; + /* Find # lines changed here in each file. */ + while(changed0[i0]) ++i0; + while(changed1[i1]) ++i1; - /* Record this change. */ - script = add_change (line0, line1, i0 - line0, i1 - line1, script); - } + /* Record this change. */ + script = add_change(line0, line1, i0 - line0, i1 - line1, script); + } - /* We have reached lines in the two files that match each other. */ - i0++, i1++; + /* We have reached lines in the two files that match each other. */ + i0++, i1++; } - return script; + return script; } /* Scan the tables of which lines are inserted and deleted, producing an edit script in forward order. */ -GnuDiff::change* GnuDiff::build_script (struct file_data const filevec[]) +GnuDiff::change *GnuDiff::build_script(struct file_data const filevec[]) { - struct change *script = 0; - bool *changed0 = filevec[0].changed; - bool *changed1 = filevec[1].changed; - lin i0 = filevec[0].buffered_lines, i1 = filevec[1].buffered_lines; + struct change *script = 0; + bool *changed0 = filevec[0].changed; + bool *changed1 = filevec[1].changed; + lin i0 = filevec[0].buffered_lines, i1 = filevec[1].buffered_lines; - /* Note that changedN[-1] does exist, and is 0. */ + /* Note that changedN[-1] does exist, and is 0. */ - while (i0 >= 0 || i1 >= 0) - { - if (changed0[i0 - 1] | changed1[i1 - 1]) + while(i0 >= 0 || i1 >= 0) { - lin line0 = i0, line1 = i1; + if(changed0[i0 - 1] | changed1[i1 - 1]) + { + lin line0 = i0, line1 = i1; - /* Find # lines changed here in each file. */ - while (changed0[i0 - 1]) --i0; - while (changed1[i1 - 1]) --i1; + /* Find # lines changed here in each file. */ + while(changed0[i0 - 1]) --i0; + while(changed1[i1 - 1]) --i1; - /* Record this change. */ - script = add_change (i0, i1, line0 - i0, line1 - i1, script); - } + /* Record this change. */ + script = add_change(i0, i1, line0 - i0, line1 - i1, script); + } - /* We have reached lines in the two files that match each other. */ - i0--, i1--; + /* We have reached lines in the two files that match each other. */ + i0--, i1--; } - return script; + return script; } - /* Report the differences of two files. */ -GnuDiff::change* GnuDiff::diff_2_files (struct comparison *cmp) +GnuDiff::change *GnuDiff::diff_2_files(struct comparison *cmp) { - lin diags; - int f; - struct change *script; + lin diags; + int f; + struct change *script; - read_files (cmp->file, files_can_be_treated_as_binary); + read_files(cmp->file, files_can_be_treated_as_binary); { - /* Allocate vectors for the results of comparison: + /* Allocate vectors for the results of comparison: a flag for each line of each file, saying whether that line is an insertion or deletion. Allocate an extra element, always 0, at each end of each vector. */ - size_t s = cmp->file[0].buffered_lines + cmp->file[1].buffered_lines + 4; - bool *flag_space = (bool*)zalloc (s * sizeof(*flag_space)); - cmp->file[0].changed = flag_space + 1; - cmp->file[1].changed = flag_space + cmp->file[0].buffered_lines + 3; + size_t s = cmp->file[0].buffered_lines + cmp->file[1].buffered_lines + 4; + bool *flag_space = (bool *)zalloc(s * sizeof(*flag_space)); + cmp->file[0].changed = flag_space + 1; + cmp->file[1].changed = flag_space + cmp->file[0].buffered_lines + 3; - /* Some lines are obviously insertions or deletions + /* Some lines are obviously insertions or deletions because they don't match anything. Detect them now, and avoid even thinking about them in the main comparison algorithm. */ - discard_confusing_lines (cmp->file); + discard_confusing_lines(cmp->file); - /* Now do the main comparison algorithm, considering just the + /* Now do the main comparison algorithm, considering just the undiscarded lines. */ - xvec = cmp->file[0].undiscarded; - yvec = cmp->file[1].undiscarded; - diags = (cmp->file[0].nondiscarded_lines - + cmp->file[1].nondiscarded_lines + 3); - fdiag = (lin*)xmalloc (diags * (2 * sizeof *fdiag)); - bdiag = fdiag + diags; - fdiag += cmp->file[1].nondiscarded_lines + 1; - bdiag += cmp->file[1].nondiscarded_lines + 1; + xvec = cmp->file[0].undiscarded; + yvec = cmp->file[1].undiscarded; + diags = (cmp->file[0].nondiscarded_lines + cmp->file[1].nondiscarded_lines + 3); + fdiag = (lin *)xmalloc(diags * (2 * sizeof *fdiag)); + bdiag = fdiag + diags; + fdiag += cmp->file[1].nondiscarded_lines + 1; + bdiag += cmp->file[1].nondiscarded_lines + 1; - /* Set TOO_EXPENSIVE to be approximate square root of input size, + /* Set TOO_EXPENSIVE to be approximate square root of input size, bounded below by 256. */ - too_expensive = 1; - for (; diags != 0; diags >>= 2) - too_expensive <<= 1; - too_expensive = MAX (256, too_expensive); + too_expensive = 1; + for(; diags != 0; diags >>= 2) + too_expensive <<= 1; + too_expensive = MAX(256, too_expensive); - files[0] = cmp->file[0]; - files[1] = cmp->file[1]; + files[0] = cmp->file[0]; + files[1] = cmp->file[1]; - compareseq (0, cmp->file[0].nondiscarded_lines, - 0, cmp->file[1].nondiscarded_lines, minimal); + compareseq(0, cmp->file[0].nondiscarded_lines, + 0, cmp->file[1].nondiscarded_lines, minimal); - free (fdiag - (cmp->file[1].nondiscarded_lines + 1)); + free(fdiag - (cmp->file[1].nondiscarded_lines + 1)); - /* Modify the results slightly to make them prettier + /* Modify the results slightly to make them prettier in cases where that can validly be done. */ - shift_boundaries (cmp->file); + shift_boundaries(cmp->file); - /* Get the results of comparison in the form of a chain + /* Get the results of comparison in the form of a chain of `struct change's -- an edit script. */ - script = build_script (cmp->file); + script = build_script(cmp->file); - free (cmp->file[0].undiscarded); + free(cmp->file[0].undiscarded); - free (flag_space); + free(flag_space); - for (f = 0; f < 2; f++) - { - free (cmp->file[f].equivs); - free (cmp->file[f].linbuf + cmp->file[f].linbuf_base); - } + for(f = 0; f < 2; f++) + { + free(cmp->file[f].equivs); + free(cmp->file[f].linbuf + cmp->file[f].linbuf_base); + } } - return script; + return script; } diff --git a/src/gnudiff_io.cpp b/src/gnudiff_io.cpp index 2a04c43..b1c8be2 100644 --- a/src/gnudiff_io.cpp +++ b/src/gnudiff_io.cpp @@ -1,558 +1,545 @@ /* File I/O for GNU DIFF. Modified for KDiff3 by Joachim Eibl 2003, 2004, 2005. The original file was part of GNU DIFF. Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002 Free Software Foundation, Inc. GNU DIFF is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU DIFF is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gnudiff_diff.h" #include /* Rotate an unsigned value to the left. */ -#define ROL(v, n) ((v) << (n) | (v) >> (sizeof (v) * CHAR_BIT - (n))) +#define ROL(v, n) ((v) << (n) | (v) >> (sizeof(v) * CHAR_BIT - (n))) /* Given a hash value and a new character, return a new hash value. */ -#define HASH(h, c) ((c) + ROL (h, 7)) +#define HASH(h, c) ((c) + ROL(h, 7)) /* The type of a hash value. */ typedef size_t hash_value; -verify (hash_value_is_unsigned, ! TYPE_SIGNED (hash_value)); +verify(hash_value_is_unsigned, !TYPE_SIGNED(hash_value)); /* Lines are put into equivalence classes of lines that match in lines_differ. Each equivalence class is represented by one of these structures, but only while the classes are being computed. Afterward, each class is represented by a number. */ -struct equivclass -{ - lin next; /* Next item in this bucket. */ - hash_value hash; /* Hash of lines in this class. */ - const QChar *line; /* A line that fits this class. */ - size_t length; /* That line's length, not counting its newline. */ +struct equivclass { + lin next; /* Next item in this bucket. */ + hash_value hash; /* Hash of lines in this class. */ + const QChar *line; /* A line that fits this class. */ + size_t length; /* That line's length, not counting its newline. */ }; /* Hash-table: array of buckets, each being a chain of equivalence classes. buckets[-1] is reserved for incomplete lines. */ static lin *buckets; /* Number of buckets in the hash table array, not counting buckets[-1]. */ static size_t nbuckets; /* Array in which the equivalence classes are allocated. The bucket-chains go through the elements in this array. The number of an equivalence class is its index in this array. */ static struct equivclass *equivs; /* Index of first free element in the array `equivs'. */ static lin equivs_index; /* Number of elements allocated in the array `equivs'. */ static lin equivs_alloc; /* Check for binary files and compare them for exact identity. */ /* Return 1 if BUF contains a non text character. SIZE is the number of characters in BUF. */ -#define binary_file_p(buf, size) (memchr (buf, 0, size) != 0) +#define binary_file_p(buf, size) (memchr(buf, 0, size) != 0) /* Compare two lines (typically one from each input file) according to the command line options. For efficiency, this is invoked only when the lines do not match exactly but an option like -i might cause us to ignore the difference. Return nonzero if the lines differ. */ -bool GnuDiff::lines_differ (const QChar *s1, size_t len1, const QChar *s2, size_t len2 ) +bool GnuDiff::lines_differ(const QChar *s1, size_t len1, const QChar *s2, size_t len2) { - const QChar *t1 = s1; - const QChar *t2 = s2; - const QChar *s1end = s1+len1; - const QChar *s2end = s2+len2; - - for ( ; ; ++t1, ++t2 ) - { - /* Test for exact char equality first, since it's a common case. */ - if ( t1!=s1end && t2!=s2end && *t1==*t2 ) - continue; - else - { - while ( t1!=s1end && - ( (bIgnoreWhiteSpace && isWhite( *t1 )) || - (bIgnoreNumbers && (t1->isDigit() || *t1=='-' || *t1=='.' )))) - { - ++t1; - } - - while ( t2 != s2end && - ( (bIgnoreWhiteSpace && isWhite( *t2 )) || - (bIgnoreNumbers && (t2->isDigit() || *t2=='-' || *t2=='.' )))) - { - ++t2; - } - - if ( t1!=s1end && t2!=s2end ) - { - if (ignore_case) - { /* Lowercase comparison. */ - if ( t1->toLower() == t2->toLower() ) - continue; + const QChar *t1 = s1; + const QChar *t2 = s2; + const QChar *s1end = s1 + len1; + const QChar *s2end = s2 + len2; + + for(;; ++t1, ++t2) + { + /* Test for exact char equality first, since it's a common case. */ + if(t1 != s1end && t2 != s2end && *t1 == *t2) + continue; + else + { + while(t1 != s1end && + ((bIgnoreWhiteSpace && isWhite(*t1)) || + (bIgnoreNumbers && (t1->isDigit() || *t1 == '-' || *t1 == '.')))) + { + ++t1; + } + + while(t2 != s2end && + ((bIgnoreWhiteSpace && isWhite(*t2)) || + (bIgnoreNumbers && (t2->isDigit() || *t2 == '-' || *t2 == '.')))) + { + ++t2; + } + + if(t1 != s1end && t2 != s2end) + { + if(ignore_case) + { /* Lowercase comparison. */ + if(t1->toLower() == t2->toLower()) + continue; + } + else if(*t1 == *t2) + continue; + else + return true; } - else if ( *t1 == *t2 ) - continue; + else if(t1 == s1end && t2 == s2end) + return false; else - return true; - } - else if ( t1==s1end && t2==s2end ) - return false; - else - return true; - } - } - return false; + return true; + } + } + return false; } - /* Split the file into lines, simultaneously computing the equivalence class for each line. */ -void GnuDiff::find_and_hash_each_line (struct file_data *current) +void GnuDiff::find_and_hash_each_line(struct file_data *current) { - hash_value h; - const QChar *p = current->prefix_end; - QChar c; - lin i, *bucket; - size_t length; - - /* Cache often-used quantities in local variables to help the compiler. */ - const QChar **linbuf = current->linbuf; - lin alloc_lines = current->alloc_lines; - lin line = 0; - lin linbuf_base = current->linbuf_base; - lin *cureqs = (lin*)xmalloc (alloc_lines * sizeof *cureqs); - struct equivclass *eqs = equivs; - lin eqs_index = equivs_index; - lin eqs_alloc = equivs_alloc; - const QChar *suffix_begin = current->suffix_begin; - const QChar *bufend = current->buffer + current->buffered; - bool diff_length_compare_anyway = - ignore_white_space != IGNORE_NO_WHITE_SPACE || bIgnoreNumbers; - bool same_length_diff_contents_compare_anyway = - diff_length_compare_anyway | ignore_case; - - while ( p < suffix_begin) + hash_value h; + const QChar *p = current->prefix_end; + QChar c; + lin i, *bucket; + size_t length; + + /* Cache often-used quantities in local variables to help the compiler. */ + const QChar **linbuf = current->linbuf; + lin alloc_lines = current->alloc_lines; + lin line = 0; + lin linbuf_base = current->linbuf_base; + lin *cureqs = (lin *)xmalloc(alloc_lines * sizeof *cureqs); + struct equivclass *eqs = equivs; + lin eqs_index = equivs_index; + lin eqs_alloc = equivs_alloc; + const QChar *suffix_begin = current->suffix_begin; + const QChar *bufend = current->buffer + current->buffered; + bool diff_length_compare_anyway = + ignore_white_space != IGNORE_NO_WHITE_SPACE || bIgnoreNumbers; + bool same_length_diff_contents_compare_anyway = + diff_length_compare_anyway | ignore_case; + + while(p < suffix_begin) { - const QChar *ip = p; + const QChar *ip = p; - h = 0; + h = 0; - /* Hash this line until we find a newline or bufend is reached. */ - if (ignore_case) - switch (ignore_white_space) - { - case IGNORE_ALL_SPACE: - while ( pbuffered_lines = line; + current->buffered_lines = line; - for (i = 0; ; i++) + for(i = 0;; i++) { - /* Record the line start for lines in the suffix that we care about. + /* Record the line start for lines in the suffix that we care about. Record one more line start than lines, so that we can compute the length of any buffered line. */ - if (line == alloc_lines) - { - /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */ - if ((lin)(PTRDIFF_MAX / 3) <= alloc_lines - || (lin)(PTRDIFF_MAX / sizeof *cureqs) <= 2 * alloc_lines - linbuf_base - || (lin)(PTRDIFF_MAX / sizeof *linbuf) <= alloc_lines - linbuf_base) - xalloc_die (); - alloc_lines = 2 * alloc_lines - linbuf_base; - linbuf += linbuf_base; - linbuf = (const QChar**)xrealloc (linbuf, - (alloc_lines - linbuf_base) * sizeof *linbuf); - linbuf -= linbuf_base; - } - linbuf[line] = p; + if(line == alloc_lines) + { + /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */ + if((lin)(PTRDIFF_MAX / 3) <= alloc_lines || (lin)(PTRDIFF_MAX / sizeof *cureqs) <= 2 * alloc_lines - linbuf_base || (lin)(PTRDIFF_MAX / sizeof *linbuf) <= alloc_lines - linbuf_base) + xalloc_die(); + alloc_lines = 2 * alloc_lines - linbuf_base; + linbuf += linbuf_base; + linbuf = (const QChar **)xrealloc(linbuf, + (alloc_lines - linbuf_base) * sizeof *linbuf); + linbuf -= linbuf_base; + } + linbuf[line] = p; - if ( p >= bufend) - break; + if(p >= bufend) + break; - if (context <= i && no_diff_means_no_output) - break; + if(context <= i && no_diff_means_no_output) + break; - line++; + line++; - while (plinbuf = linbuf; - current->valid_lines = line; - current->alloc_lines = alloc_lines; - current->equivs = cureqs; - equivs = eqs; - equivs_alloc = eqs_alloc; - equivs_index = eqs_index; + /* Done with cache in local variables. */ + current->linbuf = linbuf; + current->valid_lines = line; + current->alloc_lines = alloc_lines; + current->equivs = cureqs; + equivs = eqs; + equivs_alloc = eqs_alloc; + equivs_index = eqs_index; } /* We have found N lines in a buffer of size S; guess the proportionate number of lines that will be found in a buffer of size T. However, do not guess a number of lines so large that the resulting line table might cause overflow in size calculations. */ static lin -guess_lines (lin n, size_t s, size_t t) +guess_lines(lin n, size_t s, size_t t) { - size_t guessed_bytes_per_line = n < 10 ? 32 : s / (n - 1); - lin guessed_lines = MAX (1, t / guessed_bytes_per_line); - return MIN (guessed_lines, (lin)(PTRDIFF_MAX / (2 * sizeof (QChar *) + 1) - 5)) + 5; + size_t guessed_bytes_per_line = n < 10 ? 32 : s / (n - 1); + lin guessed_lines = MAX(1, t / guessed_bytes_per_line); + return MIN(guessed_lines, (lin)(PTRDIFF_MAX / (2 * sizeof(QChar *) + 1) - 5)) + 5; } /* Given a vector of two file_data objects, find the identical prefixes and suffixes of each object. */ -void GnuDiff::find_identical_ends (struct file_data filevec[]) +void GnuDiff::find_identical_ends(struct file_data filevec[]) { - /* Find identical prefix. */ - const QChar *p0, *p1, *buffer0, *buffer1; - p0 = buffer0 = filevec[0].buffer; - p1 = buffer1 = filevec[1].buffer; - size_t n0, n1; - n0 = filevec[0].buffered; - n1 = filevec[1].buffered; - const QChar* const pEnd0 = p0 + n0; - const QChar* const pEnd1 = p1 + n1; - - if (p0 == p1) - /* The buffers are the same; sentinels won't work. */ - p0 = p1 += n1; - else + /* Find identical prefix. */ + const QChar *p0, *p1, *buffer0, *buffer1; + p0 = buffer0 = filevec[0].buffer; + p1 = buffer1 = filevec[1].buffer; + size_t n0, n1; + n0 = filevec[0].buffered; + n1 = filevec[1].buffered; + const QChar *const pEnd0 = p0 + n0; + const QChar *const pEnd1 = p1 + n1; + + if(p0 == p1) + /* The buffers are the same; sentinels won't work. */ + p0 = p1 += n1; + else { - /* Loop until first mismatch, or end. */ - while ( p0!=pEnd0 && p1!=pEnd1 && *p0 == *p1 ) - { - p0++; - p1++; - } + /* Loop until first mismatch, or end. */ + while(p0 != pEnd0 && p1 != pEnd1 && *p0 == *p1) + { + p0++; + p1++; + } } - /* Now P0 and P1 point at the first nonmatching characters. */ + /* Now P0 and P1 point at the first nonmatching characters. */ - /* Skip back to last line-beginning in the prefix. */ - while (p0 != buffer0 && ! isEndOfLine(p0[-1]) ) - p0--, p1--; + /* Skip back to last line-beginning in the prefix. */ + while(p0 != buffer0 && !isEndOfLine(p0[-1])) + p0--, p1--; - /* Record the prefix. */ - filevec[0].prefix_end = p0; - filevec[1].prefix_end = p1; + /* Record the prefix. */ + filevec[0].prefix_end = p0; + filevec[1].prefix_end = p1; - /* Find identical suffix. */ + /* Find identical suffix. */ - /* P0 and P1 point beyond the last chars not yet compared. */ - p0 = buffer0 + n0; - p1 = buffer1 + n1; + /* P0 and P1 point beyond the last chars not yet compared. */ + p0 = buffer0 + n0; + p1 = buffer1 + n1; - const QChar *end0, *beg0; - end0 = p0; /* Addr of last char in file 0. */ + const QChar *end0, *beg0; + end0 = p0; /* Addr of last char in file 0. */ - /* Get value of P0 at which we should stop scanning backward: + /* Get value of P0 at which we should stop scanning backward: this is when either P0 or P1 points just past the last char of the identical prefix. */ - beg0 = filevec[0].prefix_end + (n0 < n1 ? 0 : n0 - n1); - - /* Scan back until chars don't match or we reach that point. */ - for (; p0 != beg0; p0--, p1--) - { - if (*p0 != *p1) - { - /* Point at the first char of the matching suffix. */ - beg0 = p0; - break; - } - } - - // Go to the next line (skip last line with a difference) - if ( p0 != end0 ) - { - if (*p0 != *p1) - ++p0; - while ( p0. */ static unsigned char const prime_offset[] = -{ - 0, 0, 1, 1, 3, 1, 3, 1, 5, 3, 3, 9, 3, 1, 3, 19, 15, 1, 5, 1, 3, 9, 3, - 15, 3, 39, 5, 39, 57, 3, 35, 1, 5, 9, 41, 31, 5, 25, 45, 7, 87, 21, - 11, 57, 17, 55, 21, 115, 59, 81, 27, 129, 47, 111, 33, 55, 5, 13, 27, - 55, 93, 1, 57, 25 -}; + { + 0, 0, 1, 1, 3, 1, 3, 1, 5, 3, 3, 9, 3, 1, 3, 19, 15, 1, 5, 1, 3, 9, 3, + 15, 3, 39, 5, 39, 57, 3, 35, 1, 5, 9, 41, 31, 5, 25, 45, 7, 87, 21, + 11, 57, 17, 55, 21, 115, 59, 81, 27, 129, 47, 111, 33, 55, 5, 13, 27, + 55, 93, 1, 57, 25}; /* Verify that this host's size_t is not too wide for the above table. */ -verify (enough_prime_offsets, - sizeof (size_t) * CHAR_BIT <= sizeof prime_offset); +verify(enough_prime_offsets, + sizeof(size_t) * CHAR_BIT <= sizeof prime_offset); /* Given a vector of two file_data objects, read the file associated with each one, and build the table of equivalence classes. Return nonzero if either file appears to be a binary file. If PRETEND_BINARY is nonzero, pretend they are binary regardless. */ -bool -GnuDiff::read_files (struct file_data filevec[], bool /*pretend_binary*/) +bool GnuDiff::read_files(struct file_data filevec[], bool /*pretend_binary*/) { - int i; + int i; - find_identical_ends (filevec); + find_identical_ends(filevec); - equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1; - if ((lin)(PTRDIFF_MAX / sizeof *equivs) <= equivs_alloc) - xalloc_die (); - equivs = (equivclass*)xmalloc (equivs_alloc * sizeof *equivs); - /* Equivalence class 0 is permanently safe for lines that were not + equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1; + if((lin)(PTRDIFF_MAX / sizeof *equivs) <= equivs_alloc) + xalloc_die(); + equivs = (equivclass *)xmalloc(equivs_alloc * sizeof *equivs); + /* Equivalence class 0 is permanently safe for lines that were not hashed. Real equivalence classes start at 1. */ - equivs_index = 1; + equivs_index = 1; - /* Allocate (one plus) a prime number of hash buckets. Use a prime + /* Allocate (one plus) a prime number of hash buckets. Use a prime number between 1/3 and 2/3 of the value of equiv_allocs, approximately. */ - for (i = 9; 1 << i < equivs_alloc / 3; i++) - continue; - nbuckets = ((size_t) 1 << i) - prime_offset[i]; - if (PTRDIFF_MAX / sizeof *buckets <= nbuckets) - xalloc_die (); - buckets = (lin*)zalloc ((nbuckets + 1) * sizeof *buckets); - buckets++; + for(i = 9; 1 << i < equivs_alloc / 3; i++) + continue; + nbuckets = ((size_t)1 << i) - prime_offset[i]; + if(PTRDIFF_MAX / sizeof *buckets <= nbuckets) + xalloc_die(); + buckets = (lin *)zalloc((nbuckets + 1) * sizeof *buckets); + buckets++; - for (i = 0; i < 2; i++) - find_and_hash_each_line (&filevec[i]); + for(i = 0; i < 2; i++) + find_and_hash_each_line(&filevec[i]); - filevec[0].equiv_max = filevec[1].equiv_max = equivs_index; + filevec[0].equiv_max = filevec[1].equiv_max = equivs_index; - free (equivs); - free (buckets - 1); + free(equivs); + free(buckets - 1); - return 0; + return 0; } diff --git a/src/gnudiff_xmalloc.cpp b/src/gnudiff_xmalloc.cpp index 9fdd52d..8761e33 100644 --- a/src/gnudiff_xmalloc.cpp +++ b/src/gnudiff_xmalloc.cpp @@ -1,84 +1,80 @@ /* xmalloc.c -- malloc with out of memory checking Modified for KDiff3 by Joachim Eibl 2003. The original file was part of GNU DIFF. Copyright (C) 1990-1999, 2000, 2002 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. */ #include - #include #include - #ifndef EXIT_FAILURE -# define EXIT_FAILURE 1 +#define EXIT_FAILURE 1 #endif #include "gnudiff_diff.h" /* If non NULL, call this function when memory is exhausted. */ //void (*xalloc_fail_func) PARAMS ((void)) = 0; void (*xalloc_fail_func)(void) = 0; - -void GnuDiff::xalloc_die (void) +void GnuDiff::xalloc_die(void) { - if (xalloc_fail_func) - (*xalloc_fail_func) (); - //error (exit_failure, 0, "%s", _(xalloc_msg_memory_exhausted)); - /* The `noreturn' cannot be given to error, since it may return if + if(xalloc_fail_func) + (*xalloc_fail_func)(); + //error (exit_failure, 0, "%s", _(xalloc_msg_memory_exhausted)); + /* The `noreturn' cannot be given to error, since it may return if its first argument is 0. To help compilers understand the xalloc_die does terminate, call exit. */ - exit (EXIT_FAILURE); + exit(EXIT_FAILURE); } /* Allocate N bytes of memory dynamically, with error checking. */ void * -GnuDiff::xmalloc (size_t n) +GnuDiff::xmalloc(size_t n) { - void *p; + void *p; - p = malloc (n == 0 ? 1 : n); // There are systems where malloc returns 0 for n==0. - if (p == 0) - xalloc_die (); - return p; + p = malloc(n == 0 ? 1 : n); // There are systems where malloc returns 0 for n==0. + if(p == 0) + xalloc_die(); + return p; } /* Change the size of an allocated block of memory P to N bytes, with error checking. */ void * -GnuDiff::xrealloc (void *p, size_t n) +GnuDiff::xrealloc(void *p, size_t n) { - p = realloc (p, n==0 ? 1 : n); - if (p == 0) - xalloc_die (); - return p; + p = realloc(p, n == 0 ? 1 : n); + if(p == 0) + xalloc_die(); + return p; } - /* Yield a new block of SIZE bytes, initialized to zero. */ void * -GnuDiff::zalloc (size_t size) +GnuDiff::zalloc(size_t size) { - void *p = xmalloc (size); - memset (p, 0, size); - return p; + void *p = xmalloc(size); + memset(p, 0, size); + return p; } diff --git a/src/kdiff3.cpp b/src/kdiff3.cpp index a9d7224..12eaef0 100644 --- a/src/kdiff3.cpp +++ b/src/kdiff3.cpp @@ -1,1104 +1,1098 @@ /*************************************************************************** kdiff3.cpp - description ------------------- begin : Don Jul 11 12:31:29 CEST 2002 copyright : (C) 2002-2007 by Joachim Eibl email : joachim.eibl at gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "difftextwindow.h" #include "mergeresultwindow.h" #include // include files for QT -#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 +#include +#include +#include #include -#include +#include // include files for KDE -#include -#include #include +#include +#include #include //#include +#include +#include #include #include -#include -#include // application specific includes -#include "kdiff3_shell.h" +#include "directorymergewindow.h" +#include "fileaccess.h" +#include "guiutils.h" // namespace KDiff3 #include "kdiff3.h" +#include "kdiff3_part.h" +#include "kdiff3_shell.h" #include "optiondialog.h" -#include "fileaccess.h" #include "progress.h" -#include "kdiff3_part.h" -#include "directorymergewindow.h" #include "smalldialogs.h" -#include "guiutils.h" // namespace KDiff3 #define ID_STATUS_MSG 1 #define MAIN_TOOLBAR_NAME "mainToolBar" KActionCollection* KDiff3App::actionCollection() { - if( m_pKDiff3Shell == 0 ) + if(m_pKDiff3Shell == 0) return m_pKDiff3Part->actionCollection(); else return m_pKDiff3Shell->actionCollection(); } QStatusBar* KDiff3App::statusBar() { - if( m_pKDiff3Shell == 0 ) + if(m_pKDiff3Shell == 0) return 0; else return m_pKDiff3Shell->statusBar(); } -KToolBar* KDiff3App::toolBar(const char* toolBarId ) +KToolBar* KDiff3App::toolBar(const char* toolBarId) { - if( m_pKDiff3Shell == 0 ) + if(m_pKDiff3Shell == 0) return 0; else - return m_pKDiff3Shell->toolBar( toolBarId ); -//return m_pKDiff3Shell->toolBar(); + return m_pKDiff3Shell->toolBar(toolBarId); + //return m_pKDiff3Shell->toolBar(); } bool KDiff3App::isPart() { return m_pKDiff3Shell == 0; } bool KDiff3App::isFileSaved() { return m_bFileSaved; } bool KDiff3App::isDirComparison() { return m_bDirCompare; } -KDiff3App::KDiff3App( QWidget* pParent, const char* /*name*/, KDiff3Part* pKDiff3Part ) - : QSplitter(pParent) //previously KMainWindow +KDiff3App::KDiff3App(QWidget* pParent, const char* /*name*/, KDiff3Part* pKDiff3Part) + : QSplitter(pParent) //previously KMainWindow { - setObjectName( "KDiff3App" ); + setObjectName("KDiff3App"); m_pKDiff3Part = pKDiff3Part; - m_pKDiff3Shell = qobject_cast( pParent ); + m_pKDiff3Shell = qobject_cast(pParent); - setWindowTitle( "KDiff3" ); - setOpaqueResize( false ); // faster resizing - setUpdatesEnabled( false ); + setWindowTitle("KDiff3"); + setOpaqueResize(false); // faster resizing + setUpdatesEnabled(false); // set Disabled to same color as enabled to prevent flicker in DirectoryMergeWindow QPalette pal; pal.setBrush(QPalette::Base, pal.brush(QPalette::Active, QPalette::Base)); pal.setColor(QPalette::Text, pal.color(QPalette::Active, QPalette::Text)); setPalette(pal); m_pMainSplitter = 0; m_pDirectoryMergeSplitter = 0; m_pDirectoryMergeWindow = 0; m_pCornerWidget = 0; m_pMainWidget = 0; m_pDiffTextWindow1 = 0; m_pDiffTextWindow2 = 0; m_pDiffTextWindow3 = 0; m_pDiffTextWindowFrame1 = 0; m_pDiffTextWindowFrame2 = 0; m_pDiffTextWindowFrame3 = 0; m_pDiffWindowSplitter = 0; - m_pOverview = 0; + m_pOverview = 0; m_bTripleDiff = false; m_pMergeResultWindow = 0; m_pMergeWindowFrame = 0; m_bOutputModified = false; m_bFileSaved = false; m_bTimerBlock = false; m_pHScrollBar = 0; m_pDiffVScrollBar = 0; m_pMergeVScrollBar = 0; viewToolBar = 0; m_bRecalcWordWrapPosted = false; m_bFinishMainInit = false; m_pEventLoopForPrinting = 0; m_bLoadFiles = false; // Needed before any file operations via FileAccess happen. if(!g_pProgressDialog) { - g_pProgressDialog = new ProgressDialog(this,statusBar()); - g_pProgressDialog->setStayHidden( true ); + g_pProgressDialog = new ProgressDialog(this, statusBar()); + g_pProgressDialog->setStayHidden(true); } // All default values must be set before calling readOptions(). - m_pOptionDialog = new OptionDialog( m_pKDiff3Shell != 0, this ); - connect( m_pOptionDialog, &OptionDialog::applyDone, this, &KDiff3App::slotRefresh ); + m_pOptionDialog = new OptionDialog(m_pKDiff3Shell != 0, this); + connect(m_pOptionDialog, &OptionDialog::applyDone, this, &KDiff3App::slotRefresh); // This is just a convenience variable to make code that accesses options more readable m_pOptions = &m_pOptionDialog->m_options; - m_pOptionDialog->readOptions( KSharedConfig::openConfig() ); + m_pOptionDialog->readOptions(KSharedConfig::openConfig()); // Option handling: Only when pParent==0 (no parent) int argCount = KDiff3Shell::getParser()->optionNames().count() + KDiff3Shell::getParser()->positionalArguments().count(); bool hasArgs = !isPart() && argCount > 0; - if( hasArgs ) { + if(hasArgs) { QString s; QString title; - if( KDiff3Shell::getParser()->isSet( "confighelp" ) ) + if(KDiff3Shell::getParser()->isSet("confighelp")) { s = m_pOptionDialog->calcOptionHelp(); - title = i18n( "Current Configuration:" ); + title = i18n("Current Configuration:"); } else { - s = m_pOptionDialog->parseOptions( KDiff3Shell::getParser()->values( "cs" ) ); - title = i18n( "Config Option Error:" ); + s = m_pOptionDialog->parseOptions(KDiff3Shell::getParser()->values("cs")); + title = i18n("Config Option Error:"); } - if( !s.isEmpty() ) + if(!s.isEmpty()) { //KMessageBox::information(0, s,i18n("KDiff3-Usage")); - QDialog* pDialog = new QDialog( this ); - pDialog->setAttribute( Qt::WA_DeleteOnClose ); - pDialog->setModal( true ); - pDialog->setWindowTitle( title ); - QVBoxLayout* pVBoxLayout = new QVBoxLayout( pDialog ); - QTextEdit* pTextEdit = new QTextEdit( pDialog ); - pTextEdit->setText( s ); - pTextEdit->setReadOnly( true ); - pTextEdit->setWordWrapMode( QTextOption::NoWrap ); - pVBoxLayout->addWidget( pTextEdit ); - pDialog->resize( 600, 400 ); + QDialog* pDialog = new QDialog(this); + pDialog->setAttribute(Qt::WA_DeleteOnClose); + pDialog->setModal(true); + pDialog->setWindowTitle(title); + QVBoxLayout* pVBoxLayout = new QVBoxLayout(pDialog); + QTextEdit* pTextEdit = new QTextEdit(pDialog); + pTextEdit->setText(s); + pTextEdit->setReadOnly(true); + pTextEdit->setWordWrapMode(QTextOption::NoWrap); + pVBoxLayout->addWidget(pTextEdit); + pDialog->resize(600, 400); pDialog->exec(); #if !defined(_WIN32) && !defined(Q_OS_OS2) // A windows program has no console - printf( "%s\n", title.toLatin1().constData() ); - printf( "%s\n", s.toLatin1().constData() ); + printf("%s\n", title.toLatin1().constData()); + printf("%s\n", s.toLatin1().constData()); #endif - exit( 1 ); + exit(1); } } - m_sd1.setOptions( m_pOptions ); - m_sd2.setOptions( m_pOptions ); - m_sd3.setOptions( m_pOptions ); + m_sd1.setOptions(m_pOptions); + m_sd2.setOptions(m_pOptions); + m_sd3.setOptions(m_pOptions); - m_bAutoFlag = false;//disable --auto option git hard codes this unwanted flag. + m_bAutoFlag = false; //disable --auto option git hard codes this unwanted flag. m_bAutoMode = m_bAutoFlag || m_pOptions->m_bAutoSaveAndQuitOnMergeWithoutConflicts; - if( hasArgs ) { - m_outputFilename = KDiff3Shell::getParser()->value( "output" ); - - if( m_outputFilename.isEmpty() ) - m_outputFilename = KDiff3Shell::getParser()->value( "out" ); - - if( ! m_outputFilename.isEmpty() ) - m_outputFilename = FileAccess( m_outputFilename, true ).absoluteFilePath(); - - if( m_bAutoMode && m_outputFilename.isEmpty() ) + if(hasArgs) { + m_outputFilename = KDiff3Shell::getParser()->value("output"); + + if(m_outputFilename.isEmpty()) + m_outputFilename = KDiff3Shell::getParser()->value("out"); + + if(!m_outputFilename.isEmpty()) + m_outputFilename = FileAccess(m_outputFilename, true).absoluteFilePath(); + + if(m_bAutoMode && m_outputFilename.isEmpty()) { - if( m_bAutoFlag ) + if(m_bAutoFlag) { //KMessageBox::information(this, i18n("Option --auto used, but no output file specified.")); - fprintf( stderr, "%s\n", ( const char* )i18n( "Option --auto used, but no output file specified." ).toLatin1() ); + fprintf(stderr, "%s\n", (const char*)i18n("Option --auto used, but no output file specified.").toLatin1()); } m_bAutoMode = false; } - - if( m_outputFilename.isEmpty() && KDiff3Shell::getParser()->isSet( "merge" ) ) + + if(m_outputFilename.isEmpty() && KDiff3Shell::getParser()->isSet("merge")) { m_outputFilename = "unnamed.txt"; m_bDefaultFilename = true; } - else { + else + { m_bDefaultFilename = false; - } - - g_bAutoSolve = !KDiff3Shell::getParser()->isSet( "qall" ); // Note that this is effective only once. - QStringList args = KDiff3Shell::getParser()->positionalArguments(); - - m_sd1.setFilename( KDiff3Shell::getParser()->value( "base" ) ); - if( m_sd1.isEmpty() ) { - if( args.count() > 0 ) m_sd1.setFilename( args[0] ); // args->arg(0) - if( args.count() > 1 ) m_sd2.setFilename( args[1] ); - if( args.count() > 2 ) m_sd3.setFilename( args[2] ); - } - else { - if( args.count() > 0 ) m_sd2.setFilename( args[0] ); - if( args.count() > 1 ) m_sd3.setFilename( args[1] ); - } - //never properly defined and redundant - QStringList aliasList;//KDiff3Shell::getParser()->values( "fname" ); - QStringList::Iterator ali = aliasList.begin(); + } - QString an1 = KDiff3Shell::getParser()->value( "L1" ); - if( !an1.isEmpty() ) { - m_sd1.setAliasName( an1 ); - } - else if( ali != aliasList.end() ) { - m_sd1.setAliasName( *ali ); - ++ali; - } + g_bAutoSolve = !KDiff3Shell::getParser()->isSet("qall"); // Note that this is effective only once. + QStringList args = KDiff3Shell::getParser()->positionalArguments(); - QString an2 = KDiff3Shell::getParser()->value( "L2" ); - if( !an2.isEmpty() ) { - m_sd2.setAliasName( an2 ); - } - else if( ali != aliasList.end() ) { - m_sd2.setAliasName( *ali ); - ++ali; + m_sd1.setFilename(KDiff3Shell::getParser()->value("base")); + if(m_sd1.isEmpty()) { + if(args.count() > 0) m_sd1.setFilename(args[0]); // args->arg(0) + if(args.count() > 1) m_sd2.setFilename(args[1]); + if(args.count() > 2) m_sd3.setFilename(args[2]); + } + else + { + if(args.count() > 0) m_sd2.setFilename(args[0]); + if(args.count() > 1) m_sd3.setFilename(args[1]); + } + //never properly defined and redundant + QStringList aliasList; //KDiff3Shell::getParser()->values( "fname" ); + QStringList::Iterator ali = aliasList.begin(); + + QString an1 = KDiff3Shell::getParser()->value("L1"); + if(!an1.isEmpty()) { + m_sd1.setAliasName(an1); + } + else if(ali != aliasList.end()) + { + m_sd1.setAliasName(*ali); + ++ali; + } + + QString an2 = KDiff3Shell::getParser()->value("L2"); + if(!an2.isEmpty()) { + m_sd2.setAliasName(an2); + } + else if(ali != aliasList.end()) + { + m_sd2.setAliasName(*ali); + ++ali; } - QString an3 = KDiff3Shell::getParser()->value( "L3" ); - if( !an3.isEmpty() ) { - m_sd3.setAliasName( an3 ); + QString an3 = KDiff3Shell::getParser()->value("L3"); + if(!an3.isEmpty()) { + m_sd3.setAliasName(an3); } - else if( ali != aliasList.end() ) { - m_sd3.setAliasName( *ali ); + else if(ali != aliasList.end()) + { + m_sd3.setAliasName(*ali); ++ali; } } - else { + else + { m_bDefaultFilename = false; g_bAutoSolve = false; } - g_pProgressDialog->setStayHidden( m_bAutoMode ); + g_pProgressDialog->setStayHidden(m_bAutoMode); /////////////////////////////////////////////////////////////////// // call inits to invoke all other construction parts - initActions( actionCollection() ); + initActions(actionCollection()); initStatusBar(); - m_pFindDialog = new FindDialog( this ); - connect( m_pFindDialog, &FindDialog::findNext, this, &KDiff3App::slotEditFindNext ); + m_pFindDialog = new FindDialog(this); + connect(m_pFindDialog, &FindDialog::findNext, this, &KDiff3App::slotEditFindNext); - autoAdvance->setChecked( m_pOptions->m_bAutoAdvance ); - showWhiteSpaceCharacters->setChecked( m_pOptions->m_bShowWhiteSpaceCharacters ); - showWhiteSpace->setChecked( m_pOptions->m_bShowWhiteSpace ); - showWhiteSpaceCharacters->setEnabled( m_pOptions->m_bShowWhiteSpace ); - showLineNumbers->setChecked( m_pOptions->m_bShowLineNumbers ); - wordWrap->setChecked( m_pOptions->m_bWordWrap ); - if( !isPart() ) + autoAdvance->setChecked(m_pOptions->m_bAutoAdvance); + showWhiteSpaceCharacters->setChecked(m_pOptions->m_bShowWhiteSpaceCharacters); + showWhiteSpace->setChecked(m_pOptions->m_bShowWhiteSpace); + showWhiteSpaceCharacters->setEnabled(m_pOptions->m_bShowWhiteSpace); + showLineNumbers->setChecked(m_pOptions->m_bShowLineNumbers); + wordWrap->setChecked(m_pOptions->m_bWordWrap); + if(!isPart()) { -// TODO -// viewToolBar->setChecked( m_pOptions->m_bShowToolBar ); -// slotViewToolBar(); + // TODO + // viewToolBar->setChecked( m_pOptions->m_bShowToolBar ); + // slotViewToolBar(); - viewStatusBar->setChecked( m_pOptions->m_bShowStatusBar ); + viewStatusBar->setChecked(m_pOptions->m_bShowStatusBar); slotViewStatusBar(); /* vrusu - commented out as new KToolBar does not hase setParPos TODO figure out how to restore bar position if( toolBar(MAIN_TOOLBAR_NAME)!=0 ) toolBar(MAIN_TOOLBAR_NAME)->setBarPos( (KToolBar::BarPosition) m_pOptions->m_toolBarPos );*/ /* QSize size = m_pOptions->m_geometry; QPoint pos = m_pOptions->m_position; if(!size.isEmpty()) { m_pKDiff3Shell->resize( size ); QRect visibleRect = QRect( pos, size ) & QApplication::desktop()->rect(); if ( visibleRect.width()>100 && visibleRect.height()>100 ) m_pKDiff3Shell->move( pos ); }*/ } slotRefresh(); m_pMainSplitter = this; //new QSplitter(this); - m_pMainSplitter->setOrientation( Qt::Vertical ); -// setCentralWidget( m_pMainSplitter ); - m_pDirectoryMergeSplitter = new QSplitter( m_pMainSplitter ); - m_pDirectoryMergeSplitter->setObjectName( "DirectoryMergeSplitter" ); - m_pMainSplitter->addWidget( m_pDirectoryMergeSplitter ); - m_pDirectoryMergeSplitter->setOrientation( Qt::Horizontal ); - m_pDirectoryMergeWindow = new DirectoryMergeWindow( m_pDirectoryMergeSplitter, m_pOptions, - KIconLoader::global() ); - m_pDirectoryMergeSplitter->addWidget( m_pDirectoryMergeWindow ); - m_pDirectoryMergeInfo = new DirectoryMergeInfo( m_pDirectoryMergeSplitter ); - m_pDirectoryMergeWindow->setDirectoryMergeInfo( m_pDirectoryMergeInfo ); - m_pDirectoryMergeSplitter->addWidget( m_pDirectoryMergeInfo ); - - connect( m_pDirectoryMergeWindow, &DirectoryMergeWindow::startDiffMerge, this, &KDiff3App::slotFileOpen2 ); - connect( m_pDirectoryMergeWindow->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KDiff3App::slotUpdateAvailabilities ); - connect( m_pDirectoryMergeWindow->selectionModel(), &QItemSelectionModel::currentChanged, this, &KDiff3App::slotUpdateAvailabilities ); - connect( m_pDirectoryMergeWindow, &DirectoryMergeWindow::checkIfCanContinue, this, &KDiff3App::slotCheckIfCanContinue ); - connect( m_pDirectoryMergeWindow, SIGNAL( updateAvailabilities() ), this, SLOT( slotUpdateAvailabilities() ) ); - connect( m_pDirectoryMergeWindow, &DirectoryMergeWindow::statusBarMessage, this, &KDiff3App::slotStatusMsg ); - - m_pDirectoryMergeWindow->initDirectoryMergeActions( this, actionCollection() ); - + m_pMainSplitter->setOrientation(Qt::Vertical); + // setCentralWidget( m_pMainSplitter ); + m_pDirectoryMergeSplitter = new QSplitter(m_pMainSplitter); + m_pDirectoryMergeSplitter->setObjectName("DirectoryMergeSplitter"); + m_pMainSplitter->addWidget(m_pDirectoryMergeSplitter); + m_pDirectoryMergeSplitter->setOrientation(Qt::Horizontal); + m_pDirectoryMergeWindow = new DirectoryMergeWindow(m_pDirectoryMergeSplitter, m_pOptions, + KIconLoader::global()); + m_pDirectoryMergeSplitter->addWidget(m_pDirectoryMergeWindow); + m_pDirectoryMergeInfo = new DirectoryMergeInfo(m_pDirectoryMergeSplitter); + m_pDirectoryMergeWindow->setDirectoryMergeInfo(m_pDirectoryMergeInfo); + m_pDirectoryMergeSplitter->addWidget(m_pDirectoryMergeInfo); + + connect(m_pDirectoryMergeWindow, &DirectoryMergeWindow::startDiffMerge, this, &KDiff3App::slotFileOpen2); + connect(m_pDirectoryMergeWindow->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KDiff3App::slotUpdateAvailabilities); + connect(m_pDirectoryMergeWindow->selectionModel(), &QItemSelectionModel::currentChanged, this, &KDiff3App::slotUpdateAvailabilities); + connect(m_pDirectoryMergeWindow, &DirectoryMergeWindow::checkIfCanContinue, this, &KDiff3App::slotCheckIfCanContinue); + connect(m_pDirectoryMergeWindow, SIGNAL(updateAvailabilities()), this, SLOT(slotUpdateAvailabilities())); + connect(m_pDirectoryMergeWindow, &DirectoryMergeWindow::statusBarMessage, this, &KDiff3App::slotStatusMsg); + + m_pDirectoryMergeWindow->initDirectoryMergeActions(this, actionCollection()); + delete KDiff3Shell::getParser(); //if( args != 0 ) args->clear(); // Free up some memory. - if( m_pKDiff3Shell == 0 ) { + if(m_pKDiff3Shell == 0) { completeInit(); } } - -void KDiff3App::completeInit( const QString& fn1, const QString& fn2, const QString& fn3 ) +void KDiff3App::completeInit(const QString& fn1, const QString& fn2, const QString& fn3) { - if (m_pKDiff3Shell!=0) - { + if(m_pKDiff3Shell != 0) + { QSize size = m_pOptions->m_geometry; QPoint pos = m_pOptions->m_position; - if( !size.isEmpty() ) + if(!size.isEmpty()) { - m_pKDiff3Shell->resize( size ); + m_pKDiff3Shell->resize(size); - QRect visibleRect = QRect( pos, size ) & QApplication::desktop()->rect(); - if( visibleRect.width() > 100 && visibleRect.height() > 100 ) - m_pKDiff3Shell->move( pos ); - if( !m_bAutoMode ) + QRect visibleRect = QRect(pos, size) & QApplication::desktop()->rect(); + if(visibleRect.width() > 100 && visibleRect.height() > 100) + m_pKDiff3Shell->move(pos); + if(!m_bAutoMode) { - if( m_pOptions->m_bMaximised ) + if(m_pOptions->m_bMaximised) m_pKDiff3Shell->showMaximized(); else m_pKDiff3Shell->show(); } } } - if( ! fn1.isEmpty() ) { - m_sd1.setFilename( fn1 ); + if(!fn1.isEmpty()) { + m_sd1.setFilename(fn1); } - if( ! fn2.isEmpty() ) { - m_sd2.setFilename( fn2 ); + if(!fn2.isEmpty()) { + m_sd2.setFilename(fn2); } - if( ! fn3.isEmpty() ) { - m_sd3.setFilename( fn3 ); + if(!fn3.isEmpty()) { + m_sd3.setFilename(fn3); } - bool bSuccess = improveFilenames( false ); + bool bSuccess = improveFilenames(false); - if( m_bAutoFlag && m_bAutoMode && m_bDirCompare ) + if(m_bAutoFlag && m_bAutoMode && m_bDirCompare) { - fprintf( stderr, "%s\n", ( const char* )i18n( "Option --auto ignored for directory comparison." ).toLatin1() ); + fprintf(stderr, "%s\n", (const char*)i18n("Option --auto ignored for directory comparison.").toLatin1()); m_bAutoMode = false; } - if( !m_bDirCompare ) + if(!m_bDirCompare) { m_pDirectoryMergeSplitter->hide(); mainInit(); - if( m_bAutoMode ) + if(m_bAutoMode) { SourceData* pSD = 0; - if( m_sd3.isEmpty() ) { - if( m_totalDiffStatus.bBinaryAEqB ) { + if(m_sd3.isEmpty()) { + if(m_totalDiffStatus.bBinaryAEqB) { pSD = &m_sd1; } } - else { - if( m_totalDiffStatus.bBinaryBEqC ) { - pSD = &m_sd3; // B==C (assume A is old) + else + { + if(m_totalDiffStatus.bBinaryBEqC) { + pSD = &m_sd3; // B==C (assume A is old) } - else if( m_totalDiffStatus.bBinaryAEqB ) { - pSD = &m_sd3; // assuming C has changed + else if(m_totalDiffStatus.bBinaryAEqB) + { + pSD = &m_sd3; // assuming C has changed + } + else if(m_totalDiffStatus.bBinaryAEqC) + { + pSD = &m_sd2; // assuming B has changed } - else if( m_totalDiffStatus.bBinaryAEqC ) { - pSD = &m_sd2; // assuming B has changed - } } - if ( pSD!=0 ) - { + if(pSD != 0) + { // Save this file directly, not via the merge result window. bool bSuccess = false; - FileAccess fa( m_outputFilename ); - if( m_pOptions->m_bDmCreateBakFiles && fa.exists() ) + FileAccess fa(m_outputFilename); + if(m_pOptions->m_bDmCreateBakFiles && fa.exists()) { QString newName = m_outputFilename + ".orig"; - if( FileAccess::exists( newName ) ) FileAccess::removeFile( newName ); - if( !FileAccess::exists( newName ) ) fa.rename( newName ); + if(FileAccess::exists(newName)) FileAccess::removeFile(newName); + if(!FileAccess::exists(newName)) fa.rename(newName); } - bSuccess = pSD->saveNormalDataAs( m_outputFilename ); - if( bSuccess ) ::exit( 0 ); - else KMessageBox::error( this, i18n( "Saving failed." ) ); + bSuccess = pSD->saveNormalDataAs(m_outputFilename); + if(bSuccess) + ::exit(0); + else + KMessageBox::error(this, i18n("Saving failed.")); } - else if( m_pMergeResultWindow->getNrOfUnsolvedConflicts() == 0 ) + else if(m_pMergeResultWindow->getNrOfUnsolvedConflicts() == 0) { - bool bSuccess = m_pMergeResultWindow->saveDocument( m_pMergeResultWindowTitle->getFileName(), m_pMergeResultWindowTitle->getEncoding(), m_pMergeResultWindowTitle->getLineEndStyle() ); - if( bSuccess ) ::exit( 0 ); + bool bSuccess = m_pMergeResultWindow->saveDocument(m_pMergeResultWindowTitle->getFileName(), m_pMergeResultWindowTitle->getEncoding(), m_pMergeResultWindowTitle->getLineEndStyle()); + if(bSuccess) ::exit(0); } } } m_bAutoMode = false; - if( m_pKDiff3Shell ) + if(m_pKDiff3Shell) { - if( m_pOptions->m_bMaximised ) + if(m_pOptions->m_bMaximised) m_pKDiff3Shell->showMaximized(); else m_pKDiff3Shell->show(); } - g_pProgressDialog->setStayHidden( false ); + g_pProgressDialog->setStayHidden(false); - if( statusBar() != 0 ) - statusBar()->setSizeGripEnabled( true ); + if(statusBar() != 0) + statusBar()->setSizeGripEnabled(true); slotClipboardChanged(); // For initialisation. slotUpdateAvailabilities(); - if( !m_bDirCompare && m_pKDiff3Shell != 0 ) + if(!m_bDirCompare && m_pKDiff3Shell != 0) { bool bFileOpenError = false; - if( ( ! m_sd1.isEmpty() && !m_sd1.hasData() ) || - ( ! m_sd2.isEmpty() && !m_sd2.hasData() ) || - ( ! m_sd3.isEmpty() && !m_sd3.hasData() ) ) + if((!m_sd1.isEmpty() && !m_sd1.hasData()) || + (!m_sd2.isEmpty() && !m_sd2.hasData()) || + (!m_sd3.isEmpty() && !m_sd3.hasData())) { - QString text( i18n( "Opening of these files failed:" ) ); + QString text(i18n("Opening of these files failed:")); text += "\n\n"; - if( ! m_sd1.isEmpty() && !m_sd1.hasData() ) + if(!m_sd1.isEmpty() && !m_sd1.hasData()) text += " - " + m_sd1.getAliasName() + "\n"; - if( ! m_sd2.isEmpty() && !m_sd2.hasData() ) + if(!m_sd2.isEmpty() && !m_sd2.hasData()) text += " - " + m_sd2.getAliasName() + "\n"; - if( ! m_sd3.isEmpty() && !m_sd3.hasData() ) + if(!m_sd3.isEmpty() && !m_sd3.hasData()) text += " - " + m_sd3.getAliasName() + "\n"; - KMessageBox::sorry( this, text, i18n( "File Open Error" ) ); + KMessageBox::sorry(this, text, i18n("File Open Error")); bFileOpenError = true; } - if( m_sd1.isEmpty() || m_sd2.isEmpty() || bFileOpenError ) + if(m_sd1.isEmpty() || m_sd2.isEmpty() || bFileOpenError) slotFileOpen(); } - else if( !bSuccess ) // Directory open failed + else if(!bSuccess) // Directory open failed { slotFileOpen(); } } KDiff3App::~KDiff3App() { - } /** * Helper function used to create actions into the ac collection */ -void KDiff3App::initActions( KActionCollection* ac ) +void KDiff3App::initActions(KActionCollection* ac) { - if( ac == 0 ) - KMessageBox::error( 0, "actionCollection==0" ); + if(ac == 0) + KMessageBox::error(0, "actionCollection==0"); - fileOpen = KStandardAction::open( this, SLOT( slotFileOpen() ), ac ); - fileOpen->setStatusTip( i18n( "Opens documents for comparison..." ) ); + fileOpen = KStandardAction::open(this, SLOT(slotFileOpen()), ac); + fileOpen->setStatusTip(i18n("Opens documents for comparison...")); - fileReload = KDiff3::createAction< QAction >( i18n( "Reload" ), QKeySequence( QKeySequence::Refresh ), this, SLOT( slotReload() ), ac, "file_reload" ); + fileReload = KDiff3::createAction(i18n("Reload"), QKeySequence(QKeySequence::Refresh), this, SLOT(slotReload()), ac, "file_reload"); - fileSave = KStandardAction::save( this, SLOT( slotFileSave() ), ac ); - fileSave->setStatusTip( i18n( "Saves the merge result. All conflicts must be solved!" ) ); - fileSaveAs = KStandardAction::saveAs( this, SLOT( slotFileSaveAs() ), ac ); - fileSaveAs->setStatusTip( i18n( "Saves the current document as..." ) ); + fileSave = KStandardAction::save(this, SLOT(slotFileSave()), ac); + fileSave->setStatusTip(i18n("Saves the merge result. All conflicts must be solved!")); + fileSaveAs = KStandardAction::saveAs(this, SLOT(slotFileSaveAs()), ac); + fileSaveAs->setStatusTip(i18n("Saves the current document as...")); #ifndef QT_NO_PRINTER - filePrint = KStandardAction::print( this, SLOT( slotFilePrint() ), ac ); - filePrint->setStatusTip( i18n( "Print the differences" ) ); + filePrint = KStandardAction::print(this, SLOT(slotFilePrint()), ac); + filePrint->setStatusTip(i18n("Print the differences")); #endif - fileQuit = KStandardAction::quit( this, SLOT( slotFileQuit() ), ac ); - fileQuit->setStatusTip( i18n( "Quits the application" ) ); - editCut = KStandardAction::cut( this, SLOT( slotEditCut() ), ac ); - editCut->setStatusTip( i18n( "Cuts the selected section and puts it to the clipboard" ) ); - editCopy = KStandardAction::copy( this, SLOT( slotEditCopy() ), ac ); - editCopy->setStatusTip( i18n( "Copies the selected section to the clipboard" ) ); - editPaste = KStandardAction::paste( this, SLOT( slotEditPaste() ), ac ); - editPaste->setStatusTip( i18n( "Pastes the clipboard contents to current position" ) ); - editSelectAll = KStandardAction::selectAll( this, SLOT( slotEditSelectAll() ), ac ); - editSelectAll->setStatusTip( i18n( "Select everything in current window" ) ); - editFind = KStandardAction::find( this, SLOT( slotEditFind() ), ac ); - editFind->setStatusTip( i18n( "Search for a string" ) ); - editFindNext = KStandardAction::findNext( this, SLOT( slotEditFindNext() ), ac ); - editFindNext->setStatusTip( i18n( "Search again for the string" ) ); + fileQuit = KStandardAction::quit(this, SLOT(slotFileQuit()), ac); + fileQuit->setStatusTip(i18n("Quits the application")); + editCut = KStandardAction::cut(this, SLOT(slotEditCut()), ac); + editCut->setStatusTip(i18n("Cuts the selected section and puts it to the clipboard")); + editCopy = KStandardAction::copy(this, SLOT(slotEditCopy()), ac); + editCopy->setStatusTip(i18n("Copies the selected section to the clipboard")); + editPaste = KStandardAction::paste(this, SLOT(slotEditPaste()), ac); + editPaste->setStatusTip(i18n("Pastes the clipboard contents to current position")); + editSelectAll = KStandardAction::selectAll(this, SLOT(slotEditSelectAll()), ac); + editSelectAll->setStatusTip(i18n("Select everything in current window")); + editFind = KStandardAction::find(this, SLOT(slotEditFind()), ac); + editFind->setStatusTip(i18n("Search for a string")); + editFindNext = KStandardAction::findNext(this, SLOT(slotEditFindNext()), ac); + editFindNext->setStatusTip(i18n("Search again for the string")); /* FIXME figure out how to implement this action viewToolBar = KStandardAction::showToolbar(this, SLOT(slotViewToolBar()), ac); viewToolBar->setStatusTip(i18n("Enables/disables the toolbar")); */ - viewStatusBar = KStandardAction::showStatusbar( this, SLOT( slotViewStatusBar() ), ac ); - viewStatusBar->setStatusTip( i18n( "Enables/disables the statusbar" ) ); - KStandardAction::keyBindings( this, SLOT( slotConfigureKeys() ), ac ); - QAction * pAction = KStandardAction::preferences( this, SLOT( slotConfigure() ), ac ); - if( isPart() ) - pAction->setText( i18n( "Configure KDiff3..." ) ); + viewStatusBar = KStandardAction::showStatusbar(this, SLOT(slotViewStatusBar()), ac); + viewStatusBar->setStatusTip(i18n("Enables/disables the statusbar")); + KStandardAction::keyBindings(this, SLOT(slotConfigureKeys()), ac); + QAction* pAction = KStandardAction::preferences(this, SLOT(slotConfigure()), ac); + if(isPart()) + pAction->setText(i18n("Configure KDiff3...")); - -#include "xpm/downend.xpm" +#include "xpm/autoadvance.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/downend.xpm" #include "xpm/iconA.xpm" #include "xpm/iconB.xpm" #include "xpm/iconC.xpm" -#include "xpm/autoadvance.xpm" +#include "xpm/nextunsolved.xpm" +#include "xpm/prevunsolved.xpm" +#include "xpm/showlinenumbers.xpm" #include "xpm/showwhitespace.xpm" #include "xpm/showwhitespacechars.xpm" -#include "xpm/showlinenumbers.xpm" -//#include "reload.xpm" - - goCurrent = KDiff3::createAction< QAction >( i18n( "Go to Current Delta" ), QIcon( QPixmap( currentpos ) ), i18n( "Current\nDelta" ), QKeySequence( Qt::CTRL + Qt::Key_Space ), this, SLOT( slotGoCurrent() ), ac, "go_current" ); - - goTop = KDiff3::createAction< QAction >( i18n( "Go to First Delta" ), QIcon( QPixmap( upend ) ), i18n( "First\nDelta" ), this, SLOT( slotGoTop() ), ac, "go_top" ); - - goBottom = KDiff3::createAction< QAction >( i18n( "Go to Last Delta" ), QIcon( QPixmap( downend ) ), i18n( "Last\nDelta" ), this, SLOT( slotGoBottom() ), ac, "go_bottom" ); - - QString omitsWhitespace = ".\n" + i18n( "(Skips white space differences when \"Show White Space\" is disabled.)" ); - QString includeWhitespace = ".\n" + i18n( "(Does not skip white space differences even when \"Show White Space\" is disabled.)" ); - goPrevDelta = KDiff3::createAction< QAction >( i18n( "Go to Previous Delta" ), QIcon( QPixmap( up1arrow ) ), i18n( "Prev\nDelta" ), QKeySequence( Qt::CTRL + Qt::Key_Up ), this, SLOT( slotGoPrevDelta() ), ac, "go_prev_delta" ); - goPrevDelta->setToolTip( goPrevDelta->text() + omitsWhitespace ); - goNextDelta = KDiff3::createAction< QAction >( i18n( "Go to Next Delta" ), QIcon( QPixmap( down1arrow ) ), i18n( "Next\nDelta" ), QKeySequence( Qt::CTRL + Qt::Key_Down ), this, SLOT( slotGoNextDelta() ), ac, "go_next_delta" ); - goNextDelta->setToolTip( goNextDelta->text() + omitsWhitespace ); - goPrevConflict = KDiff3::createAction< QAction >( i18n( "Go to Previous Conflict" ), QIcon( QPixmap( up2arrow ) ), i18n( "Prev\nConflict" ), QKeySequence( Qt::CTRL + Qt::Key_PageUp ), this, SLOT( slotGoPrevConflict() ), ac, "go_prev_conflict" ); - goPrevConflict->setToolTip( goPrevConflict->text() + omitsWhitespace ); - goNextConflict = KDiff3::createAction< QAction >( i18n( "Go to Next Conflict" ), QIcon( QPixmap( down2arrow ) ), i18n( "Next\nConflict" ), QKeySequence( Qt::CTRL + Qt::Key_PageDown ), this, SLOT( slotGoNextConflict() ), ac, "go_next_conflict" ); - goNextConflict->setToolTip( goNextConflict->text() + omitsWhitespace ); - goPrevUnsolvedConflict = KDiff3::createAction< QAction >( i18n( "Go to Previous Unsolved Conflict" ), QIcon( QPixmap( prevunsolved ) ), i18n( "Prev\nUnsolved" ), this, SLOT( slotGoPrevUnsolvedConflict() ), ac, "go_prev_unsolved_conflict" ); - goPrevUnsolvedConflict->setToolTip( goPrevUnsolvedConflict->text() + includeWhitespace ); - goNextUnsolvedConflict = KDiff3::createAction< QAction >( i18n( "Go to Next Unsolved Conflict" ), QIcon( QPixmap( nextunsolved ) ), i18n( "Next\nUnsolved" ), this, SLOT( slotGoNextUnsolvedConflict() ), ac, "go_next_unsolved_conflict" ); - goNextUnsolvedConflict->setToolTip( goNextUnsolvedConflict->text() + includeWhitespace ); - chooseA = KDiff3::createAction< KToggleAction >( i18n( "Select Line(s) From A" ), QIcon( QPixmap( iconA ) ), i18n( "Choose\nA" ), QKeySequence( Qt::CTRL + Qt::Key_1 ), this, SLOT( slotChooseA() ), ac, "merge_choose_a" ); - chooseB = KDiff3::createAction< KToggleAction >( i18n( "Select Line(s) From B" ), QIcon( QPixmap( iconB ) ), i18n( "Choose\nB" ), QKeySequence( Qt::CTRL + Qt::Key_2 ), this, SLOT( slotChooseB() ), ac, "merge_choose_b" ); - chooseC = KDiff3::createAction< KToggleAction >( i18n( "Select Line(s) From C" ), QIcon( QPixmap( iconC ) ), i18n( "Choose\nC" ), QKeySequence( Qt::CTRL + Qt::Key_3 ), this, SLOT( slotChooseC() ), ac, "merge_choose_c" ); - autoAdvance = KDiff3::createAction< KToggleAction >( i18n( "Automatically Go to Next Unsolved Conflict After Source Selection" ), QIcon( QPixmap( autoadvance ) ), i18n( "Auto\nNext" ), this, SLOT( slotAutoAdvanceToggled() ), ac, "merge_autoadvance" ); - - showWhiteSpaceCharacters = KDiff3::createAction< KToggleAction >( i18n( "Show Space && Tabulator Characters" ), QIcon( QPixmap( showwhitespacechars ) ), i18n( "White\nCharacters" ), this, SLOT( slotShowWhiteSpaceToggled() ), ac, "diff_show_whitespace_characters" ); - showWhiteSpace = KDiff3::createAction< KToggleAction >( i18n( "Show White Space" ), QIcon( QPixmap( showwhitespace ) ), i18n( "White\nDeltas" ), this, SLOT( slotShowWhiteSpaceToggled() ), ac, "diff_show_whitespace" ); - - showLineNumbers = KDiff3::createAction< KToggleAction >( i18n( "Show Line Numbers" ), QIcon( QPixmap( showlinenumbers ) ), i18n( "Line\nNumbers" ), this, SLOT( slotShowLineNumbersToggled() ), ac, "diff_showlinenumbers" ); - chooseAEverywhere = KDiff3::createAction< QAction >( i18n( "Choose A Everywhere" ), QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_1 ), this, SLOT( slotChooseAEverywhere() ), ac, "merge_choose_a_everywhere" ); - chooseBEverywhere = KDiff3::createAction< QAction >( i18n( "Choose B Everywhere" ), QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_2 ), this, SLOT( slotChooseBEverywhere() ), ac, "merge_choose_b_everywhere" ); - chooseCEverywhere = KDiff3::createAction< QAction >( i18n( "Choose C Everywhere" ), QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_3 ), this, SLOT( slotChooseCEverywhere() ), ac, "merge_choose_c_everywhere" ); - chooseAForUnsolvedConflicts = KDiff3::createAction< QAction >( i18n( "Choose A for All Unsolved Conflicts" ), this, SLOT( slotChooseAForUnsolvedConflicts() ), ac, "merge_choose_a_for_unsolved_conflicts" ); - chooseBForUnsolvedConflicts = KDiff3::createAction< QAction >( i18n( "Choose B for All Unsolved Conflicts" ), this, SLOT( slotChooseBForUnsolvedConflicts() ), ac, "merge_choose_b_for_unsolved_conflicts" ); - chooseCForUnsolvedConflicts = KDiff3::createAction< QAction >( i18n( "Choose C for All Unsolved Conflicts" ), this, SLOT( slotChooseCForUnsolvedConflicts() ), ac, "merge_choose_c_for_unsolved_conflicts" ); - chooseAForUnsolvedWhiteSpaceConflicts = KDiff3::createAction< QAction >( i18n( "Choose A for All Unsolved Whitespace Conflicts" ), this, SLOT( slotChooseAForUnsolvedWhiteSpaceConflicts() ), ac, "merge_choose_a_for_unsolved_whitespace_conflicts" ); - chooseBForUnsolvedWhiteSpaceConflicts = KDiff3::createAction< QAction >( i18n( "Choose B for All Unsolved Whitespace Conflicts" ), this, SLOT( slotChooseBForUnsolvedWhiteSpaceConflicts() ), ac, "merge_choose_b_for_unsolved_whitespace_conflicts" ); - chooseCForUnsolvedWhiteSpaceConflicts = KDiff3::createAction< QAction >( i18n( "Choose C for All Unsolved Whitespace Conflicts" ), this, SLOT( slotChooseCForUnsolvedWhiteSpaceConflicts() ), ac, "merge_choose_c_for_unsolved_whitespace_conflicts" ); - autoSolve = KDiff3::createAction< QAction >( i18n( "Automatically Solve Simple Conflicts" ), this, SLOT( slotAutoSolve() ), ac, "merge_autosolve" ); - unsolve = KDiff3::createAction< QAction >( i18n( "Set Deltas to Conflicts" ), this, SLOT( slotUnsolve() ), ac, "merge_autounsolve" ); - mergeRegExp = KDiff3::createAction< QAction >( i18n( "Run Regular Expression Auto Merge" ), this, SLOT( slotRegExpAutoMerge() ), ac, "merge_regexp_automerge" ); - mergeHistory = KDiff3::createAction< QAction >( i18n( "Automatically Solve History Conflicts" ), this, SLOT( slotMergeHistory() ), ac, "merge_versioncontrol_history" ); - splitDiff = KDiff3::createAction< QAction >( i18n( "Split Diff At Selection" ), this, SLOT( slotSplitDiff() ), ac, "merge_splitdiff" ); - joinDiffs = KDiff3::createAction< QAction >( i18n( "Join Selected Diffs" ), this, SLOT( slotJoinDiffs() ), ac, "merge_joindiffs" ); - - showWindowA = KDiff3::createAction< KToggleAction >( i18n( "Show Window A" ), this, SLOT( slotShowWindowAToggled() ), ac, "win_show_a" ); - showWindowB = KDiff3::createAction< KToggleAction >( i18n( "Show Window B" ), this, SLOT( slotShowWindowBToggled() ), ac, "win_show_b" ); - showWindowC = KDiff3::createAction< KToggleAction >( i18n( "Show Window C" ), this, SLOT( slotShowWindowCToggled() ), ac, "win_show_c" ); - winFocusNext = KDiff3::createAction< QAction >( i18n( "Focus Next Window" ), QKeySequence( Qt::ALT + Qt::Key_Right ), this, SLOT( slotWinFocusNext() ), ac, "win_focus_next" ); - - overviewModeNormal = KDiff3::createAction< KToggleAction >( i18n( "Normal Overview" ), this, SLOT( slotOverviewNormal() ), ac, "diff_overview_normal" ); - overviewModeAB = KDiff3::createAction< KToggleAction >( i18n( "A vs. B Overview" ), this, SLOT( slotOverviewAB() ), ac, "diff_overview_ab" ); - overviewModeAC = KDiff3::createAction< KToggleAction >( i18n( "A vs. C Overview" ), this, SLOT( slotOverviewAC() ), ac, "diff_overview_ac" ); - overviewModeBC = KDiff3::createAction< KToggleAction >( i18n( "B vs. C Overview" ), this, SLOT( slotOverviewBC() ), ac, "diff_overview_bc" ); - wordWrap = KDiff3::createAction< KToggleAction >( i18n( "Word Wrap Diff Windows" ), this, SLOT( slotWordWrapToggled() ), ac, "diff_wordwrap" ); - addManualDiffHelp = KDiff3::createAction< QAction >( i18n( "Add Manual Diff Alignment" ), QKeySequence( Qt::CTRL + Qt::Key_Y ), this, SLOT( slotAddManualDiffHelp() ), ac, "diff_add_manual_diff_help" ); - clearManualDiffHelpList = KDiff3::createAction< QAction >( i18n( "Clear All Manual Diff Alignments" ), QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_Y ), this, SLOT( slotClearManualDiffHelpList() ), ac, "diff_clear_manual_diff_help_list" ); +#include "xpm/up1arrow.xpm" +#include "xpm/up2arrow.xpm" +#include "xpm/upend.xpm" + //#include "reload.xpm" + + goCurrent = KDiff3::createAction(i18n("Go to Current Delta"), QIcon(QPixmap(currentpos)), i18n("Current\nDelta"), QKeySequence(Qt::CTRL + Qt::Key_Space), this, SLOT(slotGoCurrent()), ac, "go_current"); + + goTop = KDiff3::createAction(i18n("Go to First Delta"), QIcon(QPixmap(upend)), i18n("First\nDelta"), this, SLOT(slotGoTop()), ac, "go_top"); + + goBottom = KDiff3::createAction(i18n("Go to Last Delta"), QIcon(QPixmap(downend)), i18n("Last\nDelta"), this, SLOT(slotGoBottom()), ac, "go_bottom"); + + QString omitsWhitespace = ".\n" + i18n("(Skips white space differences when \"Show White Space\" is disabled.)"); + QString includeWhitespace = ".\n" + i18n("(Does not skip white space differences even when \"Show White Space\" is disabled.)"); + goPrevDelta = KDiff3::createAction(i18n("Go to Previous Delta"), QIcon(QPixmap(up1arrow)), i18n("Prev\nDelta"), QKeySequence(Qt::CTRL + Qt::Key_Up), this, SLOT(slotGoPrevDelta()), ac, "go_prev_delta"); + goPrevDelta->setToolTip(goPrevDelta->text() + omitsWhitespace); + goNextDelta = KDiff3::createAction(i18n("Go to Next Delta"), QIcon(QPixmap(down1arrow)), i18n("Next\nDelta"), QKeySequence(Qt::CTRL + Qt::Key_Down), this, SLOT(slotGoNextDelta()), ac, "go_next_delta"); + goNextDelta->setToolTip(goNextDelta->text() + omitsWhitespace); + goPrevConflict = KDiff3::createAction(i18n("Go to Previous Conflict"), QIcon(QPixmap(up2arrow)), i18n("Prev\nConflict"), QKeySequence(Qt::CTRL + Qt::Key_PageUp), this, SLOT(slotGoPrevConflict()), ac, "go_prev_conflict"); + goPrevConflict->setToolTip(goPrevConflict->text() + omitsWhitespace); + goNextConflict = KDiff3::createAction(i18n("Go to Next Conflict"), QIcon(QPixmap(down2arrow)), i18n("Next\nConflict"), QKeySequence(Qt::CTRL + Qt::Key_PageDown), this, SLOT(slotGoNextConflict()), ac, "go_next_conflict"); + goNextConflict->setToolTip(goNextConflict->text() + omitsWhitespace); + goPrevUnsolvedConflict = KDiff3::createAction(i18n("Go to Previous Unsolved Conflict"), QIcon(QPixmap(prevunsolved)), i18n("Prev\nUnsolved"), this, SLOT(slotGoPrevUnsolvedConflict()), ac, "go_prev_unsolved_conflict"); + goPrevUnsolvedConflict->setToolTip(goPrevUnsolvedConflict->text() + includeWhitespace); + goNextUnsolvedConflict = KDiff3::createAction(i18n("Go to Next Unsolved Conflict"), QIcon(QPixmap(nextunsolved)), i18n("Next\nUnsolved"), this, SLOT(slotGoNextUnsolvedConflict()), ac, "go_next_unsolved_conflict"); + goNextUnsolvedConflict->setToolTip(goNextUnsolvedConflict->text() + includeWhitespace); + chooseA = KDiff3::createAction(i18n("Select Line(s) From A"), QIcon(QPixmap(iconA)), i18n("Choose\nA"), QKeySequence(Qt::CTRL + Qt::Key_1), this, SLOT(slotChooseA()), ac, "merge_choose_a"); + chooseB = KDiff3::createAction(i18n("Select Line(s) From B"), QIcon(QPixmap(iconB)), i18n("Choose\nB"), QKeySequence(Qt::CTRL + Qt::Key_2), this, SLOT(slotChooseB()), ac, "merge_choose_b"); + chooseC = KDiff3::createAction(i18n("Select Line(s) From C"), QIcon(QPixmap(iconC)), i18n("Choose\nC"), QKeySequence(Qt::CTRL + Qt::Key_3), this, SLOT(slotChooseC()), ac, "merge_choose_c"); + autoAdvance = KDiff3::createAction(i18n("Automatically Go to Next Unsolved Conflict After Source Selection"), QIcon(QPixmap(autoadvance)), i18n("Auto\nNext"), this, SLOT(slotAutoAdvanceToggled()), ac, "merge_autoadvance"); + + showWhiteSpaceCharacters = KDiff3::createAction(i18n("Show Space && Tabulator Characters"), QIcon(QPixmap(showwhitespacechars)), i18n("White\nCharacters"), this, SLOT(slotShowWhiteSpaceToggled()), ac, "diff_show_whitespace_characters"); + showWhiteSpace = KDiff3::createAction(i18n("Show White Space"), QIcon(QPixmap(showwhitespace)), i18n("White\nDeltas"), this, SLOT(slotShowWhiteSpaceToggled()), ac, "diff_show_whitespace"); + + showLineNumbers = KDiff3::createAction(i18n("Show Line Numbers"), QIcon(QPixmap(showlinenumbers)), i18n("Line\nNumbers"), this, SLOT(slotShowLineNumbersToggled()), ac, "diff_showlinenumbers"); + chooseAEverywhere = KDiff3::createAction(i18n("Choose A Everywhere"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_1), this, SLOT(slotChooseAEverywhere()), ac, "merge_choose_a_everywhere"); + chooseBEverywhere = KDiff3::createAction(i18n("Choose B Everywhere"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_2), this, SLOT(slotChooseBEverywhere()), ac, "merge_choose_b_everywhere"); + chooseCEverywhere = KDiff3::createAction(i18n("Choose C Everywhere"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_3), this, SLOT(slotChooseCEverywhere()), ac, "merge_choose_c_everywhere"); + chooseAForUnsolvedConflicts = KDiff3::createAction(i18n("Choose A for All Unsolved Conflicts"), this, SLOT(slotChooseAForUnsolvedConflicts()), ac, "merge_choose_a_for_unsolved_conflicts"); + chooseBForUnsolvedConflicts = KDiff3::createAction(i18n("Choose B for All Unsolved Conflicts"), this, SLOT(slotChooseBForUnsolvedConflicts()), ac, "merge_choose_b_for_unsolved_conflicts"); + chooseCForUnsolvedConflicts = KDiff3::createAction(i18n("Choose C for All Unsolved Conflicts"), this, SLOT(slotChooseCForUnsolvedConflicts()), ac, "merge_choose_c_for_unsolved_conflicts"); + chooseAForUnsolvedWhiteSpaceConflicts = KDiff3::createAction(i18n("Choose A for All Unsolved Whitespace Conflicts"), this, SLOT(slotChooseAForUnsolvedWhiteSpaceConflicts()), ac, "merge_choose_a_for_unsolved_whitespace_conflicts"); + chooseBForUnsolvedWhiteSpaceConflicts = KDiff3::createAction(i18n("Choose B for All Unsolved Whitespace Conflicts"), this, SLOT(slotChooseBForUnsolvedWhiteSpaceConflicts()), ac, "merge_choose_b_for_unsolved_whitespace_conflicts"); + chooseCForUnsolvedWhiteSpaceConflicts = KDiff3::createAction(i18n("Choose C for All Unsolved Whitespace Conflicts"), this, SLOT(slotChooseCForUnsolvedWhiteSpaceConflicts()), ac, "merge_choose_c_for_unsolved_whitespace_conflicts"); + autoSolve = KDiff3::createAction(i18n("Automatically Solve Simple Conflicts"), this, SLOT(slotAutoSolve()), ac, "merge_autosolve"); + unsolve = KDiff3::createAction(i18n("Set Deltas to Conflicts"), this, SLOT(slotUnsolve()), ac, "merge_autounsolve"); + mergeRegExp = KDiff3::createAction(i18n("Run Regular Expression Auto Merge"), this, SLOT(slotRegExpAutoMerge()), ac, "merge_regexp_automerge"); + mergeHistory = KDiff3::createAction(i18n("Automatically Solve History Conflicts"), this, SLOT(slotMergeHistory()), ac, "merge_versioncontrol_history"); + splitDiff = KDiff3::createAction(i18n("Split Diff At Selection"), this, SLOT(slotSplitDiff()), ac, "merge_splitdiff"); + joinDiffs = KDiff3::createAction(i18n("Join Selected Diffs"), this, SLOT(slotJoinDiffs()), ac, "merge_joindiffs"); + + showWindowA = KDiff3::createAction(i18n("Show Window A"), this, SLOT(slotShowWindowAToggled()), ac, "win_show_a"); + showWindowB = KDiff3::createAction(i18n("Show Window B"), this, SLOT(slotShowWindowBToggled()), ac, "win_show_b"); + showWindowC = KDiff3::createAction(i18n("Show Window C"), this, SLOT(slotShowWindowCToggled()), ac, "win_show_c"); + winFocusNext = KDiff3::createAction(i18n("Focus Next Window"), QKeySequence(Qt::ALT + Qt::Key_Right), this, SLOT(slotWinFocusNext()), ac, "win_focus_next"); + + overviewModeNormal = KDiff3::createAction(i18n("Normal Overview"), this, SLOT(slotOverviewNormal()), ac, "diff_overview_normal"); + overviewModeAB = KDiff3::createAction(i18n("A vs. B Overview"), this, SLOT(slotOverviewAB()), ac, "diff_overview_ab"); + overviewModeAC = KDiff3::createAction(i18n("A vs. C Overview"), this, SLOT(slotOverviewAC()), ac, "diff_overview_ac"); + overviewModeBC = KDiff3::createAction(i18n("B vs. C Overview"), this, SLOT(slotOverviewBC()), ac, "diff_overview_bc"); + wordWrap = KDiff3::createAction(i18n("Word Wrap Diff Windows"), this, SLOT(slotWordWrapToggled()), ac, "diff_wordwrap"); + addManualDiffHelp = KDiff3::createAction(i18n("Add Manual Diff Alignment"), QKeySequence(Qt::CTRL + Qt::Key_Y), this, SLOT(slotAddManualDiffHelp()), ac, "diff_add_manual_diff_help"); + clearManualDiffHelpList = KDiff3::createAction(i18n("Clear All Manual Diff Alignments"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Y), this, SLOT(slotClearManualDiffHelpList()), ac, "diff_clear_manual_diff_help_list"); #if defined(_WIN32) || defined(Q_OS_OS2) - KDiff3::createAction< QAction >( i18n( "Focus Next Window" ), QKeySequence( Qt::CTRL + Qt::Key_Tab ), this, SLOT( slotWinFocusNext() ), ac, "win_focus_next" ); + KDiff3::createAction(i18n("Focus Next Window"), QKeySequence(Qt::CTRL + Qt::Key_Tab), this, SLOT(slotWinFocusNext()), ac, "win_focus_next"); #endif - winFocusPrev = KDiff3::createAction< QAction >( i18n( "Focus Prev Window" ), QKeySequence( Qt::ALT + Qt::Key_Left ), this, SLOT( slotWinFocusPrev() ), ac, "win_focus_prev" ); - winToggleSplitOrientation = KDiff3::createAction< QAction >( i18n( "Toggle Split Orientation" ), this, SLOT( slotWinToggleSplitterOrientation() ), ac, "win_toggle_split_orientation" ); + winFocusPrev = KDiff3::createAction(i18n("Focus Prev Window"), QKeySequence(Qt::ALT + Qt::Key_Left), this, SLOT(slotWinFocusPrev()), ac, "win_focus_prev"); + winToggleSplitOrientation = KDiff3::createAction(i18n("Toggle Split Orientation"), this, SLOT(slotWinToggleSplitterOrientation()), ac, "win_toggle_split_orientation"); - dirShowBoth = KDiff3::createAction< KToggleAction >( i18n( "Dir && Text Split Screen View" ), this, SLOT( slotDirShowBoth() ), ac, "win_dir_show_both" ); - dirShowBoth->setChecked( true ); - dirViewToggle = KDiff3::createAction< QAction >( i18n( "Toggle Between Dir && Text View" ), this, SLOT( slotDirViewToggle() ), ac, "win_dir_view_toggle" ); + dirShowBoth = KDiff3::createAction(i18n("Dir && Text Split Screen View"), this, SLOT(slotDirShowBoth()), ac, "win_dir_show_both"); + dirShowBoth->setChecked(true); + dirViewToggle = KDiff3::createAction(i18n("Toggle Between Dir && Text View"), this, SLOT(slotDirViewToggle()), ac, "win_dir_view_toggle"); - m_pMergeEditorPopupMenu = new QMenu( this ); + m_pMergeEditorPopupMenu = new QMenu(this); /* chooseA->plug( m_pMergeEditorPopupMenu ); chooseB->plug( m_pMergeEditorPopupMenu ); chooseC->plug( m_pMergeEditorPopupMenu );*/ - m_pMergeEditorPopupMenu->addAction( chooseA ); - m_pMergeEditorPopupMenu->addAction( chooseB ); - m_pMergeEditorPopupMenu->addAction( chooseC ); + m_pMergeEditorPopupMenu->addAction(chooseA); + m_pMergeEditorPopupMenu->addAction(chooseB); + m_pMergeEditorPopupMenu->addAction(chooseC); } - -void KDiff3App::showPopupMenu( const QPoint& point ) +void KDiff3App::showPopupMenu(const QPoint& point) { - m_pMergeEditorPopupMenu->popup( point ); + m_pMergeEditorPopupMenu->popup(point); } void KDiff3App::initStatusBar() { /////////////////////////////////////////////////////////////////// // STATUSBAR - if( statusBar() != 0 ) - statusBar()->showMessage( i18n( "Ready." ) ); + if(statusBar() != 0) + statusBar()->showMessage(i18n("Ready.")); } -void KDiff3App::saveOptions( KSharedConfigPtr config ) +void KDiff3App::saveOptions(KSharedConfigPtr config) { - if ( !m_bAutoMode ) - { - if (!isPart()) - { + if(!m_bAutoMode) + { + if(!isPart()) + { m_pOptions->m_bMaximised = m_pKDiff3Shell->isMaximized(); - if( ! m_pKDiff3Shell->isMaximized() && m_pKDiff3Shell->isVisible() ) + if(!m_pKDiff3Shell->isMaximized() && m_pKDiff3Shell->isVisible()) { m_pOptions->m_geometry = m_pKDiff3Shell->size(); m_pOptions->m_position = m_pKDiff3Shell->pos(); } /* TODO change this option as now KToolbar uses QToolbar positioning style if ( toolBar(MAIN_TOOLBAR_NAME)!=0 ) m_pOptionDialog->m_toolBarPos = (int) toolBar(MAIN_TOOLBAR_NAME)->allowedAreas();*/ } - m_pOptionDialog->saveOptions( config ); + m_pOptionDialog->saveOptions(config); } } - - - bool KDiff3App::queryClose() { - saveOptions( KSharedConfig::openConfig() ); - - if(m_bOutputModified) - { - int result = KMessageBox::warningYesNoCancel( this, - i18n( "The merge result hasn't been saved." ), - i18n( "Warning" ), - KGuiItem( i18n( "Save && Quit" ) ), - KGuiItem( i18n( "Quit Without Saving" ) ) ); - if( result == KMessageBox::Cancel ) + saveOptions(KSharedConfig::openConfig()); + + if(m_bOutputModified) + { + int result = KMessageBox::warningYesNoCancel(this, + i18n("The merge result hasn't been saved."), + i18n("Warning"), + KGuiItem(i18n("Save && Quit")), + KGuiItem(i18n("Quit Without Saving"))); + if(result == KMessageBox::Cancel) return false; - else if ( result==KMessageBox::Yes ) - { + else if(result == KMessageBox::Yes) + { slotFileSave(); - if ( m_bOutputModified ) + if(m_bOutputModified) { - KMessageBox::sorry( this, i18n( "Saving the merge result failed." ), i18n( "Warning" ) ); + KMessageBox::sorry(this, i18n("Saving the merge result failed."), i18n("Warning")); return false; } } } m_bOutputModified = false; - if ( m_pDirectoryMergeWindow->isDirectoryMergeInProgress() ) + 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" ), - KStandardGuiItem::quit(), - KStandardGuiItem::cont() /* i18n("Continue Merging") */ ); - if( result != KMessageBox::Yes ) + int result = KMessageBox::warningYesNo(this, + i18n("You are currently doing a directory merge. Are you sure, you want to abort?"), + i18n("Warning"), + KStandardGuiItem::quit(), + KStandardGuiItem::cont() /* i18n("Continue Merging") */); + if(result != KMessageBox::Yes) return false; } return true; } - ///////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATION ///////////////////////////////////////////////////////////////////// - void KDiff3App::slotFileSave() { - if ( m_bDefaultFilename ) + if(m_bDefaultFilename) { slotFileSaveAs(); } else { - slotStatusMsg( i18n( "Saving file..." ) ); + slotStatusMsg(i18n("Saving file...")); - bool bSuccess = m_pMergeResultWindow->saveDocument( m_outputFilename, m_pMergeResultWindowTitle->getEncoding(), m_pMergeResultWindowTitle->getLineEndStyle() ); - if( bSuccess ) + bool bSuccess = m_pMergeResultWindow->saveDocument(m_outputFilename, m_pMergeResultWindowTitle->getEncoding(), m_pMergeResultWindowTitle->getLineEndStyle()); + if(bSuccess) { m_bFileSaved = true; m_bOutputModified = false; - if( m_bDirCompare ) - m_pDirectoryMergeWindow->mergeResultSaved( m_outputFilename ); + if(m_bDirCompare) + m_pDirectoryMergeWindow->mergeResultSaved(m_outputFilename); } - slotStatusMsg( i18n( "Ready." ) ); + slotStatusMsg(i18n("Ready.")); } } void KDiff3App::slotFileSaveAs() { - slotStatusMsg( i18n( "Saving file with a new filename..." ) ); + slotStatusMsg(i18n("Saving file with a new filename...")); - QString s = QFileDialog::getSaveFileUrl( this, i18n( "Save As..." ), QUrl::fromLocalFile(QDir::currentPath()), 0 ).url(QUrl::PreferLocalFile); - if( !s.isEmpty() ) { + QString s = QFileDialog::getSaveFileUrl(this, i18n("Save As..."), QUrl::fromLocalFile(QDir::currentPath()), 0).url(QUrl::PreferLocalFile); + if(!s.isEmpty()) { m_outputFilename = s; - m_pMergeResultWindowTitle->setFileName( m_outputFilename ); - bool bSuccess = m_pMergeResultWindow->saveDocument( m_outputFilename, m_pMergeResultWindowTitle->getEncoding(), m_pMergeResultWindowTitle->getLineEndStyle() ); - if( bSuccess ) + m_pMergeResultWindowTitle->setFileName(m_outputFilename); + bool bSuccess = m_pMergeResultWindow->saveDocument(m_outputFilename, m_pMergeResultWindowTitle->getEncoding(), m_pMergeResultWindowTitle->getLineEndStyle()); + if(bSuccess) { m_bOutputModified = false; - if( m_bDirCompare ) - m_pDirectoryMergeWindow->mergeResultSaved( m_outputFilename ); + if(m_bDirCompare) + m_pDirectoryMergeWindow->mergeResultSaved(m_outputFilename); } //setWindowTitle(url.fileName(),doc->isModified()); m_bDefaultFilename = false; } - slotStatusMsg( i18n( "Ready." ) ); + slotStatusMsg(i18n("Ready.")); } - -void printDiffTextWindow( MyPainter& painter, const QRect& view, const QString& headerText, DiffTextWindow* pDiffTextWindow, int line, int linesPerPage, QColor fgColor ) +void printDiffTextWindow(MyPainter& painter, const QRect& view, const QString& headerText, DiffTextWindow* pDiffTextWindow, int line, int linesPerPage, QColor fgColor) { QRect clipRect = view; - clipRect.setTop( 0 ); - painter.setClipRect( clipRect ); - painter.translate( view.left() , 0 ); + clipRect.setTop(0); + painter.setClipRect(clipRect); + painter.translate(view.left(), 0); QFontMetrics fm = painter.fontMetrics(); //if ( fm.width(headerText) > view.width() ) { // A simple wrapline algorithm int l = 0; - for (int p=0; p view.width() ) + for(i = 2; i < s.length(); ++i) + if(fm.width(s, i) > view.width()) { --i; break; } //QString s2 = s.left(i); - painter.drawText( 0, l * fm.height() + fm.ascent(), s.left( i ) ); + painter.drawText(0, l * fm.height() + fm.ascent(), s.left(i)); p += i; ++l; } - painter.setPen( fgColor ); - painter.drawLine( 0, view.top() - 2, view.width(), view.top() - 2 ); + painter.setPen(fgColor); + painter.drawLine(0, view.top() - 2, view.width(), view.top() - 2); } - painter.translate( 0, view.top() ); - pDiffTextWindow->print( painter, view, line, linesPerPage ); + painter.translate(0, view.top()); + pDiffTextWindow->print(painter, view, line, linesPerPage); painter.resetMatrix(); } void KDiff3App::slotFilePrint() { - if( !m_pDiffTextWindow1 ) + if(!m_pDiffTextWindow1) return; #ifdef QT_NO_PRINTER - slotStatusMsg( i18n( "Printing not implemented." ) ); + slotStatusMsg(i18n("Printing not implemented.")); #endif #ifndef QT_NO_PRINTER QPrinter printer; - QPrintDialog printDialog( &printer, this ); + QPrintDialog printDialog(&printer, this); int firstSelectionD3LIdx = -1; int lastSelectionD3LIdx = -1; - if( m_pDiffTextWindow1 ) { - m_pDiffTextWindow1->getSelectionRange( &firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords ); + if(m_pDiffTextWindow1) { + m_pDiffTextWindow1->getSelectionRange(&firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords); } - if( firstSelectionD3LIdx < 0 && m_pDiffTextWindow2 ) { - m_pDiffTextWindow2->getSelectionRange( &firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords ); + if(firstSelectionD3LIdx < 0 && m_pDiffTextWindow2) { + m_pDiffTextWindow2->getSelectionRange(&firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords); } - if( firstSelectionD3LIdx < 0 && m_pDiffTextWindow3 ) { - m_pDiffTextWindow3->getSelectionRange( &firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords ); + if(firstSelectionD3LIdx < 0 && m_pDiffTextWindow3) { + m_pDiffTextWindow3->getSelectionRange(&firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords); } - if( firstSelectionD3LIdx >= 0 ) { - printDialog.addEnabledOption( QPrintDialog::PrintSelection ); + if(firstSelectionD3LIdx >= 0) { + printDialog.addEnabledOption(QPrintDialog::PrintSelection); //printer.setOptionEnabled(QPrinter::PrintSelection,true); - printDialog.setPrintRange( QAbstractPrintDialog::Selection ); + printDialog.setPrintRange(QAbstractPrintDialog::Selection); } - if( firstSelectionD3LIdx == -1 ) - printDialog.setPrintRange( QAbstractPrintDialog::AllPages ); + if(firstSelectionD3LIdx == -1) + printDialog.setPrintRange(QAbstractPrintDialog::AllPages); //printDialog.setMinMax(0,0); - printDialog.setFromTo( 0, 0 ); + printDialog.setFromTo(0, 0); int currentFirstLine = m_pDiffTextWindow1->getFirstLine(); - int currentFirstD3LIdx = m_pDiffTextWindow1->convertLineToDiff3LineIdx( currentFirstLine ); + int currentFirstD3LIdx = m_pDiffTextWindow1->convertLineToDiff3LineIdx(currentFirstLine); // do some printer initialization - printer.setFullPage( false ); + printer.setFullPage(false); // initialize the printer using the print dialog - if( printDialog.exec() == QDialog::Accepted ) + if(printDialog.exec() == QDialog::Accepted) { - slotStatusMsg( i18n( "Printing..." ) ); + slotStatusMsg(i18n("Printing...")); // create a painter to paint on the printer object - MyPainter painter( &printer, m_pOptions->m_bRightToLeftLanguage, width(), fontMetrics().width( 'W' ) ); + MyPainter painter(&printer, m_pOptions->m_bRightToLeftLanguage, width(), fontMetrics().width('W')); QPaintDevice* pPaintDevice = painter.device(); int dpiy = pPaintDevice->logicalDpiY(); - int columnDistance = ( int )( ( 0.5 / 2.54 ) * dpiy ); // 0.5 cm between the columns + int columnDistance = (int)((0.5 / 2.54) * dpiy); // 0.5 cm between the columns int columns = m_bTripleDiff ? 3 : 2; - int columnWidth = ( pPaintDevice->width() - ( columns - 1 ) * columnDistance ) / columns; + int columnWidth = (pPaintDevice->width() - (columns - 1) * columnDistance) / columns; QFont f = m_pOptions->m_font; - f.setPointSizeF( f.pointSizeF() - 1 ); // Print with slightly smaller font. - painter.setFont( f ); + f.setPointSizeF(f.pointSizeF() - 1); // Print with slightly smaller font. + painter.setFont(f); QFontMetrics fm = painter.fontMetrics(); - QString topLineText = i18n( "Top line" ); + QString topLineText = i18n("Top line"); //int headerWidth = fm.width( m_sd1.getAliasName() + ", "+topLineText+": 01234567" ); - int headerLines = fm.width( m_sd1.getAliasName() + ", " + topLineText + ": 01234567" ) / columnWidth + 1; + int headerLines = fm.width(m_sd1.getAliasName() + ", " + topLineText + ": 01234567") / columnWidth + 1; int headerMargin = headerLines * fm.height() + 3; // Text + one horizontal line int footerMargin = fm.height() + 3; - QRect view( 0, headerMargin, pPaintDevice->width(), pPaintDevice->height() - ( headerMargin + footerMargin ) ); - QRect view1( 0 * ( columnWidth + columnDistance ), view.top(), columnWidth, view.height() ); - QRect view2( 1 * ( columnWidth + columnDistance ), view.top(), columnWidth, view.height() ); - QRect view3( 2 * ( columnWidth + columnDistance ), view.top(), columnWidth, view.height() ); + QRect view(0, headerMargin, pPaintDevice->width(), pPaintDevice->height() - (headerMargin + footerMargin)); + QRect view1(0 * (columnWidth + columnDistance), view.top(), columnWidth, view.height()); + QRect view2(1 * (columnWidth + columnDistance), view.top(), columnWidth, view.height()); + QRect view3(2 * (columnWidth + columnDistance), view.top(), columnWidth, view.height()); int linesPerPage = view.height() / fm.lineSpacing(); QEventLoop eventLoopForPrinting; m_pEventLoopForPrinting = &eventLoopForPrinting; - if( m_pOptions->m_bWordWrap ) + if(m_pOptions->m_bWordWrap) { // For printing the lines are wrapped differently (this invalidates the first line) - recalcWordWrap( columnWidth ); + recalcWordWrap(columnWidth); m_pEventLoopForPrinting->exec(); } - int totalNofLines = max2( m_pDiffTextWindow1->getNofLines(), m_pDiffTextWindow2->getNofLines() ); - if( m_bTripleDiff && m_pDiffTextWindow3 ) - totalNofLines = max2( totalNofLines, m_pDiffTextWindow3->getNofLines() ); + int totalNofLines = max2(m_pDiffTextWindow1->getNofLines(), m_pDiffTextWindow2->getNofLines()); + if(m_bTripleDiff && m_pDiffTextWindow3) + totalNofLines = max2(totalNofLines, m_pDiffTextWindow3->getNofLines()); - QList pageList;// = printer.pageList(); + QList pageList; // = printer.pageList(); bool bPrintCurrentPage = false; bool bFirstPrintedPage = false; bool bPrintSelection = false; - int totalNofPages = ( totalNofLines + linesPerPage - 1 ) / linesPerPage; + int totalNofPages = (totalNofLines + linesPerPage - 1) / linesPerPage; int line = -1; int selectionEndLine = -1; - if( printer.printRange() == QPrinter::AllPages ) { + if(printer.printRange() == QPrinter::AllPages) { pageList.clear(); - for( int i = 0; i < totalNofPages; ++i ) + for(int i = 0; i < totalNofPages; ++i) { - pageList.push_back( i + 1 ); + pageList.push_back(i + 1); } } - else if( printer.printRange() == QPrinter::PageRange ) + else if(printer.printRange() == QPrinter::PageRange) { pageList.clear(); - for( int i = printer.fromPage(); i <= printer.toPage(); ++i ) + for(int i = printer.fromPage(); i <= printer.toPage(); ++i) { - pageList.push_back( i ); + pageList.push_back(i); } } - if( printer.printRange() == QPrinter::Selection ) + if(printer.printRange() == QPrinter::Selection) { bPrintSelection = true; - if( firstSelectionD3LIdx >= 0 ) + if(firstSelectionD3LIdx >= 0) { - line = m_pDiffTextWindow1->convertDiff3LineIdxToLine( firstSelectionD3LIdx ); - selectionEndLine = m_pDiffTextWindow1->convertDiff3LineIdxToLine( lastSelectionD3LIdx + 1 ); - totalNofPages = ( selectionEndLine - line + linesPerPage - 1 ) / linesPerPage; + line = m_pDiffTextWindow1->convertDiff3LineIdxToLine(firstSelectionD3LIdx); + selectionEndLine = m_pDiffTextWindow1->convertDiff3LineIdxToLine(lastSelectionD3LIdx + 1); + totalNofPages = (selectionEndLine - line + linesPerPage - 1) / linesPerPage; } } int page = 1; ProgressProxy pp; pp.setMaxNofSteps(totalNofPages); QList::iterator pageListIt = pageList.begin(); - for( ;; ) { - pp.setInformation(i18n("Printing page %1 of %2").arg(page).arg(totalNofPages),false); + for(;;) { + pp.setInformation(i18n("Printing page %1 of %2").arg(page).arg(totalNofPages), false); pp.setCurrent(page - 1); - if (pp.wasCancelled()) + if(pp.wasCancelled()) { - printer.abort(); - break; + printer.abort(); + break; } - if( !bPrintSelection ) { - if( pageListIt == pageList.end() ) + if(!bPrintSelection) { + if(pageListIt == pageList.end()) break; page = *pageListIt; - line = ( page - 1 ) * linesPerPage; - if( page == 10000 ) { // This means "Print the current page" + line = (page - 1) * linesPerPage; + if(page == 10000) { // This means "Print the current page" bPrintCurrentPage = true; // Detect the first visible line in the window. - line = m_pDiffTextWindow1->convertDiff3LineIdxToLine( currentFirstD3LIdx ); + line = m_pDiffTextWindow1->convertDiff3LineIdxToLine(currentFirstD3LIdx); } } - else { - if( line >= selectionEndLine ) { + else + { + if(line >= selectionEndLine) { break; } else { - if( selectionEndLine - line < linesPerPage ) + if(selectionEndLine - line < linesPerPage) linesPerPage = selectionEndLine - line; } } - if( line >= 0 && line < totalNofLines ) + if(line >= 0 && line < totalNofLines) { - if( bFirstPrintedPage ) + if(bFirstPrintedPage) printer.newPage(); - painter.setClipping( true ); + painter.setClipping(true); - painter.setPen( m_pOptions->m_colorA ); - QString headerText1 = m_sd1.getAliasName() + ", " + topLineText + ": " + QString::number( m_pDiffTextWindow1->calcTopLineInFile( line ) + 1 ); - printDiffTextWindow( painter, view1, headerText1, m_pDiffTextWindow1, line, linesPerPage, m_pOptions->m_fgColor ); + painter.setPen(m_pOptions->m_colorA); + QString headerText1 = m_sd1.getAliasName() + ", " + topLineText + ": " + QString::number(m_pDiffTextWindow1->calcTopLineInFile(line) + 1); + printDiffTextWindow(painter, view1, headerText1, m_pDiffTextWindow1, line, linesPerPage, m_pOptions->m_fgColor); - painter.setPen( m_pOptions->m_colorB ); - QString headerText2 = m_sd2.getAliasName() + ", " + topLineText + ": " + QString::number( m_pDiffTextWindow2->calcTopLineInFile( line ) + 1 ); - printDiffTextWindow( painter, view2, headerText2, m_pDiffTextWindow2, line, linesPerPage, m_pOptions->m_fgColor ); + painter.setPen(m_pOptions->m_colorB); + QString headerText2 = m_sd2.getAliasName() + ", " + topLineText + ": " + QString::number(m_pDiffTextWindow2->calcTopLineInFile(line) + 1); + printDiffTextWindow(painter, view2, headerText2, m_pDiffTextWindow2, line, linesPerPage, m_pOptions->m_fgColor); - if( m_bTripleDiff && m_pDiffTextWindow3 ) + if(m_bTripleDiff && m_pDiffTextWindow3) { - painter.setPen( m_pOptions->m_colorC ); - QString headerText3 = m_sd3.getAliasName() + ", " + topLineText + ": " + QString::number( m_pDiffTextWindow3->calcTopLineInFile( line ) + 1 ); - printDiffTextWindow( painter, view3, headerText3, m_pDiffTextWindow3, line, linesPerPage, m_pOptions->m_fgColor ); + painter.setPen(m_pOptions->m_colorC); + QString headerText3 = m_sd3.getAliasName() + ", " + topLineText + ": " + QString::number(m_pDiffTextWindow3->calcTopLineInFile(line) + 1); + printDiffTextWindow(painter, view3, headerText3, m_pDiffTextWindow3, line, linesPerPage, m_pOptions->m_fgColor); } - painter.setClipping( false ); + painter.setClipping(false); - painter.setPen( m_pOptions->m_fgColor ); - painter.drawLine( 0, view.bottom() + 3, view.width(), view.bottom() + 3 ); - QString s = bPrintCurrentPage ? QString( "" ) - : QString::number( page ) + "/" + QString::number( totalNofPages ); - if( bPrintSelection ) s += " (" + i18n( "Selection" ) + ")"; - painter.drawText( ( view.right() - painter.fontMetrics().width( s ) ) / 2, - view.bottom() + painter.fontMetrics().ascent() + 5, s ); + painter.setPen(m_pOptions->m_fgColor); + painter.drawLine(0, view.bottom() + 3, view.width(), view.bottom() + 3); + QString s = bPrintCurrentPage ? QString("") + : QString::number(page) + "/" + QString::number(totalNofPages); + if(bPrintSelection) s += " (" + i18n("Selection") + ")"; + painter.drawText((view.right() - painter.fontMetrics().width(s)) / 2, + view.bottom() + painter.fontMetrics().ascent() + 5, s); bFirstPrintedPage = true; } - if( bPrintSelection ) + if(bPrintSelection) { line += linesPerPage; ++page; } else { ++pageListIt; } } painter.end(); - if( m_pOptions->m_bWordWrap ) + if(m_pOptions->m_bWordWrap) { recalcWordWrap(); m_pEventLoopForPrinting->exec(); - m_pDiffVScrollBar->setValue( m_pDiffTextWindow1->convertDiff3LineIdxToLine( currentFirstD3LIdx ) ); + m_pDiffVScrollBar->setValue(m_pDiffTextWindow1->convertDiff3LineIdxToLine(currentFirstD3LIdx)); } - slotStatusMsg( i18n( "Printing completed." ) ); + slotStatusMsg(i18n("Printing completed.")); } else { - slotStatusMsg( i18n( "Printing aborted." ) ); + slotStatusMsg(i18n("Printing aborted.")); } #endif } void KDiff3App::slotFileQuit() { - slotStatusMsg( i18n( "Exiting..." ) ); + slotStatusMsg(i18n("Exiting...")); - if( !queryClose() ) - return; // Don't quit + if(!queryClose()) + return; // Don't quit - QApplication::exit( isFileSaved() || isDirComparison() ? 0 : 1 ); + QApplication::exit(isFileSaved() || isDirComparison() ? 0 : 1); } - - void KDiff3App::slotViewToolBar() { - assert( viewToolBar != 0 ); - slotStatusMsg( i18n( "Toggling toolbar..." ) ); + assert(viewToolBar != 0); + slotStatusMsg(i18n("Toggling toolbar...")); m_pOptions->m_bShowToolBar = viewToolBar->isChecked(); /////////////////////////////////////////////////////////////////// // turn Toolbar on or off - if( toolBar( MAIN_TOOLBAR_NAME ) != 0 ) + if(toolBar(MAIN_TOOLBAR_NAME) != 0) { - if( !m_pOptions->m_bShowToolBar ) + if(!m_pOptions->m_bShowToolBar) { - toolBar( MAIN_TOOLBAR_NAME )->hide(); + toolBar(MAIN_TOOLBAR_NAME)->hide(); } else { - toolBar( MAIN_TOOLBAR_NAME )->show(); + toolBar(MAIN_TOOLBAR_NAME)->show(); } } - slotStatusMsg( i18n( "Ready." ) ); + slotStatusMsg(i18n("Ready.")); } void KDiff3App::slotViewStatusBar() { - slotStatusMsg( i18n( "Toggle the statusbar..." ) ); + slotStatusMsg(i18n("Toggle the statusbar...")); m_pOptions->m_bShowStatusBar = viewStatusBar->isChecked(); /////////////////////////////////////////////////////////////////// //turn Statusbar on or off - if( statusBar() != 0 ) + if(statusBar() != 0) { - if( !viewStatusBar->isChecked() ) + if(!viewStatusBar->isChecked()) { statusBar()->hide(); } else { statusBar()->show(); } } - slotStatusMsg( i18n( "Ready." ) ); + slotStatusMsg(i18n("Ready.")); } - -void KDiff3App::slotStatusMsg(const QString &text) +void KDiff3App::slotStatusMsg(const QString& text) { /////////////////////////////////////////////////////////////////// // change status message permanently - if( statusBar() != 0 ) + if(statusBar() != 0) { statusBar()->clearMessage(); - statusBar()->showMessage( text ); + statusBar()->showMessage(text); } } - - - //#include "kdiff3.moc" diff --git a/src/kdiff3_part.cpp b/src/kdiff3_part.cpp index 066d074..fd1fc1b 100644 --- a/src/kdiff3_part.cpp +++ b/src/kdiff3_part.cpp @@ -1,280 +1,278 @@ /*************************************************************************** * Copyright (C) 2003-2007 Joachim Eibl * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "kdiff3_part.h" #include -#include #include +#include #include -#include #include +#include -#include "kdiff3.h" #include "fileaccess.h" +#include "kdiff3.h" -#include #include +#include #include "version.h" - static KAboutData createAboutData() { - QByteArray appVersion = QByteArray( VERSION ); - if ( sizeof(void*)==8 ) - appVersion += " (64 bit)"; - else if ( sizeof(void*)==4 ) - appVersion += " (32 bit)"; - - KAboutData aboutData( "kdiff3part", i18n( "KDiff3 Part" ), - appVersion, i18n( "A KPart to display SVG images" ), - KAboutLicense::GPL_V2, - i18n( "Copyright 2007, Aurélien Gâteau " ) ); - aboutData.addAuthor( i18n( "Joachim Eibl" ), QString(), QByteArray( "joachim.eibl at gmx.de" ) ); + QByteArray appVersion = QByteArray(VERSION); + if(sizeof(void*) == 8) + appVersion += " (64 bit)"; + else if(sizeof(void*) == 4) + appVersion += " (32 bit)"; + + KAboutData aboutData("kdiff3part", i18n("KDiff3 Part"), + appVersion, i18n("A KPart to display SVG images"), + KAboutLicense::GPL_V2, + i18n("Copyright 2007, Aurélien Gâteau ")); + aboutData.addAuthor(i18n("Joachim Eibl"), QString(), QByteArray("joachim.eibl at gmx.de")); return aboutData; } -K_PLUGIN_FACTORY( KDiff3PartFactory, registerPlugin(); ) +K_PLUGIN_FACTORY(KDiff3PartFactory, registerPlugin();) //K_EXPORT_PLUGIN( KDiff3PartFactory(createAboutData())) -KDiff3Part::KDiff3Part( QWidget *parentWidget, QObject *parent, const QVariantList &args ) - : KParts::ReadWritePart( parent ) { +KDiff3Part::KDiff3Part(QWidget* parentWidget, QObject* parent, const QVariantList& args) + : KParts::ReadWritePart(parent) +{ //set AboutData setComponentData(createAboutData()); - const char *widgetName = args[0].toString().toUtf8().data(); + const char* widgetName = args[0].toString().toUtf8().data(); // this should be your custom internal widget - m_widget = new KDiff3App( parentWidget, widgetName, this ); - + m_widget = new KDiff3App(parentWidget, widgetName, this); + //FIXME: This hack is necessary to avoid a crash when the program terminates. - m_bIsShell = qobject_cast(parentWidget)!=0; + m_bIsShell = qobject_cast(parentWidget) != 0; // notify the part that this is our internal widget setWidget(m_widget); // create our actions //KStandardAction::open(this, SLOT(fileOpen()), actionCollection()); //KStandardAction::saveAs(this, SLOT(fileSaveAs()), actionCollection()); //KStandardAction::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 ) + if(m_widget != 0 && !m_bIsShell) { - m_widget->saveOptions( KSharedConfig::openConfig() ); + m_widget->saveOptions(KSharedConfig::openConfig()); } } void KDiff3Part::setReadWrite(bool /*rw*/) { -// ReadWritePart::setReadWrite(rw); + // ReadWritePart::setReadWrite(rw); } void KDiff3Part::setModified(bool /*modified*/) { -/* + /* // get a handle on our Save action and make sure it is valid QAction *save = actionCollection()->action(KStandardAction::stdName(KStandardAction::Save)); if (!save) return; // if so, we either enable or disable it based on the current // state if (modified) save->setEnabled(true); else save->setEnabled(false); // in any event, we want our parent to do it's thing ReadWritePart::setModified(modified); */ } -static void getNameAndVersion( const QString& str, const QString& lineStart, QString& fileName, QString& version ) +static void getNameAndVersion(const QString& str, const QString& lineStart, QString& fileName, QString& version) { - if( str.left( lineStart.length() ) == lineStart && fileName.isEmpty() ) + if(str.left(lineStart.length()) == lineStart && fileName.isEmpty()) { int pos = lineStart.length(); - while( pos < str.length() && ( str[pos] == ' ' || str[pos] == '\t' ) ) ++pos; + while(pos < str.length() && (str[pos] == ' ' || str[pos] == '\t')) ++pos; int pos2 = str.length() - 1; - while( pos2 > pos ) + while(pos2 > pos) { - while( pos2 > pos && str[pos2] != ' ' && str[pos2] != '\t' ) --pos2; - fileName = str.mid( pos, pos2 - pos ); - fprintf( stderr, "KDiff3: %s\n", fileName.toLatin1().constData() ); - if( FileAccess(fileName).exists() ) break; + while(pos2 > pos && str[pos2] != ' ' && str[pos2] != '\t') --pos2; + fileName = str.mid(pos, pos2 - pos); + fprintf(stderr, "KDiff3: %s\n", fileName.toLatin1().constData()); + if(FileAccess(fileName).exists()) break; --pos2; } int vpos = str.lastIndexOf("\t", -1); - if( vpos > 0 && vpos > ( int )pos2 ) + if(vpos > 0 && vpos > (int)pos2) { - version = str.mid( vpos + 1 ); - while( !version.right( 1 )[0].isLetterOrNumber() ) - version.truncate( version.length() - 1 ); + version = str.mid(vpos + 1); + while(!version.right(1)[0].isLetterOrNumber()) + version.truncate(version.length() - 1); } } } - bool KDiff3Part::openFile() { - // m_file is always local so we can use QFile on it - fprintf(stderr, "KDiff3: %s\n", localFilePath().toLatin1().constData()); - QFile file(localFilePath()); - if (file.open(QIODevice::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.atEnd() && (fileName1.isEmpty() || fileName2.isEmpty()) ) - { - str = stream.readLine() + "\n"; - getNameAndVersion( str, "---", fileName1, version1 ); - getNameAndVersion( str, "+++", fileName2, version2 ); - } - - file.close(); - - if( fileName1.isEmpty() && fileName2.isEmpty() ) - { - KMessageBox::sorry(m_widget, i18n("Couldn't find files for comparison.")); - return false; - } - - FileAccess f1(fileName1); - FileAccess f2(fileName2); - - if( f1.exists() && f2.exists() && fileName1!=fileName2 ) - { - m_widget->slotFileOpen2( fileName1, fileName2, "", "", "", "", "", 0 ); - return true; - } - else if( version1.isEmpty() && f1.exists() ) - { - // Normal patch - // patch -f -u --ignore-whitespace -i [inputfile] -o [outfile] [patchfile] - QString tempFileName = FileAccess::tempFileName(); - QString cmd = "patch -f -u --ignore-whitespace -i \"" + localFilePath() + - "\" -o \""+tempFileName + "\" \"" + fileName1+ "\""; - - QProcess process; - process.start( cmd ); - process.waitForFinished(-1); - - m_widget->slotFileOpen2( fileName1, tempFileName, "", "", - "", version2.isEmpty() ? fileName2 : "REV:"+version2+":"+fileName2, "", 0 ); // alias names -// std::cerr << "KDiff3: f1:" << fileName1.toLatin1() <<"<->"<slotFileOpen2( tempFileName, fileName2, "", "", - version1.isEmpty() ? fileName1 : "REV:"+version1+":"+fileName1, "", "", 0 ); // alias name -// std::cerr << "KDiff3: f2:" << fileName2.toLatin1() <<"<->"<%s\n", fileName1.toLatin1().constData(), fileName2.toLatin1().constData()); - // 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+"\""; - QProcess process1; - process1.start( cmd1 ); - process1.waitForFinished(-1); - - QString tempFileName2 = FileAccess::tempFileName(); - QString cmd2 = "cvs update -p -r " + version2 + " \"" + fileName2 + "\" >\""+tempFileName2+"\""; - QProcess process2; - process2.start( cmd2 ); - process2.waitForFinished(-1); - - m_widget->slotFileOpen2( tempFileName1, tempFileName2, "", "", - "REV:"+version1+":"+fileName1, - "REV:"+version2+":"+fileName2, - "", 0 - ); - -// std::cerr << "KDiff3: f1/2:" << tempFileName1.toLatin1() <<"<->"<slotFileOpen2(fileName1, fileName2, "", "", "", "", "", 0); + return true; + } + else if(version1.isEmpty() && f1.exists()) + { + // Normal patch + // patch -f -u --ignore-whitespace -i [inputfile] -o [outfile] [patchfile] + QString tempFileName = FileAccess::tempFileName(); + QString cmd = "patch -f -u --ignore-whitespace -i \"" + localFilePath() + + "\" -o \"" + tempFileName + "\" \"" + fileName1 + "\""; + + QProcess process; + process.start(cmd); + process.waitForFinished(-1); + + m_widget->slotFileOpen2(fileName1, tempFileName, "", "", + "", version2.isEmpty() ? fileName2 : "REV:" + version2 + ":" + fileName2, "", 0); // alias names + // std::cerr << "KDiff3: f1:" << fileName1.toLatin1() <<"<->"<slotFileOpen2(tempFileName, fileName2, "", "", + version1.isEmpty() ? fileName1 : "REV:" + version1 + ":" + fileName1, "", "", 0); // alias name + // std::cerr << "KDiff3: f2:" << fileName2.toLatin1() <<"<->"<%s\n", fileName1.toLatin1().constData(), fileName2.toLatin1().constData()); + // 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 + "\""; + QProcess process1; + process1.start(cmd1); + process1.waitForFinished(-1); + + QString tempFileName2 = FileAccess::tempFileName(); + QString cmd2 = "cvs update -p -r " + version2 + " \"" + fileName2 + "\" >\"" + tempFileName2 + "\""; + QProcess process2; + process2.start(cmd2); + process2.waitForFinished(-1); + + m_widget->slotFileOpen2(tempFileName1, tempFileName2, "", "", + "REV:" + version1 + ":" + fileName1, + "REV:" + version2 + ":" + fileName2, + "", 0); + + // std::cerr << "KDiff3: f1/2:" << tempFileName1.toLatin1() <<"<->"<text(); file.close(); return true; */ - return false; // Not implemented + return false; // Not implemented } // Suppress warning with --enable-final #undef VERSION #include "kdiff3_part.moc" diff --git a/src/kdiff3_shell.cpp b/src/kdiff3_shell.cpp index b182313..50960f9 100644 --- a/src/kdiff3_shell.cpp +++ b/src/kdiff3_shell.cpp @@ -1,177 +1,176 @@ /*************************************************************************** * Copyright (C) 2003-2007 Joachim Eibl * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "kdiff3_shell.h" #include "kdiff3.h" #include "kdiff3_part.h" -#include #include -#include #include +#include +#include -#include #include +#include -#include #include -#include #include -#include #include +#include +#include +#include #include -KDiff3Shell::KDiff3Shell( bool bCompleteInit ) - : KParts::MainWindow( ) +KDiff3Shell::KDiff3Shell(bool bCompleteInit) + : KParts::MainWindow() { m_bUnderConstruction = true; // set the shell's ui resource file setXMLFile("kdiff3_shell.rc"); // and a status bar statusBar()->show(); /*const QVector plugin_offers = KPluginLoader::findPlugins( "kf5/kdiff3part" ); foreach( const KPluginMetaData & service, plugin_offers ) { KPluginFactory *factory = KPluginLoader( service.fileName() ).factory(); m_part = factory->create( this, QVariantList() << QVariant( QLatin1String( "KDiff3Part" ) ) ); if( m_part ) break; }*/ - m_part = new KDiff3Part( this, this, QVariantList() << QVariant(QLatin1String("KDiff3Part")) ); - m_widget = qobject_cast(m_part->widget()); + m_part = new KDiff3Part(this, this, QVariantList() << QVariant(QLatin1String("KDiff3Part"))); + m_widget = qobject_cast(m_part->widget()); - if (m_part) - { - // and integrate the part's GUI with the shell's - createGUI(m_part); - //toolBar()->setToolButtonStyle( Qt::ToolButtonIconOnly ); + if(m_part) + { + // and integrate the part's GUI with the shell's + createGUI(m_part); + //toolBar()->setToolButtonStyle( Qt::ToolButtonIconOnly ); - // tell the KParts::MainWindow that this is indeed the main widget - setCentralWidget(m_widget); + // tell the KParts::MainWindow that this is indeed the main widget + setCentralWidget(m_widget); - if (bCompleteInit) - m_widget ->completeInit(); - connect(m_widget, SIGNAL(createNewInstance(const QString&, const QString&, const QString&)), this, SLOT(slotNewInstance(const QString&, const QString&, const QString&))); - } + if(bCompleteInit) + m_widget->completeInit(); + connect(m_widget, SIGNAL(createNewInstance(const QString&, const QString&, const QString&)), this, SLOT(slotNewInstance(const QString&, const QString&, const QString&))); + } else { // if we couldn't find our Part, we exit since the Shell by // itself can't do anything useful KMessageBox::error(this, i18n("Could not initialize the KDiff3 part.\n" - "This usually happens due to an installation problem. " - "Please read the README-file in the source package for details.") - ); + "This usually happens due to an installation problem. " + "Please read the README-file in the source package for details.")); //kapp->quit(); ::exit(-1); //kapp->quit() doesn't work here yet. // we return here, cause kapp->quit() only means "exit the // next time we enter the event loop... return; } // apply the saved mainwindow settings, if any, and ask the mainwindow // to automatically save settings if changed: window size, toolbar // position, icon size, etc. setAutoSaveSettings(); m_bUnderConstruction = false; } KDiff3Shell::~KDiff3Shell() { } bool KDiff3Shell::queryClose() { - if (m_part) - return ((KDiff3App*)m_part->widget())->queryClose(); - else - return true; + if(m_part) + return ((KDiff3App*)m_part->widget())->queryClose(); + else + return true; } bool KDiff3Shell::queryExit() { - return true; + return true; } -void KDiff3Shell::closeEvent(QCloseEvent*e) +void KDiff3Shell::closeEvent(QCloseEvent* e) { - if ( queryClose() ) - { - e->accept(); - bool bFileSaved = ((KDiff3App*)m_part->widget())->isFileSaved(); - bool bDirCompare = ((KDiff3App*)m_part->widget())->isDirComparison(); - QApplication::exit( bFileSaved || bDirCompare ? 0 : 1 ); - } - else - e->ignore(); + if(queryClose()) + { + e->accept(); + bool bFileSaved = ((KDiff3App*)m_part->widget())->isFileSaved(); + bool bDirCompare = ((KDiff3App*)m_part->widget())->isDirComparison(); + QApplication::exit(bFileSaved || bDirCompare ? 0 : 1); + } + else + e->ignore(); } void KDiff3Shell::optionsShowToolbar() { // this is all very cut and paste code for showing/hiding the // toolbar - if (m_toolbarAction->isChecked()) + 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()) + if(m_statusbarAction->isChecked()) statusBar()->show(); else statusBar()->hide(); } void KDiff3Shell::optionsConfigureKeys() { - KShortcutsDialog::configure(actionCollection() /*, "kdiff3_shell.rc" */ ); + KShortcutsDialog::configure(actionCollection() /*, "kdiff3_shell.rc" */); } void KDiff3Shell::optionsConfigureToolbars() { - KConfigGroup mainWindowGroup( KSharedConfig::openConfig(), "MainWindow" ); - saveMainWindowSettings( mainWindowGroup ); + KConfigGroup mainWindowGroup(KSharedConfig::openConfig(), "MainWindow"); + saveMainWindowSettings(mainWindowGroup); // use the standard toolbar editor KEditToolBar dlg(factory()); connect(&dlg, &KEditToolBar::newToolbarConfig, this, &KDiff3Shell::applyNewToolbarConfig); dlg.exec(); } void KDiff3Shell::applyNewToolbarConfig() { - KConfigGroup mainWindowGroup( KSharedConfig::openConfig(), "MainWindow" ); - applyMainWindowSettings( mainWindowGroup ); + KConfigGroup mainWindowGroup(KSharedConfig::openConfig(), "MainWindow"); + applyMainWindowSettings(mainWindowGroup); } -void KDiff3Shell::slotNewInstance( const QString& fn1, const QString& fn2, const QString& fn3 ) +void KDiff3Shell::slotNewInstance(const QString& fn1, const QString& fn2, const QString& fn3) { - KDiff3Shell* pKDiff3Shell = new KDiff3Shell(false); - ((KDiff3App*)pKDiff3Shell->m_part->widget())->completeInit(fn1,fn2,fn3); + KDiff3Shell* pKDiff3Shell = new KDiff3Shell(false); + ((KDiff3App*)pKDiff3Shell->m_part->widget())->completeInit(fn1, fn2, fn3); } //#include "kdiff3_shell.moc" diff --git a/src/main.cpp b/src/main.cpp index 6b7a1bf..7afcf76 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,292 +1,293 @@ /*************************************************************************** main.cpp - Where everything starts. ------------------- begin : Don Jul 11 12:31:29 CEST 2002 copyright : (C) 2002-2007 by Joachim Eibl email : joachim.eibl at gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ -#include "kdiff3_shell.h" #include "common.h" +#include "kdiff3_shell.h" #include "version.h" #include -#include #include +#include #include +#include #include #include #include #include #include #include #include #include #include #include -#include #include #ifdef _WIN32 #include #include #endif -void initialiseCmdLineArgs(QCommandLineParser *cmdLineParser) +void initialiseCmdLineArgs(QCommandLineParser* cmdLineParser) { - QString configFileName = QStandardPaths::locate(QStandardPaths::GenericConfigLocation , "kdiff3rc" ); - QFile configFile( configFileName ); + QString configFileName = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, "kdiff3rc"); + QFile configFile(configFileName); QString ignorableOptionsLine = "-u;-query;-html;-abort"; - if( configFile.open( QIODevice::ReadOnly ) ) + if(configFile.open(QIODevice::ReadOnly)) { - QTextStream ts( &configFile ); + QTextStream ts(&configFile); while(!ts.atEnd()) { QString line = ts.readLine(); - if( line.startsWith("IgnorableCmdLineOptions=") ) + if(line.startsWith("IgnorableCmdLineOptions=")) { int pos = line.indexOf('='); - if(pos>=0) + if(pos >= 0) { - ignorableOptionsLine = line.mid(pos+1); + ignorableOptionsLine = line.mid(pos + 1); } break; } } } //support our own old preferances this is obsolete - QStringList sl = ignorableOptionsLine.split( ',' ); + QStringList sl = ignorableOptionsLine.split(','); if(!sl.isEmpty()) { - QStringList ignorableOptions = sl.front().split( ';' ); - for(QStringList::iterator i=ignorableOptions.begin(); i!=ignorableOptions.end(); ++i) + QStringList ignorableOptions = sl.front().split(';'); + for(QStringList::iterator i = ignorableOptions.begin(); i != ignorableOptions.end(); ++i) { (*i).remove('-'); if(!(*i).isEmpty()) { - if( i->length()==1 ) { - cmdLineParser->addOption( QCommandLineOption( QStringList() << i->toLatin1() << QLatin1String( "ignore" ), i18n( "Ignored. (User defined.)" ) ) ); + if(i->length() == 1) { + cmdLineParser->addOption(QCommandLineOption(QStringList() << i->toLatin1() << QLatin1String("ignore"), i18n("Ignored. (User defined.)"))); } - else { - cmdLineParser->addOption( QCommandLineOption( QStringList() << i->toLatin1(), i18n( "Ignored. (User defined.)" ) ) ); + else + { + cmdLineParser->addOption(QCommandLineOption(QStringList() << i->toLatin1(), i18n("Ignored. (User defined.)"))); } } } } } #ifdef _WIN32 // This command checks the comm static bool isOptionUsed(const QString& s, int argc, char* argv[]) { - for(int j=0; jsetApplicationDescription(aboutData.shortDescription()); cmdLineParser->addVersionOption(); cmdLineParser->addHelpOption(); initialiseCmdLineArgs(cmdLineParser); // ignorable command options cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("m") << QLatin1String("merge"), i18n("Merge the input."))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("b") << QLatin1String("base"), i18n("Explicit base file. For compatibility with certain tools."), QLatin1String("file"))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("o") << QLatin1String("output"), i18n("Output file. Implies -m. E.g.: -o newfile.txt"), QLatin1String("file"))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("out"), i18n("Output file, again. (For compatibility with certain tools.)"), QLatin1String("file"))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("auto"), i18n("No GUI if all conflicts are auto-solvable. (Needs -o file)"))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("qall"), i18n("Don't solve conflicts automatically."))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("L1"), i18n("Visible name replacement for input file 1 (base)."), QLatin1String("alias1"))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("L2"), i18n("Visible name replacement for input file 2."), QLatin1String("alias2"))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("L3"), i18n("Visible name replacement for input file 3."), QLatin1String("alias3"))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("L") << QLatin1String("fname alias"), i18n("Alternative visible name replacement. Supply this once for every input."))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("cs"), i18n("Override a config setting. Use once for every setting. E.g.: --cs \"AutoAdvance=1\""), QLatin1String("string"))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("confighelp"), i18n("Show list of config settings and current values."))); cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("config"), i18n("Use a different config file."), QLatin1String("file"))); // other command options cmdLineParser->addPositionalArgument(QLatin1String("[File1]"), i18n("file1 to open (base, if not specified via --base)")); cmdLineParser->addPositionalArgument(QLatin1String("[File2]"), i18n("file2 to open")); cmdLineParser->addPositionalArgument(QLatin1String("[File3]"), i18n("file3 to open")); /* Don't use QCommandLineParser::process as it auto terminates the program if an option is not reconized. Further more errors are directed to the console alone if not running on windows. This makes for a bad user experiance when run from a graphical interface such as kde. Don't assume that this only happens when running from a commandline. */ if(!cmdLineParser->parse(QCoreApplication::arguments())) { QString errorMessage = cmdLineParser->errorText(); QString helpText = cmdLineParser->helpText(); QMessageBox::warning(0, aboutData.displayName(), "

" + errorMessage + "

" + helpText + "
"); #if !defined(_WIN32) && !defined(Q_OS_OS2) fputs(qPrintable(errorMessage), stderr); fputs("\n\n", stderr); fputs(qPrintable(helpText + "\n"), stderr); fputs("\n", stderr); #endif exit(1); } if(cmdLineParser->isSet(QStringLiteral("version"))) { QMessageBox::information(0, aboutData.displayName(), aboutData.displayName() + ' ' + aboutData.version()); #if !defined(_WIN32) && !defined(Q_OS_OS2) printf("%s %s\n", appName.constData(), appVersion.constData()); #endif exit(0); } if(cmdLineParser->isSet(QStringLiteral("help"))) { QMessageBox::warning(0, aboutData.displayName(), "
" + cmdLineParser->helpText() + "
"); #if !defined(_WIN32) && !defined(Q_OS_OS2) fputs(qPrintable(cmdLineParser->helpText()), stdout); #endif exit(0); } //cmdLineParser->process( app ); //must be after process or parse call aboutData.setupCommandLine(cmdLineParser); /** * take component name and org. name from KAboutData */ app.setApplicationName(aboutData.componentName()); app.setApplicationDisplayName(aboutData.displayName()); app.setOrganizationDomain(aboutData.organizationDomain()); app.setApplicationVersion(aboutData.version()); #if defined(KREPLACEMENTS_H) && !defined(QT_NO_TRANSLATION) QString locale; locale = app.config()->readEntry("Language", "Auto"); int spacePos = locale.indexOf(' '); if(spacePos > 0) locale = locale.left(spacePos); ContextFreeTranslator kdiff3Translator(0); QTranslator qtTranslator(0); if(locale != "en_orig") { QString translationDir = getTranslationDir(locale); kdiff3Translator.load(QLocale::system(), QString("kdiff3_"), translationDir); app.installTranslator(&kdiff3Translator); qtTranslator.load(QLocale::system(), QString("qt_"), translationDir); app.installTranslator(&qtTranslator); } #endif KDiff3Shell* p = new KDiff3Shell(); p->show(); - p->setWindowState( p->windowState() | Qt::WindowActive ); // Patch for ubuntu: window not active on startup -//app.installEventFilter( new CFilter ); - int retVal = app.exec(); - if (QApplication::clipboard()->text().size() == 0) - QApplication::clipboard()->clear(); // Patch for Ubuntu: Fix issue with Qt clipboard - return retVal; + p->setWindowState(p->windowState() | Qt::WindowActive); // Patch for ubuntu: window not active on startup + //app.installEventFilter( new CFilter ); + int retVal = app.exec(); + if(QApplication::clipboard()->text().size() == 0) + QApplication::clipboard()->clear(); // Patch for Ubuntu: Fix issue with Qt clipboard + return retVal; } // Suppress warning with --enable-final #undef VERSION diff --git a/src/merger.cpp b/src/merger.cpp index b681c9b..da6c56f 100644 --- a/src/merger.cpp +++ b/src/merger.cpp @@ -1,85 +1,82 @@ /*************************************************************************** merger.cpp - description ------------------- begin : Sun Mar 24 2002 copyright : (C) 2002-2007 by Joachim Eibl email : joachim.eibl at gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "merger.h" #include -Merger::Merger( const DiffList* pDiffListAB, const DiffList* pDiffListCA ) -: md1( pDiffListAB, 0 ), md2( pDiffListCA, 1 ) +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) +Merger::MergeData::MergeData(const DiffList* p, int i) + : d(0, 0, 0) { - idx=i; - pDiffList = p; - if ( p!=0 ) - { - it=p->begin(); - update(); - } + idx = i; + pDiffList = p; + if(p != 0) + { + it = p->begin(); + update(); + } } bool Merger::MergeData::eq() { - return pDiffList==0 || d.nofEquals > 0; + 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 ) - ) ); + 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; + 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; - } + 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(); + md1.update(); + md2.update(); } int Merger::whatChanged() { - int changed = 0; - changed |= md1.eq() ? 0 : 1; - changed |= md2.eq() ? 0 : 2; - return changed; + int changed = 0; + changed |= md1.eq() ? 0 : 1; + changed |= md2.eq() ? 0 : 2; + return changed; } bool Merger::isEndReached() { - return md1.isEnd() && md2.isEnd(); + return md1.isEnd() && md2.isEnd(); } diff --git a/src/mergeresultwindow.cpp b/src/mergeresultwindow.cpp index f95db3c..6e248d7 100644 --- a/src/mergeresultwindow.cpp +++ b/src/mergeresultwindow.cpp @@ -1,3483 +1,3583 @@ /*************************************************************************** mergeresultwindow.cpp - description ------------------- begin : Sun Apr 14 2002 copyright : (C) 2002-2007 by Joachim Eibl email : joachim.eibl at gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "mergeresultwindow.h" #include "options.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 +#include #include //Added by qt3to4: -#include -#include -#include -#include -#include +#include #include +#include #include -#include +#include #include +#include +#include #include -#include +#include +#include #include #include int g_bAutoSolve = true; #undef leftInfoWidth MergeResultWindow::MergeResultWindow( - QWidget* pParent, - Options* pOptions, - QStatusBar* pStatusBar - ) -: QWidget( pParent ) -{ - setObjectName( "MergeResultWindow" ); - setFocusPolicy( Qt::ClickFocus ); - - m_firstLine = 0; - m_horizScrollOffset = 0; - m_nofLines = 0; - m_totalSize = 0; - m_bMyUpdate = false; - m_bInsertMode = true; - m_scrollDeltaX = 0; - m_scrollDeltaY = 0; - m_bModified = false; - m_eOverviewMode=Overview::eOMNormal; - - m_pldA = 0; - m_pldB = 0; - m_pldC = 0; - m_sizeA = 0; - m_sizeB = 0; - m_sizeC = 0; - - m_pDiff3LineList = 0; - m_pTotalDiffStatus = 0; - m_pStatusBar = pStatusBar; - if (m_pStatusBar) - connect( m_pStatusBar, SIGNAL(messageChanged(const QString&)), this, SLOT(slotStatusMessageChanged(const QString&)) ); - - m_pOptions = pOptions; - m_bPaintingAllowed = false; - m_delayedDrawTimer = 0; - - m_cursorXPos=0; - m_cursorOldXPixelPos=0; - m_cursorYPos=0; - m_bCursorOn = true; - m_bCursorUpdate = false; - m_maxTextWidth = -1; - connect( &m_cursorTimer, SIGNAL(timeout()), this, SLOT( slotCursorUpdate() ) ); - m_cursorTimer.setSingleShot(true); - m_cursorTimer.start( 500 /*ms*/ ); - m_selection.reset(); - - setMinimumSize( QSize(20,20) ); - setFont( m_pOptions->m_font ); + QWidget* pParent, + Options* pOptions, + QStatusBar* pStatusBar) + : QWidget(pParent) +{ + setObjectName("MergeResultWindow"); + setFocusPolicy(Qt::ClickFocus); + + m_firstLine = 0; + m_horizScrollOffset = 0; + m_nofLines = 0; + m_totalSize = 0; + m_bMyUpdate = false; + m_bInsertMode = true; + m_scrollDeltaX = 0; + m_scrollDeltaY = 0; + m_bModified = false; + m_eOverviewMode = Overview::eOMNormal; + + m_pldA = 0; + m_pldB = 0; + m_pldC = 0; + m_sizeA = 0; + m_sizeB = 0; + m_sizeC = 0; + + m_pDiff3LineList = 0; + m_pTotalDiffStatus = 0; + m_pStatusBar = pStatusBar; + if(m_pStatusBar) + connect(m_pStatusBar, SIGNAL(messageChanged(const QString&)), this, SLOT(slotStatusMessageChanged(const QString&))); + + m_pOptions = pOptions; + m_bPaintingAllowed = false; + m_delayedDrawTimer = 0; + + m_cursorXPos = 0; + m_cursorOldXPixelPos = 0; + m_cursorYPos = 0; + m_bCursorOn = true; + m_bCursorUpdate = false; + m_maxTextWidth = -1; + connect(&m_cursorTimer, SIGNAL(timeout()), this, SLOT(slotCursorUpdate())); + m_cursorTimer.setSingleShot(true); + m_cursorTimer.start(500 /*ms*/); + m_selection.reset(); + + setMinimumSize(QSize(20, 20)); + setFont(m_pOptions->m_font); } void MergeResultWindow::init( - const LineData* pLineDataA, int sizeA, - const LineData* pLineDataB, int sizeB, - const LineData* pLineDataC, int sizeC, - const Diff3LineList* pDiff3LineList, - TotalDiffStatus* pTotalDiffStatus - ) -{ - m_firstLine = 0; - m_horizScrollOffset = 0; - m_nofLines = 0; - m_bMyUpdate = false; - m_bInsertMode = true; - m_scrollDeltaX = 0; - m_scrollDeltaY = 0; - setModified( false ); - - m_pldA = pLineDataA; - m_pldB = pLineDataB; - m_pldC = pLineDataC; - m_sizeA = sizeA; - m_sizeB = sizeB; - m_sizeC = sizeC; - - m_pDiff3LineList = pDiff3LineList; - m_pTotalDiffStatus = pTotalDiffStatus; - - m_selection.reset(); - m_cursorXPos=0; - m_cursorOldXPixelPos=0; - m_cursorYPos=0; - - m_maxTextWidth = -1; - - merge( g_bAutoSolve, -1 ); - g_bAutoSolve = true; - update(); - updateSourceMask(); - - showUnsolvedConflictsStatusMessage(); + const LineData* pLineDataA, int sizeA, + const LineData* pLineDataB, int sizeB, + const LineData* pLineDataC, int sizeC, + const Diff3LineList* pDiff3LineList, + TotalDiffStatus* pTotalDiffStatus) +{ + m_firstLine = 0; + m_horizScrollOffset = 0; + m_nofLines = 0; + m_bMyUpdate = false; + m_bInsertMode = true; + m_scrollDeltaX = 0; + m_scrollDeltaY = 0; + setModified(false); + + m_pldA = pLineDataA; + m_pldB = pLineDataB; + m_pldC = pLineDataC; + m_sizeA = sizeA; + m_sizeB = sizeB; + m_sizeC = sizeC; + + m_pDiff3LineList = pDiff3LineList; + m_pTotalDiffStatus = pTotalDiffStatus; + + m_selection.reset(); + m_cursorXPos = 0; + m_cursorOldXPixelPos = 0; + m_cursorYPos = 0; + + m_maxTextWidth = -1; + + merge(g_bAutoSolve, -1); + g_bAutoSolve = true; + update(); + updateSourceMask(); + + showUnsolvedConflictsStatusMessage(); } void MergeResultWindow::showUnsolvedConflictsStatusMessage() { - if (m_pStatusBar) - { - int wsc; - int nofUnsolved = getNrOfUnsolvedConflicts(&wsc); + if(m_pStatusBar) + { + int wsc; + int nofUnsolved = getNrOfUnsolvedConflicts(&wsc); - m_persistentStatusMessage = i18n("Number of remaining unsolved conflicts: %1 (of which %2 are whitespace)" - ,nofUnsolved,wsc); - m_pStatusBar->showMessage( m_persistentStatusMessage ); - } + m_persistentStatusMessage = i18n("Number of remaining unsolved conflicts: %1 (of which %2 are whitespace)", nofUnsolved, wsc); + m_pStatusBar->showMessage(m_persistentStatusMessage); + } } void MergeResultWindow::slotStatusMessageChanged(const QString& s) { - if ( s.isEmpty() && !m_persistentStatusMessage.isEmpty() ) - { - m_pStatusBar->showMessage( m_persistentStatusMessage, 0 ); - } + if(s.isEmpty() && !m_persistentStatusMessage.isEmpty()) + { + m_pStatusBar->showMessage(m_persistentStatusMessage, 0); + } } void MergeResultWindow::reset() { - m_pDiff3LineList = 0; - m_pTotalDiffStatus = 0; - m_pldA = 0; - m_pldB = 0; - m_pldC = 0; - if (!m_persistentStatusMessage.isEmpty()) - { - m_persistentStatusMessage = QString(); - } + m_pDiff3LineList = 0; + m_pTotalDiffStatus = 0; + m_pldA = 0; + m_pldB = 0; + m_pldC = 0; + if(!m_persistentStatusMessage.isEmpty()) + { + m_persistentStatusMessage = QString(); + } } // Calculate the merge information for the given Diff3Line. // Results will be stored in mergeDetails, bConflict, bLineRemoved and src. void mergeOneLine( - const Diff3Line& d, e_MergeDetails& mergeDetails, bool& bConflict, - bool& bLineRemoved, int& src, bool bTwoInputs - ) -{ - mergeDetails = eDefault; - bConflict = false; - bLineRemoved = false; - src = 0; - - if ( bTwoInputs ) // Only two input files - { - if ( d.lineA!=-1 && d.lineB!=-1 ) - { - if ( d.pFineAB == 0 ) - { - mergeDetails = eNoChange; src = A; - } - else - { - mergeDetails = eBChanged; bConflict = true; - } - } - else - { - if ( d.lineA!=-1 && d.lineB==-1 ) - { - mergeDetails = eBDeleted; bConflict = true; - } - else if ( d.lineA==-1 && d.lineB!=-1 ) - { - mergeDetails = eBDeleted; bConflict = true; - } - } - return; - } - - // A is base. - if ( d.lineA!=-1 && d.lineB!=-1 && d.lineC!=-1 ) - { - if ( d.pFineAB == 0 && d.pFineBC == 0 && d.pFineCA == 0) - { - mergeDetails = eNoChange; src = A; - } - else if( d.pFineAB == 0 && d.pFineBC != 0 && d.pFineCA != 0 ) - { - mergeDetails = eCChanged; src = C; - } - else if( d.pFineAB != 0 && d.pFineBC != 0 && d.pFineCA == 0 ) - { - mergeDetails = eBChanged; src = B; - } - else if( d.pFineAB != 0 && d.pFineBC == 0 && d.pFineCA != 0 ) - { - mergeDetails = eBCChangedAndEqual; src = C; - } - else if( d.pFineAB != 0 && d.pFineBC != 0 && d.pFineCA != 0 ) - { - mergeDetails = eBCChanged; bConflict = true; - } - else - assert(false); - } - else if ( d.lineA!=-1 && d.lineB!=-1 && d.lineC==-1 ) - { - if( d.pFineAB != 0 ) - { - mergeDetails = eBChanged_CDeleted; bConflict = true; - } - else - { - mergeDetails = eCDeleted; bLineRemoved = true; src = C; - } - } - else if ( d.lineA!=-1 && d.lineB==-1 && d.lineC!=-1 ) - { - if( d.pFineCA != 0 ) - { - mergeDetails = eCChanged_BDeleted; bConflict = true; - } - else - { - mergeDetails = eBDeleted; bLineRemoved = true; src = B; - } - } - else if ( d.lineA==-1 && d.lineB!=-1 && d.lineC!=-1 ) - { - if( d.pFineBC != 0 ) - { - mergeDetails = eBCAdded; bConflict = true; - } - else // B==C - { - mergeDetails = eBCAddedAndEqual; src = C; - } - } - else if ( d.lineA==-1 && d.lineB==-1 && d.lineC!= -1 ) - { - mergeDetails = eCAdded; src = C; - } - else if ( d.lineA==-1 && d.lineB!=-1 && d.lineC== -1 ) - { - mergeDetails = eBAdded; src = B; - } - else if ( d.lineA!=-1 && d.lineB==-1 && d.lineC==-1 ) - { - mergeDetails = eBCDeleted; bLineRemoved = true; src = C; - } - else - assert(false); -} - -bool MergeResultWindow::sameKindCheck( const MergeLine& ml1, const MergeLine& ml2 ) -{ - if ( ml1.bConflict && ml2.bConflict ) - { - // Both lines have conflicts: If one is only a white space conflict and - // the other one is a real conflict, then this line returns false. - return ml1.id3l->bAEqC == ml2.id3l->bAEqC && ml1.id3l->bAEqB == ml2.id3l->bAEqB; - } - else - return ( - ( !ml1.bConflict && !ml2.bConflict && ml1.bDelta && ml2.bDelta && ml1.srcSelect == ml2.srcSelect - && (ml1.mergeDetails==ml2.mergeDetails || (ml1.mergeDetails!=eBCAddedAndEqual && ml2.mergeDetails!=eBCAddedAndEqual) ) ) - || - (!ml1.bDelta && !ml2.bDelta) - ); -} - -void MergeResultWindow::merge(bool bAutoSolve, int defaultSelector, bool bConflictsOnly, bool bWhiteSpaceOnly ) -{ - if ( !bConflictsOnly ) - { - if(m_bModified) - { - int result = KMessageBox::warningYesNo(this, - i18n("The output has been modified.\n" - "If you continue your changes will be lost."), - i18n("Warning"), - KStandardGuiItem::cont(), - KStandardGuiItem::cancel()); - if ( result==KMessageBox::No ) - return; - } - - m_mergeLineList.clear(); - m_totalSize = 0; - int lineIdx = 0; - Diff3LineList::const_iterator it; - for( it=m_pDiff3LineList->begin(); it!=m_pDiff3LineList->end(); ++it, ++lineIdx ) - { - const Diff3Line& d = *it; - - MergeLine ml; - bool bLineRemoved; - mergeOneLine( d, ml.mergeDetails, ml.bConflict, bLineRemoved, ml.srcSelect, m_pldC==0 ); - - // Automatic solving for only whitespace changes. - if ( ml.bConflict && - ( (m_pldC==0 && (d.bAEqB || (d.bWhiteLineA && d.bWhiteLineB))) || - (m_pldC!=0 && ((d.bAEqB && d.bAEqC) || (d.bWhiteLineA && d.bWhiteLineB && d.bWhiteLineC) ) ) ) ) - { - ml.bWhiteSpaceConflict = true; - } - - ml.d3lLineIdx = lineIdx; - ml.bDelta = ml.srcSelect != A; - ml.id3l = it; - ml.srcRangeLength = 1; - - MergeLine* back = m_mergeLineList.empty() ? 0 : &m_mergeLineList.back(); - - bool bSame = back!=0 && sameKindCheck( ml, *back ); - if( bSame ) - { - ++back->srcRangeLength; - if ( back->bWhiteSpaceConflict && !ml.bWhiteSpaceConflict ) - back->bWhiteSpaceConflict = false; - } - else - { - ml.mergeEditLineList.setTotalSizePtr(&m_totalSize); - m_mergeLineList.push_back( ml ); - } - - if ( ! ml.bConflict ) - { - MergeLine& tmpBack = m_mergeLineList.back(); - MergeEditLine mel(ml.id3l); - mel.setSource( ml.srcSelect, bLineRemoved ); - tmpBack.mergeEditLineList.push_back(mel); - } - else if ( back==0 || ! back->bConflict || !bSame ) - { - MergeLine& tmpBack = m_mergeLineList.back(); - MergeEditLine mel(ml.id3l); - mel.setConflict(); - tmpBack.mergeEditLineList.push_back(mel); - } - } - } - - bool bSolveWhiteSpaceConflicts = false; - if ( bAutoSolve ) // when true, then the other params are not used and we can change them here. (see all invocations of merge()) - { - if ( m_pldC==0 && m_pOptions->m_whiteSpace2FileMergeDefault != 0 ) // Only two inputs - { - defaultSelector = m_pOptions->m_whiteSpace2FileMergeDefault; - bWhiteSpaceOnly = true; - bSolveWhiteSpaceConflicts = true; - } - else if ( m_pldC!=0 && m_pOptions->m_whiteSpace3FileMergeDefault != 0 ) - { - defaultSelector = m_pOptions->m_whiteSpace3FileMergeDefault; - bWhiteSpaceOnly = true; - bSolveWhiteSpaceConflicts = true; - } - } - - if ( !bAutoSolve || bSolveWhiteSpaceConflicts ) - { - // Change all auto selections - MergeLineList::iterator mlIt; - for( mlIt=m_mergeLineList.begin(); mlIt!=m_mergeLineList.end(); ++mlIt ) - { - MergeLine& ml = *mlIt; - bool bConflict = ml.mergeEditLineList.empty() || ml.mergeEditLineList.begin()->isConflict(); - if ( ml.bDelta && ( !bConflictsOnly || bConflict ) && (!bWhiteSpaceOnly || ml.bWhiteSpaceConflict )) - { - ml.mergeEditLineList.clear(); - if ( defaultSelector==-1 && ml.bDelta ) + 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) { - MergeEditLine mel(ml.id3l);; - mel.setConflict(); - ml.bConflict = true; - ml.mergeEditLineList.push_back(mel); + mergeDetails = eNoChange; + src = A; } 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(ml.id3l); - mel.setRemoved( defaultSelector ); - ml.mergeEditLineList.push_back(mel); - } + mergeDetails = eBChanged; + bConflict = true; } - } - } - } - - MergeLineList::iterator mlIt; - for( mlIt=m_mergeLineList.begin(); mlIt!=m_mergeLineList.end(); ++mlIt ) - { - MergeLine& ml = *mlIt; - // Remove all lines that are empty, because no src lines are there. - - int oldSrcLine = -1; - int oldSrc = -1; - MergeEditLineList::iterator melIt; - for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ) - { - MergeEditLine& mel = *melIt; - int melsrc = mel.src(); - - int srcLine = mel.isRemoved() ? -1 : - melsrc==1 ? mel.id3l()->lineA : - melsrc==2 ? mel.id3l()->lineB : - melsrc==3 ? mel.id3l()->lineC : -1; - - // At least one line remains because oldSrc != melsrc for first line in list - // Other empty lines will be removed - if ( srcLine == -1 && oldSrcLine==-1 && oldSrc == melsrc ) - melIt = ml.mergeEditLineList.erase( melIt ); - else - ++melIt; + } + else + { + if(d.lineA != -1 && d.lineB == -1) + { + mergeDetails = eBDeleted; + bConflict = true; + } + else if(d.lineA == -1 && d.lineB != -1) + { + mergeDetails = eBDeleted; + bConflict = true; + } + } + return; + } + + // A is base. + if(d.lineA != -1 && d.lineB != -1 && d.lineC != -1) + { + if(d.pFineAB == 0 && d.pFineBC == 0 && d.pFineCA == 0) + { + mergeDetails = eNoChange; + src = A; + } + else if(d.pFineAB == 0 && d.pFineBC != 0 && d.pFineCA != 0) + { + mergeDetails = eCChanged; + src = C; + } + else if(d.pFineAB != 0 && d.pFineBC != 0 && d.pFineCA == 0) + { + mergeDetails = eBChanged; + src = B; + } + else if(d.pFineAB != 0 && d.pFineBC == 0 && d.pFineCA != 0) + { + mergeDetails = eBCChangedAndEqual; + src = C; + } + else if(d.pFineAB != 0 && d.pFineBC != 0 && d.pFineCA != 0) + { + mergeDetails = eBCChanged; + bConflict = true; + } + else + assert(false); + } + else if(d.lineA != -1 && d.lineB != -1 && d.lineC == -1) + { + if(d.pFineAB != 0) + { + mergeDetails = eBChanged_CDeleted; + bConflict = true; + } + else + { + mergeDetails = eCDeleted; + bLineRemoved = true; + src = C; + } + } + else if(d.lineA != -1 && d.lineB == -1 && d.lineC != -1) + { + if(d.pFineCA != 0) + { + mergeDetails = eCChanged_BDeleted; + bConflict = true; + } + else + { + mergeDetails = eBDeleted; + bLineRemoved = true; + src = B; + } + } + else if(d.lineA == -1 && d.lineB != -1 && d.lineC != -1) + { + if(d.pFineBC != 0) + { + mergeDetails = eBCAdded; + bConflict = true; + } + else // B==C + { + mergeDetails = eBCAddedAndEqual; + src = C; + } + } + else if(d.lineA == -1 && d.lineB == -1 && d.lineC != -1) + { + mergeDetails = eCAdded; + src = C; + } + else if(d.lineA == -1 && d.lineB != -1 && d.lineC == -1) + { + mergeDetails = eBAdded; + src = B; + } + else if(d.lineA != -1 && d.lineB == -1 && d.lineC == -1) + { + mergeDetails = eBCDeleted; + bLineRemoved = true; + src = C; + } + else + assert(false); +} + +bool MergeResultWindow::sameKindCheck(const MergeLine& ml1, const MergeLine& ml2) +{ + if(ml1.bConflict && ml2.bConflict) + { + // Both lines have conflicts: If one is only a white space conflict and + // the other one is a real conflict, then this line returns false. + return ml1.id3l->bAEqC == ml2.id3l->bAEqC && ml1.id3l->bAEqB == ml2.id3l->bAEqB; + } + else + return ( + (!ml1.bConflict && !ml2.bConflict && ml1.bDelta && ml2.bDelta && ml1.srcSelect == ml2.srcSelect && (ml1.mergeDetails == ml2.mergeDetails || (ml1.mergeDetails != eBCAddedAndEqual && ml2.mergeDetails != eBCAddedAndEqual))) || + (!ml1.bDelta && !ml2.bDelta)); +} + +void MergeResultWindow::merge(bool bAutoSolve, int defaultSelector, bool bConflictsOnly, bool bWhiteSpaceOnly) +{ + if(!bConflictsOnly) + { + if(m_bModified) + { + int result = KMessageBox::warningYesNo(this, + i18n("The output has been modified.\n" + "If you continue your changes will be lost."), + i18n("Warning"), + KStandardGuiItem::cont(), + KStandardGuiItem::cancel()); + if(result == KMessageBox::No) + return; + } + + m_mergeLineList.clear(); + m_totalSize = 0; + int lineIdx = 0; + Diff3LineList::const_iterator it; + for(it = m_pDiff3LineList->begin(); it != m_pDiff3LineList->end(); ++it, ++lineIdx) + { + const Diff3Line& d = *it; + + MergeLine ml; + bool bLineRemoved; + mergeOneLine(d, ml.mergeDetails, ml.bConflict, bLineRemoved, ml.srcSelect, m_pldC == 0); + + // Automatic solving for only whitespace changes. + if(ml.bConflict && + ((m_pldC == 0 && (d.bAEqB || (d.bWhiteLineA && d.bWhiteLineB))) || + (m_pldC != 0 && ((d.bAEqB && d.bAEqC) || (d.bWhiteLineA && d.bWhiteLineB && d.bWhiteLineC))))) + { + ml.bWhiteSpaceConflict = true; + } + + ml.d3lLineIdx = lineIdx; + ml.bDelta = ml.srcSelect != A; + ml.id3l = it; + ml.srcRangeLength = 1; + + MergeLine* back = m_mergeLineList.empty() ? 0 : &m_mergeLineList.back(); + + bool bSame = back != 0 && sameKindCheck(ml, *back); + if(bSame) + { + ++back->srcRangeLength; + if(back->bWhiteSpaceConflict && !ml.bWhiteSpaceConflict) + back->bWhiteSpaceConflict = false; + } + else + { + ml.mergeEditLineList.setTotalSizePtr(&m_totalSize); + m_mergeLineList.push_back(ml); + } + + if(!ml.bConflict) + { + MergeLine& tmpBack = m_mergeLineList.back(); + MergeEditLine mel(ml.id3l); + mel.setSource(ml.srcSelect, bLineRemoved); + tmpBack.mergeEditLineList.push_back(mel); + } + else if(back == 0 || !back->bConflict || !bSame) + { + MergeLine& tmpBack = m_mergeLineList.back(); + MergeEditLine mel(ml.id3l); + mel.setConflict(); + tmpBack.mergeEditLineList.push_back(mel); + } + } + } + + bool bSolveWhiteSpaceConflicts = false; + if(bAutoSolve) // when true, then the other params are not used and we can change them here. (see all invocations of merge()) + { + if(m_pldC == 0 && m_pOptions->m_whiteSpace2FileMergeDefault != 0) // Only two inputs + { + defaultSelector = m_pOptions->m_whiteSpace2FileMergeDefault; + bWhiteSpaceOnly = true; + bSolveWhiteSpaceConflicts = true; + } + else if(m_pldC != 0 && m_pOptions->m_whiteSpace3FileMergeDefault != 0) + { + defaultSelector = m_pOptions->m_whiteSpace3FileMergeDefault; + bWhiteSpaceOnly = true; + bSolveWhiteSpaceConflicts = true; + } + } + + if(!bAutoSolve || bSolveWhiteSpaceConflicts) + { + // Change all auto selections + MergeLineList::iterator mlIt; + for(mlIt = m_mergeLineList.begin(); mlIt != m_mergeLineList.end(); ++mlIt) + { + MergeLine& ml = *mlIt; + bool bConflict = ml.mergeEditLineList.empty() || ml.mergeEditLineList.begin()->isConflict(); + if(ml.bDelta && (!bConflictsOnly || bConflict) && (!bWhiteSpaceOnly || ml.bWhiteSpaceConflict)) + { + ml.mergeEditLineList.clear(); + if(defaultSelector == -1 && ml.bDelta) + { + MergeEditLine mel(ml.id3l); + ; + mel.setConflict(); + ml.bConflict = true; + ml.mergeEditLineList.push_back(mel); + } + else + { + Diff3LineList::const_iterator d3llit = ml.id3l; + int j; + + for(j = 0; j < ml.srcRangeLength; ++j) + { + MergeEditLine mel(d3llit); + mel.setSource(defaultSelector, false); + + int srcLine = defaultSelector == 1 ? d3llit->lineA : defaultSelector == 2 ? d3llit->lineB : defaultSelector == 3 ? d3llit->lineC : -1; + + if(srcLine != -1) + { + ml.mergeEditLineList.push_back(mel); + } + + ++d3llit; + } + + if(ml.mergeEditLineList.empty()) // Make a line nevertheless + { + MergeEditLine mel(ml.id3l); + mel.setRemoved(defaultSelector); + ml.mergeEditLineList.push_back(mel); + } + } + } + } + } + + MergeLineList::iterator mlIt; + for(mlIt = m_mergeLineList.begin(); mlIt != m_mergeLineList.end(); ++mlIt) + { + MergeLine& ml = *mlIt; + // Remove all lines that are empty, because no src lines are there. + + int oldSrcLine = -1; + int oldSrc = -1; + MergeEditLineList::iterator melIt; + for(melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end();) + { + MergeEditLine& mel = *melIt; + int melsrc = mel.src(); + + int srcLine = mel.isRemoved() ? -1 : melsrc == 1 ? mel.id3l()->lineA : melsrc == 2 ? mel.id3l()->lineB : melsrc == 3 ? mel.id3l()->lineC : -1; - oldSrcLine = srcLine; - oldSrc = melsrc; - } - } + // At least one line remains because oldSrc != melsrc for first line in list + // Other empty lines will be removed + if(srcLine == -1 && oldSrcLine == -1 && oldSrc == melsrc) + melIt = ml.mergeEditLineList.erase(melIt); + else + ++melIt; - if ( bAutoSolve && !bConflictsOnly ) - { - if ( m_pOptions->m_bRunHistoryAutoMergeOnMergeStart ) - slotMergeHistory(); - if ( m_pOptions->m_bRunRegExpAutoMergeOnMergeStart ) - slotRegExpAutoMerge(); - if ( m_pldC != 0 && ! doRelevantChangesExist() ) - emit noRelevantChangesDetected(); - } + oldSrcLine = srcLine; + oldSrc = melsrc; + } + } - int nrOfSolvedConflicts = 0; - int nrOfUnsolvedConflicts = 0; - int nrOfWhiteSpaceConflicts = 0; + if(bAutoSolve && !bConflictsOnly) + { + if(m_pOptions->m_bRunHistoryAutoMergeOnMergeStart) + slotMergeHistory(); + if(m_pOptions->m_bRunRegExpAutoMergeOnMergeStart) + slotRegExpAutoMerge(); + if(m_pldC != 0 && !doRelevantChangesExist()) + emit noRelevantChangesDetected(); + } - MergeLineList::iterator i; - for ( i = m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i ) - { - if ( i->bConflict ) - ++nrOfUnsolvedConflicts; - else if ( i->bDelta ) - ++nrOfSolvedConflicts; + int nrOfSolvedConflicts = 0; + int nrOfUnsolvedConflicts = 0; + int nrOfWhiteSpaceConflicts = 0; - if ( i->bWhiteSpaceConflict ) - ++nrOfWhiteSpaceConflicts; - } + MergeLineList::iterator i; + for(i = m_mergeLineList.begin(); i != m_mergeLineList.end(); ++i) + { + if(i->bConflict) + ++nrOfUnsolvedConflicts; + else if(i->bDelta) + ++nrOfSolvedConflicts; - m_pTotalDiffStatus->nofUnsolvedConflicts = nrOfUnsolvedConflicts; - m_pTotalDiffStatus->nofSolvedConflicts = nrOfSolvedConflicts; - m_pTotalDiffStatus->nofWhitespaceConflicts = nrOfWhiteSpaceConflicts; + if(i->bWhiteSpaceConflict) + ++nrOfWhiteSpaceConflicts; + } + m_pTotalDiffStatus->nofUnsolvedConflicts = nrOfUnsolvedConflicts; + m_pTotalDiffStatus->nofSolvedConflicts = nrOfSolvedConflicts; + m_pTotalDiffStatus->nofWhitespaceConflicts = nrOfWhiteSpaceConflicts; - m_cursorXPos=0; - m_cursorOldXPixelPos=0; - m_cursorYPos=0; - m_maxTextWidth = -1; + m_cursorXPos = 0; + m_cursorOldXPixelPos = 0; + m_cursorYPos = 0; + m_maxTextWidth = -1; - //m_firstLine = 0; // Must not set line/column without scrolling there - //m_horizScrollOffset = 0; + //m_firstLine = 0; // Must not set line/column without scrolling there + //m_horizScrollOffset = 0; - setModified(false); + setModified(false); - m_currentMergeLineIt = m_mergeLineList.begin(); - slotGoTop(); + m_currentMergeLineIt = m_mergeLineList.begin(); + slotGoTop(); - updateAvailabilities(); - update(); + updateAvailabilities(); + update(); } void MergeResultWindow::setFirstLine(int firstLine) { - m_firstLine = max2(0,firstLine); - update(); + m_firstLine = max2(0, firstLine); + update(); } void MergeResultWindow::setHorizScrollOffset(int horizScrollOffset) { - m_horizScrollOffset = max2(0,horizScrollOffset); - update(); + m_horizScrollOffset = max2(0, horizScrollOffset); + update(); } int MergeResultWindow::getMaxTextWidth() { - if ( m_maxTextWidth < 0 ) - { - m_maxTextWidth=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; - QString s = mel.getString( this ); + if(m_maxTextWidth < 0) + { + m_maxTextWidth = 0; - QTextLayout textLayout( s, font(), this ); - textLayout.beginLayout(); - textLayout.createLine(); - textLayout.endLayout(); - if ( m_maxTextWidth < textLayout.maximumWidth() ) + 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) { - m_maxTextWidth = textLayout.maximumWidth(); + MergeEditLine& mel = *melIt; + QString s = mel.getString(this); + + QTextLayout textLayout(s, font(), this); + textLayout.beginLayout(); + textLayout.createLine(); + textLayout.endLayout(); + if(m_maxTextWidth < textLayout.maximumWidth()) + { + m_maxTextWidth = textLayout.maximumWidth(); + } } - } - } - m_maxTextWidth += 5; // cursorwidth - } - return m_maxTextWidth; + } + m_maxTextWidth += 5; // cursorwidth + } + return m_maxTextWidth; } int MergeResultWindow::getNofLines() { - return m_totalSize; + return m_totalSize; } int MergeResultWindow::getVisibleTextAreaWidth() { - // QFontMetrics fm = fontMetrics(); // FIXME used? - return width() - getTextXOffset(); + // QFontMetrics fm = fontMetrics(); // FIXME used? + return width() - getTextXOffset(); } int MergeResultWindow::getNofVisibleLines() { - QFontMetrics fm = fontMetrics(); - return (height()-3)/fm.lineSpacing()-2; + QFontMetrics fm = fontMetrics(); + return (height() - 3) / fm.lineSpacing() - 2; } int MergeResultWindow::getTextXOffset() { - QFontMetrics fm = fontMetrics(); - return 3 * fm.width('0'); + QFontMetrics fm = fontMetrics(); + return 3 * fm.width('0'); } -void MergeResultWindow::resizeEvent( QResizeEvent* e ) +void MergeResultWindow::resizeEvent(QResizeEvent* e) { - QWidget::resizeEvent(e); - emit resizeSignal(); + QWidget::resizeEvent(e); + emit resizeSignal(); } Overview::e_OverviewMode MergeResultWindow::getOverviewMode() { - return m_eOverviewMode; + return m_eOverviewMode; } -void MergeResultWindow::setOverviewMode( Overview::e_OverviewMode eOverviewMode ) +void MergeResultWindow::setOverviewMode(Overview::e_OverviewMode eOverviewMode) { - m_eOverviewMode = eOverviewMode; + m_eOverviewMode = eOverviewMode; } // Check whether we should ignore current delta when moving to next/previous delta -bool MergeResultWindow::checkOverviewIgnore(MergeLineList::iterator &i) +bool MergeResultWindow::checkOverviewIgnore(MergeLineList::iterator& i) { - if (m_eOverviewMode == Overview::eOMNormal) return false; - if (m_eOverviewMode == Overview::eOMAvsB) - return i->mergeDetails == eCAdded || i->mergeDetails == eCDeleted || i->mergeDetails == eCChanged; - if (m_eOverviewMode == Overview::eOMAvsC) - return i->mergeDetails == eBAdded || i->mergeDetails == eBDeleted || i->mergeDetails == eBChanged; - if (m_eOverviewMode == Overview::eOMBvsC) - return i->mergeDetails == eBCAddedAndEqual || i->mergeDetails == eBCDeleted || i->mergeDetails == eBCChangedAndEqual; - return false; + if(m_eOverviewMode == Overview::eOMNormal) return false; + if(m_eOverviewMode == Overview::eOMAvsB) + return i->mergeDetails == eCAdded || i->mergeDetails == eCDeleted || i->mergeDetails == eCChanged; + if(m_eOverviewMode == Overview::eOMAvsC) + return i->mergeDetails == eBAdded || i->mergeDetails == eBDeleted || i->mergeDetails == eBChanged; + if(m_eOverviewMode == Overview::eOMBvsC) + return i->mergeDetails == eBCAddedAndEqual || i->mergeDetails == eBCDeleted || i->mergeDetails == eBCChangedAndEqual; + return false; } // Go to prev/next delta/conflict or first/last delta. -void MergeResultWindow::go( e_Direction eDir, e_EndPoint eEndPoint ) -{ - assert( eDir==eUp || eDir==eDown ); - MergeLineList::iterator i = m_currentMergeLineIt; - bool bSkipWhiteConflicts = ! m_pOptions->m_bShowWhiteSpace; - if( eEndPoint==eEnd ) - { - if (eDir==eUp) i = m_mergeLineList.begin(); // first mergeline - else i = --m_mergeLineList.end(); // last mergeline - - while ( isItAtEnd(eDir==eUp, i) && ! i->bDelta ) - { - if ( eDir==eUp ) ++i; // search downwards - else --i; // search upwards - } - } - else if ( eEndPoint == eDelta && isItAtEnd(eDir!=eUp, i) ) - { - do - { - if ( eDir==eUp ) --i; - else ++i; - } - while ( isItAtEnd(eDir!=eUp, i) && ( i->bDelta == false || checkOverviewIgnore(i) || (bSkipWhiteConflicts && i->bWhiteSpaceConflict) ) ); - } - else if ( eEndPoint == eConflict && isItAtEnd(eDir!=eUp, i) ) - { - do - { - if ( eDir==eUp ) --i; - else ++i; - } - while ( isItAtEnd(eDir!=eUp, i) && (i->bConflict == false || (bSkipWhiteConflicts && i->bWhiteSpaceConflict) ) ); - } - else if ( isItAtEnd(eDir!=eUp, i) && eEndPoint == eUnsolvedConflict ) - { - do - { - if ( eDir==eUp ) --i; - else ++i; - } - while ( isItAtEnd(eDir!=eUp, i) && ! i->mergeEditLineList.begin()->isConflict() ); - } - - if ( isVisible() ) - setFocus(); - - setFastSelector( i ); +void MergeResultWindow::go(e_Direction eDir, e_EndPoint eEndPoint) +{ + assert(eDir == eUp || eDir == eDown); + MergeLineList::iterator i = m_currentMergeLineIt; + bool bSkipWhiteConflicts = !m_pOptions->m_bShowWhiteSpace; + if(eEndPoint == eEnd) + { + if(eDir == eUp) + i = m_mergeLineList.begin(); // first mergeline + else + i = --m_mergeLineList.end(); // last mergeline + + while(isItAtEnd(eDir == eUp, i) && !i->bDelta) + { + if(eDir == eUp) + ++i; // search downwards + else + --i; // search upwards + } + } + else if(eEndPoint == eDelta && isItAtEnd(eDir != eUp, i)) + { + do + { + if(eDir == eUp) + --i; + else + ++i; + } while(isItAtEnd(eDir != eUp, i) && (i->bDelta == false || checkOverviewIgnore(i) || (bSkipWhiteConflicts && i->bWhiteSpaceConflict))); + } + else if(eEndPoint == eConflict && isItAtEnd(eDir != eUp, i)) + { + do + { + if(eDir == eUp) + --i; + else + ++i; + } while(isItAtEnd(eDir != eUp, i) && (i->bConflict == false || (bSkipWhiteConflicts && i->bWhiteSpaceConflict))); + } + else if(isItAtEnd(eDir != eUp, i) && eEndPoint == eUnsolvedConflict) + { + do + { + if(eDir == eUp) + --i; + else + ++i; + } while(isItAtEnd(eDir != eUp, i) && !i->mergeEditLineList.begin()->isConflict()); + } + + if(isVisible()) + setFocus(); + + setFastSelector(i); } bool MergeResultWindow::isDeltaAboveCurrent() { - bool bSkipWhiteConflicts = ! m_pOptions->m_bShowWhiteSpace; - if (m_mergeLineList.empty()) return false; - MergeLineList::iterator i = m_currentMergeLineIt; - if (i == m_mergeLineList.begin()) return false; - do - { - --i; - if ( i->bDelta && !checkOverviewIgnore(i) && !( bSkipWhiteConflicts && i->bWhiteSpaceConflict ) ) return true; - } - while (i!=m_mergeLineList.begin()); + bool bSkipWhiteConflicts = !m_pOptions->m_bShowWhiteSpace; + if(m_mergeLineList.empty()) return false; + MergeLineList::iterator i = m_currentMergeLineIt; + if(i == m_mergeLineList.begin()) return false; + do + { + --i; + if(i->bDelta && !checkOverviewIgnore(i) && !(bSkipWhiteConflicts && i->bWhiteSpaceConflict)) return true; + } while(i != m_mergeLineList.begin()); - return false; + return false; } bool MergeResultWindow::isDeltaBelowCurrent() { - bool bSkipWhiteConflicts = ! m_pOptions->m_bShowWhiteSpace; - if (m_mergeLineList.empty()) return false; + bool bSkipWhiteConflicts = !m_pOptions->m_bShowWhiteSpace; + if(m_mergeLineList.empty()) return false; - MergeLineList::iterator i = m_currentMergeLineIt; - if (i!=m_mergeLineList.end()) - { - ++i; - for( ; i!=m_mergeLineList.end(); ++i ) - { - if ( i->bDelta && !checkOverviewIgnore(i) && !( bSkipWhiteConflicts && i->bWhiteSpaceConflict ) ) return true; - } - } - return false; + MergeLineList::iterator i = m_currentMergeLineIt; + if(i != m_mergeLineList.end()) + { + ++i; + for(; i != m_mergeLineList.end(); ++i) + { + if(i->bDelta && !checkOverviewIgnore(i) && !(bSkipWhiteConflicts && i->bWhiteSpaceConflict)) return true; + } + } + return false; } bool MergeResultWindow::isConflictAboveCurrent() { - if (m_mergeLineList.empty()) return false; - MergeLineList::iterator i = m_currentMergeLineIt; - if (i == m_mergeLineList.begin()) return false; + if(m_mergeLineList.empty()) return false; + MergeLineList::iterator i = m_currentMergeLineIt; + if(i == m_mergeLineList.begin()) return false; - bool bSkipWhiteConflicts = ! m_pOptions->m_bShowWhiteSpace; + bool bSkipWhiteConflicts = !m_pOptions->m_bShowWhiteSpace; - do - { - --i; - if ( i->bConflict && !(bSkipWhiteConflicts && i->bWhiteSpaceConflict) ) return true; - } - while (i!=m_mergeLineList.begin()); - - return false; + do + { + --i; + if(i->bConflict && !(bSkipWhiteConflicts && i->bWhiteSpaceConflict)) return true; + } while(i != m_mergeLineList.begin()); + + return false; } bool MergeResultWindow::isConflictBelowCurrent() { - MergeLineList::iterator i = m_currentMergeLineIt; - if (m_mergeLineList.empty()) return false; + MergeLineList::iterator i = m_currentMergeLineIt; + if(m_mergeLineList.empty()) return false; - bool bSkipWhiteConflicts = ! m_pOptions->m_bShowWhiteSpace; + bool bSkipWhiteConflicts = !m_pOptions->m_bShowWhiteSpace; - if (i!=m_mergeLineList.end()) - { - ++i; - for( ; i!=m_mergeLineList.end(); ++i ) - { - if ( i->bConflict && !(bSkipWhiteConflicts && i->bWhiteSpaceConflict) ) return true; - } - } - return false; + if(i != m_mergeLineList.end()) + { + ++i; + for(; i != m_mergeLineList.end(); ++i) + { + if(i->bConflict && !(bSkipWhiteConflicts && i->bWhiteSpaceConflict)) return true; + } + } + return false; } bool MergeResultWindow::isUnsolvedConflictAtCurrent() { - if (m_mergeLineList.empty()) return false; - MergeLineList::iterator i = m_currentMergeLineIt; - return i->mergeEditLineList.begin()->isConflict(); + if(m_mergeLineList.empty()) return false; + MergeLineList::iterator i = m_currentMergeLineIt; + return i->mergeEditLineList.begin()->isConflict(); } bool MergeResultWindow::isUnsolvedConflictAboveCurrent() { - if (m_mergeLineList.empty()) return false; - MergeLineList::iterator i = m_currentMergeLineIt; - if (i == m_mergeLineList.begin()) return false; - - do - { - --i; - if ( i->mergeEditLineList.begin()->isConflict() ) return true; - } - while (i!=m_mergeLineList.begin()); - - return false; + if(m_mergeLineList.empty()) return false; + MergeLineList::iterator i = m_currentMergeLineIt; + if(i == m_mergeLineList.begin()) return false; + + do + { + --i; + if(i->mergeEditLineList.begin()->isConflict()) return true; + } while(i != m_mergeLineList.begin()); + + return false; } bool MergeResultWindow::isUnsolvedConflictBelowCurrent() { - MergeLineList::iterator i = m_currentMergeLineIt; - if (m_mergeLineList.empty()) return false; - - if (i!=m_mergeLineList.end()) - { - ++i; - for( ; i!=m_mergeLineList.end(); ++i ) - { - if ( i->mergeEditLineList.begin()->isConflict() ) return true; - } - } - return false; + MergeLineList::iterator i = m_currentMergeLineIt; + if(m_mergeLineList.empty()) return false; + + if(i != m_mergeLineList.end()) + { + ++i; + for(; i != m_mergeLineList.end(); ++i) + { + if(i->mergeEditLineList.begin()->isConflict()) return true; + } + } + return false; } void MergeResultWindow::slotGoTop() { - go( eUp, eEnd ); + go(eUp, eEnd); } void MergeResultWindow::slotGoCurrent() { - setFastSelector( m_currentMergeLineIt ); + setFastSelector(m_currentMergeLineIt); } void MergeResultWindow::slotGoBottom() { - go( eDown, eEnd ); + go(eDown, eEnd); } void MergeResultWindow::slotGoPrevDelta() { - go( eUp, eDelta ); + go(eUp, eDelta); } void MergeResultWindow::slotGoNextDelta() { - go( eDown, eDelta ); + go(eDown, eDelta); } void MergeResultWindow::slotGoPrevConflict() { - go( eUp, eConflict ); + go(eUp, eConflict); } void MergeResultWindow::slotGoNextConflict() { - go( eDown, eConflict ); + go(eDown, eConflict); } void MergeResultWindow::slotGoPrevUnsolvedConflict() { - go( eUp, eUnsolvedConflict ); + go(eUp, eUnsolvedConflict); } void MergeResultWindow::slotGoNextUnsolvedConflict() { - go( eDown, eUnsolvedConflict ); + go(eDown, eUnsolvedConflict); } /** The line is given as a index in the Diff3LineList. The function calculates the corresponding iterator. */ -void MergeResultWindow::slotSetFastSelectorLine( int line ) -{ - MergeLineList::iterator i; - for ( i = m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i ) - { - if ( line>=i->d3lLineIdx && line < i->d3lLineIdx + i->srcRangeLength ) - { - //if ( i->bDelta ) - { - setFastSelector( i ); - } - break; - } - } -} - -int MergeResultWindow::getNrOfUnsolvedConflicts( int* pNrOfWhiteSpaceConflicts ) -{ - int nrOfUnsolvedConflicts = 0; - if (pNrOfWhiteSpaceConflicts!=0) - *pNrOfWhiteSpaceConflicts = 0; - - MergeLineList::iterator mlIt = m_mergeLineList.begin(); - for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt) - { - MergeLine& ml = *mlIt; - MergeEditLineList::iterator melIt = ml.mergeEditLineList.begin(); - if ( melIt->isConflict() ) - { - ++nrOfUnsolvedConflicts; - if ( ml.bWhiteSpaceConflict && pNrOfWhiteSpaceConflicts!=0 ) - ++ *pNrOfWhiteSpaceConflicts; - } - } - - return nrOfUnsolvedConflicts; +void MergeResultWindow::slotSetFastSelectorLine(int line) +{ + MergeLineList::iterator i; + for(i = m_mergeLineList.begin(); i != m_mergeLineList.end(); ++i) + { + if(line >= i->d3lLineIdx && line < i->d3lLineIdx + i->srcRangeLength) + { + //if ( i->bDelta ) + { + setFastSelector(i); + } + break; + } + } +} + +int MergeResultWindow::getNrOfUnsolvedConflicts(int* pNrOfWhiteSpaceConflicts) +{ + int nrOfUnsolvedConflicts = 0; + if(pNrOfWhiteSpaceConflicts != 0) + *pNrOfWhiteSpaceConflicts = 0; + + MergeLineList::iterator mlIt = m_mergeLineList.begin(); + for(mlIt = m_mergeLineList.begin(); mlIt != m_mergeLineList.end(); ++mlIt) + { + MergeLine& ml = *mlIt; + MergeEditLineList::iterator melIt = ml.mergeEditLineList.begin(); + if(melIt->isConflict()) + { + ++nrOfUnsolvedConflicts; + if(ml.bWhiteSpaceConflict && pNrOfWhiteSpaceConflicts != 0) + ++*pNrOfWhiteSpaceConflicts; + } + } + + return nrOfUnsolvedConflicts; } void MergeResultWindow::showNrOfConflicts() { - if (!m_pOptions->m_bShowInfoDialogs) - return; - int nrOfConflicts = 0; - MergeLineList::iterator i; - for ( i = m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i ) - { - if ( i->bConflict || i->bDelta ) - ++nrOfConflicts; - } - QString totalInfo; - if ( m_pTotalDiffStatus->bBinaryAEqB && m_pTotalDiffStatus->bBinaryAEqC ) - totalInfo += i18n("All input files are binary equal."); - else if ( m_pTotalDiffStatus->bTextAEqB && m_pTotalDiffStatus->bTextAEqC ) - totalInfo += i18n("All input files contain the same text."); - else { - if ( m_pTotalDiffStatus->bBinaryAEqB ) totalInfo += i18n("Files %1 and %2 are binary equal.\n",QString("A"),QString("B")); - else if ( m_pTotalDiffStatus->bTextAEqB ) totalInfo += i18n("Files %1 and %2 have equal text.\n",QString("A"),QString("B")); - if ( m_pTotalDiffStatus->bBinaryAEqC ) totalInfo += i18n("Files %1 and %2 are binary equal.\n",QString("A"),QString("C")); - else if ( m_pTotalDiffStatus->bTextAEqC ) totalInfo += i18n("Files %1 and %2 have equal text.\n",QString("A"),QString("C")); - if ( m_pTotalDiffStatus->bBinaryBEqC ) totalInfo += i18n("Files %1 and %2 are binary equal.\n",QString("B"),QString("C")); - else if ( m_pTotalDiffStatus->bTextBEqC ) totalInfo += i18n("Files %1 and %2 have equal text.\n",QString("B"),QString("C")); - } - - int nrOfUnsolvedConflicts = getNrOfUnsolvedConflicts(); - - KMessageBox::information( this, - i18n("Total number of conflicts: ") + QString::number(nrOfConflicts) + - i18n("\nNr of automatically solved conflicts: ") + QString::number(nrOfConflicts-nrOfUnsolvedConflicts) + - i18n("\nNr of unsolved conflicts: ") + QString::number(nrOfUnsolvedConflicts) + - "\n"+totalInfo, - i18n("Conflicts") - ); + if(!m_pOptions->m_bShowInfoDialogs) + return; + int nrOfConflicts = 0; + MergeLineList::iterator i; + for(i = m_mergeLineList.begin(); i != m_mergeLineList.end(); ++i) + { + if(i->bConflict || i->bDelta) + ++nrOfConflicts; + } + QString totalInfo; + if(m_pTotalDiffStatus->bBinaryAEqB && m_pTotalDiffStatus->bBinaryAEqC) + totalInfo += i18n("All input files are binary equal."); + else if(m_pTotalDiffStatus->bTextAEqB && m_pTotalDiffStatus->bTextAEqC) + totalInfo += i18n("All input files contain the same text."); + else + { + if(m_pTotalDiffStatus->bBinaryAEqB) + totalInfo += i18n("Files %1 and %2 are binary equal.\n", QString("A"), QString("B")); + else if(m_pTotalDiffStatus->bTextAEqB) + totalInfo += i18n("Files %1 and %2 have equal text.\n", QString("A"), QString("B")); + if(m_pTotalDiffStatus->bBinaryAEqC) + totalInfo += i18n("Files %1 and %2 are binary equal.\n", QString("A"), QString("C")); + else if(m_pTotalDiffStatus->bTextAEqC) + totalInfo += i18n("Files %1 and %2 have equal text.\n", QString("A"), QString("C")); + if(m_pTotalDiffStatus->bBinaryBEqC) + totalInfo += i18n("Files %1 and %2 are binary equal.\n", QString("B"), QString("C")); + else if(m_pTotalDiffStatus->bTextBEqC) + totalInfo += i18n("Files %1 and %2 have equal text.\n", QString("B"), QString("C")); + } + + int nrOfUnsolvedConflicts = getNrOfUnsolvedConflicts(); + + KMessageBox::information(this, + i18n("Total number of conflicts: ") + QString::number(nrOfConflicts) + + i18n("\nNr of automatically solved conflicts: ") + QString::number(nrOfConflicts - nrOfUnsolvedConflicts) + + i18n("\nNr of unsolved conflicts: ") + QString::number(nrOfUnsolvedConflicts) + + "\n" + totalInfo, + i18n("Conflicts")); } void MergeResultWindow::setFastSelector(MergeLineList::iterator i) { - if ( i==m_mergeLineList.end() ) - return; - m_currentMergeLineIt = i; - emit setFastSelectorRange( i->d3lLineIdx, i->srcRangeLength ); - - int line1 = 0; - - MergeLineList::iterator mlIt = m_mergeLineList.begin(); - for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt) - { - if(mlIt==m_currentMergeLineIt) - break; - line1 += mlIt->mergeEditLineList.size(); - } - - int nofLines = m_currentMergeLineIt->mergeEditLineList.size(); - int newFirstLine = getBestFirstLine( line1, nofLines, m_firstLine, getNofVisibleLines() ); - if ( newFirstLine != m_firstLine ) - { - scroll( 0, newFirstLine - m_firstLine ); - } - - if ( m_selection.isEmpty() ) - { - m_cursorXPos = 0; - m_cursorOldXPixelPos = 0; - m_cursorYPos = line1; - } - - update(); - updateSourceMask(); - emit updateAvailabilities(); -} - -void MergeResultWindow::choose( int selector ) -{ - if ( m_currentMergeLineIt==m_mergeLineList.end() ) - return; - - setModified(); - - // First find range for which this change works. - MergeLine& ml = *m_currentMergeLineIt; - - MergeEditLineList::iterator melIt; - - // Now check if selector is active for this range already. - bool bActive = false; - - // Remove unneeded lines in the range. - for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ) - { - MergeEditLine& mel = *melIt; - if ( mel.src()==selector ) - bActive = true; - - if ( mel.src()==selector || !mel.isEditableText() || mel.isModified() ) - melIt = ml.mergeEditLineList.erase( melIt ); - else - ++melIt; - } - - if ( !bActive ) // Selected source wasn't active. - { // Append the lines from selected source here at rangeEnd. - Diff3LineList::const_iterator d3llit=ml.id3l; - int j; - - for( j=0; jlineA : - mel.src()==2 ? mel.id3l()->lineB : - mel.src()==3 ? mel.id3l()->lineC : -1; - - if ( srcLine == -1 ) - melIt = ml.mergeEditLineList.erase( melIt ); - else + 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_cursorOldXPixelPos = 0; + m_cursorYPos = line1; + } + + update(); + updateSourceMask(); + emit updateAvailabilities(); +} + +void MergeResultWindow::choose(int selector) +{ + if(m_currentMergeLineIt == m_mergeLineList.end()) + return; + + setModified(); + + // First find range for which this change works. + MergeLine& ml = *m_currentMergeLineIt; + + MergeEditLineList::iterator melIt; + + // Now check if selector is active for this range already. + bool bActive = false; + + // Remove unneeded lines in the range. + for(melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end();) + { + MergeEditLine& mel = *melIt; + if(mel.src() == selector) + bActive = true; + + if(mel.src() == selector || !mel.isEditableText() || mel.isModified()) + melIt = ml.mergeEditLineList.erase(melIt); + else ++melIt; - } - } + } + + if(!bActive) // Selected source wasn't active. + { // Append the lines from selected source here at rangeEnd. + Diff3LineList::const_iterator d3llit = ml.id3l; + int j; + + for(j = 0; j < ml.srcRangeLength; ++j) + { + MergeEditLine mel(d3llit); + mel.setSource(selector, false); + ml.mergeEditLineList.push_back(mel); + + ++d3llit; + } + } + + if(!ml.mergeEditLineList.empty()) + { + // Remove all lines that are empty, because no src lines are there. + for(melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end();) + { + MergeEditLine& mel = *melIt; - if ( ml.mergeEditLineList.empty() ) - { - // Insert a dummy line: - MergeEditLine mel(ml.id3l); + int srcLine = mel.src() == 1 ? mel.id3l()->lineA : mel.src() == 2 ? mel.id3l()->lineB : mel.src() == 3 ? mel.id3l()->lineC : -1; - if ( bActive ) mel.setConflict(); // All src entries deleted => conflict - else mel.setRemoved(selector); // No lines in corresponding src found. + if(srcLine == -1) + melIt = ml.mergeEditLineList.erase(melIt); + else + ++melIt; + } + } + + if(ml.mergeEditLineList.empty()) + { + // Insert a dummy line: + MergeEditLine mel(ml.id3l); - ml.mergeEditLineList.push_back(mel); - } + if(bActive) + mel.setConflict(); // All src entries deleted => conflict + else + mel.setRemoved(selector); // No lines in corresponding src found. - if ( m_cursorYPos >= m_totalSize ) - { - m_cursorYPos = m_totalSize-1; - m_cursorXPos = 0; - } + ml.mergeEditLineList.push_back(mel); + } + + if(m_cursorYPos >= m_totalSize) + { + m_cursorYPos = m_totalSize - 1; + m_cursorXPos = 0; + } - m_maxTextWidth = -1; - update(); - updateSourceMask(); - emit updateAvailabilities(); - showUnsolvedConflictsStatusMessage(); + m_maxTextWidth = -1; + update(); + updateSourceMask(); + emit updateAvailabilities(); + showUnsolvedConflictsStatusMessage(); } // bConflictsOnly: automatically choose for conflicts only (true) or for everywhere (false) -void MergeResultWindow::chooseGlobal(int selector, bool bConflictsOnly, bool bWhiteSpaceOnly ) +void MergeResultWindow::chooseGlobal(int selector, bool bConflictsOnly, bool bWhiteSpaceOnly) { - resetSelection(); + resetSelection(); - merge( false, selector, bConflictsOnly, bWhiteSpaceOnly ); - setModified( true ); - update(); - showUnsolvedConflictsStatusMessage(); + merge(false, selector, bConflictsOnly, bWhiteSpaceOnly); + setModified(true); + update(); + showUnsolvedConflictsStatusMessage(); } void MergeResultWindow::slotAutoSolve() { - resetSelection(); - merge( true, -1 ); - setModified( true ); - update(); - showUnsolvedConflictsStatusMessage(); + resetSelection(); + merge(true, -1); + setModified(true); + update(); + showUnsolvedConflictsStatusMessage(); } void MergeResultWindow::slotUnsolve() { - resetSelection(); - merge( false, -1 ); - setModified( true ); - update(); - showUnsolvedConflictsStatusMessage(); + resetSelection(); + merge(false, -1); + setModified(true); + update(); + showUnsolvedConflictsStatusMessage(); } -static QString calcHistoryLead(const QString& s ) +static QString calcHistoryLead(const QString& s) { - // Return the start of the line until the first white char after the first non white char. - int i; - for( i=0; ibegin(), idxBegin=0; iBegin!=pD3LList->end(); ++iBegin, ++idxBegin ) - { - if ( historyStart.exactMatch( iBegin->getString(A) ) && - historyStart.exactMatch( iBegin->getString(B) ) && - ( !bThreeFiles || historyStart.exactMatch( iBegin->getString(C) ) ) ) - { - historyLead = calcHistoryLead( iBegin->getString(A) ); - break; - } - } - // Search for end of history - for( iEnd = iBegin, idxEnd = idxBegin; iEnd!=pD3LList->end(); ++iEnd, ++idxEnd ) - { - QString sA = iEnd->getString(A); - QString sB = iEnd->getString(B); - QString sC = iEnd->getString(C); - if ( ! ((sA.isEmpty() || historyLead == calcHistoryLead(sA) ) && - (sB.isEmpty() || historyLead == calcHistoryLead(sB) ) && - (!bThreeFiles || sC.isEmpty() || historyLead == calcHistoryLead(sC) ) - )) - { - break; // End of the history - } - } -} - -bool findParenthesesGroups( const QString& s, QStringList& sl ) -{ - sl.clear(); - int i=0; - std::list startPosStack; - int length = s.length(); - for( i=0; i(int)parenthesesGroupList.size() ) - continue; - QString s = matchedRegExpr.cap( groupIdx ); - if ( groupIdx == 0 ) - { - key += s + " "; - continue; - } - - QString groupRegExp = parenthesesGroupList[groupIdx-1]; - if( groupRegExp.indexOf('|')<0 || groupRegExp.indexOf('(')>=0 ) - { - bool bOk = false; - int i = s.toInt( &bOk ); - if ( bOk && i>=0 && i<10000 ) - s.sprintf("%04d", i); // This should help for correct sorting of numbers. - key += s + " "; - } - else - { - // Assume that the groupRegExp consists of something like "Jan|Feb|Mar|Apr" - // s is the string that managed to match. - // Now we want to know at which position it occurred. e.g. Jan=0, Feb=1, Mar=2, etc. - QStringList sl = groupRegExp.split( '|' ); - int idx = sl.indexOf( s ); - if (idx<0) - { - // Didn't match - } - else - { - QString sIdx; - sIdx.sprintf("%02d", idx+1 ); // Up to 99 words in the groupRegExp (more than 12 aren't expected) - key += sIdx + " "; - } - } - } - return key; + return s; // Very unlikely + } + } + return ""; // Must be an empty string, not a null string. } -void MergeResultWindow::collectHistoryInformation( - int src, Diff3LineList::const_iterator iHistoryBegin, Diff3LineList::const_iterator iHistoryEnd, - HistoryMap& historyMap, - std::list< HistoryMap::iterator >& hitList // list of iterators - ) -{ - std::list< HistoryMap::iterator >::iterator itHitListFront = hitList.begin(); - Diff3LineList::const_iterator id3l = iHistoryBegin; - QString historyLead; - { - const LineData* pld = id3l->getLineData(src); - QString s( pld->pLine, pld->size ); - historyLead = calcHistoryLead(s); - } - QRegExp historyStart( m_pOptions->m_historyStartRegExp ); - if ( id3l == iHistoryEnd ) - return; - ++id3l; // Skip line with "$Log ... $" - QRegExp newHistoryEntry( m_pOptions->m_historyEntryStartRegExp ); - QStringList parenthesesGroups; - findParenthesesGroups( m_pOptions->m_historyEntryStartRegExp, parenthesesGroups ); - QString key; - MergeEditLineList melList; - bool bPrevLineIsEmpty = true; - bool bUseRegExp = !m_pOptions->m_historyEntryStartRegExp.isEmpty(); - for(; id3l != iHistoryEnd; ++id3l ) - { - const LineData* pld = id3l->getLineData(src); - if ( !pld ) continue; - QString s( pld->pLine, pld->size ); - if (historyLead.isEmpty()) historyLead = calcHistoryLead(s); - QString sLine = s.mid(historyLead.length()); - if ( ( !bUseRegExp && !sLine.trimmed().isEmpty() && bPrevLineIsEmpty ) - || (bUseRegExp && newHistoryEntry.exactMatch( sLine ) ) - ) - { - if ( !key.isEmpty() && !melList.empty() ) - { - // Only insert new HistoryMapEntry if key not found; in either case p.first is a valid iterator to element key. - std::pair p = historyMap.insert(HistoryMap::value_type(key,HistoryMapEntry())); - HistoryMapEntry& hme = p.first->second; - if ( src==A ) hme.mellA = melList; - if ( src==B ) hme.mellB = melList; - if ( src==C ) hme.mellC = melList; - if ( p.second ) // Not in list yet? - { - hitList.insert( itHitListFront, p.first ); - } - } - - if ( ! bUseRegExp ) - key = sLine; - else - key = calcHistorySortKey(m_pOptions->m_historyEntryStartSortKeyOrder,newHistoryEntry,parenthesesGroups); - - melList.clear(); - melList.push_back( MergeEditLine(id3l,src) ); - } - else if ( ! historyStart.exactMatch( s ) ) - { - melList.push_back( MergeEditLine(id3l,src) ); - } - - bPrevLineIsEmpty = sLine.trimmed().isEmpty(); - } - if ( !key.isEmpty() ) - { - // Only insert new HistoryMapEntry if key not found; in either case p.first is a valid iterator to element key. - std::pair p = historyMap.insert(HistoryMap::value_type(key,HistoryMapEntry())); - HistoryMapEntry& hme = p.first->second; - if ( src==A ) hme.mellA = melList; - if ( src==B ) hme.mellB = melList; - if ( src==C ) hme.mellC = melList; - if ( p.second ) // Not in list yet? - { - hitList.insert( itHitListFront, p.first ); - } - } - // End of the history -} - -MergeResultWindow::MergeEditLineList& MergeResultWindow::HistoryMapEntry::choice( bool bThreeInputs ) -{ - if ( !bThreeInputs ) - return mellA.empty() ? mellB : mellA; - else - { - if ( mellA.empty() ) - return mellC.empty() ? mellB : mellC; // A doesn't exist, return one that exists - else if ( ! mellB.empty() && ! mellC.empty() ) - { // A, B and C exist - return mellA; - } - else - return mellB.empty() ? mellB : mellC; // A exists, return the one that doesn't exist - } -} - -bool MergeResultWindow::HistoryMapEntry::staysInPlace( bool bThreeInputs, Diff3LineList::const_iterator& iHistoryEnd ) -{ - // The entry should stay in place if the decision made by the automerger is correct. - Diff3LineList::const_iterator& iHistoryLast = iHistoryEnd; - --iHistoryLast; - if ( !bThreeInputs ) - { - if ( !mellA.empty() && !mellB.empty() && mellA.begin()->id3l()==mellB.begin()->id3l() && - mellA.back().id3l() == iHistoryLast && mellB.back().id3l() == iHistoryLast ) - { - iHistoryEnd = mellA.begin()->id3l(); - return true; - } - else - { - return false; - } - } - else - { - if ( !mellA.empty() && !mellB.empty() && !mellC.empty() - && mellA.begin()->id3l()==mellB.begin()->id3l() && mellA.begin()->id3l()==mellC.begin()->id3l() - && mellA.back().id3l() == iHistoryLast && mellB.back().id3l() == iHistoryLast && mellC.back().id3l() == iHistoryLast ) - { - iHistoryEnd = mellA.begin()->id3l(); - return true; - } - else - { - return false; - } - } +static void findHistoryRange(const QRegExp& historyStart, bool bThreeFiles, const Diff3LineList* pD3LList, + Diff3LineList::const_iterator& iBegin, Diff3LineList::const_iterator& iEnd, int& idxBegin, int& idxEnd) +{ + QString historyLead; + // Search for start of history + for(iBegin = pD3LList->begin(), idxBegin = 0; iBegin != pD3LList->end(); ++iBegin, ++idxBegin) + { + if(historyStart.exactMatch(iBegin->getString(A)) && + historyStart.exactMatch(iBegin->getString(B)) && + (!bThreeFiles || historyStart.exactMatch(iBegin->getString(C)))) + { + historyLead = calcHistoryLead(iBegin->getString(A)); + break; + } + } + // Search for end of history + for(iEnd = iBegin, idxEnd = idxBegin; iEnd != pD3LList->end(); ++iEnd, ++idxEnd) + { + QString sA = iEnd->getString(A); + QString sB = iEnd->getString(B); + QString sC = iEnd->getString(C); + if(!((sA.isEmpty() || historyLead == calcHistoryLead(sA)) && + (sB.isEmpty() || historyLead == calcHistoryLead(sB)) && + (!bThreeFiles || sC.isEmpty() || historyLead == calcHistoryLead(sC)))) + { + break; // End of the history + } + } } -void MergeResultWindow::slotMergeHistory() +bool findParenthesesGroups(const QString& s, QStringList& sl) +{ + sl.clear(); + int i = 0; + std::list startPosStack; + int length = s.length(); + for(i = 0; i < length; ++i) + { + if(s[i] == '\\' && i + 1 < length && (s[i + 1] == '\\' || s[i + 1] == '(' || s[i + 1] == ')')) + { + ++i; + continue; + } + if(s[i] == '(') + { + startPosStack.push_back(i); + } + else if(s[i] == ')') + { + if(startPosStack.empty()) + return false; // Parentheses don't match + int startPos = startPosStack.back(); + startPosStack.pop_back(); + sl.push_back(s.mid(startPos + 1, i - startPos - 1)); + } + } + return startPosStack.empty(); // false if parentheses don't match +} + +QString calcHistorySortKey(const QString& keyOrder, QRegExp& matchedRegExpr, const QStringList& parenthesesGroupList) { - Diff3LineList::const_iterator iD3LHistoryBegin; - Diff3LineList::const_iterator iD3LHistoryEnd; - int d3lHistoryBeginLineIdx = -1; - int d3lHistoryEndLineIdx = -1; - - // Search for history start, history end in the diff3LineList - findHistoryRange( QRegExp(m_pOptions->m_historyStartRegExp), m_pldC!=0, m_pDiff3LineList, iD3LHistoryBegin, iD3LHistoryEnd, d3lHistoryBeginLineIdx, d3lHistoryEndLineIdx ); - - if ( iD3LHistoryBegin != m_pDiff3LineList->end() ) - { - // Now collect the historyMap information - HistoryMap historyMap; - std::list< HistoryMap::iterator > hitList; - if (m_pldC==0) - { - collectHistoryInformation( A, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList ); - collectHistoryInformation( B, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList ); - } - else - { - collectHistoryInformation( A, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList ); - collectHistoryInformation( B, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList ); - collectHistoryInformation( C, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList ); - } - - Diff3LineList::const_iterator iD3LHistoryOrigEnd = iD3LHistoryEnd; - - bool bHistoryMergeSorting = m_pOptions->m_bHistoryMergeSorting && ! m_pOptions->m_historyEntryStartSortKeyOrder.isEmpty() && - ! m_pOptions->m_historyEntryStartRegExp.isEmpty(); - - if ( m_pOptions->m_maxNofHistoryEntries==-1 ) - { - // Remove parts from the historyMap and hitList that stay in place - if ( bHistoryMergeSorting ) - { - while ( ! historyMap.empty() ) + QStringList keyOrderList = keyOrder.split(','); + QString key; + for(QStringList::iterator keyIt = keyOrderList.begin(); keyIt != keyOrderList.end(); ++keyIt) + { + if((*keyIt).isEmpty()) + continue; + bool bOk = false; + int groupIdx = (*keyIt).toInt(&bOk); + if(!bOk || groupIdx < 0 || groupIdx > (int)parenthesesGroupList.size()) + continue; + QString s = matchedRegExpr.cap(groupIdx); + if(groupIdx == 0) + { + key += s + " "; + continue; + } + + QString groupRegExp = parenthesesGroupList[groupIdx - 1]; + if(groupRegExp.indexOf('|') < 0 || groupRegExp.indexOf('(') >= 0) + { + bool bOk = false; + int i = s.toInt(&bOk); + if(bOk && i >= 0 && i < 10000) + s.sprintf("%04d", i); // This should help for correct sorting of numbers. + key += s + " "; + } + else + { + // Assume that the groupRegExp consists of something like "Jan|Feb|Mar|Apr" + // s is the string that managed to match. + // Now we want to know at which position it occurred. e.g. Jan=0, Feb=1, Mar=2, etc. + QStringList sl = groupRegExp.split('|'); + int idx = sl.indexOf(s); + if(idx < 0) { - HistoryMap::iterator hMapIt = historyMap.begin(); - if( hMapIt->second.staysInPlace( m_pldC!=0, iD3LHistoryEnd ) ) - historyMap.erase(hMapIt); - else - break; + // Didn't match } - } - else - { - while ( ! hitList.empty() ) + else { - HistoryMap::iterator hMapIt = hitList.back(); - if( hMapIt->second.staysInPlace( m_pldC!=0, iD3LHistoryEnd ) ) - hitList.pop_back(); - else - break; + QString sIdx; + sIdx.sprintf("%02d", idx + 1); // Up to 99 words in the groupRegExp (more than 12 aren't expected) + key += sIdx + " "; } - } - while (iD3LHistoryOrigEnd != iD3LHistoryEnd) - { - --iD3LHistoryOrigEnd; - --d3lHistoryEndLineIdx; - } - } - - MergeLineList::iterator iMLLStart = splitAtDiff3LineIdx(d3lHistoryBeginLineIdx); - MergeLineList::iterator iMLLEnd = splitAtDiff3LineIdx(d3lHistoryEndLineIdx); - // Now join all MergeLines in the history - MergeLineList::iterator i = iMLLStart; - if ( i != iMLLEnd ) - { - ++i; - while ( i!=iMLLEnd ) - { - iMLLStart->join(*i); - i = m_mergeLineList.erase( i ); - } - } - iMLLStart->mergeEditLineList.clear(); - // Now insert the complete history into the first MergeLine of the history - iMLLStart->mergeEditLineList.push_back( MergeEditLine( iD3LHistoryBegin, m_pldC == 0 ? B : C ) ); - QString lead = calcHistoryLead( iD3LHistoryBegin->getString(A) ); - MergeEditLine mel( m_pDiff3LineList->end() ); - mel.setString( lead ); - iMLLStart->mergeEditLineList.push_back(mel); - - int historyCount = 0; - if ( bHistoryMergeSorting ) - { - // Create a sorted history - HistoryMap::reverse_iterator hmit; - for ( hmit = historyMap.rbegin(); hmit != historyMap.rend(); ++hmit ) - { - if ( historyCount==m_pOptions->m_maxNofHistoryEntries ) - break; - ++historyCount; - HistoryMapEntry& hme = hmit->second; - MergeEditLineList& mell = hme.choice(m_pldC!=0); - if (!mell.empty()) - iMLLStart->mergeEditLineList.splice( iMLLStart->mergeEditLineList.end(), mell, mell.begin(), mell.end() ); - } - } - else - { - // Create history in order of appearance - std::list< HistoryMap::iterator >::iterator hlit; - for ( hlit = hitList.begin(); hlit != hitList.end(); ++hlit ) - { - if ( historyCount==m_pOptions->m_maxNofHistoryEntries ) - break; - ++historyCount; - HistoryMapEntry& hme = (*hlit)->second; - MergeEditLineList& mell = hme.choice(m_pldC!=0); - if (!mell.empty()) - iMLLStart->mergeEditLineList.splice( iMLLStart->mergeEditLineList.end(), mell, mell.begin(), mell.end() ); - } - // If the end of start is empty and the first line at the end is empty remove the last line of start - if ( !iMLLStart->mergeEditLineList.empty() && !iMLLEnd->mergeEditLineList.empty() ) - { - QString lastLineOfStart = iMLLStart->mergeEditLineList.back().getString(this); - QString firstLineOfEnd = iMLLEnd->mergeEditLineList.front().getString(this); - if ( lastLineOfStart.mid(lead.length()).trimmed().isEmpty() && firstLineOfEnd.mid(lead.length()).trimmed().isEmpty() ) - iMLLStart->mergeEditLineList.pop_back(); - } - } - setFastSelector( iMLLStart ); - update(); - } + } + } + return key; } -void MergeResultWindow::slotRegExpAutoMerge() -{ - if ( m_pOptions->m_autoMergeRegExp.isEmpty() ) - return; - - QRegExp vcsKeywords( m_pOptions->m_autoMergeRegExp ); - MergeLineList::iterator i; - for ( i=m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i ) - { - if (i->bConflict ) - { - Diff3LineList::const_iterator id3l = i->id3l; - if ( vcsKeywords.exactMatch( id3l->getString(A) ) && - vcsKeywords.exactMatch( id3l->getString(B) ) && - (m_pldC==0 || vcsKeywords.exactMatch( id3l->getString(C) ))) - { - MergeEditLine& mel = *i->mergeEditLineList.begin(); - mel.setSource( m_pldC==0 ? B : C, false ); - splitAtDiff3LineIdx( i->d3lLineIdx+1 ); - } - } - } - update(); -} +void MergeResultWindow::collectHistoryInformation( + int src, Diff3LineList::const_iterator iHistoryBegin, Diff3LineList::const_iterator iHistoryEnd, + HistoryMap& historyMap, + std::list& hitList // list of iterators + ) +{ + std::list::iterator itHitListFront = hitList.begin(); + Diff3LineList::const_iterator id3l = iHistoryBegin; + QString historyLead; + { + const LineData* pld = id3l->getLineData(src); + QString s(pld->pLine, pld->size); + historyLead = calcHistoryLead(s); + } + QRegExp historyStart(m_pOptions->m_historyStartRegExp); + if(id3l == iHistoryEnd) + return; + ++id3l; // Skip line with "$Log ... $" + QRegExp newHistoryEntry(m_pOptions->m_historyEntryStartRegExp); + QStringList parenthesesGroups; + findParenthesesGroups(m_pOptions->m_historyEntryStartRegExp, parenthesesGroups); + QString key; + MergeEditLineList melList; + bool bPrevLineIsEmpty = true; + bool bUseRegExp = !m_pOptions->m_historyEntryStartRegExp.isEmpty(); + for(; id3l != iHistoryEnd; ++id3l) + { + const LineData* pld = id3l->getLineData(src); + if(!pld) continue; + QString s(pld->pLine, pld->size); + if(historyLead.isEmpty()) historyLead = calcHistoryLead(s); + QString sLine = s.mid(historyLead.length()); + if((!bUseRegExp && !sLine.trimmed().isEmpty() && bPrevLineIsEmpty) || (bUseRegExp && newHistoryEntry.exactMatch(sLine))) + { + if(!key.isEmpty() && !melList.empty()) + { + // Only insert new HistoryMapEntry if key not found; in either case p.first is a valid iterator to element key. + std::pair p = historyMap.insert(HistoryMap::value_type(key, HistoryMapEntry())); + HistoryMapEntry& hme = p.first->second; + if(src == A) hme.mellA = melList; + if(src == B) hme.mellB = melList; + if(src == C) hme.mellC = melList; + if(p.second) // Not in list yet? + { + hitList.insert(itHitListFront, p.first); + } + } -// This doesn't detect user modifications and should only be called after automatic merge -// This will only do something for three file merge. -// Irrelevant changes are those where all contributions from B are already contained in C. -// Also irrelevant are conflicts automatically solved (automerge regexp and history automerge) -// Precondition: The VCS-keyword would also be C. -bool MergeResultWindow::doRelevantChangesExist() -{ - if ( m_pldC==0 || m_mergeLineList.size() <= 1 ) - return true; + if(!bUseRegExp) + key = sLine; + else + key = calcHistorySortKey(m_pOptions->m_historyEntryStartSortKeyOrder, newHistoryEntry, parenthesesGroups); - MergeLineList::iterator i; - for ( i=m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i ) - { - if ( ( i->bConflict && i->mergeEditLineList.begin()->src()!=C ) - || i->srcSelect == B ) - { - return true; - } - } + melList.clear(); + melList.push_back(MergeEditLine(id3l, src)); + } + else if(!historyStart.exactMatch(s)) + { + melList.push_back(MergeEditLine(id3l, src)); + } - return false; + bPrevLineIsEmpty = sLine.trimmed().isEmpty(); + } + if(!key.isEmpty()) + { + // Only insert new HistoryMapEntry if key not found; in either case p.first is a valid iterator to element key. + std::pair p = historyMap.insert(HistoryMap::value_type(key, HistoryMapEntry())); + HistoryMapEntry& hme = p.first->second; + if(src == A) hme.mellA = melList; + if(src == B) hme.mellB = melList; + if(src == C) hme.mellC = melList; + if(p.second) // Not in list yet? + { + hitList.insert(itHitListFront, p.first); + } + } + // End of the history } -// Returns the iterator to the MergeLine after the split -MergeResultWindow::MergeLineList::iterator MergeResultWindow::splitAtDiff3LineIdx( int d3lLineIdx ) -{ - MergeLineList::iterator i; - for ( i = m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i ) - { - if ( i->d3lLineIdx==d3lLineIdx ) - { - // No split needed, this is the beginning of a MergeLine - return i; - } - else if ( i->d3lLineIdx > d3lLineIdx ) - { - // The split must be in the previous MergeLine - --i; - MergeLine& ml = *i; - MergeLine newML; - ml.split(newML,d3lLineIdx); - ++i; - return m_mergeLineList.insert( i, newML ); - } - } - // The split must be in the previous MergeLine - --i; - MergeLine& ml = *i; - MergeLine newML; - ml.split(newML,d3lLineIdx); - ++i; - return m_mergeLineList.insert( i, newML ); -} - -void MergeResultWindow::slotSplitDiff( int firstD3lLineIdx, int lastD3lLineIdx ) -{ - if (lastD3lLineIdx>=0) - splitAtDiff3LineIdx( lastD3lLineIdx + 1 ); - setFastSelector( splitAtDiff3LineIdx(firstD3lLineIdx) ); -} - -void MergeResultWindow::slotJoinDiffs( int firstD3lLineIdx, int lastD3lLineIdx ) -{ - MergeLineList::iterator i; - MergeLineList::iterator iMLLStart = m_mergeLineList.end(); - MergeLineList::iterator iMLLEnd = m_mergeLineList.end(); - for ( i=m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i ) - { - MergeLine& ml = *i; - if ( firstD3lLineIdx >= ml.d3lLineIdx && firstD3lLineIdx < ml.d3lLineIdx + ml.srcRangeLength ) - { - iMLLStart = i; - } - if ( lastD3lLineIdx >= ml.d3lLineIdx && lastD3lLineIdx < ml.d3lLineIdx + ml.srcRangeLength ) - { - iMLLEnd = i; - ++iMLLEnd; - break; - } - } - - bool bJoined = false; - for( i=iMLLStart; i!=iMLLEnd && i!=m_mergeLineList.end(); ) - { - if ( i==iMLLStart ) - { - ++i; - } - else - { - iMLLStart->join(*i); - i = m_mergeLineList.erase( i ); - bJoined = true; - } - } - if (bJoined) - { - iMLLStart->mergeEditLineList.clear(); - // Insert a conflict line as placeholder - iMLLStart->mergeEditLineList.push_back( MergeEditLine( iMLLStart->id3l ) ); - } - setFastSelector( iMLLStart ); +MergeResultWindow::MergeEditLineList& MergeResultWindow::HistoryMapEntry::choice(bool bThreeInputs) +{ + if(!bThreeInputs) + return mellA.empty() ? mellB : mellA; + else + { + if(mellA.empty()) + return mellC.empty() ? mellB : mellC; // A doesn't exist, return one that exists + else if(!mellB.empty() && !mellC.empty()) + { // A, B and C exist + return mellA; + } + else + return mellB.empty() ? mellB : mellC; // A exists, return the one that doesn't exist + } } -void MergeResultWindow::myUpdate(int afterMilliSecs) +bool MergeResultWindow::HistoryMapEntry::staysInPlace(bool bThreeInputs, Diff3LineList::const_iterator& iHistoryEnd) { - if ( m_delayedDrawTimer ) - killTimer(m_delayedDrawTimer); - m_bMyUpdate = true; - m_delayedDrawTimer = startTimer( afterMilliSecs ); + // The entry should stay in place if the decision made by the automerger is correct. + Diff3LineList::const_iterator& iHistoryLast = iHistoryEnd; + --iHistoryLast; + if(!bThreeInputs) + { + if(!mellA.empty() && !mellB.empty() && mellA.begin()->id3l() == mellB.begin()->id3l() && + mellA.back().id3l() == iHistoryLast && mellB.back().id3l() == iHistoryLast) + { + iHistoryEnd = mellA.begin()->id3l(); + return true; + } + else + { + return false; + } + } + else + { + if(!mellA.empty() && !mellB.empty() && !mellC.empty() && mellA.begin()->id3l() == mellB.begin()->id3l() && mellA.begin()->id3l() == mellC.begin()->id3l() && mellA.back().id3l() == iHistoryLast && mellB.back().id3l() == iHistoryLast && mellC.back().id3l() == iHistoryLast) + { + iHistoryEnd = mellA.begin()->id3l(); + return true; + } + else + { + return false; + } + } } -void MergeResultWindow::timerEvent(QTimerEvent*) +void MergeResultWindow::slotMergeHistory() { - killTimer(m_delayedDrawTimer); - m_delayedDrawTimer = 0; - - if ( m_bMyUpdate ) - { - update(); - m_bMyUpdate = false; - } - - if ( m_scrollDeltaX != 0 || m_scrollDeltaY != 0 ) - { - m_selection.end( m_selection.lastLine + m_scrollDeltaY, m_selection.lastPos + m_scrollDeltaX ); - emit scroll( m_scrollDeltaX, m_scrollDeltaY ); - killTimer(m_delayedDrawTimer); - m_delayedDrawTimer = startTimer(50); - } -} - -QString MergeResultWindow::MergeEditLine::getString( const MergeResultWindow* mrw ) -{ - if ( isRemoved() ) { return QString(); } - - if ( ! isModified() ) - { - int src = m_src; - if ( src == 0 ) { return QString(); } - const Diff3Line& d3l = *m_id3l; - const LineData* pld = 0; - assert( src == A || src == B || src == C ); - if ( src == A && d3l.lineA!=-1 ) pld = &mrw->m_pldA[ d3l.lineA ]; - else if ( src == B && d3l.lineB!=-1 ) pld = &mrw->m_pldB[ d3l.lineB ]; - else if ( src == C && d3l.lineC!=-1 ) pld = &mrw->m_pldC[ d3l.lineC ]; - - if ( pld == 0 ) - { - // assert(false); This is no error. - return QString(); - } - - return QString( pld->pLine, pld->size ); - } - else - { - return m_str; - } - return 0; + Diff3LineList::const_iterator iD3LHistoryBegin; + Diff3LineList::const_iterator iD3LHistoryEnd; + int d3lHistoryBeginLineIdx = -1; + int d3lHistoryEndLineIdx = -1; + + // Search for history start, history end in the diff3LineList + findHistoryRange(QRegExp(m_pOptions->m_historyStartRegExp), m_pldC != 0, m_pDiff3LineList, iD3LHistoryBegin, iD3LHistoryEnd, d3lHistoryBeginLineIdx, d3lHistoryEndLineIdx); + + if(iD3LHistoryBegin != m_pDiff3LineList->end()) + { + // Now collect the historyMap information + HistoryMap historyMap; + std::list hitList; + if(m_pldC == 0) + { + collectHistoryInformation(A, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList); + collectHistoryInformation(B, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList); + } + else + { + collectHistoryInformation(A, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList); + collectHistoryInformation(B, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList); + collectHistoryInformation(C, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList); + } + + Diff3LineList::const_iterator iD3LHistoryOrigEnd = iD3LHistoryEnd; + + bool bHistoryMergeSorting = m_pOptions->m_bHistoryMergeSorting && !m_pOptions->m_historyEntryStartSortKeyOrder.isEmpty() && + !m_pOptions->m_historyEntryStartRegExp.isEmpty(); + + if(m_pOptions->m_maxNofHistoryEntries == -1) + { + // Remove parts from the historyMap and hitList that stay in place + if(bHistoryMergeSorting) + { + while(!historyMap.empty()) + { + HistoryMap::iterator hMapIt = historyMap.begin(); + if(hMapIt->second.staysInPlace(m_pldC != 0, iD3LHistoryEnd)) + historyMap.erase(hMapIt); + else + break; + } + } + else + { + while(!hitList.empty()) + { + HistoryMap::iterator hMapIt = hitList.back(); + if(hMapIt->second.staysInPlace(m_pldC != 0, iD3LHistoryEnd)) + hitList.pop_back(); + else + break; + } + } + while(iD3LHistoryOrigEnd != iD3LHistoryEnd) + { + --iD3LHistoryOrigEnd; + --d3lHistoryEndLineIdx; + } + } + + MergeLineList::iterator iMLLStart = splitAtDiff3LineIdx(d3lHistoryBeginLineIdx); + MergeLineList::iterator iMLLEnd = splitAtDiff3LineIdx(d3lHistoryEndLineIdx); + // Now join all MergeLines in the history + MergeLineList::iterator i = iMLLStart; + if(i != iMLLEnd) + { + ++i; + while(i != iMLLEnd) + { + iMLLStart->join(*i); + i = m_mergeLineList.erase(i); + } + } + iMLLStart->mergeEditLineList.clear(); + // Now insert the complete history into the first MergeLine of the history + iMLLStart->mergeEditLineList.push_back(MergeEditLine(iD3LHistoryBegin, m_pldC == 0 ? B : C)); + QString lead = calcHistoryLead(iD3LHistoryBegin->getString(A)); + MergeEditLine mel(m_pDiff3LineList->end()); + mel.setString(lead); + iMLLStart->mergeEditLineList.push_back(mel); + + int historyCount = 0; + if(bHistoryMergeSorting) + { + // Create a sorted history + HistoryMap::reverse_iterator hmit; + for(hmit = historyMap.rbegin(); hmit != historyMap.rend(); ++hmit) + { + if(historyCount == m_pOptions->m_maxNofHistoryEntries) + break; + ++historyCount; + HistoryMapEntry& hme = hmit->second; + MergeEditLineList& mell = hme.choice(m_pldC != 0); + if(!mell.empty()) + iMLLStart->mergeEditLineList.splice(iMLLStart->mergeEditLineList.end(), mell, mell.begin(), mell.end()); + } + } + else + { + // Create history in order of appearance + std::list::iterator hlit; + for(hlit = hitList.begin(); hlit != hitList.end(); ++hlit) + { + if(historyCount == m_pOptions->m_maxNofHistoryEntries) + break; + ++historyCount; + HistoryMapEntry& hme = (*hlit)->second; + MergeEditLineList& mell = hme.choice(m_pldC != 0); + if(!mell.empty()) + iMLLStart->mergeEditLineList.splice(iMLLStart->mergeEditLineList.end(), mell, mell.begin(), mell.end()); + } + // If the end of start is empty and the first line at the end is empty remove the last line of start + if(!iMLLStart->mergeEditLineList.empty() && !iMLLEnd->mergeEditLineList.empty()) + { + QString lastLineOfStart = iMLLStart->mergeEditLineList.back().getString(this); + QString firstLineOfEnd = iMLLEnd->mergeEditLineList.front().getString(this); + if(lastLineOfStart.mid(lead.length()).trimmed().isEmpty() && firstLineOfEnd.mid(lead.length()).trimmed().isEmpty()) + iMLLStart->mergeEditLineList.pop_back(); + } + } + setFastSelector(iMLLStart); + update(); + } +} + +void MergeResultWindow::slotRegExpAutoMerge() +{ + if(m_pOptions->m_autoMergeRegExp.isEmpty()) + return; + + QRegExp vcsKeywords(m_pOptions->m_autoMergeRegExp); + MergeLineList::iterator i; + for(i = m_mergeLineList.begin(); i != m_mergeLineList.end(); ++i) + { + if(i->bConflict) + { + Diff3LineList::const_iterator id3l = i->id3l; + if(vcsKeywords.exactMatch(id3l->getString(A)) && + vcsKeywords.exactMatch(id3l->getString(B)) && + (m_pldC == 0 || vcsKeywords.exactMatch(id3l->getString(C)))) + { + MergeEditLine& mel = *i->mergeEditLineList.begin(); + mel.setSource(m_pldC == 0 ? B : C, false); + splitAtDiff3LineIdx(i->d3lLineIdx + 1); + } + } + } + update(); +} + +// This doesn't detect user modifications and should only be called after automatic merge +// This will only do something for three file merge. +// Irrelevant changes are those where all contributions from B are already contained in C. +// Also irrelevant are conflicts automatically solved (automerge regexp and history automerge) +// Precondition: The VCS-keyword would also be C. +bool MergeResultWindow::doRelevantChangesExist() +{ + if(m_pldC == 0 || m_mergeLineList.size() <= 1) + return true; + + MergeLineList::iterator i; + for(i = m_mergeLineList.begin(); i != m_mergeLineList.end(); ++i) + { + if((i->bConflict && i->mergeEditLineList.begin()->src() != C) || i->srcSelect == B) + { + return true; + } + } + + return false; +} + +// Returns the iterator to the MergeLine after the split +MergeResultWindow::MergeLineList::iterator MergeResultWindow::splitAtDiff3LineIdx(int d3lLineIdx) +{ + MergeLineList::iterator i; + for(i = m_mergeLineList.begin(); i != m_mergeLineList.end(); ++i) + { + if(i->d3lLineIdx == d3lLineIdx) + { + // No split needed, this is the beginning of a MergeLine + return i; + } + else if(i->d3lLineIdx > d3lLineIdx) + { + // The split must be in the previous MergeLine + --i; + MergeLine& ml = *i; + MergeLine newML; + ml.split(newML, d3lLineIdx); + ++i; + return m_mergeLineList.insert(i, newML); + } + } + // The split must be in the previous MergeLine + --i; + MergeLine& ml = *i; + MergeLine newML; + ml.split(newML, d3lLineIdx); + ++i; + return m_mergeLineList.insert(i, newML); +} + +void MergeResultWindow::slotSplitDiff(int firstD3lLineIdx, int lastD3lLineIdx) +{ + if(lastD3lLineIdx >= 0) + splitAtDiff3LineIdx(lastD3lLineIdx + 1); + setFastSelector(splitAtDiff3LineIdx(firstD3lLineIdx)); +} + +void MergeResultWindow::slotJoinDiffs(int firstD3lLineIdx, int lastD3lLineIdx) +{ + MergeLineList::iterator i; + MergeLineList::iterator iMLLStart = m_mergeLineList.end(); + MergeLineList::iterator iMLLEnd = m_mergeLineList.end(); + for(i = m_mergeLineList.begin(); i != m_mergeLineList.end(); ++i) + { + MergeLine& ml = *i; + if(firstD3lLineIdx >= ml.d3lLineIdx && firstD3lLineIdx < ml.d3lLineIdx + ml.srcRangeLength) + { + iMLLStart = i; + } + if(lastD3lLineIdx >= ml.d3lLineIdx && lastD3lLineIdx < ml.d3lLineIdx + ml.srcRangeLength) + { + iMLLEnd = i; + ++iMLLEnd; + break; + } + } + + bool bJoined = false; + for(i = iMLLStart; i != iMLLEnd && i != m_mergeLineList.end();) + { + if(i == iMLLStart) + { + ++i; + } + else + { + iMLLStart->join(*i); + i = m_mergeLineList.erase(i); + bJoined = true; + } + } + if(bJoined) + { + iMLLStart->mergeEditLineList.clear(); + // Insert a conflict line as placeholder + iMLLStart->mergeEditLineList.push_back(MergeEditLine(iMLLStart->id3l)); + } + setFastSelector(iMLLStart); +} + +void MergeResultWindow::myUpdate(int afterMilliSecs) +{ + if(m_delayedDrawTimer) + killTimer(m_delayedDrawTimer); + m_bMyUpdate = true; + m_delayedDrawTimer = startTimer(afterMilliSecs); +} + +void MergeResultWindow::timerEvent(QTimerEvent*) +{ + killTimer(m_delayedDrawTimer); + m_delayedDrawTimer = 0; + + if(m_bMyUpdate) + { + update(); + m_bMyUpdate = false; + } + + if(m_scrollDeltaX != 0 || m_scrollDeltaY != 0) + { + m_selection.end(m_selection.lastLine + m_scrollDeltaY, m_selection.lastPos + m_scrollDeltaX); + emit scroll(m_scrollDeltaX, m_scrollDeltaY); + killTimer(m_delayedDrawTimer); + m_delayedDrawTimer = startTimer(50); + } +} + +QString MergeResultWindow::MergeEditLine::getString(const MergeResultWindow* mrw) +{ + if(isRemoved()) { + return QString(); + } + + if(!isModified()) + { + int src = m_src; + if(src == 0) { + return QString(); + } + const Diff3Line& d3l = *m_id3l; + const LineData* pld = 0; + assert(src == A || src == B || src == C); + if(src == A && d3l.lineA != -1) + pld = &mrw->m_pldA[d3l.lineA]; + else if(src == B && d3l.lineB != -1) + pld = &mrw->m_pldB[d3l.lineB]; + else if(src == C && d3l.lineC != -1) + pld = &mrw->m_pldC[d3l.lineC]; + + if(pld == 0) + { + // assert(false); This is no error. + return QString(); + } + + return QString(pld->pLine, pld->size); + } + else + { + return m_str; + } + return 0; } /// Converts the cursor-posOnScreen into a text index, considering tabulators. -int convertToPosInText( const QString& /*s*/, int posOnScreen, int /*tabSize*/ ) +int convertToPosInText(const QString& /*s*/, int posOnScreen, int /*tabSize*/) { - return posOnScreen; + return posOnScreen; } // int localPosOnScreen = 0; // int size=s.length(); // for ( int i=0; i=posOnScreen ) // return i; // // All letters except tabulator have width one. // int letterWidth = s[i]!='\t' ? 1 : tabber( localPosOnScreen, tabSize ); // localPosOnScreen += letterWidth; // if ( localPosOnScreen>posOnScreen ) // return i; // } // return size; //} - /// Converts the index into the text to a cursor-posOnScreen considering tabulators. -int convertToPosOnScreen( const QString& /*p*/, int posInText, int /*tabSize*/ ) +int convertToPosOnScreen(const QString& /*p*/, int posInText, int /*tabSize*/) { - return posInText; + return posInText; } // int posOnScreen = 0; // for ( int i=0; i MergeResultWindow::getTextLayoutForLine( int line, const QString& str, QTextLayout& textLayout ) +QVector MergeResultWindow::getTextLayoutForLine(int line, const QString& str, QTextLayout& textLayout) { // tabs QTextOption textOption; - textOption.setTabStop( QFontMetricsF(font()).width(' ') * m_pOptions->m_tabSize ); - if( m_pOptions->m_bShowWhiteSpaceCharacters ) + textOption.setTabStop(QFontMetricsF(font()).width(' ') * m_pOptions->m_tabSize); + if(m_pOptions->m_bShowWhiteSpaceCharacters) { - textOption.setFlags( QTextOption::ShowTabsAndSpaces ); + textOption.setFlags(QTextOption::ShowTabsAndSpaces); } - textLayout.setTextOption( textOption ); + textLayout.setTextOption(textOption); - if( m_pOptions->m_bShowWhiteSpaceCharacters ) + if(m_pOptions->m_bShowWhiteSpaceCharacters) { // This additional format is only necessary for the tab arrow QList formats; QTextLayout::FormatRange formatRange; formatRange.start = 0; formatRange.length = str.length(); - formatRange.format.setFont( font() ); - formats.append( formatRange ); - textLayout.setAdditionalFormats( formats ); + formatRange.format.setFont(font()); + formats.append(formatRange); + textLayout.setAdditionalFormats(formats); } QVector selectionFormat; textLayout.beginLayout(); - if( m_selection.lineWithin( line ) ) + if(m_selection.lineWithin(line)) { - int firstPosInText = convertToPosInText( str, m_selection.firstPosInLine(line), m_pOptions->m_tabSize ); - int lastPosInText = convertToPosInText( str, m_selection.lastPosInLine(line), m_pOptions->m_tabSize ); - int lengthInText = max2( 0, lastPosInText - firstPosInText ); - if( lengthInText>0 ) + int firstPosInText = convertToPosInText(str, m_selection.firstPosInLine(line), m_pOptions->m_tabSize); + int lastPosInText = convertToPosInText(str, m_selection.lastPosInLine(line), m_pOptions->m_tabSize); + int lengthInText = max2(0, lastPosInText - firstPosInText); + if(lengthInText > 0) m_selection.bSelectionContainsData = true; QTextLayout::FormatRange selection; selection.start = firstPosInText; selection.length = lengthInText; - selection.format.setBackground( palette().highlight() ); - selection.format.setForeground( palette().highlightedText().color() ); - selectionFormat.push_back( selection ); + selection.format.setBackground(palette().highlight()); + selection.format.setForeground(palette().highlightedText().color()); + selectionFormat.push_back(selection); } QTextLine textLine = textLayout.createLine(); - textLine.setPosition( QPointF(0, fontMetrics().leading()) ); + textLine.setPosition(QPointF(0, fontMetrics().leading())); textLayout.endLayout(); int cursorWidth = 5; - if( m_pOptions->m_bRightToLeftLanguage ) - textLayout.setPosition( QPointF(width()-textLayout.maximumWidth()-getTextXOffset()+m_horizScrollOffset-cursorWidth, 0) ); + if(m_pOptions->m_bRightToLeftLanguage) + textLayout.setPosition(QPointF(width() - textLayout.maximumWidth() - getTextXOffset() + m_horizScrollOffset - cursorWidth, 0)); else - textLayout.setPosition( QPointF(getTextXOffset() - m_horizScrollOffset, 0) ); + textLayout.setPosition(QPointF(getTextXOffset() - m_horizScrollOffset, 0)); return selectionFormat; } void MergeResultWindow::writeLine( - MyPainter& p, int line, const QString& str, - int srcSelect, e_MergeDetails mergeDetails, int rangeMark, bool bUserModified, bool bLineRemoved, bool bWhiteSpaceConflict - ) -{ - const QFontMetrics& fm = fontMetrics(); - int fontHeight = fm.lineSpacing(); - int fontAscent = fm.ascent(); - - int topLineYOffset = 0; - int xOffset = getTextXOffset(); - - int yOffset = ( line-m_firstLine ) * fontHeight; - if ( yOffset < 0 || yOffset > height() ) - return; - - yOffset += topLineYOffset; - - QString srcName = " "; - if ( bUserModified ) srcName = "m"; - else if ( srcSelect == A && mergeDetails != eNoChange ) srcName = "A"; - else if ( srcSelect == B ) srcName = "B"; - else if ( srcSelect == C ) srcName = "C"; - - if ( rangeMark & 4 ) - { - p.fillRect( xOffset, yOffset, width(), fontHeight, m_pOptions->m_currentRangeBgColor ); - } - - if( (srcSelect > 0 || bUserModified ) && !bLineRemoved ) - { - if ( ! m_pOptions->m_bRightToLeftLanguage ) - p.setClipRect( QRectF(xOffset,0,width()-xOffset,height()) ); - else - p.setClipRect( QRectF(0,0,width()-xOffset,height()) ); - - int outPos = 0; - QString s; - int size = str.length(); - for ( int i=0; im_tabSize ); - for( int j=0; jm_fgColor ); - - QTextLayout textLayout( str, font(), this ); - QVector selectionFormat = getTextLayoutForLine( line, str, textLayout ); - textLayout.draw( &p, QPointF(0, yOffset), selectionFormat ); - - if ( line == m_cursorYPos ) - { - m_cursorXPixelPos = textLayout.lineAt(0).cursorToX( m_cursorXPos ); - if ( m_pOptions->m_bRightToLeftLanguage ) - m_cursorXPixelPos += textLayout.position().x() - m_horizScrollOffset; - } - - p.setClipping( false ); - - p.setPen( m_pOptions->m_fgColor ); - - p.drawText( 1, yOffset+fontAscent, srcName, true ); - } - else if ( bLineRemoved ) - { - p.setPen( m_pOptions->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_pOptions->m_colorForConflict ); - if ( bWhiteSpaceConflict ) - p.drawText( xOffset, yOffset+fontAscent, i18n("") ); - else - p.drawText( xOffset, yOffset+fontAscent, i18n("") ); - p.drawText( 1, yOffset+fontAscent, "?" ); - if ( m_cursorYPos==line ) m_cursorXPos = 0; - } - else assert(false); - - xOffset -= fm.width('0'); - p.setPen( m_pOptions->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_pOptions->m_fgColor ); -/* p.setPen( blue ); + MyPainter& p, int line, const QString& str, + int srcSelect, e_MergeDetails mergeDetails, int rangeMark, bool bUserModified, bool bLineRemoved, bool bWhiteSpaceConflict) +{ + const QFontMetrics& fm = fontMetrics(); + int fontHeight = fm.lineSpacing(); + int fontAscent = fm.ascent(); + + int topLineYOffset = 0; + int xOffset = getTextXOffset(); + + int yOffset = (line - m_firstLine) * fontHeight; + if(yOffset < 0 || yOffset > height()) + return; + + yOffset += topLineYOffset; + + QString srcName = " "; + if(bUserModified) + srcName = "m"; + else if(srcSelect == A && mergeDetails != eNoChange) + srcName = "A"; + else if(srcSelect == B) + srcName = "B"; + else if(srcSelect == C) + srcName = "C"; + + if(rangeMark & 4) + { + p.fillRect(xOffset, yOffset, width(), fontHeight, m_pOptions->m_currentRangeBgColor); + } + + if((srcSelect > 0 || bUserModified) && !bLineRemoved) + { + if(!m_pOptions->m_bRightToLeftLanguage) + p.setClipRect(QRectF(xOffset, 0, width() - xOffset, height())); + else + p.setClipRect(QRectF(0, 0, width() - xOffset, height())); + + int outPos = 0; + QString s; + int size = str.length(); + for(int i = 0; i < size; ++i) + { + int spaces = 1; + if(str[i] == '\t') + { + spaces = tabber(outPos, m_pOptions->m_tabSize); + for(int j = 0; j < spaces; ++j) + s += ' '; + } + else + { + s += str[i]; + } + outPos += spaces; + } + + p.setPen(m_pOptions->m_fgColor); + + QTextLayout textLayout(str, font(), this); + QVector selectionFormat = getTextLayoutForLine(line, str, textLayout); + textLayout.draw(&p, QPointF(0, yOffset), selectionFormat); + + if(line == m_cursorYPos) + { + m_cursorXPixelPos = textLayout.lineAt(0).cursorToX(m_cursorXPos); + if(m_pOptions->m_bRightToLeftLanguage) + m_cursorXPixelPos += textLayout.position().x() - m_horizScrollOffset; + } + + p.setClipping(false); + + p.setPen(m_pOptions->m_fgColor); + + p.drawText(1, yOffset + fontAscent, srcName, true); + } + else if(bLineRemoved) + { + p.setPen(m_pOptions->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_pOptions->m_colorForConflict); + if(bWhiteSpaceConflict) + p.drawText(xOffset, yOffset + fontAscent, i18n("")); + else + p.drawText(xOffset, yOffset + fontAscent, i18n("")); + p.drawText(1, yOffset + fontAscent, "?"); + if(m_cursorYPos == line) m_cursorXPos = 0; + } + else + assert(false); + + xOffset -= fm.width('0'); + p.setPen(m_pOptions->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_pOptions->m_fgColor); + /* p.setPen( blue ); p.drawLine( xOffset+2, yOffset, xOffset+2, yOffset+fontHeight-1 ); p.drawLine( xOffset+3, yOffset, xOffset+3, yOffset+fontHeight-1 );*/ - } + } } void MergeResultWindow::setPaintingAllowed(bool bPaintingAllowed) { - m_bPaintingAllowed = bPaintingAllowed; - if ( !m_bPaintingAllowed ) - { - m_currentMergeLineIt = m_mergeLineList.end(); - reset(); - } - update(); -} - -void MergeResultWindow::paintEvent( QPaintEvent* ) -{ - if (m_pDiff3LineList==0 || !m_bPaintingAllowed) - return; - - bool bOldSelectionContainsData = m_selection.bSelectionContainsData; - const QFontMetrics& fm = fontMetrics(); - int fontWidth = fm.width('0'); - - if ( !m_bCursorUpdate ) // Don't redraw everything for blinking cursor? - { - m_selection.bSelectionContainsData = false; - if ( size() != m_pixmap.size() ) - m_pixmap = QPixmap(size()); - - MyPainter p(&m_pixmap, m_pOptions->m_bRightToLeftLanguage, width(), fontWidth); - p.setFont( font() ); - p.QPainter::fillRect( rect(), m_pOptions->m_bgColor ); - - //int visibleLines = height() / fontHeight; - - int lastVisibleLine = m_firstLine + getNofVisibleLines() + 5; - 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 + m_bPaintingAllowed = bPaintingAllowed; + if(!m_bPaintingAllowed) + { + m_currentMergeLineIt = m_mergeLineList.end(); + reset(); + } + update(); +} - if ( mlIt == m_currentMergeLineIt ) rangeMark |= 4; // Mark of the current line +void MergeResultWindow::paintEvent(QPaintEvent*) +{ + if(m_pDiff3LineList == 0 || !m_bPaintingAllowed) + return; - QString s; - s = mel.getString( this ); + bool bOldSelectionContainsData = m_selection.bSelectionContainsData; + const QFontMetrics& fm = fontMetrics(); + int fontWidth = fm.width('0'); - writeLine( p, line, s, mel.src(), ml.mergeDetails, rangeMark, - mel.isModified(), mel.isRemoved(), ml.bWhiteSpaceConflict ); - } - ++line; + if(!m_bCursorUpdate) // Don't redraw everything for blinking cursor? + { + m_selection.bSelectionContainsData = false; + if(size() != m_pixmap.size()) + m_pixmap = QPixmap(size()); + + MyPainter p(&m_pixmap, m_pOptions->m_bRightToLeftLanguage, width(), fontWidth); + p.setFont(font()); + p.QPainter::fillRect(rect(), m_pOptions->m_bgColor); + + //int visibleLines = height() / fontHeight; + + int lastVisibleLine = m_firstLine + getNofVisibleLines() + 5; + int line = 0; + MergeLineList::iterator mlIt = m_mergeLineList.begin(); + for(mlIt = m_mergeLineList.begin(); mlIt != m_mergeLineList.end(); ++mlIt) + { + MergeLine& ml = *mlIt; + if(line > lastVisibleLine || line + ml.mergeEditLineList.size() < m_firstLine) + { + line += ml.mergeEditLineList.size(); + } + else + { + MergeEditLineList::iterator melIt; + for(melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt) + { + if(line >= m_firstLine && line <= lastVisibleLine) + { + MergeEditLine& mel = *melIt; + MergeEditLineList::iterator melIt1 = melIt; + ++melIt1; + + int rangeMark = 0; + if(melIt == ml.mergeEditLineList.begin()) rangeMark |= 1; // Begin range mark + if(melIt1 == ml.mergeEditLineList.end()) rangeMark |= 2; // End range mark + + if(mlIt == m_currentMergeLineIt) rangeMark |= 4; // Mark of the current line + + QString s; + s = mel.getString(this); + + writeLine(p, line, s, mel.src(), ml.mergeDetails, rangeMark, + mel.isModified(), mel.isRemoved(), ml.bWhiteSpaceConflict); + } + ++line; + } } - } - } + } - if ( line != m_nofLines ) - { - m_nofLines = line; - assert( m_nofLines == m_totalSize ); + if(line != m_nofLines) + { + m_nofLines = line; + assert(m_nofLines == m_totalSize); - emit resizeSignal(); - } + emit resizeSignal(); + } - p.end(); - } + p.end(); + } - QPainter painter(this); + QPainter painter(this); - if ( !m_bCursorUpdate ) - painter.drawPixmap(0,0, m_pixmap); - else - { - painter.drawPixmap(0,0, m_pixmap ); // Draw everything. (Internally cursor rect is clipped anyway.) - m_bCursorUpdate = false; - } - painter.end(); + if(!m_bCursorUpdate) + painter.drawPixmap(0, 0, m_pixmap); + else + { + painter.drawPixmap(0, 0, m_pixmap); // Draw everything. (Internally cursor rect is clipped anyway.) + m_bCursorUpdate = false; + } + painter.end(); - if ( m_bCursorOn && hasFocus() && m_cursorYPos>=m_firstLine ) - { - QPainter painter(this); + if(m_bCursorOn && hasFocus() && m_cursorYPos >= m_firstLine) + { + QPainter painter(this); - painter.setPen( m_pOptions->m_fgColor ); + painter.setPen(m_pOptions->m_fgColor); - QString str = getString(m_cursorYPos); - QTextLayout textLayout( str, font(), this ); - getTextLayoutForLine( m_cursorYPos, str, textLayout ); - textLayout.drawCursor( &painter, QPointF(0, (m_cursorYPos-m_firstLine)*fontMetrics().lineSpacing()), m_cursorXPos ); - } + QString str = getString(m_cursorYPos); + QTextLayout textLayout(str, font(), this); + getTextLayoutForLine(m_cursorYPos, str, textLayout); + textLayout.drawCursor(&painter, QPointF(0, (m_cursorYPos - m_firstLine) * fontMetrics().lineSpacing()), m_cursorXPos); + } - if( !bOldSelectionContainsData && m_selection.bSelectionContainsData ) - emit newSelection(); + if(!bOldSelectionContainsData && m_selection.bSelectionContainsData) + emit newSelection(); } void MergeResultWindow::updateSourceMask() { - int srcMask=0; - int enabledMask = 0; - if( !hasFocus() || m_pDiff3LineList==0 || !m_bPaintingAllowed || m_currentMergeLineIt == m_mergeLineList.end() ) - { - srcMask = 0; - enabledMask = 0; - } - else - { - enabledMask = m_pldC==0 ? 3 : 7; - MergeLine& ml = *m_currentMergeLineIt; - - srcMask = 0; - bool bModified = false; - MergeEditLineList::iterator melIt; - for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt ) - { - MergeEditLine& mel = *melIt; - if ( mel.src()==1 ) srcMask |= 1; - if ( mel.src()==2 ) srcMask |= 2; - if ( mel.src()==3 ) srcMask |= 4; - if ( mel.isModified() || !mel.isEditableText() ) bModified = true; - } - - if ( ml.mergeDetails == eNoChange ) - { - srcMask = 0; - enabledMask = bModified ? 1 : 0; - } - } + int srcMask = 0; + int enabledMask = 0; + if(!hasFocus() || m_pDiff3LineList == 0 || !m_bPaintingAllowed || m_currentMergeLineIt == m_mergeLineList.end()) + { + srcMask = 0; + enabledMask = 0; + } + else + { + enabledMask = m_pldC == 0 ? 3 : 7; + MergeLine& ml = *m_currentMergeLineIt; + + srcMask = 0; + bool bModified = false; + MergeEditLineList::iterator melIt; + for(melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt) + { + MergeEditLine& mel = *melIt; + if(mel.src() == 1) srcMask |= 1; + if(mel.src() == 2) srcMask |= 2; + if(mel.src() == 3) srcMask |= 4; + if(mel.isModified() || !mel.isEditableText()) bModified = true; + } + + if(ml.mergeDetails == eNoChange) + { + srcMask = 0; + enabledMask = bModified ? 1 : 0; + } + } - emit sourceMask( srcMask, enabledMask ); + emit sourceMask(srcMask, enabledMask); } -void MergeResultWindow::focusInEvent( QFocusEvent* e ) +void MergeResultWindow::focusInEvent(QFocusEvent* e) { - updateSourceMask(); - QWidget::focusInEvent(e); + updateSourceMask(); + QWidget::focusInEvent(e); } -int MergeResultWindow::convertToLine( int y ) +int MergeResultWindow::convertToLine(int y) { - const QFontMetrics& fm = fontMetrics(); - int fontHeight = fm.lineSpacing(); - int topLineYOffset = 0; + const QFontMetrics& fm = fontMetrics(); + int fontHeight = fm.lineSpacing(); + int topLineYOffset = 0; - int yOffset = topLineYOffset - m_firstLine * fontHeight; + int yOffset = topLineYOffset - m_firstLine * fontHeight; - int line = min2( ( y - yOffset ) / fontHeight, m_totalSize-1 ); - return line; + int line = min2((y - yOffset) / fontHeight, m_totalSize - 1); + return line; } -void MergeResultWindow::mousePressEvent ( QMouseEvent* e ) +void MergeResultWindow::mousePressEvent(QMouseEvent* e) { - m_bCursorOn = true; + m_bCursorOn = true; - int xOffset = getTextXOffset(); + int xOffset = getTextXOffset(); - int line = convertToLine( e->y() ); - QString s = getString(line); - QTextLayout textLayout( s, font(), this ); - getTextLayoutForLine( line, s, textLayout ); - int pos = textLayout.lineAt(0).xToCursor( e->x() - textLayout.position().x() ); + int line = convertToLine(e->y()); + QString s = getString(line); + QTextLayout textLayout(s, font(), this); + getTextLayoutForLine(line, s, textLayout); + int pos = textLayout.lineAt(0).xToCursor(e->x() - textLayout.position().x()); - bool bLMB = e->button() == Qt::LeftButton; - bool bMMB = e->button() == Qt::MidButton; - bool bRMB = e->button() == Qt::RightButton; + bool bLMB = e->button() == Qt::LeftButton; + bool bMMB = e->button() == Qt::MidButton; + bool bRMB = e->button() == Qt::RightButton; - if ( (bLMB && (e->x()< xOffset) ) || bRMB ) // Fast range selection - { - m_cursorXPos = 0; - m_cursorOldXPixelPos = 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; + if((bLMB && (e->x() < xOffset)) || bRMB) // Fast range selection + { + m_cursorXPos = 0; + m_cursorOldXPixelPos = 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->QInputEvent::modifiers() & Qt::ShiftModifier) + { + 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_cursorXPixelPos = textLayout.lineAt(0).cursorToX(pos); + if(m_pOptions->m_bRightToLeftLanguage) + m_cursorXPixelPos += textLayout.position().x() - m_horizScrollOffset; + m_cursorOldXPixelPos = m_cursorXPixelPos; + m_cursorYPos = line; - 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->QInputEvent::modifiers() & Qt::ShiftModifier ) - { - 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_cursorXPixelPos = textLayout.lineAt(0).cursorToX( pos ); - if ( m_pOptions->m_bRightToLeftLanguage ) - m_cursorXPixelPos += textLayout.position().x() - m_horizScrollOffset; - m_cursorOldXPixelPos = m_cursorXPixelPos; - 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_cursorOldXPixelPos = m_cursorXPixelPos; - m_cursorYPos = line; - - pasteClipboard( true ); - } -} - -void MergeResultWindow::mouseDoubleClickEvent( QMouseEvent* e ) -{ - if ( e->button() == Qt::LeftButton ) - { - int line = convertToLine( e->y() ); - QString s = getString(line); - QTextLayout textLayout( s, font(), this ); - getTextLayoutForLine( line, s, textLayout ); - int pos = textLayout.lineAt(0).xToCursor( e->x() - textLayout.position().x() ); - m_cursorXPos = pos; - m_cursorOldXPixelPos = m_cursorXPixelPos; - m_cursorYPos = line; - - if ( !s.isEmpty() ) - { - int pos1, pos2; - - calcTokenPos( s, pos, pos1, pos2, m_pOptions->m_tabSize ); - - resetSelection(); - m_selection.start( line, convertToPosOnScreen( s, pos1, m_pOptions->m_tabSize ) ); - m_selection.end( line, convertToPosOnScreen( s, pos2, m_pOptions->m_tabSize ) ); - - update(); - // emit selectionEnd() happens in the mouseReleaseEvent. - } - } -} - -void MergeResultWindow::mouseReleaseEvent ( QMouseEvent * e ) -{ - if ( e->button() == Qt::LeftButton ) - { - if (m_delayedDrawTimer) - { - killTimer(m_delayedDrawTimer); - m_delayedDrawTimer = 0; - } - - if (m_selection.firstLine != -1 ) - { - emit selectionEnd(); - } - } -} - -void MergeResultWindow::mouseMoveEvent ( QMouseEvent * e ) -{ - int line = convertToLine( e->y() ); - QString s = getString(line); - QTextLayout textLayout( s, font(), this ); - getTextLayoutForLine( line, s, textLayout ); - int pos = textLayout.lineAt(0).xToCursor( e->x() - textLayout.position().x() ); - m_cursorXPos = pos; - m_cursorOldXPixelPos = m_cursorXPixelPos; - m_cursorYPos = line; - if (m_selection.firstLine != -1 ) - { - m_selection.end( line, pos ); - myUpdate(0); - - //showStatusLine( line, m_winIdx, m_pFilename, m_pDiff3LineList, m_pStatusBar ); - - // Scroll because mouse moved out of the window - const QFontMetrics& fm = fontMetrics(); - int fontWidth = fm.width('0'); - int topLineYOffset = 0; - int deltaX=0; - int deltaY=0; - if ( ! m_pOptions->m_bRightToLeftLanguage ) - { - if ( e->x() < getTextXOffset() ) deltaX=-1; - if ( e->x() > width() ) deltaX=+1; - } - else - { - if ( e->x() > width()-1-getTextXOffset() ) deltaX=-1; - if ( e->x() < fontWidth ) deltaX=+1; - } - if ( e->y() < topLineYOffset ) deltaY=-1; - if ( e->y() > height() ) deltaY=+1; - m_scrollDeltaX = deltaX; - m_scrollDeltaY = deltaY; - if ( deltaX != 0 || deltaY!= 0) - { - emit scroll( deltaX, deltaY ); - } - } + 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_cursorOldXPixelPos = m_cursorXPixelPos; + m_cursorYPos = line; + + pasteClipboard(true); + } +} + +void MergeResultWindow::mouseDoubleClickEvent(QMouseEvent* e) +{ + if(e->button() == Qt::LeftButton) + { + int line = convertToLine(e->y()); + QString s = getString(line); + QTextLayout textLayout(s, font(), this); + getTextLayoutForLine(line, s, textLayout); + int pos = textLayout.lineAt(0).xToCursor(e->x() - textLayout.position().x()); + m_cursorXPos = pos; + m_cursorOldXPixelPos = m_cursorXPixelPos; + m_cursorYPos = line; + + if(!s.isEmpty()) + { + int pos1, pos2; + + calcTokenPos(s, pos, pos1, pos2, m_pOptions->m_tabSize); + + resetSelection(); + m_selection.start(line, convertToPosOnScreen(s, pos1, m_pOptions->m_tabSize)); + m_selection.end(line, convertToPosOnScreen(s, pos2, m_pOptions->m_tabSize)); + + update(); + // emit selectionEnd() happens in the mouseReleaseEvent. + } + } } +void MergeResultWindow::mouseReleaseEvent(QMouseEvent* e) +{ + if(e->button() == Qt::LeftButton) + { + if(m_delayedDrawTimer) + { + killTimer(m_delayedDrawTimer); + m_delayedDrawTimer = 0; + } + + if(m_selection.firstLine != -1) + { + emit selectionEnd(); + } + } +} + +void MergeResultWindow::mouseMoveEvent(QMouseEvent* e) +{ + int line = convertToLine(e->y()); + QString s = getString(line); + QTextLayout textLayout(s, font(), this); + getTextLayoutForLine(line, s, textLayout); + int pos = textLayout.lineAt(0).xToCursor(e->x() - textLayout.position().x()); + m_cursorXPos = pos; + m_cursorOldXPixelPos = m_cursorXPixelPos; + m_cursorYPos = line; + if(m_selection.firstLine != -1) + { + m_selection.end(line, pos); + myUpdate(0); + + //showStatusLine( line, m_winIdx, m_pFilename, m_pDiff3LineList, m_pStatusBar ); + + // Scroll because mouse moved out of the window + const QFontMetrics& fm = fontMetrics(); + int fontWidth = fm.width('0'); + int topLineYOffset = 0; + int deltaX = 0; + int deltaY = 0; + if(!m_pOptions->m_bRightToLeftLanguage) + { + if(e->x() < getTextXOffset()) deltaX = -1; + if(e->x() > width()) deltaX = +1; + } + else + { + if(e->x() > width() - 1 - getTextXOffset()) deltaX = -1; + if(e->x() < fontWidth) deltaX = +1; + } + if(e->y() < topLineYOffset) deltaY = -1; + if(e->y() > height()) deltaY = +1; + m_scrollDeltaX = deltaX; + m_scrollDeltaY = deltaY; + if(deltaX != 0 || deltaY != 0) + { + emit scroll(deltaX, deltaY); + } + } +} void MergeResultWindow::slotCursorUpdate() { - m_cursorTimer.stop(); - m_bCursorOn = !m_bCursorOn; + m_cursorTimer.stop(); + m_bCursorOn = !m_bCursorOn; - if ( isVisible() ) - { - m_bCursorUpdate = true; + if(isVisible()) + { + m_bCursorUpdate = true; - const QFontMetrics& fm = fontMetrics(); - int topLineYOffset = 0; - int yOffset = ( m_cursorYPos - m_firstLine ) * fm.lineSpacing() + topLineYOffset; + const QFontMetrics& fm = fontMetrics(); + int topLineYOffset = 0; + int yOffset = (m_cursorYPos - m_firstLine) * fm.lineSpacing() + topLineYOffset; - repaint( 0, yOffset, width(), fm.lineSpacing()+2 ); + repaint(0, yOffset, width(), fm.lineSpacing() + 2); - m_bCursorUpdate=false; - } + m_bCursorUpdate = false; + } - m_cursorTimer.start(500); + m_cursorTimer.start(500); } - -void MergeResultWindow::wheelEvent( QWheelEvent* e ) +void MergeResultWindow::wheelEvent(QWheelEvent* e) { - int d = -e->delta()*QApplication::wheelScrollLines()/120; + int d = -e->delta() * QApplication::wheelScrollLines() / 120; e->accept(); - scroll( 0, min2(d, getNofVisibleLines()) ); -} - -bool MergeResultWindow::event( QEvent* e ) -{ - if ( e->type()==QEvent::KeyPress ) - { - QKeyEvent *ke = static_cast(e); - if (ke->key() == Qt::Key_Tab) - { - // special tab handling here to avoid moving focus - keyPressEvent( ke ); - return true; - } - } - return QWidget::event(e); -} -void MergeResultWindow::keyPressEvent( QKeyEvent* e ) -{ - int y = m_cursorYPos; - MergeLineList::iterator mlIt; - MergeEditLineList::iterator melIt; - calcIteratorFromLineNr( y, mlIt, melIt ); - - QString str = melIt->getString( this ); - int x = convertToPosInText( str, m_cursorXPos, m_pOptions->m_tabSize ); - - QTextLayout textLayoutOrig( str, font(), this ); - getTextLayoutForLine( y, str, textLayoutOrig ); - - bool bCtrl = ( e->QInputEvent::modifiers() & Qt::ControlModifier ) != 0 ; - bool bShift = ( e->QInputEvent::modifiers() & Qt::ShiftModifier ) != 0 ; - #ifdef _WIN32 - bool bAlt = ( e->QInputEvent::modifiers() & Qt::AltModifier ) != 0 ; - if ( bCtrl && bAlt ){ bCtrl=false; bAlt=false; } // AltGr-Key pressed. - #endif - - bool bYMoveKey = false; - // Special keys - switch ( e->key() ) - { - case Qt::Key_Escape: break; - //case Key_Tab: break; - case Qt::Key_Backtab: break; - case Qt::Key_Delete: - { - if ( deleteSelection2( str, x, y, mlIt, melIt )) break; - if( !melIt->isEditableText() ) break; - if (x>=(int)str.length()) - { - if ( ytype() == QEvent::KeyPress) + { + QKeyEvent* ke = static_cast(e); + if(ke->key() == Qt::Key_Tab) + { + // special tab handling here to avoid moving focus + keyPressEvent(ke); + return true; + } + } + return QWidget::event(e); +} +void MergeResultWindow::keyPressEvent(QKeyEvent* e) +{ + int y = m_cursorYPos; + MergeLineList::iterator mlIt; + MergeEditLineList::iterator melIt; + calcIteratorFromLineNr(y, mlIt, melIt); + + QString str = melIt->getString(this); + int x = convertToPosInText(str, m_cursorXPos, m_pOptions->m_tabSize); + + QTextLayout textLayoutOrig(str, font(), this); + getTextLayoutForLine(y, str, textLayoutOrig); + + bool bCtrl = (e->QInputEvent::modifiers() & Qt::ControlModifier) != 0; + bool bShift = (e->QInputEvent::modifiers() & Qt::ShiftModifier) != 0; +#ifdef _WIN32 + bool bAlt = (e->QInputEvent::modifiers() & Qt::AltModifier) != 0; + if(bCtrl && bAlt) { + bCtrl = false; + bAlt = false; + } // AltGr-Key pressed. +#endif + + bool bYMoveKey = false; + // Special keys + switch(e->key()) + { + case Qt::Key_Escape: + break; + //case Key_Tab: break; + case Qt::Key_Backtab: + break; + case Qt::Key_Delete: + { + if(deleteSelection2(str, x, y, mlIt, melIt)) break; + if(!melIt->isEditableText()) break; + if(x >= (int)str.length()) + { + if(y < m_totalSize - 1) { - setModified(); - MergeLineList::iterator mlIt1; - MergeEditLineList::iterator melIt1; - calcIteratorFromLineNr( y+1, mlIt1, melIt1 ); - if ( melIt1->isEditableText() ) - { - QString s2 = melIt1->getString( this ); - melIt->setString( str + s2 ); - - // Remove the line - if ( mlIt1->mergeEditLineList.size()>1 ) - mlIt1->mergeEditLineList.erase( melIt1 ); - else - melIt1->setRemoved(); - } + setModified(); + MergeLineList::iterator mlIt1; + MergeEditLineList::iterator melIt1; + calcIteratorFromLineNr(y + 1, mlIt1, melIt1); + if(melIt1->isEditableText()) + { + QString s2 = melIt1->getString(this); + melIt->setString(str + s2); + + // Remove the line + if(mlIt1->mergeEditLineList.size() > 1) + mlIt1->mergeEditLineList.erase(melIt1); + else + melIt1->setRemoved(); + } } - } - else - { + } + else + { QString s = str.left(x); - s += str.midRef( x+1 ); - melIt->setString( s ); + s += str.midRef(x + 1); + melIt->setString(s); setModified(); - } - break; - } - case Qt::Key_Backspace: - { - if ( deleteSelection2( str, x, y, mlIt, melIt )) break; - if( !melIt->isEditableText() ) break; - if (x==0) - { - if ( y>0 ) + } + break; + } + case Qt::Key_Backspace: + { + if(deleteSelection2(str, x, y, mlIt, melIt)) break; + if(!melIt->isEditableText()) break; + if(x == 0) + { + if(y > 0) { - setModified(); - MergeLineList::iterator mlIt1; - MergeEditLineList::iterator melIt1; - calcIteratorFromLineNr( y-1, mlIt1, melIt1 ); - if ( melIt1->isEditableText() ) - { - QString s1 = melIt1->getString( this ); - melIt1->setString( s1 + str ); - - // Remove the previous line - if ( mlIt->mergeEditLineList.size()>1 ) - mlIt->mergeEditLineList.erase( melIt ); - else - melIt->setRemoved(); - - --y; - x=str.length(); - } + setModified(); + MergeLineList::iterator mlIt1; + MergeEditLineList::iterator melIt1; + calcIteratorFromLineNr(y - 1, mlIt1, melIt1); + if(melIt1->isEditableText()) + { + QString s1 = melIt1->getString(this); + melIt1->setString(s1 + str); + + // Remove the previous line + if(mlIt->mergeEditLineList.size() > 1) + mlIt->mergeEditLineList.erase(melIt); + else + melIt->setRemoved(); + + --y; + x = str.length(); + } } - } - else - { - QString s = str.left( x-1 ); - s += str.midRef( x ); + } + else + { + QString s = str.left(x - 1); + s += str.midRef(x); --x; - melIt->setString( s ); + melIt->setString(s); setModified(); - } - break; - } - case Qt::Key_Return: - case Qt::Key_Enter: - { - if( !melIt->isEditableText() ) break; - deleteSelection2( str, x, y, mlIt, melIt ); - setModified(); - QString indentation; - if ( m_pOptions->m_bAutoIndentation ) - { // calc last indentation + } + break; + } + case Qt::Key_Return: + case Qt::Key_Enter: + { + if(!melIt->isEditableText()) break; + deleteSelection2(str, x, y, mlIt, melIt); + setModified(); + QString indentation; + if(m_pOptions->m_bAutoIndentation) + { // calc last indentation MergeLineList::iterator mlIt1 = mlIt; MergeEditLineList::iterator melIt1 = melIt; for(;;) { - const QString s = melIt1->getString(this); - if ( !s.isEmpty() ) { - int i; - for( i=0; imergeEditLineList.begin() ) - --melIt1; - else - { - if ( mlIt1 == m_mergeLineList.begin() ) break; - --mlIt1; - melIt1 = mlIt1->mergeEditLineList.end(); - --melIt1; - } + const QString s = melIt1->getString(this); + if(!s.isEmpty()) { + int i; + for(i = 0; i < s.length(); ++i) { + if(s[i] != ' ' && s[i] != '\t') break; + } + if(i < s.length()) { + indentation = s.left(i); + break; + } + } + // Go back one line + if(melIt1 != mlIt1->mergeEditLineList.begin()) + --melIt1; + else + { + if(mlIt1 == m_mergeLineList.begin()) break; + --mlIt1; + melIt1 = mlIt1->mergeEditLineList.end(); + --melIt1; + } } - } - MergeEditLine mel(mlIt->id3l); // Associate every mel with an id3l, even if not really valid. - mel.setString( indentation + str.mid(x) ); + } + MergeEditLine mel(mlIt->id3l); // Associate every mel with an id3l, even if not really valid. + mel.setString(indentation + str.mid(x)); - if ( x<(int)str.length() ) // Cut off the old line. - { + if(x < (int)str.length()) // Cut off the old line. + { // Since ps possibly points into melIt->str, first copy it into a temporary. QString temp = str.left(x); - melIt->setString( temp ); - } - - ++melIt; - mlIt->mergeEditLineList.insert( melIt, mel ); - x = indentation.length(); - ++y; - break; - } - case Qt::Key_Insert: m_bInsertMode = !m_bInsertMode; break; - case Qt::Key_Pause: break; - case Qt::Key_Print: break; - case Qt::Key_SysReq: break; - case Qt::Key_Home: x=0; if(bCtrl){y=0; } break; // cursor movement - case Qt::Key_End: x=INT_MAX; if(bCtrl){y=INT_MAX;} break; - - case Qt::Key_Left: - case Qt::Key_Right: - if ( (e->key()==Qt::Key_Left) != m_pOptions->m_bRightToLeftLanguage ) - { - if ( !bCtrl ) + melIt->setString(temp); + } + + ++melIt; + mlIt->mergeEditLineList.insert(melIt, mel); + x = indentation.length(); + ++y; + break; + } + case Qt::Key_Insert: + m_bInsertMode = !m_bInsertMode; + break; + case Qt::Key_Pause: + break; + case Qt::Key_Print: + break; + case Qt::Key_SysReq: + break; + case Qt::Key_Home: + x = 0; + if(bCtrl) { + y = 0; + } + break; // cursor movement + case Qt::Key_End: + x = INT_MAX; + if(bCtrl) { + y = INT_MAX; + } + break; + + case Qt::Key_Left: + case Qt::Key_Right: + if((e->key() == Qt::Key_Left) != m_pOptions->m_bRightToLeftLanguage) + { + if(!bCtrl) { - int newX = textLayoutOrig.previousCursorPosition(x); - if( newX == x && y>0 ){--y; x=INT_MAX;} - else { x = newX; } + int newX = textLayoutOrig.previousCursorPosition(x); + if(newX == x && y > 0) { + --y; + x = INT_MAX; + } + else + { + x = newX; + } } else { - while( x>0 && (str[x-1]==' ' || str[x-1]=='\t') ) - { - int newX = textLayoutOrig.previousCursorPosition(x); - if ( newX==x ) break; - x = newX; - } - while( x>0 && (str[x-1]!=' ' && str[x-1]!='\t') ) - { - int newX = textLayoutOrig.previousCursorPosition(x); - if ( newX==x ) break; - x = newX; - } + while(x > 0 && (str[x - 1] == ' ' || str[x - 1] == '\t')) + { + int newX = textLayoutOrig.previousCursorPosition(x); + if(newX == x) break; + x = newX; + } + while(x > 0 && (str[x - 1] != ' ' && str[x - 1] != '\t')) + { + int newX = textLayoutOrig.previousCursorPosition(x); + if(newX == x) break; + x = newX; + } } - } - else - { - if ( !bCtrl ) + } + else + { + if(!bCtrl) { - int newX = textLayoutOrig.nextCursorPosition(x); - if( newX == x && ytext(); - if( t.isEmpty() || bCtrl ) - { e->ignore(); return; } - else - { - if( bCtrl ) + } + break; + + case Qt::Key_Up: + if(!bCtrl) { + --y; + bYMoveKey = true; + } + break; + case Qt::Key_Down: + if(!bCtrl) { + ++y; + bYMoveKey = true; + } + break; + case Qt::Key_PageUp: + if(!bCtrl) { + y -= getNofVisibleLines(); + bYMoveKey = true; + } + break; + case Qt::Key_PageDown: + if(!bCtrl) { + y += getNofVisibleLines(); + bYMoveKey = true; + } + break; + default: + { + QString t = e->text(); + if(t.isEmpty() || bCtrl) + { + e->ignore(); + return; + } + else + { + if(bCtrl) { - e->ignore(); return; + e->ignore(); + return; } else { - if( !melIt->isEditableText() ) break; - deleteSelection2( str, x, y, mlIt, melIt ); - - setModified(); - // Characters to insert - QString s=str; - if ( t[0]=='\t' && m_pOptions->m_bReplaceTabs ) - { - int spaces = (m_cursorXPos / m_pOptions->m_tabSize + 1)*m_pOptions->m_tabSize - m_cursorXPos; - t.fill( ' ', spaces ); - } - if ( m_bInsertMode ) - s.insert( x, t ); - else - s.replace( x, t.length(), t ); - - melIt->setString( s ); - x += t.length(); - bShift = false; + if(!melIt->isEditableText()) break; + deleteSelection2(str, x, y, mlIt, melIt); + + setModified(); + // Characters to insert + QString s = str; + if(t[0] == '\t' && m_pOptions->m_bReplaceTabs) + { + int spaces = (m_cursorXPos / m_pOptions->m_tabSize + 1) * m_pOptions->m_tabSize - m_cursorXPos; + t.fill(' ', spaces); + } + if(m_bInsertMode) + s.insert(x, t); + else + s.replace(x, t.length(), t); + + melIt->setString(s); + x += t.length(); + bShift = false; } - } - } - } - - y = minMaxLimiter( y, 0, m_totalSize-1 ); - - calcIteratorFromLineNr( y, mlIt, melIt ); - str = melIt->getString( this ); - - x = minMaxLimiter( x, 0, (int)str.length() ); - - int newFirstLine = m_firstLine; - int newHorizScrollOffset = m_horizScrollOffset; - - if ( y m_firstLine + getNofVisibleLines() ) - newFirstLine = y - getNofVisibleLines(); - - - QTextLayout textLayout( str, font(), this ); - getTextLayoutForLine( m_cursorYPos, str, textLayout ); - - // try to preserve cursor x pixel position when moving to another line - if (bYMoveKey) - { - if ( m_pOptions->m_bRightToLeftLanguage ) - x = textLayout.lineAt(0).xToCursor( m_cursorOldXPixelPos - (textLayout.position().x() - m_horizScrollOffset)); - else - x = textLayout.lineAt(0).xToCursor( m_cursorOldXPixelPos ); - } - - m_cursorXPixelPos = textLayout.lineAt(0).cursorToX( x ); - int hF = 1; // horizontal factor - if ( m_pOptions->m_bRightToLeftLanguage ) - { - m_cursorXPixelPos += textLayout.position().x() - m_horizScrollOffset; - hF=-1; - } - int cursorWidth = 5; - if ( m_cursorXPixelPos < hF * m_horizScrollOffset ) - newHorizScrollOffset = hF * m_cursorXPixelPos; - else if ( m_cursorXPixelPos > hF * m_horizScrollOffset + getVisibleTextAreaWidth() - cursorWidth ) - newHorizScrollOffset = hF * (m_cursorXPixelPos - (getVisibleTextAreaWidth() - cursorWidth )); - - int newCursorX = x; - if ( bShift ) - { - if (m_selection.firstLine==-1) - m_selection.start( m_cursorYPos, m_cursorXPos ); - - m_selection.end( y, newCursorX ); - } - else - m_selection.reset(); - - m_cursorYPos = y; - m_cursorXPos = newCursorX; - - // TODO if width of current line exceeds the current maximum width then force recalculating the scrollbars - if ( textLayout.maximumWidth()>getMaxTextWidth() ) - { - m_maxTextWidth = textLayout.maximumWidth(); - emit resizeSignal(); - } - if ( ! bYMoveKey ) - m_cursorOldXPixelPos = m_cursorXPixelPos; - - m_bCursorOn = true; - m_cursorTimer.start(500); - - update(); - if ( newFirstLine!=m_firstLine || newHorizScrollOffset!=m_horizScrollOffset ) - { - scroll( newHorizScrollOffset-m_horizScrollOffset, newFirstLine-m_firstLine ); - return; - } -} + } + } + } -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); -} + y = minMaxLimiter(y, 0, m_totalSize - 1); + calcIteratorFromLineNr(y, mlIt, melIt); + str = melIt->getString(this); -QString MergeResultWindow::getSelection() -{ - QString selectionString; - - int line = 0; - MergeLineList::iterator mlIt = m_mergeLineList.begin(); - for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt) - { - MergeLine& ml = *mlIt; - MergeEditLineList::iterator melIt; - for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt ) - { - MergeEditLine& mel = *melIt; - - if ( m_selection.lineWithin(line) ) - { - int outPos = 0; - if (mel.isEditableText()) - { - const QString str = mel.getString( this ); + x = minMaxLimiter(x, 0, (int)str.length()); - // Consider tabs + int newFirstLine = m_firstLine; + int newHorizScrollOffset = m_horizScrollOffset; - for( int i=0; im_tabSize ); - } + if(y < m_firstLine) + newFirstLine = y; + else if(y > m_firstLine + getNofVisibleLines()) + newFirstLine = y - getNofVisibleLines(); - if( m_selection.within( line, outPos ) ) - { - selectionString += str[i]; - } + QTextLayout textLayout(str, font(), this); + getTextLayoutForLine(m_cursorYPos, str, textLayout); - outPos += spaces; - } - } - else if ( mel.isConflict() ) + // try to preserve cursor x pixel position when moving to another line + if(bYMoveKey) + { + if(m_pOptions->m_bRightToLeftLanguage) + x = textLayout.lineAt(0).xToCursor(m_cursorOldXPixelPos - (textLayout.position().x() - m_horizScrollOffset)); + else + x = textLayout.lineAt(0).xToCursor(m_cursorOldXPixelPos); + } + + m_cursorXPixelPos = textLayout.lineAt(0).cursorToX(x); + int hF = 1; // horizontal factor + if(m_pOptions->m_bRightToLeftLanguage) + { + m_cursorXPixelPos += textLayout.position().x() - m_horizScrollOffset; + hF = -1; + } + int cursorWidth = 5; + if(m_cursorXPixelPos < hF * m_horizScrollOffset) + newHorizScrollOffset = hF * m_cursorXPixelPos; + else if(m_cursorXPixelPos > hF * m_horizScrollOffset + getVisibleTextAreaWidth() - cursorWidth) + newHorizScrollOffset = hF * (m_cursorXPixelPos - (getVisibleTextAreaWidth() - cursorWidth)); + + int newCursorX = x; + if(bShift) + { + if(m_selection.firstLine == -1) + m_selection.start(m_cursorYPos, m_cursorXPos); + + m_selection.end(y, newCursorX); + } + else + m_selection.reset(); + + m_cursorYPos = y; + m_cursorXPos = newCursorX; + + // TODO if width of current line exceeds the current maximum width then force recalculating the scrollbars + if(textLayout.maximumWidth() > getMaxTextWidth()) + { + m_maxTextWidth = textLayout.maximumWidth(); + emit resizeSignal(); + } + if(!bYMoveKey) + m_cursorOldXPixelPos = m_cursorXPixelPos; + + m_bCursorOn = true; + m_cursorTimer.start(500); + + update(); + if(newFirstLine != m_firstLine || newHorizScrollOffset != m_horizScrollOffset) + { + scroll(newHorizScrollOffset - m_horizScrollOffset, newFirstLine - m_firstLine); + return; + } +} + +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) { - selectionString += i18n(""); + --line; + if(line < 0) return; } + } + } + assert(false); +} + +QString MergeResultWindow::getSelection() +{ + QString selectionString; - if( m_selection.within( line, outPos ) ) + 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)) { - #ifdef _WIN32 - selectionString += '\r'; - #endif - selectionString += '\n'; + int outPos = 0; + if(mel.isEditableText()) + { + const QString str = mel.getString(this); + + // Consider tabs + + for(int i = 0; i < str.length(); ++i) + { + int spaces = 1; + if(str[i] == '\t') + { + spaces = tabber(outPos, m_pOptions->m_tabSize); + } + + if(m_selection.within(line, outPos)) + { + selectionString += str[i]; + } + + outPos += spaces; + } + } + else if(mel.isConflict()) + { + selectionString += i18n(""); + } + + if(m_selection.within(line, outPos)) + { +#ifdef _WIN32 + selectionString += '\r'; +#endif + selectionString += '\n'; + } } - } - ++line; - } - } + ++line; + } + } - return selectionString; + return selectionString; } -bool MergeResultWindow::deleteSelection2( QString& s, int& x, int& y, - MergeLineList::iterator& mlIt, MergeEditLineList::iterator& melIt ) +bool MergeResultWindow::deleteSelection2(QString& s, int& x, int& y, + MergeLineList::iterator& mlIt, MergeEditLineList::iterator& melIt) { - if (m_selection.firstLine!=-1 && m_selection.bSelectionContainsData ) - { - deleteSelection(); - y = m_cursorYPos; - calcIteratorFromLineNr( y, mlIt, melIt ); - s = melIt->getString( this ); - x = convertToPosInText( s, m_cursorXPos, m_pOptions->m_tabSize ); - return true; - } - return false; + if(m_selection.firstLine != -1 && m_selection.bSelectionContainsData) + { + deleteSelection(); + y = m_cursorYPos; + calcIteratorFromLineNr(y, mlIt, melIt); + s = melIt->getString(this); + x = convertToPosInText(s, m_cursorXPos, m_pOptions->m_tabSize); + return true; + } + return false; } void MergeResultWindow::deleteSelection() { - if ( m_selection.firstLine==-1 || !m_selection.bSelectionContainsData ) - { - return; - } - setModified(); - - int line = 0; - MergeLineList::iterator mlItFirst; - MergeEditLineList::iterator melItFirst; - QString firstLineString; - - int firstLine = -1; - int lastLine = -1; - - MergeLineList::iterator mlIt; - for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt) - { - MergeLine& ml = *mlIt; - MergeEditLineList::iterator melIt; - for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt ) - { - MergeEditLine& mel = *melIt; - - if ( mel.isEditableText() && m_selection.lineWithin(line) ) - { - if ( firstLine==-1 ) - firstLine = line; - lastLine = line; - } - - ++line; - } - } - - if ( firstLine == -1 ) - { - return; // Nothing to delete. - } - - line = 0; - for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt) - { - MergeLine& ml = *mlIt; - MergeEditLineList::iterator melIt, melIt1; - for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ) - { - MergeEditLine& mel = *melIt; - melIt1 = melIt; - ++melIt1; - - if ( mel.isEditableText() && m_selection.lineWithin(line) ) - { - QString lineString = mel.getString( this ); - - int firstPosInLine = m_selection.firstPosInLine(line); - int lastPosInLine = m_selection.lastPosInLine(line); - - if ( line==firstLine ) - { - mlItFirst = mlIt; - melItFirst = melIt; - int pos = convertToPosInText( lineString, firstPosInLine, m_pOptions->m_tabSize ); - firstLineString = lineString.left( pos ); - } + if(m_selection.firstLine == -1 || !m_selection.bSelectionContainsData) + { + return; + } + setModified(); + + int line = 0; + MergeLineList::iterator mlItFirst; + MergeEditLineList::iterator melItFirst; + QString firstLineString; + + int firstLine = -1; + int lastLine = -1; - if ( line==lastLine ) + 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)) { - // This is the last line in the selection - int pos = convertToPosInText( lineString, lastPosInLine, m_pOptions->m_tabSize ); - firstLineString += lineString.midRef( pos ); // rest of line - melItFirst->setString( firstLineString ); + if(firstLine == -1) + firstLine = line; + lastLine = line; } - if ( line!=firstLine ) + ++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)) { - // Remove the line - if ( mlIt->mergeEditLineList.size()>1 ) - mlIt->mergeEditLineList.erase( melIt ); - else - melIt->setRemoved(); + QString lineString = mel.getString(this); + + int firstPosInLine = m_selection.firstPosInLine(line); + int lastPosInLine = m_selection.lastPosInLine(line); + + if(line == firstLine) + { + mlItFirst = mlIt; + melItFirst = melIt; + int pos = convertToPosInText(lineString, firstPosInLine, m_pOptions->m_tabSize); + firstLineString = lineString.left(pos); + } + + if(line == lastLine) + { + // This is the last line in the selection + int pos = convertToPosInText(lineString, lastPosInLine, m_pOptions->m_tabSize); + firstLineString += lineString.midRef(pos); // rest of line + melItFirst->setString(firstLineString); + } + + if(line != firstLine) + { + // Remove the line + if(mlIt->mergeEditLineList.size() > 1) + mlIt->mergeEditLineList.erase(melIt); + else + melIt->setRemoved(); + } } - } - - ++line; - melIt = melIt1; - } - } - - m_cursorYPos = m_selection.beginLine(); - m_cursorXPos = m_selection.beginPos(); - m_cursorOldXPixelPos = m_cursorXPixelPos; - - m_selection.reset(); -} - -void MergeResultWindow::pasteClipboard( bool bFromSelection ) -{ - if (m_selection.firstLine != -1 ) - deleteSelection(); - - setModified(); - - int y = m_cursorYPos; - MergeLineList::iterator mlIt; - MergeEditLineList::iterator melIt, melItAfter; - calcIteratorFromLineNr( y, mlIt, melIt ); - melItAfter = melIt; - ++melItAfter; - QString str = melIt->getString( this ); - int x = convertToPosInText( str, m_cursorXPos, m_pOptions->m_tabSize ); - - if ( !QApplication::clipboard()->supportsSelection() ) - bFromSelection = false; - - QString clipBoard = QApplication::clipboard()->text( bFromSelection ? QClipboard::Selection : QClipboard::Clipboard ); - - QString currentLine = str.left(x); - QString endOfLine = str.mid(x); - int i; - int len = clipBoard.length(); - for( i=0; isetString( currentLine ); - MergeEditLine mel(mlIt->id3l); // Associate every mel with an id3l, even if not really valid. - melIt = mlIt->mergeEditLineList.insert( melItAfter, mel ); - currentLine = ""; - x=0; - ++y; - } - else - { - currentLine += c; - ++x; - } - } - - currentLine += endOfLine; - melIt->setString( currentLine ); - - m_cursorYPos = y; - m_cursorXPos = convertToPosOnScreen( currentLine, x, m_pOptions->m_tabSize ); - m_cursorOldXPixelPos = m_cursorXPixelPos; - - update(); + + ++line; + melIt = melIt1; + } + } + + m_cursorYPos = m_selection.beginLine(); + m_cursorXPos = m_selection.beginPos(); + m_cursorOldXPixelPos = m_cursorXPixelPos; + + m_selection.reset(); +} + +void MergeResultWindow::pasteClipboard(bool bFromSelection) +{ + if(m_selection.firstLine != -1) + deleteSelection(); + + setModified(); + + int y = m_cursorYPos; + MergeLineList::iterator mlIt; + MergeEditLineList::iterator melIt, melItAfter; + calcIteratorFromLineNr(y, mlIt, melIt); + melItAfter = melIt; + ++melItAfter; + QString str = melIt->getString(this); + int x = convertToPosInText(str, m_cursorXPos, m_pOptions->m_tabSize); + + if(!QApplication::clipboard()->supportsSelection()) + bFromSelection = false; + + QString clipBoard = QApplication::clipboard()->text(bFromSelection ? QClipboard::Selection : QClipboard::Clipboard); + + QString currentLine = str.left(x); + QString endOfLine = str.mid(x); + int i; + int len = clipBoard.length(); + for(i = 0; i < len; ++i) + { + QChar c = clipBoard[i]; + if(c == '\r') continue; + if(c == '\n') + { + melIt->setString(currentLine); + MergeEditLine mel(mlIt->id3l); // Associate every mel with an id3l, even if not really valid. + melIt = mlIt->mergeEditLineList.insert(melItAfter, mel); + currentLine = ""; + x = 0; + ++y; + } + else + { + currentLine += c; + ++x; + } + } + + currentLine += endOfLine; + melIt->setString(currentLine); + + m_cursorYPos = y; + m_cursorXPos = convertToPosOnScreen(currentLine, x, m_pOptions->m_tabSize); + m_cursorOldXPixelPos = m_cursorXPixelPos; + + update(); } void MergeResultWindow::resetSelection() { - m_selection.reset(); - update(); + m_selection.reset(); + update(); } void MergeResultWindow::setModified(bool bModified) { - if (bModified != m_bModified) - { - m_bModified = bModified; - emit modifiedChanged(m_bModified); - } + if(bModified != m_bModified) + { + m_bModified = bModified; + emit modifiedChanged(m_bModified); + } } /// Saves and returns true when successful. -bool MergeResultWindow::saveDocument( const QString& fileName, QTextCodec* pEncoding, e_LineEndStyle eLineEndStyle ) -{ - // Are still conflicts somewhere? - if ( getNrOfUnsolvedConflicts()>0 ) - { - KMessageBox::error( this, - i18n("Not all conflicts are solved yet.\n" - "File not saved.\n"), - i18n("Conflicts Left")); - return false; - } - - if ( eLineEndStyle==eLineEndStyleConflict || eLineEndStyle==eLineEndStyleUndefined ) - { - KMessageBox::error( this, - i18n("There is a line end style conflict. Please choose the line end style manually.\n" - "File not saved.\n"), - i18n("Conflicts Left")); - return false; - } - - update(); - - FileAccess file( fileName, true /*bWantToWrite*/ ); - if ( m_pOptions->m_bDmCreateBakFiles && file.exists() ) - { - bool bSuccess = file.createBackup(".orig"); - if ( !bSuccess ) - { - KMessageBox::error( this, file.getStatusText() + i18n("\n\nCreating backup failed. File not saved."), i18n("File Save Error") ); - return false; - } - } - - QByteArray dataArray; - QTextStream textOutStream(&dataArray, QIODevice::WriteOnly); - if ( pEncoding->name()=="UTF-8" ) - textOutStream.setGenerateByteOrderMark( false ); // Shouldn't be necessary. Bug in Qt or docs - else - textOutStream.setGenerateByteOrderMark( true ); // Only for UTF-16 - textOutStream.setCodec( pEncoding ); - - int line = 0; - MergeLineList::iterator mlIt = m_mergeLineList.begin(); - for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt) - { - MergeLine& ml = *mlIt; - MergeEditLineList::iterator melIt; - for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt ) - { - MergeEditLine& mel = *melIt; - - if ( mel.isEditableText() ) - { - QString str = mel.getString( this ); - - if (line>0) // Prepend line feed, but not for first line +bool MergeResultWindow::saveDocument(const QString& fileName, QTextCodec* pEncoding, e_LineEndStyle eLineEndStyle) +{ + // Are still conflicts somewhere? + if(getNrOfUnsolvedConflicts() > 0) + { + KMessageBox::error(this, + i18n("Not all conflicts are solved yet.\n" + "File not saved.\n"), + i18n("Conflicts Left")); + return false; + } + + if(eLineEndStyle == eLineEndStyleConflict || eLineEndStyle == eLineEndStyleUndefined) + { + KMessageBox::error(this, + i18n("There is a line end style conflict. Please choose the line end style manually.\n" + "File not saved.\n"), + i18n("Conflicts Left")); + return false; + } + + update(); + + FileAccess file(fileName, true /*bWantToWrite*/); + if(m_pOptions->m_bDmCreateBakFiles && file.exists()) + { + bool bSuccess = file.createBackup(".orig"); + if(!bSuccess) + { + KMessageBox::error(this, file.getStatusText() + i18n("\n\nCreating backup failed. File not saved."), i18n("File Save Error")); + return false; + } + } + + QByteArray dataArray; + QTextStream textOutStream(&dataArray, QIODevice::WriteOnly); + if(pEncoding->name() == "UTF-8") + textOutStream.setGenerateByteOrderMark(false); // Shouldn't be necessary. Bug in Qt or docs + else + textOutStream.setGenerateByteOrderMark(true); // Only for UTF-16 + textOutStream.setCodec(pEncoding); + + int line = 0; + MergeLineList::iterator mlIt = m_mergeLineList.begin(); + for(mlIt = m_mergeLineList.begin(); mlIt != m_mergeLineList.end(); ++mlIt) + { + MergeLine& ml = *mlIt; + MergeEditLineList::iterator melIt; + for(melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt) + { + MergeEditLine& mel = *melIt; + + if(mel.isEditableText()) { - if ( eLineEndStyle == eLineEndStyleDos ) - { str.prepend("\r\n"); } - else - { str.prepend("\n"); } + QString str = mel.getString(this); + + if(line > 0) // Prepend line feed, but not for first line + { + if(eLineEndStyle == eLineEndStyleDos) + { + str.prepend("\r\n"); + } + else + { + str.prepend("\n"); + } + } + + textOutStream << str; + ++line; } + } + } + textOutStream.flush(); + bool bSuccess = file.writeFile(dataArray.data(), dataArray.size()); + if(!bSuccess) + { + KMessageBox::error(this, i18n("Error while writing."), i18n("File Save Error")); + return false; + } - textOutStream << str; - ++line; - } - } - } - textOutStream.flush(); - bool bSuccess = file.writeFile( dataArray.data(), dataArray.size() ); - if ( ! bSuccess ) - { - KMessageBox::error( this, i18n("Error while writing."), i18n("File Save Error") ); - return false; - } - - setModified( false ); - update(); - - return true; -} - -QString MergeResultWindow::getString( int lineIdx ) -{ - MergeResultWindow::MergeLineList::iterator mlIt; - MergeResultWindow::MergeEditLineList::iterator melIt; - calcIteratorFromLineNr( lineIdx, mlIt, melIt ); - QString s = melIt->getString( this ); - return s; -} - -bool MergeResultWindow::findString( const QString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive ) -{ - int it = d3vLine; - int endIt = bDirDown ? getNofLines() : -1; - int step = bDirDown ? 1 : -1; - int startPos = posInLine; - - for( ; it!=endIt; it+=step ) - { - QString line = getString( it ); - if ( !line.isEmpty() ) - { - int pos = line.indexOf( s, startPos, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive ); - if ( pos != -1 ) - { - d3vLine = it; - posInLine = pos; - return true; - } + setModified(false); + update(); - startPos = 0; - } - } - return false; + return true; } -void MergeResultWindow::setSelection( int firstLine, int startPos, int lastLine, int endPos ) +QString MergeResultWindow::getString(int lineIdx) { - if ( lastLine >= getNofLines() ) - { - lastLine = getNofLines()-1; - QString s = getString( lastLine ); - endPos = s.length(); - } - m_selection.reset(); - m_selection.start( firstLine, convertToPosOnScreen( getString(firstLine), startPos, m_pOptions->m_tabSize ) ); - m_selection.end( lastLine, convertToPosOnScreen( getString(lastLine), endPos, m_pOptions->m_tabSize ) ); - update(); + MergeResultWindow::MergeLineList::iterator mlIt; + MergeResultWindow::MergeEditLineList::iterator melIt; + calcIteratorFromLineNr(lineIdx, mlIt, melIt); + QString s = melIt->getString(this); + return s; } -Overview::Overview( Options* pOptions ) +bool MergeResultWindow::findString(const QString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive) +{ + int it = d3vLine; + int endIt = bDirDown ? getNofLines() : -1; + int step = bDirDown ? 1 : -1; + int startPos = posInLine; + + for(; it != endIt; it += step) + { + QString line = getString(it); + if(!line.isEmpty()) + { + int pos = line.indexOf(s, startPos, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive); + if(pos != -1) + { + d3vLine = it; + posInLine = pos; + return true; + } + + startPos = 0; + } + } + return false; +} + +void MergeResultWindow::setSelection(int firstLine, int startPos, int lastLine, int endPos) +{ + if(lastLine >= getNofLines()) + { + lastLine = getNofLines() - 1; + QString s = getString(lastLine); + endPos = s.length(); + } + m_selection.reset(); + m_selection.start(firstLine, convertToPosOnScreen(getString(firstLine), startPos, m_pOptions->m_tabSize)); + m_selection.end(lastLine, convertToPosOnScreen(getString(lastLine), endPos, m_pOptions->m_tabSize)); + update(); +} + +Overview::Overview(Options* pOptions) //: QWidget( pParent, 0, Qt::WNoAutoErase ) { - m_pDiff3LineList = 0; - m_pOptions = pOptions; - m_bTripleDiff = false; - m_eOverviewMode = eOMNormal; - m_nofLines = 1; - m_bPaintingAllowed = false; - setFixedWidth(20); + m_pDiff3LineList = 0; + m_pOptions = pOptions; + m_bTripleDiff = false; + m_eOverviewMode = eOMNormal; + m_nofLines = 1; + m_bPaintingAllowed = false; + setFixedWidth(20); } -void Overview::init( Diff3LineList* pDiff3LineList, bool bTripleDiff ) +void Overview::init(Diff3LineList* pDiff3LineList, bool bTripleDiff) { - m_pDiff3LineList = pDiff3LineList; - m_bTripleDiff = bTripleDiff; - m_pixmap = QPixmap( QSize(0,0) ); // make sure that a redraw happens - update(); + m_pDiff3LineList = pDiff3LineList; + m_bTripleDiff = bTripleDiff; + m_pixmap = QPixmap(QSize(0, 0)); // make sure that a redraw happens + update(); } void Overview::reset() { - m_pDiff3LineList = 0; + m_pDiff3LineList = 0; } void Overview::slotRedraw() { - m_pixmap = QPixmap( QSize(0,0) ); // make sure that a redraw happens - update(); + m_pixmap = QPixmap(QSize(0, 0)); // make sure that a redraw happens + update(); } -void Overview::setRange( int firstLine, int pageHeight ) +void Overview::setRange(int firstLine, int pageHeight) { - m_firstLine = firstLine; - m_pageHeight = pageHeight; - update(); + m_firstLine = firstLine; + m_pageHeight = pageHeight; + update(); } -void Overview::setFirstLine( int firstLine ) +void Overview::setFirstLine(int firstLine) { - m_firstLine = firstLine; - update(); + m_firstLine = firstLine; + update(); } -void Overview::setOverviewMode( e_OverviewMode eOverviewMode ) +void Overview::setOverviewMode(e_OverviewMode eOverviewMode) { - m_eOverviewMode = eOverviewMode; - slotRedraw(); + m_eOverviewMode = eOverviewMode; + slotRedraw(); } Overview::e_OverviewMode Overview::getOverviewMode() { - return m_eOverviewMode; + return m_eOverviewMode; } -void Overview::mousePressEvent( QMouseEvent* e ) +void Overview::mousePressEvent(QMouseEvent* e) { - int h = height()-1; - int h1 = h * m_pageHeight / max2(1,m_nofLines)+3; - if ( h>0 ) - emit setLine( ( e->y() - h1/2 )*m_nofLines/h ); + int h = height() - 1; + int h1 = h * m_pageHeight / max2(1, m_nofLines) + 3; + if(h > 0) + emit setLine((e->y() - h1 / 2) * m_nofLines / h); } -void Overview::mouseMoveEvent( QMouseEvent* e ) +void Overview::mouseMoveEvent(QMouseEvent* e) { - mousePressEvent(e); + mousePressEvent(e); } -void Overview::setPaintingAllowed( bool bAllowPainting ) +void Overview::setPaintingAllowed(bool bAllowPainting) { - if (m_bPaintingAllowed != bAllowPainting) - { - m_bPaintingAllowed = bAllowPainting; - if ( m_bPaintingAllowed ) update(); - else reset(); - } + if(m_bPaintingAllowed != bAllowPainting) + { + m_bPaintingAllowed = bAllowPainting; + if(m_bPaintingAllowed) + update(); + else + reset(); + } } -void Overview::drawColumn( QPainter& p, e_OverviewMode eOverviewMode, int x, int w, int h, int nofLines ) +void Overview::drawColumn(QPainter& p, e_OverviewMode eOverviewMode, int x, int w, int h, int nofLines) { - p.setPen(Qt::black); - p.drawLine( x, 0, x, h ); + p.setPen(Qt::black); + p.drawLine(x, 0, x, h); - if (nofLines==0) return; - - int line = 0; - int oldY = 0; - int oldConflictY = -1; - int wrapLineIdx=0; - Diff3LineList::const_iterator i; - for( i = m_pDiff3LineList->begin(); i!= m_pDiff3LineList->end(); ) - { - const Diff3Line& d3l = *i; - int y = h * (line+1) / nofLines; - e_MergeDetails md; - bool bConflict; - bool bLineRemoved; - int src; - mergeOneLine( d3l, md, bConflict, bLineRemoved, src, !m_bTripleDiff ); + if(nofLines == 0) return; - QColor c = m_pOptions->m_bgColor; - bool bWhiteSpaceChange = false; - //if( bConflict ) c=m_pOptions->m_colorForConflict; - //else - if ( eOverviewMode==eOMNormal ) - { - switch( md ) - { - case eDefault: - case eNoChange: - c = m_pOptions->m_bgColor; - break; + int line = 0; + int oldY = 0; + int oldConflictY = -1; + int wrapLineIdx = 0; + Diff3LineList::const_iterator i; + for(i = m_pDiff3LineList->begin(); i != m_pDiff3LineList->end();) + { + const Diff3Line& d3l = *i; + int y = h * (line + 1) / nofLines; + e_MergeDetails md; + bool bConflict; + bool bLineRemoved; + int src; + mergeOneLine(d3l, md, bConflict, bLineRemoved, src, !m_bTripleDiff); + + QColor c = m_pOptions->m_bgColor; + bool bWhiteSpaceChange = false; + //if( bConflict ) c=m_pOptions->m_colorForConflict; + //else + if(eOverviewMode == eOMNormal) + { + switch(md) + { + case eDefault: + case eNoChange: + c = m_pOptions->m_bgColor; + break; + + case eBAdded: + case eBDeleted: + case eBChanged: + c = bConflict ? m_pOptions->m_colorForConflict : m_pOptions->m_colorB; + bWhiteSpaceChange = d3l.bAEqB || (d3l.bWhiteLineA && d3l.bWhiteLineB); + break; + + case eCAdded: + case eCDeleted: + case eCChanged: + bWhiteSpaceChange = d3l.bAEqC || (d3l.bWhiteLineA && d3l.bWhiteLineC); + c = bConflict ? m_pOptions->m_colorForConflict : m_pOptions->m_colorC; + break; + + case eBCChanged: // conflict + case eBCChangedAndEqual: // possible conflict + case eBCDeleted: // possible conflict + case eBChanged_CDeleted: // conflict + case eCChanged_BDeleted: // conflict + case eBCAdded: // conflict + case eBCAddedAndEqual: // possible conflict + c = m_pOptions->m_colorForConflict; + break; + default: + assert(false); + break; + } + } + else if(eOverviewMode == eOMAvsB) + { + switch(md) + { + case eDefault: + case eNoChange: + case eCAdded: + case eCDeleted: + case eCChanged: + break; + default: + c = m_pOptions->m_colorForConflict; + bWhiteSpaceChange = d3l.bAEqB || (d3l.bWhiteLineA && d3l.bWhiteLineB); + break; + } + } + else if(eOverviewMode == eOMAvsC) + { + switch(md) + { + case eDefault: + case eNoChange: + case eBAdded: + case eBDeleted: + case eBChanged: + break; + default: + c = m_pOptions->m_colorForConflict; + bWhiteSpaceChange = d3l.bAEqC || (d3l.bWhiteLineA && d3l.bWhiteLineC); + break; + } + } + else if(eOverviewMode == eOMBvsC) + { + switch(md) + { + case eDefault: + case eNoChange: + case eBCChangedAndEqual: + case eBCDeleted: + case eBCAddedAndEqual: + break; + default: + c = m_pOptions->m_colorForConflict; + bWhiteSpaceChange = d3l.bBEqC || (d3l.bWhiteLineB && d3l.bWhiteLineC); + break; + } + } - case eBAdded: - case eBDeleted: - case eBChanged: - c = bConflict ? m_pOptions->m_colorForConflict : m_pOptions->m_colorB; - bWhiteSpaceChange = d3l.bAEqB || (d3l.bWhiteLineA && d3l.bWhiteLineB); - break; + int x2 = x; + int w2 = w; - case eCAdded: - case eCDeleted: - case eCChanged: - bWhiteSpaceChange = d3l.bAEqC || (d3l.bWhiteLineA && d3l.bWhiteLineC); - c = bConflict ? m_pOptions->m_colorForConflict : m_pOptions->m_colorC; - break; + if(!m_bTripleDiff) + { + if(d3l.lineA == -1 && d3l.lineB >= 0) + { + c = m_pOptions->m_colorA; + x2 = w / 2; + w2 = x2; + } + if(d3l.lineA >= 0 && d3l.lineB == -1) + { + c = m_pOptions->m_colorB; + w2 = w / 2; + } + } + + if(!bWhiteSpaceChange || m_pOptions->m_bShowWhiteSpace) + { + // Make sure that lines with conflict are not overwritten. + if(c == m_pOptions->m_colorForConflict) + { + p.fillRect(x2 + 1, oldY, w2, max2(1, y - oldY), bWhiteSpaceChange ? QBrush(c, Qt::Dense4Pattern) : QBrush(c)); + oldConflictY = oldY; + } + else if(c != m_pOptions->m_bgColor && oldY > oldConflictY) + { + p.fillRect(x2 + 1, oldY, w2, max2(1, y - oldY), bWhiteSpaceChange ? QBrush(c, Qt::Dense4Pattern) : QBrush(c)); + } + } - case eBCChanged: // conflict - case eBCChangedAndEqual: // possible conflict - case eBCDeleted: // possible conflict - case eBChanged_CDeleted: // conflict - case eCChanged_BDeleted: // conflict - case eBCAdded: // conflict - case eBCAddedAndEqual: // possible conflict - c=m_pOptions->m_colorForConflict; - break; - default: assert(false); break; - } - } - else if ( eOverviewMode==eOMAvsB ) - { - switch( md ) - { - case eDefault: - case eNoChange: - case eCAdded: - case eCDeleted: - case eCChanged: break; - default: c = m_pOptions->m_colorForConflict; - bWhiteSpaceChange = d3l.bAEqB || (d3l.bWhiteLineA && d3l.bWhiteLineB); - break; - } - } - else if ( eOverviewMode==eOMAvsC ) - { - switch( md ) - { - case eDefault: - case eNoChange: - case eBAdded: - case eBDeleted: - case eBChanged: break; - default: c = m_pOptions->m_colorForConflict; - bWhiteSpaceChange = d3l.bAEqC || (d3l.bWhiteLineA && d3l.bWhiteLineC); - break; - } - } - else if ( eOverviewMode==eOMBvsC ) - { - switch( md ) - { - case eDefault: - case eNoChange: - case eBCChangedAndEqual: - case eBCDeleted: - case eBCAddedAndEqual: break; - default: c=m_pOptions->m_colorForConflict; - bWhiteSpaceChange = d3l.bBEqC || (d3l.bWhiteLineB && d3l.bWhiteLineC); - break; - } - } - - int x2 = x; - int w2 = w; - - if ( ! m_bTripleDiff ) - { - if ( d3l.lineA == -1 && d3l.lineB>=0 ) - { - c = m_pOptions->m_colorA; - x2 = w/2; - w2 = x2; - } - if ( d3l.lineA >= 0 && d3l.lineB==-1 ) - { - c = m_pOptions->m_colorB; - w2 = w/2; - } - } - - if (!bWhiteSpaceChange || m_pOptions->m_bShowWhiteSpace ) - { - // Make sure that lines with conflict are not overwritten. - if ( c == m_pOptions->m_colorForConflict ) - { - p.fillRect(x2+1, oldY, w2, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Qt::Dense4Pattern) : QBrush(c) ); - oldConflictY = oldY; - } - else if ( c!=m_pOptions->m_bgColor && oldY>oldConflictY ) - { - p.fillRect(x2+1, oldY, w2, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Qt::Dense4Pattern) : QBrush(c) ); - } - } - - oldY = y; - - ++line; - if ( m_pOptions->m_bWordWrap ) - { - ++wrapLineIdx; - if(wrapLineIdx>=d3l.linesNeededForDisplay) - { - wrapLineIdx=0; + oldY = y; + + ++line; + if(m_pOptions->m_bWordWrap) + { + ++wrapLineIdx; + if(wrapLineIdx >= d3l.linesNeededForDisplay) + { + wrapLineIdx = 0; + ++i; + } + } + else + { ++i; - } - } - else - { - ++i; - } - } -} - -void Overview::paintEvent( QPaintEvent* ) -{ - if (m_pDiff3LineList==0 || !m_bPaintingAllowed ) return; - int h = height()-1; - int w = width(); - - - if ( m_pixmap.size() != size() ) - { - if ( m_pOptions->m_bWordWrap ) - { - m_nofLines = 0; - Diff3LineList::const_iterator i; - for( i = m_pDiff3LineList->begin(); i!= m_pDiff3LineList->end(); ++i ) - { - m_nofLines += i->linesNeededForDisplay; - } - } - else - { - m_nofLines = m_pDiff3LineList->size(); - } - - m_pixmap = QPixmap( size() ); - - QPainter p(&m_pixmap); - p.fillRect( rect(), m_pOptions->m_bgColor ); - - if ( !m_bTripleDiff || m_eOverviewMode == eOMNormal ) - { - drawColumn( p, eOMNormal, 0, w, h, m_nofLines ); - } - else - { - drawColumn( p, eOMNormal, 0, w/2, h, m_nofLines ); - drawColumn( p, m_eOverviewMode, w/2, w/2, h, m_nofLines ); - } - } - - QPainter painter( this ); - painter.drawPixmap( 0,0, m_pixmap ); - - int y1 = h * m_firstLine / m_nofLines-1; - int h1 = h * m_pageHeight / m_nofLines+3; - painter.setPen(Qt::black); - painter.drawRect( 1, y1, w-1, h1 ); + } + } +} + +void Overview::paintEvent(QPaintEvent*) +{ + if(m_pDiff3LineList == 0 || !m_bPaintingAllowed) return; + int h = height() - 1; + int w = width(); + + if(m_pixmap.size() != size()) + { + if(m_pOptions->m_bWordWrap) + { + m_nofLines = 0; + Diff3LineList::const_iterator i; + for(i = m_pDiff3LineList->begin(); i != m_pDiff3LineList->end(); ++i) + { + m_nofLines += i->linesNeededForDisplay; + } + } + else + { + m_nofLines = m_pDiff3LineList->size(); + } + + m_pixmap = QPixmap(size()); + + QPainter p(&m_pixmap); + p.fillRect(rect(), m_pOptions->m_bgColor); + + if(!m_bTripleDiff || m_eOverviewMode == eOMNormal) + { + drawColumn(p, eOMNormal, 0, w, h, m_nofLines); + } + else + { + drawColumn(p, eOMNormal, 0, w / 2, h, m_nofLines); + drawColumn(p, m_eOverviewMode, w / 2, w / 2, h, m_nofLines); + } + } + + QPainter painter(this); + painter.drawPixmap(0, 0, m_pixmap); + + int y1 = h * m_firstLine / m_nofLines - 1; + int h1 = h * m_pageHeight / m_nofLines + 3; + painter.setPen(Qt::black); + painter.drawRect(1, y1, w - 1, h1); } WindowTitleWidget::WindowTitleWidget(Options* pOptions) { - m_pOptions = pOptions; - setAutoFillBackground(true); + m_pOptions = pOptions; + setAutoFillBackground(true); - QHBoxLayout* pHLayout = new QHBoxLayout(this); - pHLayout->setMargin(2); - pHLayout->setSpacing(2); + QHBoxLayout* pHLayout = new QHBoxLayout(this); + pHLayout->setMargin(2); + pHLayout->setSpacing(2); - m_pLabel = new QLabel(i18n("Output")+":"); - pHLayout->addWidget( m_pLabel ); + m_pLabel = new QLabel(i18n("Output") + ":"); + pHLayout->addWidget(m_pLabel); - m_pFileNameLineEdit = new QLineEdit(); - pHLayout->addWidget( m_pFileNameLineEdit, 6 ); - m_pFileNameLineEdit->installEventFilter( this ); - m_pFileNameLineEdit->setReadOnly( true ); + m_pFileNameLineEdit = new QLineEdit(); + pHLayout->addWidget(m_pFileNameLineEdit, 6); + m_pFileNameLineEdit->installEventFilter(this); + m_pFileNameLineEdit->setReadOnly(true); - //m_pBrowseButton = new QPushButton("..."); - //pHLayout->addWidget( m_pBrowseButton, 0 ); - //connect( m_pBrowseButton, SIGNAL(clicked()), this, SLOT(slotBrowseButtonClicked())); + //m_pBrowseButton = new QPushButton("..."); + //pHLayout->addWidget( m_pBrowseButton, 0 ); + //connect( m_pBrowseButton, SIGNAL(clicked()), this, SLOT(slotBrowseButtonClicked())); - m_pModifiedLabel = new QLabel(i18n("[Modified]")); - pHLayout->addWidget( m_pModifiedLabel ); - m_pModifiedLabel->setMinimumSize( m_pModifiedLabel->sizeHint() ); - m_pModifiedLabel->setText(""); + m_pModifiedLabel = new QLabel(i18n("[Modified]")); + pHLayout->addWidget(m_pModifiedLabel); + m_pModifiedLabel->setMinimumSize(m_pModifiedLabel->sizeHint()); + m_pModifiedLabel->setText(""); - pHLayout->addStretch(1); + pHLayout->addStretch(1); - m_pEncodingLabel = new QLabel(i18n("Encoding for saving")+":"); - pHLayout->addWidget( m_pEncodingLabel ); + m_pEncodingLabel = new QLabel(i18n("Encoding for saving") + ":"); + pHLayout->addWidget(m_pEncodingLabel); - m_pEncodingSelector = new QComboBox(); - m_pEncodingSelector->setSizeAdjustPolicy( QComboBox::AdjustToContents ); - pHLayout->addWidget( m_pEncodingSelector, 2 ); - setEncodings(0,0,0); + m_pEncodingSelector = new QComboBox(); + m_pEncodingSelector->setSizeAdjustPolicy(QComboBox::AdjustToContents); + pHLayout->addWidget(m_pEncodingSelector, 2); + setEncodings(0, 0, 0); - m_pLineEndStyleLabel = new QLabel( i18n("Line end style:") ); - pHLayout->addWidget( m_pLineEndStyleLabel ); - m_pLineEndStyleSelector = new QComboBox(); - m_pLineEndStyleSelector->setSizeAdjustPolicy( QComboBox::AdjustToContents ); - pHLayout->addWidget( m_pLineEndStyleSelector ); - setLineEndStyles(eLineEndStyleUndefined,eLineEndStyleUndefined,eLineEndStyleUndefined); + m_pLineEndStyleLabel = new QLabel(i18n("Line end style:")); + pHLayout->addWidget(m_pLineEndStyleLabel); + m_pLineEndStyleSelector = new QComboBox(); + m_pLineEndStyleSelector->setSizeAdjustPolicy(QComboBox::AdjustToContents); + pHLayout->addWidget(m_pLineEndStyleSelector); + setLineEndStyles(eLineEndStyleUndefined, eLineEndStyleUndefined, eLineEndStyleUndefined); } -void WindowTitleWidget::setFileName( const QString& fileName ) +void WindowTitleWidget::setFileName(const QString& fileName) { - m_pFileNameLineEdit->setText( QDir::toNativeSeparators(fileName) ); + m_pFileNameLineEdit->setText(QDir::toNativeSeparators(fileName)); } QString WindowTitleWidget::getFileName() { - return m_pFileNameLineEdit->text(); + return m_pFileNameLineEdit->text(); } //static QString getLineEndStyleName( e_LineEndStyle eLineEndStyle ) //{ // if ( eLineEndStyle == eLineEndStyleDos ) // return "DOS"; // else if ( eLineEndStyle == eLineEndStyleUnix ) // return "Unix"; // return QString(); //} -void WindowTitleWidget::setLineEndStyles( e_LineEndStyle eLineEndStyleA, e_LineEndStyle eLineEndStyleB, e_LineEndStyle eLineEndStyleC) -{ - m_pLineEndStyleSelector->clear(); - QString dosUsers; - if ( eLineEndStyleA == eLineEndStyleDos ) - dosUsers += "A"; - if ( eLineEndStyleB == eLineEndStyleDos ) - dosUsers += (dosUsers.isEmpty() ? "" : ", ") + QString("B"); - if ( eLineEndStyleC == eLineEndStyleDos ) - dosUsers += (dosUsers.isEmpty() ? "" : ", ") + QString("C"); - QString unxUsers; - if ( eLineEndStyleA == eLineEndStyleUnix ) - unxUsers += "A"; - if ( eLineEndStyleB == eLineEndStyleUnix ) - unxUsers += (unxUsers.isEmpty() ? "" : ", ") + QString("B"); - if ( eLineEndStyleC == eLineEndStyleUnix ) - unxUsers += (unxUsers.isEmpty() ? "" : ", ") + QString("C"); - - m_pLineEndStyleSelector->addItem( i18n("Unix") + (unxUsers.isEmpty() ? QString("") : " (" + unxUsers + ")" ) ); - m_pLineEndStyleSelector->addItem( i18n("DOS") + (dosUsers.isEmpty() ? QString("") : " (" + dosUsers + ")" ) ); - - e_LineEndStyle autoChoice = (e_LineEndStyle)m_pOptions->m_lineEndStyle; - - if ( m_pOptions->m_lineEndStyle == eLineEndStyleAutoDetect ) - { - if ( eLineEndStyleA != eLineEndStyleUndefined && eLineEndStyleB != eLineEndStyleUndefined && eLineEndStyleC != eLineEndStyleUndefined ) - { - if ( eLineEndStyleA == eLineEndStyleB ) - autoChoice = eLineEndStyleC; - else if ( eLineEndStyleA == eLineEndStyleC ) - autoChoice = eLineEndStyleB; - else - autoChoice = eLineEndStyleConflict; //conflict (not likely while only two values exist) - } - else - { - e_LineEndStyle c1, c2; - if ( eLineEndStyleA == eLineEndStyleUndefined ) { c1 = eLineEndStyleB; c2 = eLineEndStyleC; } - else if( eLineEndStyleB == eLineEndStyleUndefined ) { c1 = eLineEndStyleA; c2 = eLineEndStyleC; } - else /*if( eLineEndStyleC == eLineEndStyleUndefined )*/ { c1 = eLineEndStyleA; c2 = eLineEndStyleB; } - if ( c1 == c2 && c1!=eLineEndStyleUndefined ) - autoChoice = c1; - else - autoChoice = eLineEndStyleConflict; - } - } - - if ( autoChoice == eLineEndStyleUnix ) - m_pLineEndStyleSelector->setCurrentIndex(0); - else if ( autoChoice == eLineEndStyleDos ) - m_pLineEndStyleSelector->setCurrentIndex(1); - else if ( autoChoice == eLineEndStyleConflict ) - { - m_pLineEndStyleSelector->addItem( i18n("Conflict") ); - m_pLineEndStyleSelector->setCurrentIndex(2); - } -} - -e_LineEndStyle WindowTitleWidget::getLineEndStyle( ) -{ - - int current = m_pLineEndStyleSelector->currentIndex(); - if (current == 0) - return eLineEndStyleUnix; - else if (current == 1) - return eLineEndStyleDos; - else - return eLineEndStyleConflict; -} - -void WindowTitleWidget::setEncodings( QTextCodec* pCodecForA, QTextCodec* pCodecForB, QTextCodec* pCodecForC ) -{ - m_pEncodingSelector->clear(); - - // First sort codec names: - std::map names; - QList mibs = QTextCodec::availableMibs(); - foreach(int i, mibs) - { - QTextCodec* c = QTextCodec::codecForMib(i); - if ( c!=0 ) - names[QString(c->name())]=c; - } - - if ( pCodecForA ) - m_pEncodingSelector->addItem( i18n("Codec from") + " A: " + pCodecForA->name(), QVariant::fromValue((void*)pCodecForA) ); - if ( pCodecForB ) - m_pEncodingSelector->addItem( i18n("Codec from") + " B: " + pCodecForB->name(), QVariant::fromValue((void*)pCodecForB) ); - if ( pCodecForC ) - m_pEncodingSelector->addItem( i18n("Codec from") + " C: " + pCodecForC->name(), QVariant::fromValue((void*)pCodecForC) ); - - std::map::iterator it; - for(it=names.begin();it!=names.end();++it) - { - m_pEncodingSelector->addItem( it->first, QVariant::fromValue((void*)it->second) ); - } - m_pEncodingSelector->setMinimumSize( m_pEncodingSelector->sizeHint() ); - - if ( pCodecForC && pCodecForB && pCodecForA ) - { - if ( pCodecForA == pCodecForB ) - m_pEncodingSelector->setCurrentIndex( 2 ); // C - else if ( pCodecForA == pCodecForC ) - m_pEncodingSelector->setCurrentIndex( 1 ); // B - else - m_pEncodingSelector->setCurrentIndex( 2 ); // C - } - else if ( pCodecForA && pCodecForB ) - m_pEncodingSelector->setCurrentIndex( 1 ); // B - else - m_pEncodingSelector->setCurrentIndex( 0 ); +void WindowTitleWidget::setLineEndStyles(e_LineEndStyle eLineEndStyleA, e_LineEndStyle eLineEndStyleB, e_LineEndStyle eLineEndStyleC) +{ + m_pLineEndStyleSelector->clear(); + QString dosUsers; + if(eLineEndStyleA == eLineEndStyleDos) + dosUsers += "A"; + if(eLineEndStyleB == eLineEndStyleDos) + dosUsers += (dosUsers.isEmpty() ? "" : ", ") + QString("B"); + if(eLineEndStyleC == eLineEndStyleDos) + dosUsers += (dosUsers.isEmpty() ? "" : ", ") + QString("C"); + QString unxUsers; + if(eLineEndStyleA == eLineEndStyleUnix) + unxUsers += "A"; + if(eLineEndStyleB == eLineEndStyleUnix) + unxUsers += (unxUsers.isEmpty() ? "" : ", ") + QString("B"); + if(eLineEndStyleC == eLineEndStyleUnix) + unxUsers += (unxUsers.isEmpty() ? "" : ", ") + QString("C"); + + m_pLineEndStyleSelector->addItem(i18n("Unix") + (unxUsers.isEmpty() ? QString("") : " (" + unxUsers + ")")); + m_pLineEndStyleSelector->addItem(i18n("DOS") + (dosUsers.isEmpty() ? QString("") : " (" + dosUsers + ")")); + + e_LineEndStyle autoChoice = (e_LineEndStyle)m_pOptions->m_lineEndStyle; + + if(m_pOptions->m_lineEndStyle == eLineEndStyleAutoDetect) + { + if(eLineEndStyleA != eLineEndStyleUndefined && eLineEndStyleB != eLineEndStyleUndefined && eLineEndStyleC != eLineEndStyleUndefined) + { + if(eLineEndStyleA == eLineEndStyleB) + autoChoice = eLineEndStyleC; + else if(eLineEndStyleA == eLineEndStyleC) + autoChoice = eLineEndStyleB; + else + autoChoice = eLineEndStyleConflict; //conflict (not likely while only two values exist) + } + else + { + e_LineEndStyle c1, c2; + if(eLineEndStyleA == eLineEndStyleUndefined) { + c1 = eLineEndStyleB; + c2 = eLineEndStyleC; + } + else if(eLineEndStyleB == eLineEndStyleUndefined) + { + c1 = eLineEndStyleA; + c2 = eLineEndStyleC; + } + else /*if( eLineEndStyleC == eLineEndStyleUndefined )*/ + { + c1 = eLineEndStyleA; + c2 = eLineEndStyleB; + } + if(c1 == c2 && c1 != eLineEndStyleUndefined) + autoChoice = c1; + else + autoChoice = eLineEndStyleConflict; + } + } + + if(autoChoice == eLineEndStyleUnix) + m_pLineEndStyleSelector->setCurrentIndex(0); + else if(autoChoice == eLineEndStyleDos) + m_pLineEndStyleSelector->setCurrentIndex(1); + else if(autoChoice == eLineEndStyleConflict) + { + m_pLineEndStyleSelector->addItem(i18n("Conflict")); + m_pLineEndStyleSelector->setCurrentIndex(2); + } +} + +e_LineEndStyle WindowTitleWidget::getLineEndStyle() +{ + + int current = m_pLineEndStyleSelector->currentIndex(); + if(current == 0) + return eLineEndStyleUnix; + else if(current == 1) + return eLineEndStyleDos; + else + return eLineEndStyleConflict; +} + +void WindowTitleWidget::setEncodings(QTextCodec* pCodecForA, QTextCodec* pCodecForB, QTextCodec* pCodecForC) +{ + m_pEncodingSelector->clear(); + + // First sort codec names: + std::map names; + QList mibs = QTextCodec::availableMibs(); + foreach(int i, mibs) + { + QTextCodec* c = QTextCodec::codecForMib(i); + if(c != 0) + names[QString(c->name())] = c; + } + + if(pCodecForA) + m_pEncodingSelector->addItem(i18n("Codec from") + " A: " + pCodecForA->name(), QVariant::fromValue((void*)pCodecForA)); + if(pCodecForB) + m_pEncodingSelector->addItem(i18n("Codec from") + " B: " + pCodecForB->name(), QVariant::fromValue((void*)pCodecForB)); + if(pCodecForC) + m_pEncodingSelector->addItem(i18n("Codec from") + " C: " + pCodecForC->name(), QVariant::fromValue((void*)pCodecForC)); + + std::map::iterator it; + for(it = names.begin(); it != names.end(); ++it) + { + m_pEncodingSelector->addItem(it->first, QVariant::fromValue((void*)it->second)); + } + m_pEncodingSelector->setMinimumSize(m_pEncodingSelector->sizeHint()); + + if(pCodecForC && pCodecForB && pCodecForA) + { + if(pCodecForA == pCodecForB) + m_pEncodingSelector->setCurrentIndex(2); // C + else if(pCodecForA == pCodecForC) + m_pEncodingSelector->setCurrentIndex(1); // B + else + m_pEncodingSelector->setCurrentIndex(2); // C + } + else if(pCodecForA && pCodecForB) + m_pEncodingSelector->setCurrentIndex(1); // B + else + m_pEncodingSelector->setCurrentIndex(0); } QTextCodec* WindowTitleWidget::getEncoding() { - return (QTextCodec*)m_pEncodingSelector->itemData( m_pEncodingSelector->currentIndex() ).value(); + return (QTextCodec*)m_pEncodingSelector->itemData(m_pEncodingSelector->currentIndex()).value(); } void WindowTitleWidget::setEncoding(QTextCodec* pEncoding) { - int idx = m_pEncodingSelector->findText( pEncoding->name() ); - if (idx>=0) - m_pEncodingSelector->setCurrentIndex( idx ); + int idx = m_pEncodingSelector->findText(pEncoding->name()); + if(idx >= 0) + m_pEncodingSelector->setCurrentIndex(idx); } //void WindowTitleWidget::slotBrowseButtonClicked() //{ // QString current = m_pFileNameLineEdit->text(); // // QUrl newURL = KFileDialog::getSaveUrl( current, 0, this, i18n("Select file (not saving yet)")); // if ( !newURL.isEmpty() ) // { -// m_pFileNameLineEdit->setText( newURL.url() ); +// m_pFileNameLineEdit->setText( newURL.url() ); // } //} -void WindowTitleWidget::slotSetModified( bool bModified ) +void WindowTitleWidget::slotSetModified(bool bModified) { - m_pModifiedLabel->setText( bModified ? i18n("[Modified]") : "" ); + m_pModifiedLabel->setText(bModified ? i18n("[Modified]") : ""); } -bool WindowTitleWidget::eventFilter( QObject* o, QEvent* e ) +bool WindowTitleWidget::eventFilter(QObject* o, QEvent* e) { - if ( e->type()==QEvent::FocusIn || e->type()==QEvent::FocusOut ) - { - QPalette p = m_pLabel->palette(); + if(e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) + { + QPalette p = m_pLabel->palette(); + + QColor c1 = m_pOptions->m_fgColor; + QColor c2 = Qt::lightGray; + if(e->type() == QEvent::FocusOut) + c2 = m_pOptions->m_bgColor; - QColor c1 = m_pOptions->m_fgColor; - QColor c2 = Qt::lightGray; - if ( e->type()==QEvent::FocusOut ) - c2 = m_pOptions->m_bgColor; + p.setColor(QPalette::Window, c2); + setPalette(p); - p.setColor(QPalette::Window, c2); - setPalette( p ); + p.setColor(QPalette::WindowText, c1); + m_pLabel->setPalette(p); + m_pEncodingLabel->setPalette(p); + m_pEncodingSelector->setPalette(p); + } + if(o == m_pFileNameLineEdit && e->type() == QEvent::Drop) + { + QDropEvent* d = static_cast(e); - p.setColor(QPalette::WindowText, c1); - m_pLabel->setPalette( p ); - m_pEncodingLabel->setPalette( p ); - m_pEncodingSelector->setPalette( p ); - } - if (o == m_pFileNameLineEdit && e->type()==QEvent::Drop) - { - QDropEvent* d = static_cast(e); - - if ( d->mimeData()->hasUrls() ) - { - QList lst = d->mimeData()->urls(); + if(d->mimeData()->hasUrls()) + { + QList lst = d->mimeData()->urls(); - if ( lst.count() > 0 ) - { - static_cast(o)->setText( lst[0].toString() ); - static_cast(o)->setFocus(); - return true; - } - } - } - return false; + if(lst.count() > 0) + { + static_cast(o)->setText(lst[0].toString()); + static_cast(o)->setFocus(); + return true; + } + } + } + return false; } //#include "mergeresultwindow.moc" diff --git a/src/optiondialog.cpp b/src/optiondialog.cpp index 8b802b6..536106b 100644 --- a/src/optiondialog.cpp +++ b/src/optiondialog.cpp @@ -1,1998 +1,2043 @@ /* * kdiff3 - Text Diff And Merge Tool * Copyright (C) 2002-2009 Joachim Eibl, joachim.eibl at gmx.de * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. * */ +#include #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 #include -#include -#include +#include +#include +#include +#include -#include #include -#include -#include -#include +#include #include #include +#include +#include +#include #include -#include "optiondialog.h" #include "diff.h" +#include "optiondialog.h" #include "smalldialogs.h" #define KDIFF3_CONFIG_GROUP "KDiff3 Options" static QString s_historyEntryStartRegExpToolTip; static QString s_historyEntryStartSortKeyOrderToolTip; static QString s_autoMergeRegExpToolTip; static QString s_historyStartRegExpToolTip; void OptionDialog::addOptionItem(OptionItem* p) { - m_optionItemList.push_back(p); + m_optionItemList.push_back(p); } class OptionItem { -public: - OptionItem( OptionDialog* pOptionDialog, const QString& saveName ) - { - assert(pOptionDialog!=0); - pOptionDialog->addOptionItem( this ); - m_saveName = saveName; - m_bPreserved = false; - } - virtual ~OptionItem(){} - virtual void setToDefault()=0; - virtual void setToCurrent()=0; - virtual void apply()=0; - virtual void write(ValueMap*)=0; - virtual void read(ValueMap*)=0; - void doPreserve(){ if (!m_bPreserved){ m_bPreserved=true; preserve(); } } - void doUnpreserve(){ if( m_bPreserved ){ unpreserve(); } } - QString getSaveName(){return m_saveName;} -protected: - virtual void preserve()=0; - virtual void unpreserve()=0; - bool m_bPreserved; - QString m_saveName; + public: + OptionItem(OptionDialog* pOptionDialog, const QString& saveName) + { + assert(pOptionDialog != 0); + pOptionDialog->addOptionItem(this); + m_saveName = saveName; + m_bPreserved = false; + } + virtual ~OptionItem() {} + virtual void setToDefault() = 0; + virtual void setToCurrent() = 0; + virtual void apply() = 0; + virtual void write(ValueMap*) = 0; + virtual void read(ValueMap*) = 0; + void doPreserve() + { + if(!m_bPreserved) { + m_bPreserved = true; + preserve(); + } + } + void doUnpreserve() + { + if(m_bPreserved) { + unpreserve(); + } + } + QString getSaveName() { return m_saveName; } + + protected: + virtual void preserve() = 0; + virtual void unpreserve() = 0; + bool m_bPreserved; + QString m_saveName; }; template class OptionItemT : public OptionItem { -public: - OptionItemT( OptionDialog* pOptionDialog, const QString& saveName ) - : OptionItem(pOptionDialog,saveName ) - {} - -protected: - virtual void preserve(){ m_preservedVal = *m_pVar; } - virtual void unpreserve(){ *m_pVar = m_preservedVal; } - T* m_pVar; - T m_preservedVal; - T m_defaultVal; + public: + OptionItemT(OptionDialog* pOptionDialog, const QString& saveName) + : OptionItem(pOptionDialog, saveName) + { + } + + protected: + virtual void preserve() { m_preservedVal = *m_pVar; } + virtual void unpreserve() { *m_pVar = m_preservedVal; } + T* m_pVar; + T m_preservedVal; + T m_defaultVal; }; class OptionCheckBox : public QCheckBox, public OptionItemT { -public: - OptionCheckBox( QString text, bool bDefaultVal, const QString& saveName, bool* pbVar, - QWidget* pParent, OptionDialog* pOD ) - : QCheckBox( text, pParent ), OptionItemT( pOD, saveName ) - { - m_pVar = pbVar; - m_defaultVal = bDefaultVal; - } - void setToDefault(){ setChecked( m_defaultVal ); } - void setToCurrent(){ setChecked( *m_pVar ); } - void apply() { *m_pVar = isChecked(); } - void write(ValueMap* config){ config->writeEntry(m_saveName, *m_pVar ); } - void read (ValueMap* config){ *m_pVar = config->readBoolEntry( m_saveName, *m_pVar ); } -private: - OptionCheckBox( const OptionCheckBox& ); // private copy constructor without implementation + public: + OptionCheckBox(QString text, bool bDefaultVal, const QString& saveName, bool* pbVar, + QWidget* pParent, OptionDialog* pOD) + : QCheckBox(text, pParent), OptionItemT(pOD, saveName) + { + m_pVar = pbVar; + m_defaultVal = bDefaultVal; + } + void setToDefault() { setChecked(m_defaultVal); } + void setToCurrent() { setChecked(*m_pVar); } + void apply() { *m_pVar = isChecked(); } + void write(ValueMap* config) { config->writeEntry(m_saveName, *m_pVar); } + void read(ValueMap* config) { *m_pVar = config->readBoolEntry(m_saveName, *m_pVar); } + + private: + OptionCheckBox(const OptionCheckBox&); // private copy constructor without implementation }; class OptionRadioButton : public QRadioButton, public OptionItemT { -public: - OptionRadioButton( QString text, bool bDefaultVal, const QString& saveName, bool* pbVar, - QWidget* pParent, OptionDialog* pOD ) - : QRadioButton( text, pParent ), OptionItemT( pOD, saveName ) - { - m_pVar = pbVar; - m_defaultVal = bDefaultVal; - } - void setToDefault(){ setChecked( m_defaultVal ); } - void setToCurrent(){ setChecked( *m_pVar ); } - void apply() { *m_pVar = isChecked(); } - void write(ValueMap* config){ config->writeEntry(m_saveName, *m_pVar ); } - void read (ValueMap* config){ *m_pVar = config->readBoolEntry( m_saveName, *m_pVar ); } -private: - OptionRadioButton( const OptionRadioButton& ); // private copy constructor without implementation + public: + OptionRadioButton(QString text, bool bDefaultVal, const QString& saveName, bool* pbVar, + QWidget* pParent, OptionDialog* pOD) + : QRadioButton(text, pParent), OptionItemT(pOD, saveName) + { + m_pVar = pbVar; + m_defaultVal = bDefaultVal; + } + void setToDefault() { setChecked(m_defaultVal); } + void setToCurrent() { setChecked(*m_pVar); } + void apply() { *m_pVar = isChecked(); } + void write(ValueMap* config) { config->writeEntry(m_saveName, *m_pVar); } + void read(ValueMap* config) { *m_pVar = config->readBoolEntry(m_saveName, *m_pVar); } + + private: + OptionRadioButton(const OptionRadioButton&); // private copy constructor without implementation }; - -template +template class OptionT : public OptionItemT { -public: - OptionT( const T& defaultVal, const QString& saveName, T* pVar, OptionDialog* pOD ) - : OptionItemT( pOD, saveName ) - { - this->m_pVar = pVar; - *this->m_pVar = defaultVal; - } - OptionT( const QString& saveName, T* pVar, OptionDialog* pOD ) - : OptionItemT( pOD, saveName ) - { - this->m_pVar = pVar; - } - void setToDefault(){} - void setToCurrent(){} - void apply() {} - void write(ValueMap* vm){ writeEntry( vm, this->m_saveName, *this->m_pVar ); } - void read (ValueMap* vm){ *this->m_pVar = vm->readEntry ( this->m_saveName, *this->m_pVar ); } -private: - OptionT( const OptionT& ); // private copy constructor without implementation + public: + OptionT(const T& defaultVal, const QString& saveName, T* pVar, OptionDialog* pOD) + : OptionItemT(pOD, saveName) + { + this->m_pVar = pVar; + *this->m_pVar = defaultVal; + } + OptionT(const QString& saveName, T* pVar, OptionDialog* pOD) + : OptionItemT(pOD, saveName) + { + this->m_pVar = pVar; + } + void setToDefault() {} + void setToCurrent() {} + void apply() {} + void write(ValueMap* vm) { writeEntry(vm, this->m_saveName, *this->m_pVar); } + void read(ValueMap* vm) { *this->m_pVar = vm->readEntry(this->m_saveName, *this->m_pVar); } + + private: + OptionT(const OptionT&); // private copy constructor without implementation }; -template void writeEntry( ValueMap* vm, const QString& saveName, const T& v ) { - vm->writeEntry( saveName, v ); +template +void writeEntry(ValueMap* vm, const QString& saveName, const T& v) +{ + vm->writeEntry(saveName, v); } -static void writeEntry( ValueMap* vm, const QString& saveName, const QStringList& v ) { - vm->writeEntry( saveName, v); +static void writeEntry(ValueMap* vm, const QString& saveName, const QStringList& v) +{ + vm->writeEntry(saveName, v); } //static void readEntry(ValueMap* vm, const QString& saveName, bool& v ) { v = vm->readBoolEntry( saveName, v ); } //static void readEntry(ValueMap* vm, const QString& saveName, int& v ) { v = vm->readNumEntry( saveName, v ); } //static void readEntry(ValueMap* vm, const QString& saveName, QSize& v ) { v = vm->readSizeEntry( saveName, &v ); } //static void readEntry(ValueMap* vm, const QString& saveName, QPoint& v ) { v = vm->readPointEntry( saveName, &v ); } //static void readEntry(ValueMap* vm, const QString& saveName, QStringList& v ){ v = vm->readListEntry( saveName, QStringList(), '|' ); } typedef OptionT OptionToggleAction; -typedef OptionT OptionNum; +typedef OptionT OptionNum; typedef OptionT OptionPoint; typedef OptionT OptionSize; typedef OptionT OptionStringList; - -FontChooser::FontChooser( QWidget* pParent ) -: QGroupBox(pParent) +FontChooser::FontChooser(QWidget* pParent) + : QGroupBox(pParent) { - QVBoxLayout* pLayout = new QVBoxLayout(this); - m_pLabel = new QLabel(QString(), this); - pLayout->addWidget(m_pLabel); - - QChar visualTab(0x2192); - QChar visualSpace((ushort)0xb7); - m_pExampleTextEdit = new QPlainTextEdit(QString("The quick brown fox jumps over the river\n" - "but the little red hen escapes with a shiver.\n" - ":-)")+visualTab+visualSpace, this); - m_pExampleTextEdit->setFont(m_font); - m_pExampleTextEdit->setReadOnly(true); - pLayout->addWidget(m_pExampleTextEdit); - - m_pSelectFont = new QPushButton(i18n("Change Font"), this); - m_pSelectFont->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - connect(m_pSelectFont, SIGNAL(clicked()), this, SLOT(slotSelectFont())); - pLayout->addWidget(m_pSelectFont); - pLayout->setAlignment(m_pSelectFont, Qt::AlignRight); + QVBoxLayout* pLayout = new QVBoxLayout(this); + m_pLabel = new QLabel(QString(), this); + pLayout->addWidget(m_pLabel); + + QChar visualTab(0x2192); + QChar visualSpace((ushort)0xb7); + m_pExampleTextEdit = new QPlainTextEdit(QString("The quick brown fox jumps over the river\n" + "but the little red hen escapes with a shiver.\n" + ":-)") + + visualTab + visualSpace, + this); + m_pExampleTextEdit->setFont(m_font); + m_pExampleTextEdit->setReadOnly(true); + pLayout->addWidget(m_pExampleTextEdit); + + m_pSelectFont = new QPushButton(i18n("Change Font"), this); + m_pSelectFont->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(m_pSelectFont, SIGNAL(clicked()), this, SLOT(slotSelectFont())); + pLayout->addWidget(m_pSelectFont); + pLayout->setAlignment(m_pSelectFont, Qt::AlignRight); } QFont FontChooser::font() { - return m_font;//QFont("courier",10); + return m_font; //QFont("courier",10); } -void FontChooser::setFont( const QFont& font, bool ) +void FontChooser::setFont(const QFont& font, bool) { - m_font = font; - m_pExampleTextEdit->setFont( m_font ); - m_pLabel->setText(i18n("Font: %1, %2, %3\n\nExample:", m_font.family(), m_font.styleName(), m_font.pointSize())); + m_font = font; + m_pExampleTextEdit->setFont(m_font); + m_pLabel->setText(i18n("Font: %1, %2, %3\n\nExample:", m_font.family(), m_font.styleName(), m_font.pointSize())); - //update(); + //update(); } void FontChooser::slotSelectFont() { - bool bOk; - m_font = QFontDialog::getFont(&bOk, m_font ); - m_pExampleTextEdit->setFont( m_font ); - m_pLabel->setText(i18n("Font: %1, %2, %3\n\nExample:", m_font.family(), m_font.styleName(), m_font.pointSize())); + bool bOk; + m_font = QFontDialog::getFont(&bOk, m_font); + m_pExampleTextEdit->setFont(m_font); + m_pLabel->setText(i18n("Font: %1, %2, %3\n\nExample:", m_font.family(), m_font.styleName(), m_font.pointSize())); } - class OptionFontChooser : public FontChooser, public OptionItemT { -public: - OptionFontChooser( const QFont& defaultVal, const QString& saveName, QFont* pVar, QWidget* pParent, OptionDialog* pOD ) : - FontChooser( pParent ), - OptionItemT( pOD, saveName ) - { - m_pVar = pVar; - *m_pVar = defaultVal; - m_defaultVal = defaultVal; - } - void setToDefault(){ setFont( m_defaultVal, false ); } - void setToCurrent(){ setFont( *m_pVar, false ); } - void apply() { *m_pVar = font();} - void write(ValueMap* config){ config->writeEntry(m_saveName, *m_pVar ); } - void read (ValueMap* config){ *m_pVar = config->readFontEntry( m_saveName, m_pVar ); } -private: - OptionFontChooser( const OptionToggleAction& ); // private copy constructor without implementation + public: + OptionFontChooser(const QFont& defaultVal, const QString& saveName, QFont* pVar, QWidget* pParent, OptionDialog* pOD) : FontChooser(pParent), + OptionItemT(pOD, saveName) + { + m_pVar = pVar; + *m_pVar = defaultVal; + m_defaultVal = defaultVal; + } + void setToDefault() { setFont(m_defaultVal, false); } + void setToCurrent() { setFont(*m_pVar, false); } + void apply() { *m_pVar = font(); } + void write(ValueMap* config) { config->writeEntry(m_saveName, *m_pVar); } + void read(ValueMap* config) { *m_pVar = config->readFontEntry(m_saveName, m_pVar); } + + private: + OptionFontChooser(const OptionToggleAction&); // private copy constructor without implementation }; class OptionColorButton : public KColorButton, public OptionItemT { -public: - OptionColorButton( QColor defaultVal, const QString& saveName, QColor* pVar, QWidget* pParent, OptionDialog* pOD ) - : KColorButton( pParent ), OptionItemT( pOD, saveName ) - { - m_pVar = pVar; - m_defaultVal = defaultVal; - } - void setToDefault(){ setColor( m_defaultVal ); } - void setToCurrent(){ setColor( *m_pVar ); } - void apply() { *m_pVar = color(); } - void write(ValueMap* config){ config->writeEntry(m_saveName, *m_pVar ); } - void read (ValueMap* config){ *m_pVar = config->readColorEntry( m_saveName, m_pVar ); } -private: - OptionColorButton( const OptionColorButton& ); // private copy constructor without implementation + public: + OptionColorButton(QColor defaultVal, const QString& saveName, QColor* pVar, QWidget* pParent, OptionDialog* pOD) + : KColorButton(pParent), OptionItemT(pOD, saveName) + { + m_pVar = pVar; + m_defaultVal = defaultVal; + } + void setToDefault() { setColor(m_defaultVal); } + void setToCurrent() { setColor(*m_pVar); } + void apply() { *m_pVar = color(); } + void write(ValueMap* config) { config->writeEntry(m_saveName, *m_pVar); } + void read(ValueMap* config) { *m_pVar = config->readColorEntry(m_saveName, m_pVar); } + + private: + OptionColorButton(const OptionColorButton&); // private copy constructor without implementation }; class OptionLineEdit : public QComboBox, public OptionItemT { - public: - OptionLineEdit( const QString& defaultVal, const QString& saveName, QString* pVar, - QWidget* pParent, OptionDialog* pOD ) - : QComboBox( pParent ), OptionItemT( pOD, saveName ) - { - setMinimumWidth(50); - setEditable(true); - m_pVar = pVar; - m_defaultVal = defaultVal; - m_list.push_back(defaultVal); - insertText(); - } - void setToDefault() - { - setEditText( m_defaultVal ); - } - void setToCurrent() - { - setEditText( *m_pVar ); - } - void apply() - { - *m_pVar = currentText(); - insertText(); - } - void write(ValueMap* config) - { - config->writeEntry( m_saveName, m_list ); - } - void read(ValueMap* config) - { - m_list = config->readListEntry( m_saveName, QStringList( m_defaultVal ) ); - if( !m_list.empty() ) *m_pVar = m_list.front(); - clear(); - insertItems(0,m_list); - } - private: - void insertText() - { // Check if the text exists. If yes remove it and push it in as first element - QString current = currentText(); - m_list.removeAll( current ); - m_list.push_front( current ); - clear(); - if( m_list.size()>10 ) - m_list.erase( m_list.begin()+10, m_list.end() ); - insertItems(0,m_list); - } - OptionLineEdit( const OptionLineEdit& ); // private copy constructor without implementation - QStringList m_list; + public: + OptionLineEdit(const QString& defaultVal, const QString& saveName, QString* pVar, + QWidget* pParent, OptionDialog* pOD) + : QComboBox(pParent), OptionItemT(pOD, saveName) + { + setMinimumWidth(50); + setEditable(true); + m_pVar = pVar; + m_defaultVal = defaultVal; + m_list.push_back(defaultVal); + insertText(); + } + void setToDefault() + { + setEditText(m_defaultVal); + } + void setToCurrent() + { + setEditText(*m_pVar); + } + void apply() + { + *m_pVar = currentText(); + insertText(); + } + void write(ValueMap* config) + { + config->writeEntry(m_saveName, m_list); + } + void read(ValueMap* config) + { + m_list = config->readListEntry(m_saveName, QStringList(m_defaultVal)); + if(!m_list.empty()) *m_pVar = m_list.front(); + clear(); + insertItems(0, m_list); + } + + private: + void insertText() + { // Check if the text exists. If yes remove it and push it in as first element + QString current = currentText(); + m_list.removeAll(current); + m_list.push_front(current); + clear(); + if(m_list.size() > 10) + m_list.erase(m_list.begin() + 10, m_list.end()); + insertItems(0, m_list); + } + OptionLineEdit(const OptionLineEdit&); // private copy constructor without implementation + QStringList m_list; }; #if defined QT_NO_VALIDATOR #error No validator #endif class OptionIntEdit : public QLineEdit, public OptionItemT { -public: - OptionIntEdit( int defaultVal, const QString& saveName, int* pVar, int rangeMin, int rangeMax, - QWidget* pParent, OptionDialog* pOD ) - : QLineEdit( pParent ), OptionItemT( 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(ValueMap* config){ config->writeEntry(m_saveName, *m_pVar ); } - void read (ValueMap* config){ *m_pVar = config->readNumEntry( m_saveName, *m_pVar ); } -private: - OptionIntEdit( const OptionIntEdit& ); // private copy constructor without implementation + public: + OptionIntEdit(int defaultVal, const QString& saveName, int* pVar, int rangeMin, int rangeMax, + QWidget* pParent, OptionDialog* pOD) + : QLineEdit(pParent), OptionItemT(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(ValueMap* config) { config->writeEntry(m_saveName, *m_pVar); } + void read(ValueMap* config) { *m_pVar = config->readNumEntry(m_saveName, *m_pVar); } + + private: + OptionIntEdit(const OptionIntEdit&); // private copy constructor without implementation }; class OptionComboBox : public QComboBox, public OptionItem { -public: - OptionComboBox( int defaultVal, const QString& saveName, int* pVarNum, - QWidget* pParent, OptionDialog* pOD ) - : QComboBox( pParent ), OptionItem( pOD, saveName ) - { - setMinimumWidth(50); - m_pVarNum = pVarNum; - m_pVarStr = 0; - m_defaultVal = defaultVal; - setEditable(false); - } - OptionComboBox( int defaultVal, const QString& saveName, QString* pVarStr, - QWidget* pParent, OptionDialog* pOD ) - : QComboBox( pParent ), OptionItem( pOD, saveName ) - { - m_pVarNum = 0; - m_pVarStr = pVarStr; - m_defaultVal = defaultVal; - setEditable(false); - } - void setToDefault() - { - setCurrentIndex( m_defaultVal ); - if (m_pVarStr!=0){ *m_pVarStr=currentText(); } - } - void setToCurrent() - { - if (m_pVarNum!=0) setCurrentIndex( *m_pVarNum ); - else setText( *m_pVarStr ); - } - void apply() - { - if (m_pVarNum!=0){ *m_pVarNum = currentIndex(); } - else { *m_pVarStr = currentText(); } - } - void write(ValueMap* config) - { - if (m_pVarStr!=0) config->writeEntry(m_saveName, *m_pVarStr ); - else config->writeEntry(m_saveName, *m_pVarNum ); - } - void read (ValueMap* config) - { - if (m_pVarStr!=0) setText( config->readEntry( m_saveName, currentText() ) ); - else *m_pVarNum = config->readNumEntry( m_saveName, *m_pVarNum ); - } - void preserve() - { - if (m_pVarStr!=0) { m_preservedStrVal = *m_pVarStr; } - else { m_preservedNumVal = *m_pVarNum; } - } - void unpreserve() - { - if (m_pVarStr!=0) { *m_pVarStr = m_preservedStrVal; } - else { *m_pVarNum = m_preservedNumVal; } - } -private: - OptionComboBox( const OptionIntEdit& ); // private copy constructor without implementation - int* m_pVarNum; - int m_preservedNumVal; - QString* m_pVarStr; - QString m_preservedStrVal; - int m_defaultVal; - - void setText(const QString& s) - { - // Find the string in the combobox-list, don't change the value if nothing fits. - for( int i=0; iwriteEntry(m_saveName, *m_pVarStr); + else + config->writeEntry(m_saveName, *m_pVarNum); + } + void read(ValueMap* config) + { + if(m_pVarStr != 0) + setText(config->readEntry(m_saveName, currentText())); + else + *m_pVarNum = config->readNumEntry(m_saveName, *m_pVarNum); + } + void preserve() + { + if(m_pVarStr != 0) { + m_preservedStrVal = *m_pVarStr; + } + else + { + m_preservedNumVal = *m_pVarNum; + } + } + void unpreserve() + { + if(m_pVarStr != 0) { + *m_pVarStr = m_preservedStrVal; + } + else + { + *m_pVarNum = m_preservedNumVal; + } + } + + private: + OptionComboBox(const OptionIntEdit&); // private copy constructor without implementation + int* m_pVarNum; + int m_preservedNumVal; + QString* m_pVarStr; + QString m_preservedStrVal; + int m_defaultVal; + + void setText(const QString& s) + { + // Find the string in the combobox-list, don't change the value if nothing fits. + for(int i = 0; i < count(); ++i) + { + if(itemText(i) == s) + { + if(m_pVarNum != 0) *m_pVarNum = i; + if(m_pVarStr != 0) *m_pVarStr = s; + setCurrentIndex(i); + return; + } + } + } }; class OptionEncodingComboBox : public QComboBox, public OptionItem { - Q_OBJECT - QVector m_codecVec; - QTextCodec** m_ppVarCodec; -public: - OptionEncodingComboBox( const QString& saveName, QTextCodec** ppVarCodec, - QWidget* pParent, OptionDialog* pOD ) - : QComboBox( pParent ), OptionItem( pOD, saveName ) - { - m_ppVarCodec = ppVarCodec; - insertCodec( i18n("Unicode, 8 bit"), QTextCodec::codecForName("UTF-8") ); - insertCodec( i18n("Unicode"), QTextCodec::codecForName("iso-10646-UCS-2") ); - insertCodec( i18n("Latin1"), QTextCodec::codecForName("iso 8859-1") ); - - // First sort codec names: - std::map names; - QList mibs = QTextCodec::availableMibs(); - foreach(int i, mibs) - { - QTextCodec* c = QTextCodec::codecForMib(i); - if ( c!=0 ) - names[QString(c->name()).toUpper()]=c; - } + Q_OBJECT + QVector m_codecVec; + QTextCodec** m_ppVarCodec; + + public: + OptionEncodingComboBox(const QString& saveName, QTextCodec** ppVarCodec, + QWidget* pParent, OptionDialog* pOD) + : QComboBox(pParent), OptionItem(pOD, saveName) + { + m_ppVarCodec = ppVarCodec; + insertCodec(i18n("Unicode, 8 bit"), QTextCodec::codecForName("UTF-8")); + insertCodec(i18n("Unicode"), QTextCodec::codecForName("iso-10646-UCS-2")); + insertCodec(i18n("Latin1"), QTextCodec::codecForName("iso 8859-1")); + + // First sort codec names: + std::map names; + QList mibs = QTextCodec::availableMibs(); + foreach(int i, mibs) + { + QTextCodec* c = QTextCodec::codecForMib(i); + if(c != 0) + names[QString(c->name()).toUpper()] = c; + } - std::map::iterator it; - for(it=names.begin();it!=names.end();++it) - { - insertCodec( "", it->second ); - } + std::map::iterator it; + for(it = names.begin(); it != names.end(); ++it) + { + insertCodec("", it->second); + } - this->setToolTip( i18n( - "Change this if non-ASCII characters are not displayed correctly." - )); - } - void insertCodec( const QString& visibleCodecName, QTextCodec* c ) - { - if (c!=0) - { - for( int i=0; iname()) : visibleCodecName+" ("+c->name()+")", (int)m_codecVec.size() ); - m_codecVec.push_back( c ); - } - } - void setToDefault() - { - QString defaultName = QTextCodec::codecForLocale()->name(); - for(int i=0;isetToolTip(i18n( + "Change this if non-ASCII characters are not displayed correctly.")); + } + void insertCodec(const QString& visibleCodecName, QTextCodec* c) + { + if(c != 0) + { + for(int i = 0; i < m_codecVec.size(); ++i) + { + if(c == m_codecVec[i]) + return; // don't insert any codec twice + } + addItem(visibleCodecName.isEmpty() ? QString(c->name()) : visibleCodecName + " (" + c->name() + ")", (int)m_codecVec.size()); + m_codecVec.push_back(c); + } + } + void setToDefault() + { + QString defaultName = QTextCodec::codecForLocale()->name(); + for(int i = 0; i < count(); ++i) + { + if(defaultName == itemText(i) && + m_codecVec[i] == QTextCodec::codecForLocale()) + { + setCurrentIndex(i); + if(m_ppVarCodec != 0) { + *m_ppVarCodec = m_codecVec[i]; + } + return; + } + } - setCurrentIndex( 0 ); - if (m_ppVarCodec!=0){ *m_ppVarCodec=m_codecVec[0]; } - } - void setToCurrent() - { - if (m_ppVarCodec!=0) - { - for( int i=0; iwriteEntry(m_saveName, QString((*m_ppVarCodec)->name()) ); - } - void read (ValueMap* config) - { - QString codecName = config->readEntry( m_saveName, QString(m_codecVec[ currentIndex() ]->name()) ); - for( int i=0; iname() ) - { - setCurrentIndex( i ); - if (m_ppVarCodec!=0) *m_ppVarCodec = m_codecVec[i]; - break; - } - } - } -protected: - void preserve() { m_preservedVal = currentIndex(); } - void unpreserve() { setCurrentIndex( m_preservedVal ); } - int m_preservedVal; -}; + } + } + void apply() + { + if(m_ppVarCodec != 0) { + *m_ppVarCodec = m_codecVec[currentIndex()]; + } + } + void write(ValueMap* config) + { + if(m_ppVarCodec != 0) config->writeEntry(m_saveName, QString((*m_ppVarCodec)->name())); + } + void read(ValueMap* config) + { + QString codecName = config->readEntry(m_saveName, QString(m_codecVec[currentIndex()]->name())); + for(int i = 0; i < m_codecVec.size(); ++i) + { + if(codecName == m_codecVec[i]->name()) + { + setCurrentIndex(i); + if(m_ppVarCodec != 0) *m_ppVarCodec = m_codecVec[i]; + break; + } + } + } + protected: + void preserve() { m_preservedVal = currentIndex(); } + void unpreserve() { setCurrentIndex(m_preservedVal); } + int m_preservedVal; +}; -OptionDialog::OptionDialog( bool bShowDirMergeSettings, QWidget *parent, char *name ) : -// KPageDialog( IconList, i18n("Configure"), Help|Default|Apply|Ok|Cancel, -// Ok, parent, name, true /*modal*/, true ) - KPageDialog( parent ) +OptionDialog::OptionDialog(bool bShowDirMergeSettings, QWidget* parent, char* name) : // KPageDialog( IconList, i18n("Configure"), Help|Default|Apply|Ok|Cancel, + // Ok, parent, name, true /*modal*/, true ) + KPageDialog(parent) { - setFaceType( List ); - setWindowTitle( i18n("Configure") ); - setStandardButtons( QDialogButtonBox::Help | QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Apply | QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); - // TODO KF5 necessary? setDefaultButton( Ok ); - setObjectName( name ); - setModal( true ); - - //showButtonSeparator( true ); - //setHelp( "kdiff3/index.html", QString::null ); - - setupFontPage(); - setupColorPage(); - setupEditPage(); - setupDiffPage(); - setupMergePage(); - setupOtherOptions(); - if (bShowDirMergeSettings) - setupDirectoryMergePage(); - - setupRegionalPage(); - setupIntegrationPage(); - - //setupKeysPage(); - - // Initialize all values in the dialog - resetToDefaults(); - slotApply(); - connect(button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &OptionDialog::slotApply); - connect(button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &OptionDialog::slotOk); - connect(button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &OptionDialog::slotDefault); - connect(button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &QDialog::reject); - connect(button(QDialogButtonBox::Help), &QPushButton::clicked, this, &OptionDialog::helpRequested); - //connect(this, &OptionDialog::applyClicked, this, &OptionDialog::slotApply); - //helpClicked() is connected in KDiff3App::KDiff3App -- Really where? - //connect(this, &OptionDialog::defaultClicked, this, &OptionDialog::slotDefault); + setFaceType(List); + setWindowTitle(i18n("Configure")); + setStandardButtons(QDialogButtonBox::Help | QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Apply | QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + // TODO KF5 necessary? setDefaultButton( Ok ); + setObjectName(name); + setModal(true); + + //showButtonSeparator( true ); + //setHelp( "kdiff3/index.html", QString::null ); + + setupFontPage(); + setupColorPage(); + setupEditPage(); + setupDiffPage(); + setupMergePage(); + setupOtherOptions(); + if(bShowDirMergeSettings) + setupDirectoryMergePage(); + + setupRegionalPage(); + setupIntegrationPage(); + + //setupKeysPage(); + + // Initialize all values in the dialog + resetToDefaults(); + slotApply(); + connect(button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &OptionDialog::slotApply); + connect(button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &OptionDialog::slotOk); + connect(button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &OptionDialog::slotDefault); + connect(button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &QDialog::reject); + connect(button(QDialogButtonBox::Help), &QPushButton::clicked, this, &OptionDialog::helpRequested); + //connect(this, &OptionDialog::applyClicked, this, &OptionDialog::slotApply); + //helpClicked() is connected in KDiff3App::KDiff3App -- Really where? + //connect(this, &OptionDialog::defaultClicked, this, &OptionDialog::slotDefault); } - -void OptionDialog::helpRequested() { - KHelpClient::invokeHelp( QStringLiteral( "kdiff3/index.html" ), QString()); +void OptionDialog::helpRequested() +{ + KHelpClient::invokeHelp(QStringLiteral("kdiff3/index.html"), QString()); } -OptionDialog::~OptionDialog( void ) +OptionDialog::~OptionDialog(void) { } void OptionDialog::setupOtherOptions() { - new OptionToggleAction( false, "AutoAdvance", &m_options.m_bAutoAdvance, this ); - new OptionToggleAction( true, "ShowWhiteSpaceCharacters", &m_options.m_bShowWhiteSpaceCharacters, this ); - new OptionToggleAction( true, "ShowWhiteSpace", &m_options.m_bShowWhiteSpace, this ); - new OptionToggleAction( false, "ShowLineNumbers", &m_options.m_bShowLineNumbers, this ); - new OptionToggleAction( true, "HorizDiffWindowSplitting", &m_options.m_bHorizDiffWindowSplitting, this ); - new OptionToggleAction( false, "WordWrap", &m_options.m_bWordWrap, this ); + new OptionToggleAction(false, "AutoAdvance", &m_options.m_bAutoAdvance, this); + new OptionToggleAction(true, "ShowWhiteSpaceCharacters", &m_options.m_bShowWhiteSpaceCharacters, this); + new OptionToggleAction(true, "ShowWhiteSpace", &m_options.m_bShowWhiteSpace, this); + new OptionToggleAction(false, "ShowLineNumbers", &m_options.m_bShowLineNumbers, this); + new OptionToggleAction(true, "HorizDiffWindowSplitting", &m_options.m_bHorizDiffWindowSplitting, this); + new OptionToggleAction(false, "WordWrap", &m_options.m_bWordWrap, this); - new OptionToggleAction( true, "ShowIdenticalFiles", &m_options.m_bDmShowIdenticalFiles, this ); + new OptionToggleAction(true, "ShowIdenticalFiles", &m_options.m_bDmShowIdenticalFiles, this); - new OptionToggleAction( true, "Show Toolbar", &m_options.m_bShowToolBar, this ); - new OptionToggleAction( true, "Show Statusbar", &m_options.m_bShowStatusBar, this ); + new OptionToggleAction(true, "Show Toolbar", &m_options.m_bShowToolBar, this); + new OptionToggleAction(true, "Show Statusbar", &m_options.m_bShowStatusBar, this); -/* + /* TODO manage toolbar positioning new OptionNum( (int)KToolBar::Top, "ToolBarPos", &m_toolBarPos, this ); */ - new OptionSize( QSize(600,400),"Geometry", &m_options.m_geometry, this ); - new OptionPoint( QPoint(0,22), "Position", &m_options.m_position, this ); - new OptionToggleAction( false, "WindowStateMaximised", &m_options.m_bMaximised, this ); - - new OptionStringList( "RecentAFiles", &m_options.m_recentAFiles, this ); - new OptionStringList( "RecentBFiles", &m_options.m_recentBFiles, this ); - new OptionStringList( "RecentCFiles", &m_options.m_recentCFiles, this ); - new OptionStringList( "RecentOutputFiles", &m_options.m_recentOutputFiles, this ); - new OptionStringList( "RecentEncodings", &m_options.m_recentEncodings, this ); - + new OptionSize(QSize(600, 400), "Geometry", &m_options.m_geometry, this); + new OptionPoint(QPoint(0, 22), "Position", &m_options.m_position, this); + new OptionToggleAction(false, "WindowStateMaximised", &m_options.m_bMaximised, this); + + new OptionStringList("RecentAFiles", &m_options.m_recentAFiles, this); + new OptionStringList("RecentBFiles", &m_options.m_recentBFiles, this); + new OptionStringList("RecentCFiles", &m_options.m_recentCFiles, this); + new OptionStringList("RecentOutputFiles", &m_options.m_recentOutputFiles, this); + new OptionStringList("RecentEncodings", &m_options.m_recentEncodings, this); } -void OptionDialog::setupFontPage( void ) +void OptionDialog::setupFontPage(void) { QFrame* page = new QFrame(); - KPageWidgetItem *pageItem = new KPageWidgetItem( page, i18n("Font") ); - - pageItem->setHeader( i18n("Editor & Diff Output Font") ); - pageItem->setIcon( QIcon::fromTheme(QStringLiteral("preferences-desktop-font")) ); - addPage( pageItem ); - - QVBoxLayout *topLayout = new QVBoxLayout( page ); - topLayout->setMargin( 5 ); - - + KPageWidgetItem* pageItem = new KPageWidgetItem(page, i18n("Font")); + + pageItem->setHeader(i18n("Editor & Diff Output Font")); + pageItem->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-font"))); + addPage(pageItem); + + QVBoxLayout* topLayout = new QVBoxLayout(page); + topLayout->setMargin(5); + //requires QT 5.2 or later. - static const QFont defaultFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);; + static const QFont defaultFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + ; static QFont defaultAppFont = QApplication::font(); - OptionFontChooser* pAppFontChooser = new OptionFontChooser( defaultAppFont, "ApplicationFont", &m_options.m_appFont, page, this ); - topLayout->addWidget( pAppFontChooser ); + OptionFontChooser* pAppFontChooser = new OptionFontChooser(defaultAppFont, "ApplicationFont", &m_options.m_appFont, page, this); + topLayout->addWidget(pAppFontChooser); pAppFontChooser->setTitle(i18n("Application font")); - - OptionFontChooser* pFontChooser = new OptionFontChooser( defaultFont, "Font", &m_options.m_font, page, this ); - topLayout->addWidget( pFontChooser ); + + OptionFontChooser* pFontChooser = new OptionFontChooser(defaultFont, "Font", &m_options.m_font, page, this); + topLayout->addWidget(pFontChooser); pFontChooser->setTitle(i18n("File view font")); - QGridLayout *gbox = new QGridLayout(); - topLayout->addLayout( gbox ); - //int line=0; - - // This currently does not work (see rendering in class DiffTextWindow) - //OptionCheckBox* pItalicDeltas = new OptionCheckBox( i18n("Italic font for deltas"), false, "ItalicForDeltas", &m_options.m_bItalicForDeltas, page, this ); - //gbox->addWidget( pItalicDeltas, line, 0, 1, 2 ); - //pItalicDeltas->setToolTip( i18n( - // "Selects the italic version of the font for differences.\n" - // "If the font doesn't support italic characters, then this does nothing.") - // ); + QGridLayout* gbox = new QGridLayout(); + topLayout->addLayout(gbox); + //int line=0; + + // This currently does not work (see rendering in class DiffTextWindow) + //OptionCheckBox* pItalicDeltas = new OptionCheckBox( i18n("Italic font for deltas"), false, "ItalicForDeltas", &m_options.m_bItalicForDeltas, page, this ); + //gbox->addWidget( pItalicDeltas, line, 0, 1, 2 ); + //pItalicDeltas->setToolTip( 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 ) +void OptionDialog::setupColorPage(void) { QFrame* page = new QFrame(); - KPageWidgetItem* pageItem = new KPageWidgetItem( page, i18n("Color") ); - pageItem->setHeader( i18n("Colors Settings") ); - pageItem->setIcon( QIcon::fromTheme(QStringLiteral("colormanagement")) ); - addPage( pageItem ); + KPageWidgetItem* pageItem = new KPageWidgetItem(page, i18n("Color")); + pageItem->setHeader(i18n("Colors Settings")); + pageItem->setIcon(QIcon::fromTheme(QStringLiteral("colormanagement"))); + addPage(pageItem); - QVBoxLayout *topLayout = new QVBoxLayout( page ); - topLayout->setMargin( 5 ); + QVBoxLayout* topLayout = new QVBoxLayout(page); + topLayout->setMargin(5); - QGridLayout *gbox = new QGridLayout(); - gbox->setColumnStretch(1,5); + QGridLayout* gbox = new QGridLayout(); + gbox->setColumnStretch(1, 5); topLayout->addLayout(gbox); QLabel* label; int line = 0; int depth = QPixmap::defaultDepth(); bool bLowColor = depth <= 8; - label = new QLabel( i18n( "Editor and Diff Views:" ), page ); - gbox->addWidget( label, line, 0 ); - QFont f( label->font() ); - f.setBold( true ); - label->setFont( f ); + label = new QLabel(i18n("Editor and Diff Views:"), page); + gbox->addWidget(label, line, 0); + QFont f(label->font()); + f.setBold(true); + label->setFont(f); ++line; - OptionColorButton* pFgColor = new OptionColorButton( Qt::black, "FgColor", &m_options.m_fgColor, page, this ); - label = new QLabel( i18n( "Foreground color:" ), page ); - label->setBuddy( pFgColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pFgColor, line, 1 ); + OptionColorButton* pFgColor = new OptionColorButton(Qt::black, "FgColor", &m_options.m_fgColor, page, this); + label = new QLabel(i18n("Foreground color:"), page); + label->setBuddy(pFgColor); + gbox->addWidget(label, line, 0); + gbox->addWidget(pFgColor, line, 1); ++line; - OptionColorButton* pBgColor = new OptionColorButton( Qt::white, "BgColor", &m_options.m_bgColor, page, this ); - label = new QLabel( i18n( "Background color:" ), page ); - label->setBuddy( pBgColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pBgColor, line, 1 ); + OptionColorButton* pBgColor = new OptionColorButton(Qt::white, "BgColor", &m_options.m_bgColor, page, this); + label = new QLabel(i18n("Background color:"), page); + label->setBuddy(pBgColor); + gbox->addWidget(label, line, 0); + gbox->addWidget(pBgColor, line, 1); ++line; OptionColorButton* pDiffBgColor = new OptionColorButton( - bLowColor ? QColor( Qt::lightGray ) : qRgb( 224, 224, 224 ), "DiffBgColor", &m_options.m_diffBgColor, page, this ); - label = new QLabel( i18n( "Diff background color:" ), page ); - label->setBuddy( pDiffBgColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pDiffBgColor, line, 1 ); + bLowColor ? QColor(Qt::lightGray) : qRgb(224, 224, 224), "DiffBgColor", &m_options.m_diffBgColor, page, this); + label = new QLabel(i18n("Diff background color:"), page); + label->setBuddy(pDiffBgColor); + 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_options.m_colorA, page, this ); - label = new QLabel( i18n( "Color A:" ), page ); - label->setBuddy( pColorA ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColorA, line, 1 ); + bLowColor ? qRgb(0, 0, 255) : qRgb(0, 0, 200) /*blue*/, "ColorA", &m_options.m_colorA, page, this); + label = new QLabel(i18n("Color A:"), page); + label->setBuddy(pColorA); + 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_options.m_colorB, page, this ); - label = new QLabel( i18n( "Color B:" ), page ); - label->setBuddy( pColorB ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColorB, line, 1 ); + bLowColor ? qRgb(0, 128, 0) : qRgb(0, 150, 0) /*green*/, "ColorB", &m_options.m_colorB, page, this); + label = new QLabel(i18n("Color B:"), page); + label->setBuddy(pColorB); + 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_options.m_colorC, page, this ); - label = new QLabel( i18n( "Color C:" ), page ); - label->setBuddy( pColorC ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColorC, line, 1 ); + bLowColor ? qRgb(128, 0, 128) : qRgb(150, 0, 150) /*magenta*/, "ColorC", &m_options.m_colorC, page, this); + label = new QLabel(i18n("Color C:"), page); + label->setBuddy(pColorC); + gbox->addWidget(label, line, 0); + gbox->addWidget(pColorC, line, 1); ++line; - OptionColorButton* pColorForConflict = new OptionColorButton( Qt::red, "ColorForConflict", &m_options.m_colorForConflict, page, this ); - label = new QLabel( i18n( "Conflict color:" ), page ); - label->setBuddy( pColorForConflict ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColorForConflict, line, 1 ); + OptionColorButton* pColorForConflict = new OptionColorButton(Qt::red, "ColorForConflict", &m_options.m_colorForConflict, page, this); + label = new QLabel(i18n("Conflict color:"), page); + label->setBuddy(pColorForConflict); + 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_options.m_currentRangeBgColor, page, this ); - label = new QLabel( i18n( "Current range background color:" ), page ); - label->setBuddy( pColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColor, line, 1 ); + bLowColor ? qRgb(192, 192, 192) : qRgb(220, 220, 100), "CurrentRangeBgColor", &m_options.m_currentRangeBgColor, page, this); + label = new QLabel(i18n("Current range background color:"), page); + label->setBuddy(pColor); + 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_options.m_currentRangeDiffBgColor, page, this ); - label = new QLabel( i18n( "Current range diff background color:" ), page ); - label->setBuddy( pColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColor, line, 1 ); + bLowColor ? qRgb(255, 255, 0) : qRgb(255, 255, 150), "CurrentRangeDiffBgColor", &m_options.m_currentRangeDiffBgColor, page, this); + label = new QLabel(i18n("Current range diff background color:"), page); + label->setBuddy(pColor); + gbox->addWidget(label, line, 0); + gbox->addWidget(pColor, line, 1); ++line; - pColor = new OptionColorButton( qRgb( 0xff, 0xd0, 0x80 ), "ManualAlignmentRangeColor", &m_options.m_manualHelpRangeColor, page, this ); - label = new QLabel( i18n( "Color for manually aligned difference ranges:" ), page ); - label->setBuddy( pColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColor, line, 1 ); + pColor = new OptionColorButton(qRgb(0xff, 0xd0, 0x80), "ManualAlignmentRangeColor", &m_options.m_manualHelpRangeColor, page, this); + label = new QLabel(i18n("Color for manually aligned difference ranges:"), page); + label->setBuddy(pColor); + gbox->addWidget(label, line, 0); + gbox->addWidget(pColor, line, 1); ++line; - label = new QLabel( i18n( "Directory Comparison View:" ), page ); - gbox->addWidget( label, line, 0 ); - label->setFont( f ); + label = new QLabel(i18n("Directory Comparison View:"), page); + gbox->addWidget(label, line, 0); + label->setFont(f); ++line; - pColor = new OptionColorButton( qRgb( 0, 0xd0, 0 ), "NewestFileColor", &m_options.m_newestFileColor, page, this ); - label = new QLabel( i18n( "Newest file color:" ), page ); - label->setBuddy( pColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColor, line, 1 ); - QString dirColorTip = i18n( "Changing this color will only be effective when starting the next directory comparison." ); - label->setToolTip( dirColorTip ); + pColor = new OptionColorButton(qRgb(0, 0xd0, 0), "NewestFileColor", &m_options.m_newestFileColor, page, this); + label = new QLabel(i18n("Newest file color:"), page); + label->setBuddy(pColor); + gbox->addWidget(label, line, 0); + gbox->addWidget(pColor, line, 1); + QString dirColorTip = i18n("Changing this color will only be effective when starting the next directory comparison."); + label->setToolTip(dirColorTip); ++line; - pColor = new OptionColorButton( qRgb( 0xf0, 0, 0 ), "OldestFileColor", &m_options.m_oldestFileColor, page, this ); - label = new QLabel( i18n( "Oldest file color:" ), page ); - label->setBuddy( pColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColor, line, 1 ); - label->setToolTip( dirColorTip ); + pColor = new OptionColorButton(qRgb(0xf0, 0, 0), "OldestFileColor", &m_options.m_oldestFileColor, page, this); + label = new QLabel(i18n("Oldest file color:"), page); + label->setBuddy(pColor); + gbox->addWidget(label, line, 0); + gbox->addWidget(pColor, line, 1); + label->setToolTip(dirColorTip); ++line; - pColor = new OptionColorButton( qRgb( 0xc0, 0xc0, 0 ), "MidAgeFileColor", &m_options.m_midAgeFileColor, page, this ); - label = new QLabel( i18n( "Middle age file color:" ), page ); - label->setBuddy( pColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColor, line, 1 ); - label->setToolTip( dirColorTip ); + pColor = new OptionColorButton(qRgb(0xc0, 0xc0, 0), "MidAgeFileColor", &m_options.m_midAgeFileColor, page, this); + label = new QLabel(i18n("Middle age file color:"), page); + label->setBuddy(pColor); + gbox->addWidget(label, line, 0); + gbox->addWidget(pColor, line, 1); + label->setToolTip(dirColorTip); ++line; - pColor = new OptionColorButton( qRgb( 0, 0, 0 ), "MissingFileColor", &m_options.m_missingFileColor, page, this ); - label = new QLabel( i18n( "Color for missing files:" ), page ); - label->setBuddy( pColor ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pColor, line, 1 ); - label->setToolTip( dirColorTip ); + pColor = new OptionColorButton(qRgb(0, 0, 0), "MissingFileColor", &m_options.m_missingFileColor, page, this); + label = new QLabel(i18n("Color for missing files:"), page); + label->setBuddy(pColor); + gbox->addWidget(label, line, 0); + gbox->addWidget(pColor, line, 1); + label->setToolTip(dirColorTip); ++line; - topLayout->addStretch( 10 ); + topLayout->addStretch(10); } - -void OptionDialog::setupEditPage( void ) +void OptionDialog::setupEditPage(void) { QFrame* page = new QFrame(); - KPageWidgetItem* pageItem = new KPageWidgetItem( page, i18n( "Editor" ) ); - pageItem->setHeader( i18n( "Editor Behavior" ) ); - pageItem->setIcon( QIcon::fromTheme( QStringLiteral( "accessories-text-editor" ) ) ); - addPage( pageItem ); + KPageWidgetItem* pageItem = new KPageWidgetItem(page, i18n("Editor")); + pageItem->setHeader(i18n("Editor Behavior")); + pageItem->setIcon(QIcon::fromTheme(QStringLiteral("accessories-text-editor"))); + addPage(pageItem); - QVBoxLayout *topLayout = new QVBoxLayout( page ); - topLayout->setMargin( 5 ); + QVBoxLayout* topLayout = new QVBoxLayout(page); + topLayout->setMargin(5); - QGridLayout *gbox = new QGridLayout(); - gbox->setColumnStretch( 1, 5 ); - topLayout->addLayout( gbox ); + QGridLayout* gbox = new QGridLayout(); + gbox->setColumnStretch(1, 5); + topLayout->addLayout(gbox); QLabel* label; int line = 0; - OptionCheckBox* pReplaceTabs = new OptionCheckBox( i18n( "Tab inserts spaces" ), false, "ReplaceTabs", &m_options.m_bReplaceTabs, page, this ); - gbox->addWidget( pReplaceTabs, line, 0, 1, 2 ); - pReplaceTabs->setToolTip( i18n( - "On: Pressing tab generates the appropriate number of spaces.\n" - "Off: A tab character will be inserted." ) - ); + OptionCheckBox* pReplaceTabs = new OptionCheckBox(i18n("Tab inserts spaces"), false, "ReplaceTabs", &m_options.m_bReplaceTabs, page, this); + gbox->addWidget(pReplaceTabs, line, 0, 1, 2); + pReplaceTabs->setToolTip(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_options.m_tabSize, 1, 100, page, this ); - label = new QLabel( i18n( "Tab size:" ), page ); - label->setBuddy( pTabSize ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pTabSize, line, 1 ); + OptionIntEdit* pTabSize = new OptionIntEdit(8, "TabSize", &m_options.m_tabSize, 1, 100, page, this); + label = new QLabel(i18n("Tab size:"), page); + label->setBuddy(pTabSize); + gbox->addWidget(label, line, 0); + gbox->addWidget(pTabSize, line, 1); ++line; - OptionCheckBox* pAutoIndentation = new OptionCheckBox( i18n( "Auto indentation" ), true, "AutoIndentation", &m_options.m_bAutoIndentation, page, this ); - gbox->addWidget( pAutoIndentation, line, 0, 1, 2 ); - pAutoIndentation->setToolTip( i18n( - "On: The indentation of the previous line is used for a new line.\n" - ) ); + OptionCheckBox* pAutoIndentation = new OptionCheckBox(i18n("Auto indentation"), true, "AutoIndentation", &m_options.m_bAutoIndentation, page, this); + gbox->addWidget(pAutoIndentation, line, 0, 1, 2); + pAutoIndentation->setToolTip(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_options.m_bAutoCopySelection, page, this ); - gbox->addWidget( pAutoCopySelection, line, 0, 1, 2 ); - pAutoCopySelection->setToolTip( i18n( - "On: Any selection is immediately written to the clipboard.\n" - "Off: You must explicitely copy e.g. via Ctrl-C." - ) ); + OptionCheckBox* pAutoCopySelection = new OptionCheckBox(i18n("Auto copy selection"), false, "AutoCopySelection", &m_options.m_bAutoCopySelection, page, this); + gbox->addWidget(pAutoCopySelection, line, 0, 1, 2); + pAutoCopySelection->setToolTip(i18n( + "On: Any selection is immediately written to the clipboard.\n" + "Off: You must explicitely copy e.g. via Ctrl-C.")); ++line; - label = new QLabel( i18n( "Line end style:" ), page ); - gbox->addWidget( label, line, 0 ); + label = new QLabel(i18n("Line end style:"), page); + gbox->addWidget(label, line, 0); - OptionComboBox* pLineEndStyle = new OptionComboBox( eLineEndStyleAutoDetect, "LineEndStyle", &m_options.m_lineEndStyle, page, this ); - gbox->addWidget( pLineEndStyle, line, 1 ); - pLineEndStyle->insertItem( eLineEndStyleUnix, "Unix" ); - pLineEndStyle->insertItem( eLineEndStyleDos, "Dos/Windows" ); - pLineEndStyle->insertItem( eLineEndStyleAutoDetect, "Autodetect" ); + OptionComboBox* pLineEndStyle = new OptionComboBox(eLineEndStyleAutoDetect, "LineEndStyle", &m_options.m_lineEndStyle, page, this); + gbox->addWidget(pLineEndStyle, line, 1); + pLineEndStyle->insertItem(eLineEndStyleUnix, "Unix"); + pLineEndStyle->insertItem(eLineEndStyleDos, "Dos/Windows"); + pLineEndStyle->insertItem(eLineEndStyleAutoDetect, "Autodetect"); - label->setToolTip( i18n( - "Sets the line endings for when an edited file is saved.\n" - "DOS/Windows: CR+LF; UNIX: LF; with CR=0D, LF=0A" ) - ); + label->setToolTip(i18n( + "Sets the line endings for when an edited file is saved.\n" + "DOS/Windows: CR+LF; UNIX: LF; with CR=0D, LF=0A")); ++line; - topLayout->addStretch( 10 ); + topLayout->addStretch(10); } - -void OptionDialog::setupDiffPage( void ) +void OptionDialog::setupDiffPage(void) { QFrame* page = new QFrame(); - KPageWidgetItem* pageItem = new KPageWidgetItem( page, i18n( "Diff" ) ); - pageItem->setHeader( i18n( "Diff Settings" ) ); - pageItem->setIcon( QIcon::fromTheme( QStringLiteral( "text-x-patch" ) ) ); - addPage( pageItem ); + KPageWidgetItem* pageItem = new KPageWidgetItem(page, i18n("Diff")); + pageItem->setHeader(i18n("Diff Settings")); + pageItem->setIcon(QIcon::fromTheme(QStringLiteral("text-x-patch"))); + addPage(pageItem); + QVBoxLayout* topLayout = new QVBoxLayout(page); + topLayout->setMargin(5); - QVBoxLayout *topLayout = new QVBoxLayout( page ); - topLayout->setMargin( 5 ); - - QGridLayout *gbox = new QGridLayout(); - gbox->setColumnStretch( 1, 5 ); - topLayout->addLayout( gbox ); + QGridLayout* gbox = new QGridLayout(); + gbox->setColumnStretch(1, 5); + topLayout->addLayout(gbox); int line = 0; QLabel* label = 0; m_options.m_bPreserveCarriageReturn = false; -/* + /* OptionCheckBox* pPreserveCarriageReturn = new OptionCheckBox( i18n("Preserve carriage return"), false, "PreserveCarriageReturn", &m_options.m_bPreserveCarriageReturn, page, this ); gbox->addWidget( pPreserveCarriageReturn, line, 0, 1, 2 ); pPreserveCarriageReturn->setToolTip( i18n( "Show carriage return characters '\\r' if they exist.\n" "Helps to compare files that were modified under different operating systems.") ); ++line; */ - QString treatAsWhiteSpace = " (" + i18n( "Treat as white space." ) + ")"; + QString treatAsWhiteSpace = " (" + i18n("Treat as white space.") + ")"; - OptionCheckBox* pIgnoreNumbers = new OptionCheckBox( i18n( "Ignore numbers" ) + treatAsWhiteSpace, false, "IgnoreNumbers", &m_options.m_bIgnoreNumbers, page, this ); - gbox->addWidget( pIgnoreNumbers, line, 0, 1, 2 ); - pIgnoreNumbers->setToolTip( i18n( - "Ignore number characters during line matching phase. (Similar to Ignore white space.)\n" - "Might help to compare files with numeric data." ) - ); + OptionCheckBox* pIgnoreNumbers = new OptionCheckBox(i18n("Ignore numbers") + treatAsWhiteSpace, false, "IgnoreNumbers", &m_options.m_bIgnoreNumbers, page, this); + gbox->addWidget(pIgnoreNumbers, line, 0, 1, 2); + pIgnoreNumbers->setToolTip(i18n( + "Ignore number characters during line matching phase. (Similar to Ignore white space.)\n" + "Might help to compare files with numeric data.")); ++line; - OptionCheckBox* pIgnoreComments = new OptionCheckBox( i18n( "Ignore C/C++ comments" ) + treatAsWhiteSpace, false, "IgnoreComments", &m_options.m_bIgnoreComments, page, this ); - gbox->addWidget( pIgnoreComments, line, 0, 1, 2 ); - pIgnoreComments->setToolTip( i18n( "Treat C/C++ comments like white space." ) - ); + OptionCheckBox* pIgnoreComments = new OptionCheckBox(i18n("Ignore C/C++ comments") + treatAsWhiteSpace, false, "IgnoreComments", &m_options.m_bIgnoreComments, page, this); + gbox->addWidget(pIgnoreComments, line, 0, 1, 2); + pIgnoreComments->setToolTip(i18n("Treat C/C++ comments like white space.")); ++line; - OptionCheckBox* pIgnoreCase = new OptionCheckBox( i18n( "Ignore case" ) + treatAsWhiteSpace, false, "IgnoreCase", &m_options.m_bIgnoreCase, page, this ); - gbox->addWidget( pIgnoreCase, line, 0, 1, 2 ); - pIgnoreCase->setToolTip( i18n( - "Treat case differences like white space changes. ('a'<=>'A')" ) - ); + OptionCheckBox* pIgnoreCase = new OptionCheckBox(i18n("Ignore case") + treatAsWhiteSpace, false, "IgnoreCase", &m_options.m_bIgnoreCase, page, this); + gbox->addWidget(pIgnoreCase, line, 0, 1, 2); + pIgnoreCase->setToolTip(i18n( + "Treat case differences like white space changes. ('a'<=>'A')")); ++line; - label = new QLabel( i18n( "Preprocessor command:" ), page ); - gbox->addWidget( label, line, 0 ); - OptionLineEdit* pLE = new OptionLineEdit( "", "PreProcessorCmd", &m_options.m_PreProcessorCmd, page, this ); - gbox->addWidget( pLE, line, 1 ); - label->setToolTip( i18n( "User defined pre-processing. (See the docs for details.)" ) ); + label = new QLabel(i18n("Preprocessor command:"), page); + gbox->addWidget(label, line, 0); + OptionLineEdit* pLE = new OptionLineEdit("", "PreProcessorCmd", &m_options.m_PreProcessorCmd, page, this); + gbox->addWidget(pLE, line, 1); + label->setToolTip(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_options.m_LineMatchingPreProcessorCmd, page, this ); - gbox->addWidget( pLE, line, 1 ); - label->setToolTip( i18n( "This pre-processor is only used during line matching.\n(See the docs for details.)" ) ); + label = new QLabel(i18n("Line-matching preprocessor command:"), page); + gbox->addWidget(label, line, 0); + pLE = new OptionLineEdit("", "LineMatchingPreProcessorCmd", &m_options.m_LineMatchingPreProcessorCmd, page, this); + gbox->addWidget(pLE, line, 1); + label->setToolTip(i18n("This pre-processor is only used during line matching.\n(See the docs for details.)")); ++line; - OptionCheckBox* pTryHard = new OptionCheckBox( i18n( "Try hard (slower)" ), true, "TryHard", &m_options.m_bTryHard, page, this ); - gbox->addWidget( pTryHard, line, 0, 1, 2 ); - pTryHard->setToolTip( i18n( - "Enables the --minimal option for the external diff.\n" - "The analysis of big files will be much slower." ) - ); + OptionCheckBox* pTryHard = new OptionCheckBox(i18n("Try hard (slower)"), true, "TryHard", &m_options.m_bTryHard, page, this); + gbox->addWidget(pTryHard, line, 0, 1, 2); + pTryHard->setToolTip(i18n( + "Enables the --minimal option for the external diff.\n" + "The analysis of big files will be much slower.")); ++line; - OptionCheckBox* pDiff3AlignBC = new OptionCheckBox( i18n( "Align B and C for 3 input files" ), false, "Diff3AlignBC", &m_options.m_bDiff3AlignBC, page, this ); - gbox->addWidget( pDiff3AlignBC, line, 0, 1, 2 ); - pDiff3AlignBC->setToolTip( i18n( - "Try to align B and C when comparing or merging three input files.\n" - "Not recommended for merging because merge might get more complicated.\n" - "(Default is off.)" ) - ); + OptionCheckBox* pDiff3AlignBC = new OptionCheckBox(i18n("Align B and C for 3 input files"), false, "Diff3AlignBC", &m_options.m_bDiff3AlignBC, page, this); + gbox->addWidget(pDiff3AlignBC, line, 0, 1, 2); + pDiff3AlignBC->setToolTip(i18n( + "Try to align B and C when comparing or merging three input files.\n" + "Not recommended for merging because merge might get more complicated.\n" + "(Default is off.)")); ++line; - topLayout->addStretch( 10 ); + topLayout->addStretch(10); } -void OptionDialog::setupMergePage( void ) +void OptionDialog::setupMergePage(void) { QFrame* page = new QFrame(); - KPageWidgetItem* pageItem = new KPageWidgetItem( page, i18n( "Merge" ) ); - pageItem->setHeader( i18n( "Merge Settings" ) ); - pageItem->setIcon( QIcon::fromTheme( QStringLiteral( "merge" ) ) ); - addPage( pageItem ); - - QVBoxLayout *topLayout = new QVBoxLayout( page ); - topLayout->setMargin( 5 ); - - QGridLayout *gbox = new QGridLayout(); - gbox->setColumnStretch( 1, 5 ); - topLayout->addLayout( gbox ); + KPageWidgetItem* pageItem = new KPageWidgetItem(page, i18n("Merge")); + pageItem->setHeader(i18n("Merge Settings")); + pageItem->setIcon(QIcon::fromTheme(QStringLiteral("merge"))); + addPage(pageItem); + + QVBoxLayout* topLayout = new QVBoxLayout(page); + topLayout->setMargin(5); + + QGridLayout* gbox = new QGridLayout(); + gbox->setColumnStretch(1, 5); + topLayout->addLayout(gbox); int line = 0; QLabel* label = 0; - label = new QLabel( i18n( "Auto advance delay (ms):" ), page ); - gbox->addWidget( label, line, 0 ); - OptionIntEdit* pAutoAdvanceDelay = new OptionIntEdit( 500, "AutoAdvanceDelay", &m_options.m_autoAdvanceDelay, 0, 2000, page, this ); - gbox->addWidget( pAutoAdvanceDelay, line, 1 ); - label->setToolTip( 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; - - OptionCheckBox* pShowInfoDialogs = new OptionCheckBox( i18n( "Show info dialogs" ), true, "ShowInfoDialogs", &m_options.m_bShowInfoDialogs, page, this ); - gbox->addWidget( pShowInfoDialogs, line, 0, 1, 2 ); - pShowInfoDialogs->setToolTip( i18n( "Show a dialog with information about the number of conflicts." ) ); - ++line; - - label = new QLabel( i18n( "White space 2-file merge default:" ), page ); - gbox->addWidget( label, line, 0 ); - OptionComboBox* pWhiteSpace2FileMergeDefault = new OptionComboBox( 0, "WhiteSpace2FileMergeDefault", &m_options.m_whiteSpace2FileMergeDefault, page, this ); - gbox->addWidget( pWhiteSpace2FileMergeDefault, line, 1 ); - pWhiteSpace2FileMergeDefault->insertItem( 0, i18n( "Manual Choice" ) ); - pWhiteSpace2FileMergeDefault->insertItem( 1, "A" ); - pWhiteSpace2FileMergeDefault->insertItem( 2, "B" ); - label->setToolTip( i18n( - "Allow the merge algorithm to automatically select an input for " - "white-space-only changes." ) - ); - ++line; - - label = new QLabel( i18n( "White space 3-file merge default:" ), page ); - gbox->addWidget( label, line, 0 ); - OptionComboBox* pWhiteSpace3FileMergeDefault = new OptionComboBox( 0, "WhiteSpace3FileMergeDefault", &m_options.m_whiteSpace3FileMergeDefault, page, this ); - gbox->addWidget( pWhiteSpace3FileMergeDefault, line, 1 ); - pWhiteSpace3FileMergeDefault->insertItem( 0, i18n( "Manual Choice" ) ); - pWhiteSpace3FileMergeDefault->insertItem( 1, "A" ); - pWhiteSpace3FileMergeDefault->insertItem( 2, "B" ); - pWhiteSpace3FileMergeDefault->insertItem( 3, "C" ); - label->setToolTip( i18n( - "Allow the merge algorithm to automatically select an input for " - "white-space-only changes." ) - ); - ++line; - - QGroupBox* pGroupBox = new QGroupBox( i18n( "Automatic Merge Regular Expression" ) ); - gbox->addWidget( pGroupBox, line, 0, 1, 2 ); - ++line; - { - QGridLayout* gbox = new QGridLayout( pGroupBox ); - gbox->setColumnStretch( 1, 10 ); + label = new QLabel(i18n("Auto advance delay (ms):"), page); + gbox->addWidget(label, line, 0); + OptionIntEdit* pAutoAdvanceDelay = new OptionIntEdit(500, "AutoAdvanceDelay", &m_options.m_autoAdvanceDelay, 0, 2000, page, this); + gbox->addWidget(pAutoAdvanceDelay, line, 1); + label->setToolTip(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; + + OptionCheckBox* pShowInfoDialogs = new OptionCheckBox(i18n("Show info dialogs"), true, "ShowInfoDialogs", &m_options.m_bShowInfoDialogs, page, this); + gbox->addWidget(pShowInfoDialogs, line, 0, 1, 2); + pShowInfoDialogs->setToolTip(i18n("Show a dialog with information about the number of conflicts.")); + ++line; + + label = new QLabel(i18n("White space 2-file merge default:"), page); + gbox->addWidget(label, line, 0); + OptionComboBox* pWhiteSpace2FileMergeDefault = new OptionComboBox(0, "WhiteSpace2FileMergeDefault", &m_options.m_whiteSpace2FileMergeDefault, page, this); + gbox->addWidget(pWhiteSpace2FileMergeDefault, line, 1); + pWhiteSpace2FileMergeDefault->insertItem(0, i18n("Manual Choice")); + pWhiteSpace2FileMergeDefault->insertItem(1, "A"); + pWhiteSpace2FileMergeDefault->insertItem(2, "B"); + label->setToolTip(i18n( + "Allow the merge algorithm to automatically select an input for " + "white-space-only changes.")); + ++line; + + label = new QLabel(i18n("White space 3-file merge default:"), page); + gbox->addWidget(label, line, 0); + OptionComboBox* pWhiteSpace3FileMergeDefault = new OptionComboBox(0, "WhiteSpace3FileMergeDefault", &m_options.m_whiteSpace3FileMergeDefault, page, this); + gbox->addWidget(pWhiteSpace3FileMergeDefault, line, 1); + pWhiteSpace3FileMergeDefault->insertItem(0, i18n("Manual Choice")); + pWhiteSpace3FileMergeDefault->insertItem(1, "A"); + pWhiteSpace3FileMergeDefault->insertItem(2, "B"); + pWhiteSpace3FileMergeDefault->insertItem(3, "C"); + label->setToolTip(i18n( + "Allow the merge algorithm to automatically select an input for " + "white-space-only changes.")); + ++line; + + QGroupBox* pGroupBox = new QGroupBox(i18n("Automatic Merge Regular Expression")); + gbox->addWidget(pGroupBox, line, 0, 1, 2); + ++line; + { + QGridLayout* gbox = new QGridLayout(pGroupBox); + gbox->setColumnStretch(1, 10); int line = 0; - label = new QLabel( i18n( "Auto merge regular expression:" ), page ); - gbox->addWidget( label, line, 0 ); - m_pAutoMergeRegExpLineEdit = new OptionLineEdit( ".*\\$(Version|Header|Date|Author).*\\$.*", "AutoMergeRegExp", &m_options.m_autoMergeRegExp, page, this ); - gbox->addWidget( m_pAutoMergeRegExpLineEdit, line, 1 ); - s_autoMergeRegExpToolTip = i18n( "Regular expression for lines where KDiff3 should automatically choose one source.\n" - "When a line with a conflict matches the regular expression then\n" - "- if available - C, otherwise B will be chosen." ); - label->setToolTip( s_autoMergeRegExpToolTip ); + label = new QLabel(i18n("Auto merge regular expression:"), page); + gbox->addWidget(label, line, 0); + m_pAutoMergeRegExpLineEdit = new OptionLineEdit(".*\\$(Version|Header|Date|Author).*\\$.*", "AutoMergeRegExp", &m_options.m_autoMergeRegExp, page, this); + gbox->addWidget(m_pAutoMergeRegExpLineEdit, line, 1); + s_autoMergeRegExpToolTip = i18n("Regular expression for lines where KDiff3 should automatically choose one source.\n" + "When a line with a conflict matches the regular expression then\n" + "- if available - C, otherwise B will be chosen."); + label->setToolTip(s_autoMergeRegExpToolTip); ++line; - OptionCheckBox* pAutoMergeRegExp = new OptionCheckBox( i18n( "Run regular expression auto merge on merge start" ), false, "RunRegExpAutoMergeOnMergeStart", &m_options.m_bRunRegExpAutoMergeOnMergeStart, page, this ); - gbox->addWidget( pAutoMergeRegExp, line, 0, 1, 2 ); - pAutoMergeRegExp->setToolTip( i18n( "Run the merge for auto merge regular expressions\n" - "immediately when a merge starts.\n" ) ); + OptionCheckBox* pAutoMergeRegExp = new OptionCheckBox(i18n("Run regular expression auto merge on merge start"), false, "RunRegExpAutoMergeOnMergeStart", &m_options.m_bRunRegExpAutoMergeOnMergeStart, page, this); + gbox->addWidget(pAutoMergeRegExp, line, 0, 1, 2); + pAutoMergeRegExp->setToolTip(i18n("Run the merge for auto merge regular expressions\n" + "immediately when a merge starts.\n")); ++line; } - pGroupBox = new QGroupBox( i18n( "Version Control History Merging" ) ); - gbox->addWidget( pGroupBox, line, 0, 1, 2 ); + pGroupBox = new QGroupBox(i18n("Version Control History Merging")); + gbox->addWidget(pGroupBox, line, 0, 1, 2); ++line; { - QGridLayout* gbox = new QGridLayout( pGroupBox ); - gbox->setColumnStretch( 1, 10 ); + QGridLayout* gbox = new QGridLayout(pGroupBox); + gbox->setColumnStretch(1, 10); int line = 0; - label = new QLabel( i18n( "History start regular expression:" ), page ); - gbox->addWidget( label, line, 0 ); - m_pHistoryStartRegExpLineEdit = new OptionLineEdit( ".*\\$Log.*\\$.*", "HistoryStartRegExp", &m_options.m_historyStartRegExp, page, this ); - gbox->addWidget( m_pHistoryStartRegExpLineEdit, line, 1 ); - s_historyStartRegExpToolTip = i18n( "Regular expression for the start of the version control history entry.\n" - "Usually this line contains the \"$Log$\" keyword.\n" - "Default value: \".*\\$Log.*\\$.*\"" ); - label->setToolTip( s_historyStartRegExpToolTip ); + label = new QLabel(i18n("History start regular expression:"), page); + gbox->addWidget(label, line, 0); + m_pHistoryStartRegExpLineEdit = new OptionLineEdit(".*\\$Log.*\\$.*", "HistoryStartRegExp", &m_options.m_historyStartRegExp, page, this); + gbox->addWidget(m_pHistoryStartRegExpLineEdit, line, 1); + s_historyStartRegExpToolTip = i18n("Regular expression for the start of the version control history entry.\n" + "Usually this line contains the \"$Log$\" keyword.\n" + "Default value: \".*\\$Log.*\\$.*\""); + label->setToolTip(s_historyStartRegExpToolTip); ++line; - label = new QLabel( i18n( "History entry start regular expression:" ), page ); - gbox->addWidget( label, line, 0 ); + label = new QLabel(i18n("History entry start regular expression:"), page); + gbox->addWidget(label, line, 0); // Example line: "** \main\rolle_fsp_dev_008\1 17 Aug 2001 10:45:44 rolle" QString historyEntryStartDefault = - "\\s*\\\\main\\\\(\\S+)\\s+" // Start with "\main\" - "([0-9]+) " // day + "\\s*\\\\main\\\\(\\S+)\\s+" // Start with "\main\" + "([0-9]+) " // day "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) " //month - "([0-9][0-9][0-9][0-9]) " // year - "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])\\s+(.*)"; // time, name - - m_pHistoryEntryStartRegExpLineEdit = new OptionLineEdit( historyEntryStartDefault, "HistoryEntryStartRegExp", &m_options.m_historyEntryStartRegExp, page, this ); - gbox->addWidget( m_pHistoryEntryStartRegExpLineEdit, line, 1 ); - s_historyEntryStartRegExpToolTip = i18n("A version control history entry consists of several lines.\n" - "Specify the regular expression to detect the first line (without the leading comment).\n" - "Use parentheses to group the keys you want to use for sorting.\n" - "If left empty, then KDiff3 assumes that empty lines separate history entries.\n" - "See the documentation for details."); - label->setToolTip( s_historyEntryStartRegExpToolTip ); - ++line; - - m_pHistoryMergeSorting = new OptionCheckBox( i18n("History merge sorting"), false, "HistoryMergeSorting", &m_options.m_bHistoryMergeSorting, page, this ); - gbox->addWidget( m_pHistoryMergeSorting, line, 0, 1, 2 ); - m_pHistoryMergeSorting->setToolTip( i18n("Sort version control history by a key.") ); - ++line; - //QString branch = newHistoryEntry.cap(1); - //int day = newHistoryEntry.cap(2).toInt(); - //int month = QString("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec").find(newHistoryEntry.cap(3))/4 + 1; - //int year = newHistoryEntry.cap(4).toInt(); - //QString time = newHistoryEntry.cap(5); - //QString name = newHistoryEntry.cap(6); - QString defaultSortKeyOrder = "4,3,2,5,1,6"; //QDate(year,month,day).toString(Qt::ISODate) +" "+ time + " " + branch + " " + name; - - label = new QLabel( i18n("History entry start sort key order:"), page ); - gbox->addWidget( label, line, 0 ); - m_pHistorySortKeyOrderLineEdit = new OptionLineEdit( defaultSortKeyOrder, "HistoryEntryStartSortKeyOrder", &m_options.m_historyEntryStartSortKeyOrder, page, this ); - gbox->addWidget( m_pHistorySortKeyOrderLineEdit, line, 1 ); - s_historyEntryStartSortKeyOrderToolTip = i18n("Each pair of parentheses used in the regular expression for the history start entry\n" - "groups a key that can be used for sorting.\n" - "Specify the list of keys (that are numbered in order of occurrence\n" - "starting with 1) using ',' as separator (e.g. \"4,5,6,1,2,3,7\").\n" - "If left empty, then no sorting will be done.\n" - "See the documentation for details."); - label->setToolTip( s_historyEntryStartSortKeyOrderToolTip ); - m_pHistorySortKeyOrderLineEdit->setEnabled(false); - connect(m_pHistoryMergeSorting, &OptionCheckBox::toggled, m_pHistorySortKeyOrderLineEdit, &OptionLineEdit::setEnabled); - ++line; - - m_pHistoryAutoMerge = new OptionCheckBox( i18n("Merge version control history on merge start"), false, "RunHistoryAutoMergeOnMergeStart", &m_options.m_bRunHistoryAutoMergeOnMergeStart, page, this ); - gbox->addWidget( m_pHistoryAutoMerge, line, 0, 1, 2 ); - m_pHistoryAutoMerge->setToolTip( i18n("Run version control history automerge on merge start.") ); - ++line; - - OptionIntEdit* pMaxNofHistoryEntries = new OptionIntEdit( -1, "MaxNofHistoryEntries", &m_options.m_maxNofHistoryEntries, -1, 1000, page, this ); - label = new QLabel( i18n("Max number of history entries:"), page ); - gbox->addWidget( label, line, 0 ); - gbox->addWidget( pMaxNofHistoryEntries, line, 1 ); - pMaxNofHistoryEntries->setToolTip( i18n("Cut off after specified number. Use -1 for infinite number of entries.") ); - ++line; - } + "([0-9][0-9][0-9][0-9]) " // year + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])\\s+(.*)"; // time, name + + m_pHistoryEntryStartRegExpLineEdit = new OptionLineEdit(historyEntryStartDefault, "HistoryEntryStartRegExp", &m_options.m_historyEntryStartRegExp, page, this); + gbox->addWidget(m_pHistoryEntryStartRegExpLineEdit, line, 1); + s_historyEntryStartRegExpToolTip = i18n("A version control history entry consists of several lines.\n" + "Specify the regular expression to detect the first line (without the leading comment).\n" + "Use parentheses to group the keys you want to use for sorting.\n" + "If left empty, then KDiff3 assumes that empty lines separate history entries.\n" + "See the documentation for details."); + label->setToolTip(s_historyEntryStartRegExpToolTip); + ++line; - QPushButton* pButton = new QPushButton( i18n("Test your regular expressions"), page ); - gbox->addWidget( pButton, line, 0 ); - connect(pButton, &QPushButton::clicked, this, &OptionDialog::slotHistoryMergeRegExpTester); - ++line; + m_pHistoryMergeSorting = new OptionCheckBox(i18n("History merge sorting"), false, "HistoryMergeSorting", &m_options.m_bHistoryMergeSorting, page, this); + gbox->addWidget(m_pHistoryMergeSorting, line, 0, 1, 2); + m_pHistoryMergeSorting->setToolTip(i18n("Sort version control history by a key.")); + ++line; + //QString branch = newHistoryEntry.cap(1); + //int day = newHistoryEntry.cap(2).toInt(); + //int month = QString("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec").find(newHistoryEntry.cap(3))/4 + 1; + //int year = newHistoryEntry.cap(4).toInt(); + //QString time = newHistoryEntry.cap(5); + //QString name = newHistoryEntry.cap(6); + QString defaultSortKeyOrder = "4,3,2,5,1,6"; //QDate(year,month,day).toString(Qt::ISODate) +" "+ time + " " + branch + " " + name; + + label = new QLabel(i18n("History entry start sort key order:"), page); + gbox->addWidget(label, line, 0); + m_pHistorySortKeyOrderLineEdit = new OptionLineEdit(defaultSortKeyOrder, "HistoryEntryStartSortKeyOrder", &m_options.m_historyEntryStartSortKeyOrder, page, this); + gbox->addWidget(m_pHistorySortKeyOrderLineEdit, line, 1); + s_historyEntryStartSortKeyOrderToolTip = i18n("Each pair of parentheses used in the regular expression for the history start entry\n" + "groups a key that can be used for sorting.\n" + "Specify the list of keys (that are numbered in order of occurrence\n" + "starting with 1) using ',' as separator (e.g. \"4,5,6,1,2,3,7\").\n" + "If left empty, then no sorting will be done.\n" + "See the documentation for details."); + label->setToolTip(s_historyEntryStartSortKeyOrderToolTip); + m_pHistorySortKeyOrderLineEdit->setEnabled(false); + connect(m_pHistoryMergeSorting, &OptionCheckBox::toggled, m_pHistorySortKeyOrderLineEdit, &OptionLineEdit::setEnabled); + ++line; - label = new QLabel( i18n("Irrelevant merge command:"), page ); - gbox->addWidget( label, line, 0 ); - OptionLineEdit* pLE = new OptionLineEdit( "", "IrrelevantMergeCmd", &m_options.m_IrrelevantMergeCmd, page, this ); - gbox->addWidget( pLE, line, 1 ); - label->setToolTip( i18n("If specified this script is run after automerge\n" - "when no other relevant changes were detected.\n" - "Called with the parameters: filename1 filename2 filename3") ); - ++line; + m_pHistoryAutoMerge = new OptionCheckBox(i18n("Merge version control history on merge start"), false, "RunHistoryAutoMergeOnMergeStart", &m_options.m_bRunHistoryAutoMergeOnMergeStart, page, this); + gbox->addWidget(m_pHistoryAutoMerge, line, 0, 1, 2); + m_pHistoryAutoMerge->setToolTip(i18n("Run version control history automerge on merge start.")); + ++line; + OptionIntEdit* pMaxNofHistoryEntries = new OptionIntEdit(-1, "MaxNofHistoryEntries", &m_options.m_maxNofHistoryEntries, -1, 1000, page, this); + label = new QLabel(i18n("Max number of history entries:"), page); + gbox->addWidget(label, line, 0); + gbox->addWidget(pMaxNofHistoryEntries, line, 1); + pMaxNofHistoryEntries->setToolTip(i18n("Cut off after specified number. Use -1 for infinite number of entries.")); + ++line; + } - OptionCheckBox* pAutoSaveAndQuit = new OptionCheckBox( i18n("Auto save and quit on merge without conflicts"), false, - "AutoSaveAndQuitOnMergeWithoutConflicts", &m_options.m_bAutoSaveAndQuitOnMergeWithoutConflicts, page, this ); - gbox->addWidget( pAutoSaveAndQuit, line, 0, 1, 2 ); - pAutoSaveAndQuit->setToolTip( i18n("If KDiff3 was started for a file-merge from the command line and all\n" - "conflicts are solvable without user interaction then automatically save and quit.\n" - "(Similar to command line option \"--auto\".)") ); - ++line; + QPushButton* pButton = new QPushButton(i18n("Test your regular expressions"), page); + gbox->addWidget(pButton, line, 0); + connect(pButton, &QPushButton::clicked, this, &OptionDialog::slotHistoryMergeRegExpTester); + ++line; + + label = new QLabel(i18n("Irrelevant merge command:"), page); + gbox->addWidget(label, line, 0); + OptionLineEdit* pLE = new OptionLineEdit("", "IrrelevantMergeCmd", &m_options.m_IrrelevantMergeCmd, page, this); + gbox->addWidget(pLE, line, 1); + label->setToolTip(i18n("If specified this script is run after automerge\n" + "when no other relevant changes were detected.\n" + "Called with the parameters: filename1 filename2 filename3")); + ++line; + + OptionCheckBox* pAutoSaveAndQuit = new OptionCheckBox(i18n("Auto save and quit on merge without conflicts"), false, + "AutoSaveAndQuitOnMergeWithoutConflicts", &m_options.m_bAutoSaveAndQuitOnMergeWithoutConflicts, page, this); + gbox->addWidget(pAutoSaveAndQuit, line, 0, 1, 2); + pAutoSaveAndQuit->setToolTip(i18n("If KDiff3 was started for a file-merge from the command line and all\n" + "conflicts are solvable without user interaction then automatically save and quit.\n" + "(Similar to command line option \"--auto\".)")); + ++line; - topLayout->addStretch(10); + topLayout->addStretch(10); } -void OptionDialog::setupDirectoryMergePage( void ) +void OptionDialog::setupDirectoryMergePage(void) { QFrame* page = new QFrame(); - KPageWidgetItem* pageItem = new KPageWidgetItem( page, i18n( "Directory" ) ); - pageItem->setHeader( i18n( "Directory" ) ); - pageItem->setIcon( QIcon::fromTheme( QStringLiteral( "inode-directory" ) ) ); - addPage( pageItem ); - - QVBoxLayout *topLayout = new QVBoxLayout( page ); - topLayout->setMargin( 5 ); - - QGridLayout *gbox = new QGridLayout(); - gbox->setColumnStretch( 1, 5 ); - topLayout->addLayout( gbox ); + KPageWidgetItem* pageItem = new KPageWidgetItem(page, i18n("Directory")); + pageItem->setHeader(i18n("Directory")); + pageItem->setIcon(QIcon::fromTheme(QStringLiteral("inode-directory"))); + addPage(pageItem); + + QVBoxLayout* topLayout = new QVBoxLayout(page); + topLayout->setMargin(5); + + QGridLayout* gbox = new QGridLayout(); + gbox->setColumnStretch(1, 5); + topLayout->addLayout(gbox); int line = 0; - OptionCheckBox* pRecursiveDirs = new OptionCheckBox( i18n( "Recursive directories" ), true, "RecursiveDirs", &m_options.m_bDmRecursiveDirs, page, this ); - gbox->addWidget( pRecursiveDirs, line, 0, 1, 2 ); - pRecursiveDirs->setToolTip( 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_options.m_DmFilePattern, page, this ); - gbox->addWidget( pFilePattern, line, 1 ); - label->setToolTip( i18n( - "Pattern(s) of files to be analyzed. \n" - "Wildcards: '*' and '?'\n" - "Several Patterns can be specified by using the separator: ';'" - ) ); - ++line; - - label = new QLabel( i18n( "File-anti-pattern(s):" ), page ); - gbox->addWidget( label, line, 0 ); - OptionLineEdit* pFileAntiPattern = new OptionLineEdit( "*.orig;*.o;*.obj;*.rej;*.bak", "FileAntiPattern", &m_options.m_DmFileAntiPattern, page, this ); - gbox->addWidget( pFileAntiPattern, line, 1 ); - label->setToolTip( i18n( - "Pattern(s) of files to be excluded from analysis. \n" - "Wildcards: '*' and '?'\n" - "Several Patterns can be specified by using the separator: ';'" - ) ); - ++line; - - label = new QLabel( i18n( "Dir-anti-pattern(s):" ), page ); - gbox->addWidget( label, line, 0 ); - OptionLineEdit* pDirAntiPattern = new OptionLineEdit( "CVS;.deps;.svn;.hg;.git", "DirAntiPattern", &m_options.m_DmDirAntiPattern, page, this ); - gbox->addWidget( pDirAntiPattern, line, 1 ); - label->setToolTip( i18n( - "Pattern(s) of directories to be excluded from analysis. \n" - "Wildcards: '*' and '?'\n" - "Several Patterns can be specified by using the separator: ';'" - ) ); - ++line; - - OptionCheckBox* pUseCvsIgnore = new OptionCheckBox( i18n( "Use .cvsignore" ), false, "UseCvsIgnore", &m_options.m_bDmUseCvsIgnore, page, this ); - gbox->addWidget( pUseCvsIgnore, line, 0, 1, 2 ); - pUseCvsIgnore->setToolTip( 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_options.m_bDmFindHidden, page, this ); - gbox->addWidget( pFindHidden, line, 0, 1, 2 ); + OptionCheckBox* pRecursiveDirs = new OptionCheckBox(i18n("Recursive directories"), true, "RecursiveDirs", &m_options.m_bDmRecursiveDirs, page, this); + gbox->addWidget(pRecursiveDirs, line, 0, 1, 2); + pRecursiveDirs->setToolTip(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_options.m_DmFilePattern, page, this); + gbox->addWidget(pFilePattern, line, 1); + label->setToolTip(i18n( + "Pattern(s) of files to be analyzed. \n" + "Wildcards: '*' and '?'\n" + "Several Patterns can be specified by using the separator: ';'")); + ++line; + + label = new QLabel(i18n("File-anti-pattern(s):"), page); + gbox->addWidget(label, line, 0); + OptionLineEdit* pFileAntiPattern = new OptionLineEdit("*.orig;*.o;*.obj;*.rej;*.bak", "FileAntiPattern", &m_options.m_DmFileAntiPattern, page, this); + gbox->addWidget(pFileAntiPattern, line, 1); + label->setToolTip(i18n( + "Pattern(s) of files to be excluded from analysis. \n" + "Wildcards: '*' and '?'\n" + "Several Patterns can be specified by using the separator: ';'")); + ++line; + + label = new QLabel(i18n("Dir-anti-pattern(s):"), page); + gbox->addWidget(label, line, 0); + OptionLineEdit* pDirAntiPattern = new OptionLineEdit("CVS;.deps;.svn;.hg;.git", "DirAntiPattern", &m_options.m_DmDirAntiPattern, page, this); + gbox->addWidget(pDirAntiPattern, line, 1); + label->setToolTip(i18n( + "Pattern(s) of directories to be excluded from analysis. \n" + "Wildcards: '*' and '?'\n" + "Several Patterns can be specified by using the separator: ';'")); + ++line; + + OptionCheckBox* pUseCvsIgnore = new OptionCheckBox(i18n("Use .cvsignore"), false, "UseCvsIgnore", &m_options.m_bDmUseCvsIgnore, page, this); + gbox->addWidget(pUseCvsIgnore, line, 0, 1, 2); + pUseCvsIgnore->setToolTip(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_options.m_bDmFindHidden, page, this); + gbox->addWidget(pFindHidden, line, 0, 1, 2); #if defined(_WIN32) || defined(Q_OS_OS2) - pFindHidden->setToolTip( i18n("Finds files and directories with the hidden attribute.") ); + pFindHidden->setToolTip(i18n("Finds files and directories with the hidden attribute.")); #else - pFindHidden->setToolTip( i18n("Finds files and directories starting with '.'.") ); + pFindHidden->setToolTip(i18n("Finds files and directories starting with '.'.")); #endif - ++line; + ++line; - OptionCheckBox* pFollowFileLinks = new OptionCheckBox( i18n("Follow file links"), false, "FollowFileLinks", &m_options.m_bDmFollowFileLinks, page, this ); - gbox->addWidget( pFollowFileLinks, line, 0, 1, 2 ); - pFollowFileLinks->setToolTip( i18n( - "On: Compare the file the link points to.\n" - "Off: Compare the links." - )); - ++line; + OptionCheckBox* pFollowFileLinks = new OptionCheckBox(i18n("Follow file links"), false, "FollowFileLinks", &m_options.m_bDmFollowFileLinks, page, this); + gbox->addWidget(pFollowFileLinks, line, 0, 1, 2); + pFollowFileLinks->setToolTip(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_options.m_bDmFollowDirLinks, page, this ); - gbox->addWidget( pFollowDirLinks, line, 0, 1, 2 ); - pFollowDirLinks->setToolTip( i18n( - "On: Compare the directory the link points to.\n" - "Off: Compare the links." - )); - ++line; + OptionCheckBox* pFollowDirLinks = new OptionCheckBox(i18n("Follow directory links"), false, "FollowDirLinks", &m_options.m_bDmFollowDirLinks, page, this); + gbox->addWidget(pFollowDirLinks, line, 0, 1, 2); + pFollowDirLinks->setToolTip(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_options.m_bDmShowOnlyDeltas, page, this ); - //gbox->addWidget( pShowOnlyDeltas, line, 0, 1, 2 ); - //pShowOnlyDeltas->setToolTip( i18n( - // "Files and directories without change will not appear in the list.")); - //++line; +//OptionCheckBox* pShowOnlyDeltas = new OptionCheckBox( i18n("List only deltas"),false,"ListOnlyDeltas", &m_options.m_bDmShowOnlyDeltas, page, this ); +//gbox->addWidget( pShowOnlyDeltas, line, 0, 1, 2 ); +//pShowOnlyDeltas->setToolTip( i18n( +// "Files and directories without change will not appear in the list.")); +//++line; #if defined(_WIN32) || defined(Q_OS_OS2) - bool bCaseSensitiveFilenameComparison = false; + bool bCaseSensitiveFilenameComparison = false; #else - bool bCaseSensitiveFilenameComparison = true; + bool bCaseSensitiveFilenameComparison = true; #endif - OptionCheckBox* pCaseSensitiveFileNames = new OptionCheckBox( i18n( "Case sensitive filename comparison" ), bCaseSensitiveFilenameComparison, "CaseSensitiveFilenameComparison", &m_options.m_bDmCaseSensitiveFilenameComparison, page, this ); - gbox->addWidget( pCaseSensitiveFileNames, line, 0, 1, 2 ); - pCaseSensitiveFileNames->setToolTip( i18n( - "The directory comparison will compare files or directories when their names match.\n" - "Set this option if the case of the names must match. (Default for Windows is off, otherwise on.)" ) ); + OptionCheckBox* pCaseSensitiveFileNames = new OptionCheckBox(i18n("Case sensitive filename comparison"), bCaseSensitiveFilenameComparison, "CaseSensitiveFilenameComparison", &m_options.m_bDmCaseSensitiveFilenameComparison, page, this); + gbox->addWidget(pCaseSensitiveFileNames, line, 0, 1, 2); + pCaseSensitiveFileNames->setToolTip(i18n( + "The directory comparison will compare files or directories when their names match.\n" + "Set this option if the case of the names must match. (Default for Windows is off, otherwise on.)")); ++line; - OptionCheckBox* pUnfoldSubdirs = new OptionCheckBox( i18n( "Unfold all subdirectories on load" ), false, "UnfoldSubdirs", &m_options.m_bDmUnfoldSubdirs, page, this ); - gbox->addWidget( pUnfoldSubdirs, line, 0, 1, 2 ); - pUnfoldSubdirs->setToolTip( i18n( - "On: Unfold all subdirectories when starting a directory diff.\n" - "Off: Leave subdirectories folded." - ) ); + OptionCheckBox* pUnfoldSubdirs = new OptionCheckBox(i18n("Unfold all subdirectories on load"), false, "UnfoldSubdirs", &m_options.m_bDmUnfoldSubdirs, page, this); + gbox->addWidget(pUnfoldSubdirs, line, 0, 1, 2); + pUnfoldSubdirs->setToolTip(i18n( + "On: Unfold all subdirectories when starting a directory diff.\n" + "Off: Leave subdirectories folded.")); ++line; - OptionCheckBox* pSkipDirStatus = new OptionCheckBox( i18n( "Skip directory status report" ), false, "SkipDirStatus", &m_options.m_bDmSkipDirStatus, page, this ); - gbox->addWidget( pSkipDirStatus, line, 0, 1, 2 ); - pSkipDirStatus->setToolTip( i18n( - "On: Do not show the Directory Comparison Status.\n" - "Off: Show the status dialog on start." - ) ); + OptionCheckBox* pSkipDirStatus = new OptionCheckBox(i18n("Skip directory status report"), false, "SkipDirStatus", &m_options.m_bDmSkipDirStatus, page, this); + gbox->addWidget(pSkipDirStatus, line, 0, 1, 2); + pSkipDirStatus->setToolTip(i18n( + "On: Do not show the Directory Comparison Status.\n" + "Off: Show the status dialog on start.")); ++line; - QGroupBox* pBG = new QGroupBox( i18n( "File Comparison Mode" ) ); - gbox->addWidget( pBG, line, 0, 1, 2 ); + QGroupBox* pBG = new QGroupBox(i18n("File Comparison Mode")); + gbox->addWidget(pBG, line, 0, 1, 2); - QVBoxLayout* pBGLayout = new QVBoxLayout( pBG ); - - OptionRadioButton* pBinaryComparison = new OptionRadioButton( i18n( "Binary comparison" ), true, "BinaryComparison", &m_options.m_bDmBinaryComparison, pBG, this ); - pBinaryComparison->setToolTip( i18n( "Binary comparison of each file. (Default)" ) ); - pBGLayout->addWidget( pBinaryComparison ); + QVBoxLayout* pBGLayout = new QVBoxLayout(pBG); - OptionRadioButton* pFullAnalysis = new OptionRadioButton( i18n( "Full analysis" ), false, "FullAnalysis", &m_options.m_bDmFullAnalysis, pBG, this ); - pFullAnalysis->setToolTip( i18n( "Do a full analysis and show statistics information in extra columns.\n" - "(Slower than a binary comparison, much slower for binary files.)" ) ); - pBGLayout->addWidget( pFullAnalysis ); + OptionRadioButton* pBinaryComparison = new OptionRadioButton(i18n("Binary comparison"), true, "BinaryComparison", &m_options.m_bDmBinaryComparison, pBG, this); + pBinaryComparison->setToolTip(i18n("Binary comparison of each file. (Default)")); + pBGLayout->addWidget(pBinaryComparison); - OptionRadioButton* pTrustDate = new OptionRadioButton( i18n( "Trust the size and modification date (unsafe)" ), false, "TrustDate", &m_options.m_bDmTrustDate, pBG, this ); - pTrustDate->setToolTip( i18n( "Assume that files are equal if the modification date and file length are equal.\n" - "Files with equal contents but different modification dates will appear as different.\n" - "Useful for big directories or slow networks." ) ); - pBGLayout->addWidget( pTrustDate ); + OptionRadioButton* pFullAnalysis = new OptionRadioButton(i18n("Full analysis"), false, "FullAnalysis", &m_options.m_bDmFullAnalysis, pBG, this); + pFullAnalysis->setToolTip(i18n("Do a full analysis and show statistics information in extra columns.\n" + "(Slower than a binary comparison, much slower for binary files.)")); + pBGLayout->addWidget(pFullAnalysis); - OptionRadioButton* pTrustDateFallbackToBinary = new OptionRadioButton( i18n( "Trust the size and date, but use binary comparison if date does not match (unsafe)" ), false, "TrustDateFallbackToBinary", &m_options.m_bDmTrustDateFallbackToBinary, pBG, this ); - pTrustDateFallbackToBinary->setToolTip( i18n( "Assume that files are equal if the modification date and file length are equal.\n" - "If the dates are not equal but the sizes are, use binary comparison.\n" - "Useful for big directories or slow networks." ) ); - pBGLayout->addWidget( pTrustDateFallbackToBinary ); + OptionRadioButton* pTrustDate = new OptionRadioButton(i18n("Trust the size and modification date (unsafe)"), false, "TrustDate", &m_options.m_bDmTrustDate, pBG, this); + pTrustDate->setToolTip(i18n("Assume that files are equal if the modification date and file length are equal.\n" + "Files with equal contents but different modification dates will appear as different.\n" + "Useful for big directories or slow networks.")); + pBGLayout->addWidget(pTrustDate); - OptionRadioButton* pTrustSize = new OptionRadioButton( i18n( "Trust the size (unsafe)" ), false, "TrustSize", &m_options.m_bDmTrustSize, pBG, this ); - pTrustSize->setToolTip( i18n( "Assume that files are equal if their file lengths are equal.\n" - "Useful for big directories or slow networks when the date is modified during download." ) ); - pBGLayout->addWidget( pTrustSize ); + OptionRadioButton* pTrustDateFallbackToBinary = new OptionRadioButton(i18n("Trust the size and date, but use binary comparison if date does not match (unsafe)"), false, "TrustDateFallbackToBinary", &m_options.m_bDmTrustDateFallbackToBinary, pBG, this); + pTrustDateFallbackToBinary->setToolTip(i18n("Assume that files are equal if the modification date and file length are equal.\n" + "If the dates are not equal but the sizes are, use binary comparison.\n" + "Useful for big directories or slow networks.")); + pBGLayout->addWidget(pTrustDateFallbackToBinary); - ++line; + OptionRadioButton* pTrustSize = new OptionRadioButton(i18n("Trust the size (unsafe)"), false, "TrustSize", &m_options.m_bDmTrustSize, pBG, this); + pTrustSize->setToolTip(i18n("Assume that files are equal if their file lengths are equal.\n" + "Useful for big directories or slow networks when the date is modified during download.")); + pBGLayout->addWidget(pTrustSize); + ++line; // Some two Dir-options: Affects only the default actions. - OptionCheckBox* pSyncMode = new OptionCheckBox( i18n( "Synchronize directories" ), false, "SyncMode", &m_options.m_bDmSyncMode, page, this ); - gbox->addWidget( pSyncMode, line, 0, 1, 2 ); - pSyncMode->setToolTip( 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." ) ); + OptionCheckBox* pSyncMode = new OptionCheckBox(i18n("Synchronize directories"), false, "SyncMode", &m_options.m_bDmSyncMode, page, this); + gbox->addWidget(pSyncMode, line, 0, 1, 2); + pSyncMode->setToolTip(i18n( + "Offers to store files in both directories so that\n" + "both directories are the same afterwards.\n" + "Works only when comparing two directories without specifying a destination.")); ++line; // Allow white-space only differences to be considered equal - OptionCheckBox* pWhiteSpaceDiffsEqual = new OptionCheckBox( i18n( "White space differences considered equal" ), true, "WhiteSpaceEqual", &m_options.m_bDmWhiteSpaceEqual, page, this ); - gbox->addWidget( pWhiteSpaceDiffsEqual, line, 0, 1, 2 ); - pWhiteSpaceDiffsEqual->setToolTip( i18n( - "If files differ only by white space consider them equal.\n" - "This is only active when full analysis is chosen." ) ); - connect( pFullAnalysis, &OptionRadioButton::toggled, pWhiteSpaceDiffsEqual, &OptionCheckBox::setEnabled ); - pWhiteSpaceDiffsEqual->setEnabled( false ); + OptionCheckBox* pWhiteSpaceDiffsEqual = new OptionCheckBox(i18n("White space differences considered equal"), true, "WhiteSpaceEqual", &m_options.m_bDmWhiteSpaceEqual, page, this); + gbox->addWidget(pWhiteSpaceDiffsEqual, line, 0, 1, 2); + pWhiteSpaceDiffsEqual->setToolTip(i18n( + "If files differ only by white space consider them equal.\n" + "This is only active when full analysis is chosen.")); + connect(pFullAnalysis, &OptionRadioButton::toggled, pWhiteSpaceDiffsEqual, &OptionCheckBox::setEnabled); + pWhiteSpaceDiffsEqual->setEnabled(false); ++line; - OptionCheckBox* pCopyNewer = new OptionCheckBox( i18n( "Copy newer instead of merging (unsafe)" ), false, "CopyNewer", &m_options.m_bDmCopyNewer, page, this ); - gbox->addWidget( pCopyNewer, line, 0, 1, 2 ); - pCopyNewer->setToolTip( 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." ) ); + OptionCheckBox* pCopyNewer = new OptionCheckBox(i18n("Copy newer instead of merging (unsafe)"), false, "CopyNewer", &m_options.m_bDmCopyNewer, page, this); + gbox->addWidget(pCopyNewer, line, 0, 1, 2); + pCopyNewer->setToolTip(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_options.m_bDmCreateBakFiles, page, this ); - gbox->addWidget( pCreateBakFiles, line, 0, 1, 2 ); - pCreateBakFiles->setToolTip( i18n( - "If 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." ) ); + OptionCheckBox* pCreateBakFiles = new OptionCheckBox(i18n("Backup files (.orig)"), true, "CreateBakFiles", &m_options.m_bDmCreateBakFiles, page, this); + gbox->addWidget(pCreateBakFiles, line, 0, 1, 2); + pCreateBakFiles->setToolTip(i18n( + "If 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 ); + topLayout->addStretch(10); } /* static void insertCodecs(OptionComboBox* p) { std::multimap m; // Using the multimap for case-insensitive sorting. int i; for(i=0;;++i) { QTextCodec* pCodec = QTextCodec::codecForIndex ( i ); if ( pCodec != 0 ) m.insert( std::make_pair( QString(pCodec->mimeName()).toUpper(), pCodec->mimeName()) ); else break; } p->insertItem( i18n("Auto"), 0 ); std::multimap::iterator mi; for(mi=m.begin(), i=0; mi!=m.end(); ++mi, ++i) p->insertItem(mi->second, i+1); } */ /* // UTF8-Codec that saves a BOM // UTF8-Codec that saves a BOM class Utf8BOMCodec : public QTextCodec { QTextCodec* m_pUtf8Codec; class PublicTextCodec : public QTextCodec { public: QString publicConvertToUnicode ( const char * p, int len, ConverterState* pState ) const { return convertToUnicode( p, len, pState ); } QByteArray publicConvertFromUnicode ( const QChar * input, int number, ConverterState * pState ) const { return convertFromUnicode( input, number, pState ); } }; public: Utf8BOMCodec() { m_pUtf8Codec = QTextCodec::codecForName("UTF-8"); } QByteArray name () const { return "UTF-8-BOM"; } int mibEnum () const { return 2123; } QByteArray convertFromUnicode ( const QChar * input, int number, ConverterState * pState ) const { QByteArray r; if ( pState && pState->state_data[2]==0) // state_data[2] not used by QUtf8::convertFromUnicode (see qutfcodec.cpp) { r += "\xEF\xBB\xBF"; pState->state_data[2]=1; pState->flags |= QTextCodec::IgnoreHeader; } r += ((PublicTextCodec*)m_pUtf8Codec)->publicConvertFromUnicode( input, number, pState ); return r; } QString convertToUnicode ( const char * p, int len, ConverterState* pState ) const { return ((PublicTextCodec*)m_pUtf8Codec)->publicConvertToUnicode( p, len, pState ); } }; */ -void OptionDialog::setupRegionalPage( void ) +void OptionDialog::setupRegionalPage(void) { - /* + /* TODO: What is this line supposed to do besides leak memmory? Intruduced as is in .91 no explaination new Utf8BOMCodec(); */ - QFrame* page = new QFrame(); - KPageWidgetItem* pageItem = new KPageWidgetItem( page, i18n("Regional Settings") ); - pageItem->setHeader( i18n("Regional Settings") ); - pageItem->setIcon( QIcon::fromTheme(QStringLiteral("preferences-desktop-locale")) ); - addPage( pageItem ); - - QVBoxLayout *topLayout = new QVBoxLayout( page ); - topLayout->setMargin( 5 ); - - QGridLayout *gbox = new QGridLayout(); - gbox->setColumnStretch( 1, 5 ); - topLayout->addLayout( gbox ); + QFrame* page = new QFrame(); + KPageWidgetItem* pageItem = new KPageWidgetItem(page, i18n("Regional Settings")); + pageItem->setHeader(i18n("Regional Settings")); + pageItem->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-locale"))); + addPage(pageItem); + + QVBoxLayout* topLayout = new QVBoxLayout(page); + topLayout->setMargin(5); + + QGridLayout* gbox = new QGridLayout(); + gbox->setColumnStretch(1, 5); + topLayout->addLayout(gbox); int line = 0; - QLabel* label; + QLabel* label; #ifdef KREPLACEMENTS_H - -static const char* countryMap[]={ -"af Afrikaans", -"ar Arabic", -"az Azerbaijani", -"be Belarusian", -"bg Bulgarian", -"bn Bengali", -"bo Tibetan", -"br Breton", -"bs Bosnian", -"ca Catalan", -"ca@valencia Catalan (Valencian)", -"cs Czech", -"cy Welsh", -"da Danish", -"de German", -"el Greek", -"en_GB British English", -"eo Esperanto", -"es Spanish", -"et Estonian", -"eu Basque", -"fa Farsi (Persian)", -"fi Finnish", -"fo Faroese", -"fr French", -"ga Irish Gaelic", -"gl Galician", -"gu Gujarati", -"he Hebrew", -"hi Hindi", -"hne Chhattisgarhi", -"hr Croatian", -"hsb Upper Sorbian", -"hu Hungarian", -"id Indonesian", -"is Icelandic", -"it Italian", -"ja Japanese", -"ka Georgian", -"ko Korean", -"ku Kurdish", -"lo Lao", -"lt Lithuanian", -"lv Latvian", -"mi Maori", -"mk Macedonian", -"ml Malayalam" -"mn Mongolian", -"ms Malay", -"mt Maltese", -"nb Norwegian Bookmal", -"nds Low Saxon", -"nl Dutch", -"nn Norwegian Nynorsk", -"nso Northern Sotho", -"oc Occitan", -"pl Polish", -"pt Portuguese", -"pt_BR Brazilian Portuguese", -"ro Romanian", -"ru Russian", -"rw Kinyarwanda", -"se Northern Sami", -"sk Slovak", -"sl Slovenian", -"sq Albanian", -"sr Serbian", -"sr@Latn Serbian", -"ss Swati", -"sv Swedish", -"ta Tamil", -"tg Tajik", -"th Thai", -"tr Turkish", -"uk Ukrainian", -"uz Uzbek", -"ven Venda", -"vi Vietnamese", -"wa Walloon", -"xh Xhosa", -"zh_CN Chinese Simplified", -"zh_TW Chinese Traditional", -"zu Zulu" -}; - label = new QLabel( i18n("Language (restart required)"), page ); - gbox->addWidget( label, line, 0 ); - OptionComboBox* pLanguage = new OptionComboBox( 0, "Language", &m_options.m_language, page, this ); - gbox->addWidget( pLanguage, line, 1 ); - pLanguage->addItem( "Auto" ); // Must not translate, won't work otherwise! - pLanguage->addItem( "en_orig" ); - + static const char* countryMap[] = { + "af Afrikaans", + "ar Arabic", + "az Azerbaijani", + "be Belarusian", + "bg Bulgarian", + "bn Bengali", + "bo Tibetan", + "br Breton", + "bs Bosnian", + "ca Catalan", + "ca@valencia Catalan (Valencian)", + "cs Czech", + "cy Welsh", + "da Danish", + "de German", + "el Greek", + "en_GB British English", + "eo Esperanto", + "es Spanish", + "et Estonian", + "eu Basque", + "fa Farsi (Persian)", + "fi Finnish", + "fo Faroese", + "fr French", + "ga Irish Gaelic", + "gl Galician", + "gu Gujarati", + "he Hebrew", + "hi Hindi", + "hne Chhattisgarhi", + "hr Croatian", + "hsb Upper Sorbian", + "hu Hungarian", + "id Indonesian", + "is Icelandic", + "it Italian", + "ja Japanese", + "ka Georgian", + "ko Korean", + "ku Kurdish", + "lo Lao", + "lt Lithuanian", + "lv Latvian", + "mi Maori", + "mk Macedonian", + "ml Malayalam" + "mn Mongolian", + "ms Malay", + "mt Maltese", + "nb Norwegian Bookmal", + "nds Low Saxon", + "nl Dutch", + "nn Norwegian Nynorsk", + "nso Northern Sotho", + "oc Occitan", + "pl Polish", + "pt Portuguese", + "pt_BR Brazilian Portuguese", + "ro Romanian", + "ru Russian", + "rw Kinyarwanda", + "se Northern Sami", + "sk Slovak", + "sl Slovenian", + "sq Albanian", + "sr Serbian", + "sr@Latn Serbian", + "ss Swati", + "sv Swedish", + "ta Tamil", + "tg Tajik", + "th Thai", + "tr Turkish", + "uk Ukrainian", + "uz Uzbek", + "ven Venda", + "vi Vietnamese", + "wa Walloon", + "xh Xhosa", + "zh_CN Chinese Simplified", + "zh_TW Chinese Traditional", + "zu Zulu"}; + + label = new QLabel(i18n("Language (restart required)"), page); + gbox->addWidget(label, line, 0); + OptionComboBox* pLanguage = new OptionComboBox(0, "Language", &m_options.m_language, page, this); + gbox->addWidget(pLanguage, line, 1); + pLanguage->addItem("Auto"); // Must not translate, won't work otherwise! + pLanguage->addItem("en_orig"); + #if !defined(_WIN32) && !defined(Q_OS_OS2) && !defined(__APPLE__) - // Read directory: Find all kdiff3_*.qm-files and insert the found files here - QDir localeDir( "/usr/share/locale" ); // See also kreplacements.cpp: getTranslationDir() - QStringList dirList = localeDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + // Read directory: Find all kdiff3_*.qm-files and insert the found files here + QDir localeDir("/usr/share/locale"); // See also kreplacements.cpp: getTranslationDir() + QStringList dirList = localeDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); - for( int i = 0; iaddItem( languageId ); - } - - label->setToolTip( i18n( - "Choose the language of the GUI strings or \"Auto\".\n" - "For a change of language to take place, quit and restart KDiff3.") - ); - ++line; + unsigned int countryIdx = 0; + for(countryIdx = 0; countryIdx < sizeof(countryMap) / sizeof(countryMap[0]); ++countryIdx) + { + QString fullName = countryMap[countryIdx]; + if(QString(languageId + " ") == fullName.left(languageId.length() + 1)) + { + languageId += " (" + fullName.mid(languageId.length() + 1) + ")"; + } + } + + pLanguage->addItem(languageId); + } + + label->setToolTip(i18n( + "Choose the language of the GUI strings or \"Auto\".\n" + "For a change of language to take place, quit and restart KDiff3.")); + ++line; /* label = new QLabel( i18n("Codec for file contents"), page ); gbox->addWidget( label, line, 0 ); OptionComboBox* pFileCodec = new OptionComboBox( 0, "FileCodec", &m_options.m_fileCodec, page, this ); gbox->addWidget( pFileCodec, line, 1 ); insertCodecs( pFileCodec ); label->setToolTip( i18n( "Choose the codec that should be used for your input files\n" "or \"Auto\" if unsure." ) ); ++line; -*/ +*/ #endif - m_pSameEncoding = new OptionCheckBox( i18n("Use the same encoding for everything:"), true, "SameEncoding", &m_options.m_bSameEncoding, page, this ); - gbox->addWidget( m_pSameEncoding, line, 0, 1, 2 ); - m_pSameEncoding->setToolTip( i18n( - "Enable this allows to change all encodings by changing the first only.\n" - "Disable this if different individual settings are needed." - ) ); - ++line; - - label = new QLabel( i18n("Note: Local Encoding is ") + "\"" + QTextCodec::codecForLocale()->name() + "\"", page ); - gbox->addWidget( label, line, 0 ); - ++line; - - label = new QLabel( i18n("File Encoding for A:"), page ); - gbox->addWidget( label, line, 0 ); - m_pEncodingAComboBox = new OptionEncodingComboBox( "EncodingForA", &m_options.m_pEncodingA, page, this ); - gbox->addWidget( m_pEncodingAComboBox, line, 1 ); + m_pSameEncoding = new OptionCheckBox(i18n("Use the same encoding for everything:"), true, "SameEncoding", &m_options.m_bSameEncoding, page, this); + gbox->addWidget(m_pSameEncoding, line, 0, 1, 2); + m_pSameEncoding->setToolTip(i18n( + "Enable this allows to change all encodings by changing the first only.\n" + "Disable this if different individual settings are needed.")); + ++line; - QString autoDetectToolTip = i18n( - "If enabled then Unicode (UTF-16 or UTF-8) encoding will be detected.\n" - "If the file is not Unicode then the selected encoding will be used as fallback.\n" - "(Unicode detection depends on the first bytes of a file.)" - ); - m_pAutoDetectUnicodeA = new OptionCheckBox( i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeA", &m_options.m_bAutoDetectUnicodeA, page, this ); - gbox->addWidget( m_pAutoDetectUnicodeA, line, 2 ); - m_pAutoDetectUnicodeA->setToolTip( autoDetectToolTip ); - ++line; + label = new QLabel(i18n("Note: Local Encoding is ") + "\"" + QTextCodec::codecForLocale()->name() + "\"", page); + gbox->addWidget(label, line, 0); + ++line; - label = new QLabel( i18n("File Encoding for B:"), page ); - gbox->addWidget( label, line, 0 ); - m_pEncodingBComboBox = new OptionEncodingComboBox( "EncodingForB", &m_options.m_pEncodingB, page, this ); - gbox->addWidget( m_pEncodingBComboBox, line, 1 ); - m_pAutoDetectUnicodeB = new OptionCheckBox( i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeB", &m_options.m_bAutoDetectUnicodeB, page, this ); - gbox->addWidget( m_pAutoDetectUnicodeB, line, 2 ); - m_pAutoDetectUnicodeB->setToolTip( autoDetectToolTip ); - ++line; + label = new QLabel(i18n("File Encoding for A:"), page); + gbox->addWidget(label, line, 0); + m_pEncodingAComboBox = new OptionEncodingComboBox("EncodingForA", &m_options.m_pEncodingA, page, this); + gbox->addWidget(m_pEncodingAComboBox, line, 1); + + QString autoDetectToolTip = i18n( + "If enabled then Unicode (UTF-16 or UTF-8) encoding will be detected.\n" + "If the file is not Unicode then the selected encoding will be used as fallback.\n" + "(Unicode detection depends on the first bytes of a file.)"); + m_pAutoDetectUnicodeA = new OptionCheckBox(i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeA", &m_options.m_bAutoDetectUnicodeA, page, this); + gbox->addWidget(m_pAutoDetectUnicodeA, line, 2); + m_pAutoDetectUnicodeA->setToolTip(autoDetectToolTip); + ++line; - label = new QLabel( i18n("File Encoding for C:"), page ); - gbox->addWidget( label, line, 0 ); - m_pEncodingCComboBox = new OptionEncodingComboBox( "EncodingForC", &m_options.m_pEncodingC, page, this ); - gbox->addWidget( m_pEncodingCComboBox, line, 1 ); - m_pAutoDetectUnicodeC = new OptionCheckBox( i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeC", &m_options.m_bAutoDetectUnicodeC, page, this ); - gbox->addWidget( m_pAutoDetectUnicodeC, line, 2 ); - m_pAutoDetectUnicodeC->setToolTip( autoDetectToolTip ); - ++line; + label = new QLabel(i18n("File Encoding for B:"), page); + gbox->addWidget(label, line, 0); + m_pEncodingBComboBox = new OptionEncodingComboBox("EncodingForB", &m_options.m_pEncodingB, page, this); + gbox->addWidget(m_pEncodingBComboBox, line, 1); + m_pAutoDetectUnicodeB = new OptionCheckBox(i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeB", &m_options.m_bAutoDetectUnicodeB, page, this); + gbox->addWidget(m_pAutoDetectUnicodeB, line, 2); + m_pAutoDetectUnicodeB->setToolTip(autoDetectToolTip); + ++line; - label = new QLabel( i18n("File Encoding for Merge Output and Saving:"), page ); - gbox->addWidget( label, line, 0 ); - m_pEncodingOutComboBox = new OptionEncodingComboBox( "EncodingForOutput", &m_options.m_pEncodingOut, page, this ); - gbox->addWidget( m_pEncodingOutComboBox, line, 1 ); - m_pAutoSelectOutEncoding = new OptionCheckBox( i18n("Auto Select"), true, "AutoSelectOutEncoding", &m_options.m_bAutoSelectOutEncoding, page, this ); - gbox->addWidget( m_pAutoSelectOutEncoding, line, 2 ); - m_pAutoSelectOutEncoding->setToolTip( i18n( - "If enabled then the encoding from the input files is used.\n" - "In ambiguous cases a dialog will ask the user to choose the encoding for saving." - ) ); - ++line; - label = new QLabel( i18n("File Encoding for Preprocessor Files:"), page ); - gbox->addWidget( label, line, 0 ); - m_pEncodingPPComboBox = new OptionEncodingComboBox( "EncodingForPP", &m_options.m_pEncodingPP, page, this ); - gbox->addWidget( m_pEncodingPPComboBox, line, 1 ); - ++line; + label = new QLabel(i18n("File Encoding for C:"), page); + gbox->addWidget(label, line, 0); + m_pEncodingCComboBox = new OptionEncodingComboBox("EncodingForC", &m_options.m_pEncodingC, page, this); + gbox->addWidget(m_pEncodingCComboBox, line, 1); + m_pAutoDetectUnicodeC = new OptionCheckBox(i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeC", &m_options.m_bAutoDetectUnicodeC, page, this); + gbox->addWidget(m_pAutoDetectUnicodeC, line, 2); + m_pAutoDetectUnicodeC->setToolTip(autoDetectToolTip); + ++line; - connect(m_pSameEncoding, &OptionCheckBox::toggled, this, &OptionDialog::slotEncodingChanged); - connect(m_pEncodingAComboBox, static_cast(&OptionEncodingComboBox::activated), this, &OptionDialog::slotEncodingChanged); - connect(m_pAutoDetectUnicodeA, &OptionCheckBox::toggled, this, &OptionDialog::slotEncodingChanged); - connect(m_pAutoSelectOutEncoding, &OptionCheckBox::toggled, this, &OptionDialog::slotEncodingChanged); + label = new QLabel(i18n("File Encoding for Merge Output and Saving:"), page); + gbox->addWidget(label, line, 0); + m_pEncodingOutComboBox = new OptionEncodingComboBox("EncodingForOutput", &m_options.m_pEncodingOut, page, this); + gbox->addWidget(m_pEncodingOutComboBox, line, 1); + m_pAutoSelectOutEncoding = new OptionCheckBox(i18n("Auto Select"), true, "AutoSelectOutEncoding", &m_options.m_bAutoSelectOutEncoding, page, this); + gbox->addWidget(m_pAutoSelectOutEncoding, line, 2); + m_pAutoSelectOutEncoding->setToolTip(i18n( + "If enabled then the encoding from the input files is used.\n" + "In ambiguous cases a dialog will ask the user to choose the encoding for saving.")); + ++line; + label = new QLabel(i18n("File Encoding for Preprocessor Files:"), page); + gbox->addWidget(label, line, 0); + m_pEncodingPPComboBox = new OptionEncodingComboBox("EncodingForPP", &m_options.m_pEncodingPP, page, this); + gbox->addWidget(m_pEncodingPPComboBox, line, 1); + ++line; - OptionCheckBox* pRightToLeftLanguage = new OptionCheckBox( i18n("Right To Left Language"), false, "RightToLeftLanguage", &m_options.m_bRightToLeftLanguage, page, this ); - gbox->addWidget( pRightToLeftLanguage, line, 0, 1, 2 ); - pRightToLeftLanguage->setToolTip( i18n( - "Some languages are read from right to left.\n" - "This setting will change the viewer and editor accordingly.")); - ++line; + connect(m_pSameEncoding, &OptionCheckBox::toggled, this, &OptionDialog::slotEncodingChanged); + connect(m_pEncodingAComboBox, static_cast(&OptionEncodingComboBox::activated), this, &OptionDialog::slotEncodingChanged); + connect(m_pAutoDetectUnicodeA, &OptionCheckBox::toggled, this, &OptionDialog::slotEncodingChanged); + connect(m_pAutoSelectOutEncoding, &OptionCheckBox::toggled, this, &OptionDialog::slotEncodingChanged); + OptionCheckBox* pRightToLeftLanguage = new OptionCheckBox(i18n("Right To Left Language"), false, "RightToLeftLanguage", &m_options.m_bRightToLeftLanguage, page, this); + gbox->addWidget(pRightToLeftLanguage, line, 0, 1, 2); + pRightToLeftLanguage->setToolTip(i18n( + "Some languages are read from right to left.\n" + "This setting will change the viewer and editor accordingly.")); + ++line; - topLayout->addStretch(10); + topLayout->addStretch(10); } #ifdef _WIN32 #include "ccInstHelper.cpp" #endif -void OptionDialog::setupIntegrationPage( void ) +void OptionDialog::setupIntegrationPage(void) { QFrame* page = new QFrame(); - KPageWidgetItem* pageItem = new KPageWidgetItem( page, i18n( "Integration" ) ); - pageItem->setHeader( i18n( "Integration Settings" ) ); - pageItem->setIcon( QIcon::fromTheme( QStringLiteral( "utilities-terminal" ) ) ); - addPage( pageItem ); - - QVBoxLayout *topLayout = new QVBoxLayout( page ); - topLayout->setMargin( 5 ); - - QGridLayout *gbox = new QGridLayout(); - gbox->setColumnStretch( 2, 5 ); - topLayout->addLayout( gbox ); + KPageWidgetItem* pageItem = new KPageWidgetItem(page, i18n("Integration")); + pageItem->setHeader(i18n("Integration Settings")); + pageItem->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); + addPage(pageItem); + + QVBoxLayout* topLayout = new QVBoxLayout(page); + topLayout->setMargin(5); + + QGridLayout* gbox = new QGridLayout(); + gbox->setColumnStretch(2, 5); + topLayout->addLayout(gbox); int line = 0; QLabel* label; - label = new QLabel( i18n( "Command line options to ignore:" ), page ); - gbox->addWidget( label, line, 0 ); - OptionLineEdit* pIgnorableCmdLineOptions = new OptionLineEdit( "-u;-query;-html;-abort", "IgnorableCmdLineOptions", &m_options.m_ignorableCmdLineOptions, page, this ); - gbox->addWidget( pIgnorableCmdLineOptions, line, 1, 1, 2 ); - label->setToolTip( i18n( - "List of command line options that should be ignored when KDiff3 is used by other tools.\n" - "Several values can be specified if separated via ';'\n" - "This will suppress the \"Unknown option\" error." - ) ); + label = new QLabel(i18n("Command line options to ignore:"), page); + gbox->addWidget(label, line, 0); + OptionLineEdit* pIgnorableCmdLineOptions = new OptionLineEdit("-u;-query;-html;-abort", "IgnorableCmdLineOptions", &m_options.m_ignorableCmdLineOptions, page, this); + gbox->addWidget(pIgnorableCmdLineOptions, line, 1, 1, 2); + label->setToolTip(i18n( + "List of command line options that should be ignored when KDiff3 is used by other tools.\n" + "Several values can be specified if separated via ';'\n" + "This will suppress the \"Unknown option\" error.")); ++line; - - OptionCheckBox* pEscapeKeyQuits = new OptionCheckBox( i18n( "Quit also via Escape key" ), false, "EscapeKeyQuits", &m_options.m_bEscapeKeyQuits, page, this ); - gbox->addWidget( pEscapeKeyQuits, line, 0, 1, 2 ); - pEscapeKeyQuits->setToolTip( i18n( - "Fast method to exit.\n" - "For those who are used to using the Escape key." ) ); + OptionCheckBox* pEscapeKeyQuits = new OptionCheckBox(i18n("Quit also via Escape key"), false, "EscapeKeyQuits", &m_options.m_bEscapeKeyQuits, page, this); + gbox->addWidget(pEscapeKeyQuits, line, 0, 1, 2); + pEscapeKeyQuits->setToolTip(i18n( + "Fast method to exit.\n" + "For those who are used to using the Escape key.")); ++line; #ifdef _WIN32 - QPushButton* pIntegrateWithClearCase = new QPushButton( i18n("Integrate with ClearCase"), page); - gbox->addWidget( pIntegrateWithClearCase, line, 0 ); - pIntegrateWithClearCase->setToolTip( i18n( - "Integrate with Rational ClearCase from IBM.\n" - "Modifies the \"map\" file in ClearCase subdir \"lib/mgrs\"\n" - "(Only enabled when ClearCase \"bin\" directory is in the path.)")); - connect(pIntegrateWithClearCase, &QPushButton::clicked, this, &OptionDialog::slotIntegrateWithClearCase); - pIntegrateWithClearCase->setEnabled( integrateWithClearCase( "existsClearCase", "" )!=0 ); - - QPushButton* pRemoveClearCaseIntegration = new QPushButton( i18n("Remove ClearCase Integration"), page); - gbox->addWidget( pRemoveClearCaseIntegration, line, 1 ); - pRemoveClearCaseIntegration->setToolTip( i18n( - "Restore the old \"map\" file from before doing the ClearCase integration.")); - connect(pRemoveClearCaseIntegration, &QPushButton::clicked, this, &OptionDialog::slotRemoveClearCaseIntegration); - pRemoveClearCaseIntegration->setEnabled( integrateWithClearCase( "existsClearCase", "" )!=0 ); + QPushButton* pIntegrateWithClearCase = new QPushButton(i18n("Integrate with ClearCase"), page); + gbox->addWidget(pIntegrateWithClearCase, line, 0); + pIntegrateWithClearCase->setToolTip(i18n( + "Integrate with Rational ClearCase from IBM.\n" + "Modifies the \"map\" file in ClearCase subdir \"lib/mgrs\"\n" + "(Only enabled when ClearCase \"bin\" directory is in the path.)")); + connect(pIntegrateWithClearCase, &QPushButton::clicked, this, &OptionDialog::slotIntegrateWithClearCase); + pIntegrateWithClearCase->setEnabled(integrateWithClearCase("existsClearCase", "") != 0); + + QPushButton* pRemoveClearCaseIntegration = new QPushButton(i18n("Remove ClearCase Integration"), page); + gbox->addWidget(pRemoveClearCaseIntegration, line, 1); + pRemoveClearCaseIntegration->setToolTip(i18n( + "Restore the old \"map\" file from before doing the ClearCase integration.")); + connect(pRemoveClearCaseIntegration, &QPushButton::clicked, this, &OptionDialog::slotRemoveClearCaseIntegration); + pRemoveClearCaseIntegration->setEnabled(integrateWithClearCase("existsClearCase", "") != 0); - ++line; + ++line; #endif - topLayout->addStretch(10); + topLayout->addStretch(10); } void OptionDialog::slotIntegrateWithClearCase() { #ifdef _WIN32 - char kdiff3CommandPath[1000]; - GetModuleFileNameA( 0, kdiff3CommandPath, sizeof(kdiff3CommandPath)-1 ); - integrateWithClearCase( "install", kdiff3CommandPath ); + char kdiff3CommandPath[1000]; + GetModuleFileNameA(0, kdiff3CommandPath, sizeof(kdiff3CommandPath) - 1); + integrateWithClearCase("install", kdiff3CommandPath); #endif } void OptionDialog::slotRemoveClearCaseIntegration() { #ifdef _WIN32 - char kdiff3CommandPath[1000]; - GetModuleFileNameA( 0, kdiff3CommandPath, sizeof(kdiff3CommandPath)-1 ); - integrateWithClearCase( "uninstall", kdiff3CommandPath ); + char kdiff3CommandPath[1000]; + GetModuleFileNameA(0, kdiff3CommandPath, sizeof(kdiff3CommandPath) - 1); + integrateWithClearCase("uninstall", kdiff3CommandPath); #endif } void OptionDialog::slotEncodingChanged() { - if ( m_pSameEncoding->isChecked() ) - { - m_pEncodingBComboBox->setEnabled( false ); - m_pEncodingBComboBox->setCurrentIndex( m_pEncodingAComboBox->currentIndex() ); - m_pEncodingCComboBox->setEnabled( false ); - m_pEncodingCComboBox->setCurrentIndex( m_pEncodingAComboBox->currentIndex() ); - m_pEncodingOutComboBox->setEnabled( false ); - m_pEncodingOutComboBox->setCurrentIndex( m_pEncodingAComboBox->currentIndex() ); - m_pEncodingPPComboBox->setEnabled( false ); - m_pEncodingPPComboBox->setCurrentIndex( m_pEncodingAComboBox->currentIndex() ); - m_pAutoDetectUnicodeB->setEnabled( false ); - m_pAutoDetectUnicodeB->setCheckState( m_pAutoDetectUnicodeA->checkState() ); - m_pAutoDetectUnicodeC->setEnabled( false ); - m_pAutoDetectUnicodeC->setCheckState( m_pAutoDetectUnicodeA->checkState() ); - m_pAutoSelectOutEncoding->setEnabled( false ); - m_pAutoSelectOutEncoding->setCheckState( m_pAutoDetectUnicodeA->checkState() ); - } - else - { - m_pEncodingBComboBox->setEnabled( true ); - m_pEncodingCComboBox->setEnabled( true ); - m_pEncodingOutComboBox->setEnabled( true ); - m_pEncodingPPComboBox->setEnabled( true ); - m_pAutoDetectUnicodeB->setEnabled( true ); - m_pAutoDetectUnicodeC->setEnabled( true ); - m_pAutoSelectOutEncoding->setEnabled( true ); - m_pEncodingOutComboBox->setEnabled( m_pAutoSelectOutEncoding->checkState()==Qt::Unchecked ); - } + if(m_pSameEncoding->isChecked()) + { + m_pEncodingBComboBox->setEnabled(false); + m_pEncodingBComboBox->setCurrentIndex(m_pEncodingAComboBox->currentIndex()); + m_pEncodingCComboBox->setEnabled(false); + m_pEncodingCComboBox->setCurrentIndex(m_pEncodingAComboBox->currentIndex()); + m_pEncodingOutComboBox->setEnabled(false); + m_pEncodingOutComboBox->setCurrentIndex(m_pEncodingAComboBox->currentIndex()); + m_pEncodingPPComboBox->setEnabled(false); + m_pEncodingPPComboBox->setCurrentIndex(m_pEncodingAComboBox->currentIndex()); + m_pAutoDetectUnicodeB->setEnabled(false); + m_pAutoDetectUnicodeB->setCheckState(m_pAutoDetectUnicodeA->checkState()); + m_pAutoDetectUnicodeC->setEnabled(false); + m_pAutoDetectUnicodeC->setCheckState(m_pAutoDetectUnicodeA->checkState()); + m_pAutoSelectOutEncoding->setEnabled(false); + m_pAutoSelectOutEncoding->setCheckState(m_pAutoDetectUnicodeA->checkState()); + } + else + { + m_pEncodingBComboBox->setEnabled(true); + m_pEncodingCComboBox->setEnabled(true); + m_pEncodingOutComboBox->setEnabled(true); + m_pEncodingPPComboBox->setEnabled(true); + m_pAutoDetectUnicodeB->setEnabled(true); + m_pAutoDetectUnicodeC->setEnabled(true); + m_pAutoSelectOutEncoding->setEnabled(true); + m_pEncodingOutComboBox->setEnabled(m_pAutoSelectOutEncoding->checkState() == Qt::Unchecked); + } } -void OptionDialog::setupKeysPage( void ) +void OptionDialog::setupKeysPage(void) { - //QVBox *page = addVBoxPage( i18n("Keys"), i18n("KeyDialog" ), - // BarIcon("fonts", KIconLoader::SizeMedium ) ); + //QVBox *page = addVBoxPage( i18n("Keys"), i18n("KeyDialog" ), + // BarIcon("fonts", KIconLoader::SizeMedium ) ); - //QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + //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 ); + //m_pKeyDialog=new KKeyDialog( false, 0 ); + //topLayout->addWidget( m_pKeyDialog ); } -void OptionDialog::slotOk( void ) +void OptionDialog::slotOk(void) { - slotApply(); + slotApply(); - accept(); + accept(); } - /** Copy the values from the widgets to the public variables.*/ -void OptionDialog::slotApply( void ) +void OptionDialog::slotApply(void) { - std::list::iterator i; - for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i) - { - (*i)->apply(); - } + std::list::iterator i; + for(i = m_optionItemList.begin(); i != m_optionItemList.end(); ++i) + { + (*i)->apply(); + } - emit applyDone(); + emit applyDone(); #ifdef _WIN32 - QString locale = m_options.m_language; - if ( locale == "Auto" || locale.isEmpty() ) - locale = QLocale::system().name().left(2); - int spacePos = locale.indexOf(' '); - if (spacePos>0) locale = locale.left(spacePos); - QSettings settings("HKEY_CURRENT_USER\\Software\\KDiff3\\diff-ext", QSettings::NativeFormat); - settings.setValue( "Language", locale ); + QString locale = m_options.m_language; + if(locale == "Auto" || locale.isEmpty()) + locale = QLocale::system().name().left(2); + int spacePos = locale.indexOf(' '); + if(spacePos > 0) locale = locale.left(spacePos); + QSettings settings("HKEY_CURRENT_USER\\Software\\KDiff3\\diff-ext", QSettings::NativeFormat); + settings.setValue("Language", locale); #endif } /** Set the default values in the widgets only, while the public variables remain unchanged. */ void OptionDialog::slotDefault() { - int result = KMessageBox::warningContinueCancel(this, i18n("This resets all options. Not only those of the current topic.") ); - if ( result==KMessageBox::Cancel ) return; - else resetToDefaults(); + 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(); - } + std::list::iterator i; + for(i = m_optionItemList.begin(); i != m_optionItemList.end(); ++i) + { + (*i)->setToDefault(); + } - slotEncodingChanged(); + slotEncodingChanged(); } /** 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(); - } + std::list::iterator i; + for(i = m_optionItemList.begin(); i != m_optionItemList.end(); ++i) + { + (*i)->setToCurrent(); + } - slotEncodingChanged(); + slotEncodingChanged(); } class ConfigValueMap : public ValueMap { - private: - KConfigGroup m_config; - public: - ConfigValueMap( const KConfigGroup& config ) : m_config( config ) { } + private: + KConfigGroup m_config; - void writeEntry( const QString& s, const QFont& v ) { - m_config.writeEntry( s, v ); - } - void writeEntry( const QString& s, const QColor& v ) { - m_config.writeEntry( s, v ); - } - void writeEntry( const QString& s, const QSize& v ) { - m_config.writeEntry( s, v ); - } - void writeEntry( const QString& s, const QPoint& v ) { - m_config.writeEntry( s, v ); - } - void writeEntry( const QString& s, int v ) { - m_config.writeEntry( s, v ); - } - void writeEntry( const QString& s, bool v ) { - m_config.writeEntry( s, v ); - } - void writeEntry( const QString& s, const QString& v ) { - m_config.writeEntry( s, v ); - } - void writeEntry( const QString& s, const char* v ) { - m_config.writeEntry( s, v ); - } + public: + ConfigValueMap(const KConfigGroup& config) : m_config(config) {} - QFont readFontEntry( const QString& s, const QFont* defaultVal ) { - return m_config.readEntry( s, *defaultVal ); - } - QColor readColorEntry( const QString& s, const QColor* defaultVal ) { - return m_config.readEntry( s, *defaultVal ); - } - QSize readSizeEntry( const QString& s, const QSize* defaultVal ) { - return m_config.readEntry( s, *defaultVal ); - } - QPoint readPointEntry( const QString& s, const QPoint* defaultVal ) { - return m_config.readEntry( s, *defaultVal ); - } - bool readBoolEntry( const QString& s, bool defaultVal ) { - return m_config.readEntry( s, defaultVal ); - } - int readNumEntry( const QString& s, int defaultVal ) { - return m_config.readEntry( s, defaultVal ); - } - QString readStringEntry( const QString& s, const QString& defaultVal ) { - return m_config.readEntry( s, defaultVal ); - } - - void writeEntry( const QString& s, const QStringList& v ) { - m_config.writeEntry( s, v ); - } - QStringList readListEntry( const QString& s, const QStringList& def) { - return m_config.readEntry( s, def ); - } -}; + void writeEntry(const QString& s, const QFont& v) + { + m_config.writeEntry(s, v); + } + void writeEntry(const QString& s, const QColor& v) + { + m_config.writeEntry(s, v); + } + void writeEntry(const QString& s, const QSize& v) + { + m_config.writeEntry(s, v); + } + void writeEntry(const QString& s, const QPoint& v) + { + m_config.writeEntry(s, v); + } + void writeEntry(const QString& s, int v) + { + m_config.writeEntry(s, v); + } + void writeEntry(const QString& s, bool v) + { + m_config.writeEntry(s, v); + } + void writeEntry(const QString& s, const QString& v) + { + m_config.writeEntry(s, v); + } + void writeEntry(const QString& s, const char* v) + { + m_config.writeEntry(s, v); + } + + QFont readFontEntry(const QString& s, const QFont* defaultVal) + { + return m_config.readEntry(s, *defaultVal); + } + QColor readColorEntry(const QString& s, const QColor* defaultVal) + { + return m_config.readEntry(s, *defaultVal); + } + QSize readSizeEntry(const QString& s, const QSize* defaultVal) + { + return m_config.readEntry(s, *defaultVal); + } + QPoint readPointEntry(const QString& s, const QPoint* defaultVal) + { + return m_config.readEntry(s, *defaultVal); + } + bool readBoolEntry(const QString& s, bool defaultVal) + { + return m_config.readEntry(s, defaultVal); + } + int readNumEntry(const QString& s, int defaultVal) + { + return m_config.readEntry(s, defaultVal); + } + QString readStringEntry(const QString& s, const QString& defaultVal) + { + return m_config.readEntry(s, defaultVal); + } + void writeEntry(const QString& s, const QStringList& v) + { + m_config.writeEntry(s, v); + } + QStringList readListEntry(const QString& s, const QStringList& def) + { + return m_config.readEntry(s, def); + } +}; -void OptionDialog::saveOptions( KSharedConfigPtr config ) +void OptionDialog::saveOptions(KSharedConfigPtr config) { - // No i18n()-Translations here! + // No i18n()-Translations here! - ConfigValueMap cvm(config->group(KDIFF3_CONFIG_GROUP)); - std::list::iterator i; - for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i) - { - (*i)->doUnpreserve(); - (*i)->write(&cvm); - } + ConfigValueMap cvm(config->group(KDIFF3_CONFIG_GROUP)); + std::list::iterator i; + for(i = m_optionItemList.begin(); i != m_optionItemList.end(); ++i) + { + (*i)->doUnpreserve(); + (*i)->write(&cvm); + } } -void OptionDialog::readOptions( KSharedConfigPtr config ) +void OptionDialog::readOptions(KSharedConfigPtr config) { - // No i18n()-Translations here! + // No i18n()-Translations here! - ConfigValueMap cvm(config->group(KDIFF3_CONFIG_GROUP)); - std::list::iterator i; - for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i) - { - (*i)->read(&cvm); - } + ConfigValueMap cvm(config->group(KDIFF3_CONFIG_GROUP)); + std::list::iterator i; + for(i = m_optionItemList.begin(); i != m_optionItemList.end(); ++i) + { + (*i)->read(&cvm); + } - setState(); + setState(); } -QString OptionDialog::parseOptions( const QStringList& optionList ) +QString OptionDialog::parseOptions(const QStringList& optionList) { - QString result; - QStringList::const_iterator i; - for ( i=optionList.begin(); i!=optionList.end(); ++i ) - { - QString s = *i; + QString result; + QStringList::const_iterator i; + for(i = optionList.begin(); i != optionList.end(); ++i) + { + QString s = *i; - int pos = s.indexOf('='); - if( pos > 0 ) // seems not to have a tag - { - QString key = s.left(pos); - QString val = s.mid(pos+1); - std::list::iterator j; - bool bFound = false; - for(j=m_optionItemList.begin(); j!=m_optionItemList.end(); ++j) - { - if ( (*j)->getSaveName()==key ) + int pos = s.indexOf('='); + if(pos > 0) // seems not to have a tag + { + QString key = s.left(pos); + QString val = s.mid(pos + 1); + std::list::iterator j; + bool bFound = false; + for(j = m_optionItemList.begin(); j != m_optionItemList.end(); ++j) { - (*j)->doPreserve(); - ValueMap config; - config.writeEntry( key, val ); // Write the value as a string and - (*j)->read(&config); // use the internal conversion from string to the needed value. - bFound = true; - break; + if((*j)->getSaveName() == key) + { + (*j)->doPreserve(); + ValueMap config; + config.writeEntry(key, val); // Write the value as a string and + (*j)->read(&config); // use the internal conversion from string to the needed value. + bFound = true; + break; + } } - } - if ( ! bFound ) - { - result += "No config item named \"" + key + "\"\n"; - } - } - else - { - result += "No '=' found in \"" + s + "\"\n"; - } - } - return result; + if(!bFound) + { + result += "No config item named \"" + key + "\"\n"; + } + } + else + { + result += "No '=' found in \"" + s + "\"\n"; + } + } + return result; } QString OptionDialog::calcOptionHelp() { - ValueMap config; - std::list::iterator j; - for(j=m_optionItemList.begin(); j!=m_optionItemList.end(); ++j) - { - (*j)->write( &config ); - } - return config.getAsString(); + ValueMap config; + std::list::iterator j; + for(j = m_optionItemList.begin(); j != m_optionItemList.end(); ++j) + { + (*j)->write(&config); + } + return config.getAsString(); } void OptionDialog::slotHistoryMergeRegExpTester() { - RegExpTester dlg(this, s_autoMergeRegExpToolTip, s_historyStartRegExpToolTip, - s_historyEntryStartRegExpToolTip, s_historyEntryStartSortKeyOrderToolTip ); - dlg.init(m_pAutoMergeRegExpLineEdit->currentText(), m_pHistoryStartRegExpLineEdit->currentText(), - m_pHistoryEntryStartRegExpLineEdit->currentText(), m_pHistorySortKeyOrderLineEdit->currentText()); - if ( dlg.exec() ) - { - m_pAutoMergeRegExpLineEdit->setEditText( dlg.autoMergeRegExp() ); - m_pHistoryStartRegExpLineEdit->setEditText( dlg.historyStartRegExp() ); - m_pHistoryEntryStartRegExpLineEdit->setEditText( dlg.historyEntryStartRegExp() ); - m_pHistorySortKeyOrderLineEdit->setEditText( dlg.historySortKeyOrder() ); - } + RegExpTester dlg(this, s_autoMergeRegExpToolTip, s_historyStartRegExpToolTip, + s_historyEntryStartRegExpToolTip, s_historyEntryStartSortKeyOrderToolTip); + dlg.init(m_pAutoMergeRegExpLineEdit->currentText(), m_pHistoryStartRegExpLineEdit->currentText(), + m_pHistoryEntryStartRegExpLineEdit->currentText(), m_pHistorySortKeyOrderLineEdit->currentText()); + if(dlg.exec()) + { + m_pAutoMergeRegExpLineEdit->setEditText(dlg.autoMergeRegExp()); + m_pHistoryStartRegExpLineEdit->setEditText(dlg.historyStartRegExp()); + m_pHistoryEntryStartRegExpLineEdit->setEditText(dlg.historyEntryStartRegExp()); + m_pHistorySortKeyOrderLineEdit->setEditText(dlg.historySortKeyOrder()); + } } - #include "optiondialog.moc" diff --git a/src/pdiff.cpp b/src/pdiff.cpp index 113a80f..f9b28cc 100644 --- a/src/pdiff.cpp +++ b/src/pdiff.cpp @@ -1,2449 +1,2513 @@ /*************************************************************************** pdiff.cpp - Implementation for class KDiff3App --------------- begin : Mon March 18 20:04:50 CET 2002 copyright : (C) 2002-2007 by Joachim Eibl email : joachim.eibl at gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #ifdef _WIN32 #include #endif #include "difftextwindow.h" -#include "mergeresultwindow.h" #include "directorymergewindow.h" +#include "mergeresultwindow.h" #include "smalldialogs.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 +#include "fileaccess.h" #include "kdiff3.h" #include "optiondialog.h" -#include "fileaccess.h" #include "progress.h" #ifdef _WIN32 #include #else -#include #include +#include #endif bool g_bIgnoreWhiteSpace = true; bool g_bIgnoreTrivialMatches = true; // Just make sure that all input lines are in the output too, exactly once. -static void debugLineCheck( Diff3LineList& d3ll, int size, int idx ) -{ - Diff3LineList::iterator it = d3ll.begin(); - int i=0; - - for ( it = d3ll.begin(); it!= d3ll.end(); ++it ) - { - int l=0; - if (idx==1) l=(*it).lineA; - else if (idx==2) l=(*it).lineB; - else if (idx==3) l=(*it).lineC; - else assert(false); - - if ( l!=-1 ) - { - if( l!=i ) - { - KMessageBox::error(0, i18n( - "Data loss error:\n" - "If it is reproducible please contact the author.\n" - ), i18n("Severe Internal Error") ); +static void debugLineCheck(Diff3LineList& d3ll, int size, int idx) +{ + Diff3LineList::iterator it = d3ll.begin(); + int i = 0; + + for(it = d3ll.begin(); it != d3ll.end(); ++it) + { + int l = 0; + if(idx == 1) + l = (*it).lineA; + else if(idx == 2) + l = (*it).lineB; + else if(idx == 3) + l = (*it).lineC; + else assert(false); - fprintf(stderr, "Severe Internal Error.\n"); - ::exit(-1); - } - ++i; - } - } - - if( size!=i ) - { - KMessageBox::error(0, i18n( - "Data loss error:\n" - "If it is reproducible please contact the author.\n" - ), i18n("Severe Internal Error") ); - assert(false); - fprintf(stderr, "Severe Internal Error.\n"); - ::exit(-1); - } -} - - - - -void KDiff3App::mainInit( TotalDiffStatus* pTotalDiffStatus, bool bLoadFiles, bool bUseCurrentEncoding) -{ - ProgressProxy pp; - - // When doing a full analysis in the directory-comparison, then the statistics-results - // will be stored in the given TotalDiffStatus. Otherwise it will be 0. - bool bGUI = pTotalDiffStatus == 0; - if (pTotalDiffStatus==0) - pTotalDiffStatus = &m_totalDiffStatus; - - //bool bPreserveCarriageReturn = m_pOptions->m_bPreserveCarriageReturn; - - bool bVisibleMergeResultWindow = ! m_outputFilename.isEmpty(); - if ( bVisibleMergeResultWindow && bGUI ) - { - //bPreserveCarriageReturn = false; - - QString msg; - - if ( !m_pOptions->m_PreProcessorCmd.isEmpty() ) - { - msg += "- " + i18n("PreprocessorCmd: ") + m_pOptions->m_PreProcessorCmd + "\n"; - } - if ( !msg.isEmpty() ) - { - int result = KMessageBox::warningYesNo( this, - i18n("The following option(s) you selected might change data:\n") + msg + - i18n("\nMost likely this is not wanted during a merge.\n" - "Do you want to disable these settings or continue with these settings active?"), - i18n("Option Unsafe for Merging"), - KGuiItem( i18n("Use These Options During Merge") ), - KGuiItem( i18n("Disable Unsafe Options") ) - ); - - if (result == KMessageBox::No ) - { - m_pOptions->m_PreProcessorCmd = ""; - } - } - } - - // Because of the progressdialog paintevents can occur, but data is invalid, - // so painting must be suppressed. - if (m_pDiffTextWindow1) m_pDiffTextWindow1->setPaintingAllowed( false ); - if (m_pDiffTextWindow2) m_pDiffTextWindow2->setPaintingAllowed( false ); - if (m_pDiffTextWindow3) m_pDiffTextWindow3->setPaintingAllowed( false ); - if (m_pOverview) m_pOverview->setPaintingAllowed( false ); - if (m_pMergeResultWindow) m_pMergeResultWindow->setPaintingAllowed( false ); - - m_diff3LineList.clear(); - - if ( bLoadFiles ) - { - QStringList errors; - m_manualDiffHelpList.clear(); - if( m_sd3.isEmpty() ) - pp.setMaxNofSteps( 4 ); // Read 2 files, 1 comparison, 1 finediff - else - pp.setMaxNofSteps( 9 ); // Read 3 files, 3 comparisons, 3 finediffs - - // First get all input data. - pp.setInformation(i18n("Loading A")); - if (bUseCurrentEncoding==true) - errors = m_sd1.readAndPreprocess(m_sd1.getEncoding(), false); - else - errors = m_sd1.readAndPreprocess(m_pOptions->m_pEncodingA, m_pOptions->m_bAutoDetectUnicodeA); - foreach(const QString &error, errors) - { - KMessageBox::error( m_pOptionDialog, error ); - } - pp.step(); - - pp.setInformation(i18n("Loading B")); - if (bUseCurrentEncoding==true) - errors = m_sd2.readAndPreprocess(m_sd2.getEncoding(), false); - else - errors = m_sd2.readAndPreprocess(m_pOptions->m_pEncodingB, m_pOptions->m_bAutoDetectUnicodeB); - foreach(const QString &error, errors) - { - KMessageBox::error( m_pOptionDialog, error ); - } - pp.step(); - } - else - { - if( m_sd3.isEmpty() ) - pp.setMaxNofSteps( 2 ); // 1 comparison, 1 finediff - else - pp.setMaxNofSteps( 6 ); // 3 comparisons, 3 finediffs - } - - pTotalDiffStatus->reset(); - // Run the diff. - if ( m_sd3.isEmpty() ) - { - pTotalDiffStatus->bBinaryAEqB = m_sd1.isBinaryEqualWith( m_sd2 ); - pp.setInformation(i18n("Diff: A <-> B")); - - runDiff( m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_diffList12,1,2, - &m_manualDiffHelpList, &m_pOptionDialog->m_options); - - pp.step(); - - pp.setInformation(i18n("Linediff: A <-> B")); - calcDiff3LineListUsingAB( &m_diffList12, m_diff3LineList ); - pTotalDiffStatus->bTextAEqB = fineDiff( m_diff3LineList, 1, m_sd1.getLineDataForDisplay(), m_sd2.getLineDataForDisplay() ); - if ( m_sd1.getSizeBytes()==0 ) pTotalDiffStatus->bTextAEqB=false; - - pp.step(); - } - else - { - if (bLoadFiles) - { - pp.setInformation(i18n("Loading C")); - if (bUseCurrentEncoding==true) - m_sd3.readAndPreprocess(m_sd3.getEncoding(), false); - else - m_sd3.readAndPreprocess(m_pOptions->m_pEncodingC, m_pOptions->m_bAutoDetectUnicodeC); - pp.step(); - } - - pTotalDiffStatus->bBinaryAEqB = m_sd1.isBinaryEqualWith( m_sd2 ); - pTotalDiffStatus->bBinaryAEqC = m_sd1.isBinaryEqualWith( m_sd3 ); - pTotalDiffStatus->bBinaryBEqC = m_sd3.isBinaryEqualWith( m_sd2 ); - - pp.setInformation(i18n("Diff: A <-> B")); - runDiff( m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_diffList12,1,2, - &m_manualDiffHelpList, &m_pOptionDialog->m_options); - pp.step(); - pp.setInformation(i18n("Diff: B <-> C")); - runDiff( m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_sd3.getLineDataForDiff(), m_sd3.getSizeLines(), m_diffList23,2,3, - &m_manualDiffHelpList, &m_pOptionDialog->m_options); - pp.step(); - pp.setInformation(i18n("Diff: A <-> C")); - runDiff( m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd3.getLineDataForDiff(), m_sd3.getSizeLines(), m_diffList13,1,3, - &m_manualDiffHelpList, &m_pOptionDialog->m_options); - pp.step(); - - calcDiff3LineListUsingAB( &m_diffList12, m_diff3LineList ); - calcDiff3LineListUsingAC( &m_diffList13, m_diff3LineList ); - correctManualDiffAlignment( m_diff3LineList, &m_manualDiffHelpList ); - calcDiff3LineListTrim( m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff(), &m_manualDiffHelpList ); - - if ( m_pOptions->m_bDiff3AlignBC ) - { - calcDiff3LineListUsingBC( &m_diffList23, m_diff3LineList ); - correctManualDiffAlignment( m_diff3LineList, &m_manualDiffHelpList ); - calcDiff3LineListTrim( m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff(), &m_manualDiffHelpList ); - } - debugLineCheck( m_diff3LineList, m_sd1.getSizeLines(), 1 ); - debugLineCheck( m_diff3LineList, m_sd2.getSizeLines(), 2 ); - debugLineCheck( m_diff3LineList, m_sd3.getSizeLines(), 3 ); - - pp.setInformation(i18n("Linediff: A <-> B")); - pTotalDiffStatus->bTextAEqB = fineDiff( m_diff3LineList, 1, m_sd1.getLineDataForDisplay(), m_sd2.getLineDataForDisplay() ); - pp.step(); - pp.setInformation(i18n("Linediff: B <-> C")); - pTotalDiffStatus->bTextBEqC = fineDiff( m_diff3LineList, 2, m_sd2.getLineDataForDisplay(), m_sd3.getLineDataForDisplay() ); - pp.step(); - pp.setInformation(i18n("Linediff: A <-> C")); - pTotalDiffStatus->bTextAEqC = fineDiff( m_diff3LineList, 3, m_sd3.getLineDataForDisplay(), m_sd1.getLineDataForDisplay() ); - pp.step(); - if ( m_sd1.getSizeBytes()==0 ) { pTotalDiffStatus->bTextAEqB=false; pTotalDiffStatus->bTextAEqC=false; } - if ( m_sd2.getSizeBytes()==0 ) { pTotalDiffStatus->bTextAEqB=false; pTotalDiffStatus->bTextBEqC=false; } - } - m_diffBufferInfo.init( &m_diff3LineList, &m_diff3LineVector, - m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), - m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), - m_sd3.getLineDataForDiff(), m_sd3.getSizeLines() ); - calcWhiteDiff3Lines( m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff() ); - calcDiff3LineVector( m_diff3LineList, m_diff3LineVector ); - - // Calc needed lines for display - m_neededLines = m_diff3LineList.size(); - - QList oldHeights; - if ( m_pDirectoryMergeSplitter->isVisible() ) - oldHeights = m_pMainSplitter->sizes(); - - initView(); - - 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]; - } - if ( oldHeights[0]==0 && oldHeights[1]==0 ) - { - oldHeights[1] = 100; - oldHeights[0] = 100; - } - m_pMainSplitter->setSizes( oldHeights ); - } - - m_pMainWidget->setVisible( bGUI ); - - m_bTripleDiff = ! m_sd3.isEmpty(); - - m_pMergeResultWindowTitle->setEncodings( m_sd1.getEncoding(), m_sd2.getEncoding(), m_sd3.getEncoding() ); - if ( ! m_pOptions->m_bAutoSelectOutEncoding ) - m_pMergeResultWindowTitle->setEncoding( m_pOptions->m_pEncodingOut ); - - m_pMergeResultWindowTitle->setLineEndStyles( m_sd1.getLineEndStyle(), m_sd2.getLineEndStyle(), m_sd3.getLineEndStyle() ); - - if ( bGUI ) - { - const ManualDiffHelpList* pMDHL = &m_manualDiffHelpList; - m_pDiffTextWindow1->init( m_sd1.getAliasName(), m_sd1.getEncoding(), m_sd1.getLineEndStyle(), - m_sd1.getLineDataForDisplay(), m_sd1.getSizeLines(), &m_diff3LineVector, pMDHL, m_bTripleDiff ); - m_pDiffTextWindow2->init( m_sd2.getAliasName(), m_sd2.getEncoding(), m_sd2.getLineEndStyle(), - m_sd2.getLineDataForDisplay(), m_sd2.getSizeLines(), &m_diff3LineVector, pMDHL, m_bTripleDiff ); - m_pDiffTextWindow3->init( m_sd3.getAliasName(), m_sd3.getEncoding(), m_sd3.getLineEndStyle(), - m_sd3.getLineDataForDisplay(), m_sd3.getSizeLines(), &m_diff3LineVector, pMDHL, m_bTripleDiff ); - - m_pDiffTextWindowFrame3->setVisible(m_bTripleDiff); - } - - m_bOutputModified = bVisibleMergeResultWindow; - - m_pMergeResultWindow->init( - m_sd1.getLineDataForDisplay(), m_sd1.getSizeLines(), - m_sd2.getLineDataForDisplay(), m_sd2.getSizeLines(), - m_bTripleDiff ? m_sd3.getLineDataForDisplay() : 0, m_sd3.getSizeLines(), - &m_diff3LineList, - pTotalDiffStatus - ); - m_pMergeResultWindowTitle->setFileName( m_outputFilename.isEmpty() ? QString("unnamed.txt") : m_outputFilename ); - - if ( !bGUI ) - { - // We now have all needed information. The rest below is only for GUI-activation. - m_sd1.reset(); - m_sd2.reset(); - m_sd3.reset(); - return; - } - - m_pOverview->init(&m_diff3LineList, m_bTripleDiff ); - m_pDiffVScrollBar->setValue( 0 ); - m_pHScrollBar->setValue( 0 ); - m_pMergeVScrollBar->setValue( 0 ); - - m_pDiffTextWindow1->setPaintingAllowed( true ); - m_pDiffTextWindow2->setPaintingAllowed( true ); - m_pDiffTextWindow3->setPaintingAllowed( true ); - m_pOverview->setPaintingAllowed( true ); - m_pMergeResultWindow->setPaintingAllowed( true ); - - - if ( !bVisibleMergeResultWindow ) - m_pMergeWindowFrame->hide(); - else - m_pMergeWindowFrame->show(); - - // Try to create a meaningful but not too long caption - if ( !isPart() ) - { - // 1. If the filenames are equal then show only one filename - QString caption; - QString f1 = m_sd1.getAliasName(); - QString f2 = m_sd2.getAliasName(); - QString f3 = m_sd3.getAliasName(); - int p; - if ( (p=f1.indexOf("@@"))>=0 ) - f1 = f1.left( p ); - if ( (p=f2.indexOf("@@"))>=0 ) - f2 = f2.left( p ); - if ( (p=f3.indexOf("@@"))>=0 ) - f3 = f3.left( p ); - - if ( (p=f1.lastIndexOf('/'))>=0 || (p=f1.lastIndexOf('\\'))>=0 ) - f1 = f1.mid( p+1 ); - if ( (p=f2.lastIndexOf('/'))>=0 || (p=f2.lastIndexOf('\\'))>=0) - f2 = f2.mid( p+1 ); - if ( (p=f3.lastIndexOf('/'))>=0 || (p=f3.lastIndexOf('\\'))>=0 ) - f3 = f3.mid( p+1 ); - - if ( !f1.isEmpty() ) - { - if ( ( f2.isEmpty() && f3.isEmpty() ) || - (f2.isEmpty() && f1==f3) || ( f3.isEmpty() && f1==f2 ) || (f1==f2 && f1==f3)) - caption = f1; - } - else if ( ! f2.isEmpty() ) - { - if ( f3.isEmpty() || f2==f3 ) - caption = f2; - } - else if ( ! f3.isEmpty() ) - caption = f3; - - // 2. If the files don't have the same name then show all names - if ( caption.isEmpty() && (!f1.isEmpty() || !f2.isEmpty() || !f3.isEmpty()) ) - { - caption = ( f1.isEmpty()? QString("") : f1 ); - caption += QString(caption.isEmpty() || f2.isEmpty() ? "" : " <-> ") + ( f2.isEmpty()? QString("") : f2 ); - caption += QString(caption.isEmpty() || f3.isEmpty() ? "" : " <-> ") + ( f3.isEmpty()? QString("") : f3 ) ; - } - - m_pKDiff3Shell->setWindowTitle( caption.isEmpty() ? QString("KDiff3") : caption+QString(" - KDiff3")); - } - - //initialize wheel tracking to zero - m_iCumulativeWheelDelta = 0; - - m_bFinishMainInit = true; // call slotFinishMainInit after finishing the word wrap - m_bLoadFiles = bLoadFiles; - postRecalcWordWrap(); + if(l != -1) + { + if(l != i) + { + KMessageBox::error(0, i18n( + "Data loss error:\n" + "If it is reproducible please contact the author.\n"), + i18n("Severe Internal Error")); + assert(false); + fprintf(stderr, "Severe Internal Error.\n"); + ::exit(-1); + } + ++i; + } + } + + if(size != i) + { + KMessageBox::error(0, i18n( + "Data loss error:\n" + "If it is reproducible please contact the author.\n"), + i18n("Severe Internal Error")); + assert(false); + fprintf(stderr, "Severe Internal Error.\n"); + ::exit(-1); + } +} + +void KDiff3App::mainInit(TotalDiffStatus* pTotalDiffStatus, bool bLoadFiles, bool bUseCurrentEncoding) +{ + ProgressProxy pp; + + // When doing a full analysis in the directory-comparison, then the statistics-results + // will be stored in the given TotalDiffStatus. Otherwise it will be 0. + bool bGUI = pTotalDiffStatus == 0; + if(pTotalDiffStatus == 0) + pTotalDiffStatus = &m_totalDiffStatus; + + //bool bPreserveCarriageReturn = m_pOptions->m_bPreserveCarriageReturn; + + bool bVisibleMergeResultWindow = !m_outputFilename.isEmpty(); + if(bVisibleMergeResultWindow && bGUI) + { + //bPreserveCarriageReturn = false; + + QString msg; + + if(!m_pOptions->m_PreProcessorCmd.isEmpty()) + { + msg += "- " + i18n("PreprocessorCmd: ") + m_pOptions->m_PreProcessorCmd + "\n"; + } + if(!msg.isEmpty()) + { + int result = KMessageBox::warningYesNo(this, + i18n("The following option(s) you selected might change data:\n") + msg + + i18n("\nMost likely this is not wanted during a merge.\n" + "Do you want to disable these settings or continue with these settings active?"), + i18n("Option Unsafe for Merging"), + KGuiItem(i18n("Use These Options During Merge")), + KGuiItem(i18n("Disable Unsafe Options"))); + + if(result == KMessageBox::No) + { + m_pOptions->m_PreProcessorCmd = ""; + } + } + } + + // Because of the progressdialog paintevents can occur, but data is invalid, + // so painting must be suppressed. + if(m_pDiffTextWindow1) m_pDiffTextWindow1->setPaintingAllowed(false); + if(m_pDiffTextWindow2) m_pDiffTextWindow2->setPaintingAllowed(false); + if(m_pDiffTextWindow3) m_pDiffTextWindow3->setPaintingAllowed(false); + if(m_pOverview) m_pOverview->setPaintingAllowed(false); + if(m_pMergeResultWindow) m_pMergeResultWindow->setPaintingAllowed(false); + + m_diff3LineList.clear(); + + if(bLoadFiles) + { + QStringList errors; + m_manualDiffHelpList.clear(); + + if(m_sd3.isEmpty()) + pp.setMaxNofSteps(4); // Read 2 files, 1 comparison, 1 finediff + else + pp.setMaxNofSteps(9); // Read 3 files, 3 comparisons, 3 finediffs + + // First get all input data. + pp.setInformation(i18n("Loading A")); + if(bUseCurrentEncoding == true) + errors = m_sd1.readAndPreprocess(m_sd1.getEncoding(), false); + else + errors = m_sd1.readAndPreprocess(m_pOptions->m_pEncodingA, m_pOptions->m_bAutoDetectUnicodeA); + foreach(const QString& error, errors) + { + KMessageBox::error(m_pOptionDialog, error); + } + pp.step(); + + pp.setInformation(i18n("Loading B")); + if(bUseCurrentEncoding == true) + errors = m_sd2.readAndPreprocess(m_sd2.getEncoding(), false); + else + errors = m_sd2.readAndPreprocess(m_pOptions->m_pEncodingB, m_pOptions->m_bAutoDetectUnicodeB); + foreach(const QString& error, errors) + { + KMessageBox::error(m_pOptionDialog, error); + } + pp.step(); + } + else + { + if(m_sd3.isEmpty()) + pp.setMaxNofSteps(2); // 1 comparison, 1 finediff + else + pp.setMaxNofSteps(6); // 3 comparisons, 3 finediffs + } + + pTotalDiffStatus->reset(); + // Run the diff. + if(m_sd3.isEmpty()) + { + pTotalDiffStatus->bBinaryAEqB = m_sd1.isBinaryEqualWith(m_sd2); + pp.setInformation(i18n("Diff: A <-> B")); + + runDiff(m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_diffList12, 1, 2, + &m_manualDiffHelpList, &m_pOptionDialog->m_options); + + pp.step(); + + pp.setInformation(i18n("Linediff: A <-> B")); + calcDiff3LineListUsingAB(&m_diffList12, m_diff3LineList); + pTotalDiffStatus->bTextAEqB = fineDiff(m_diff3LineList, 1, m_sd1.getLineDataForDisplay(), m_sd2.getLineDataForDisplay()); + if(m_sd1.getSizeBytes() == 0) pTotalDiffStatus->bTextAEqB = false; + + pp.step(); + } + else + { + if(bLoadFiles) + { + pp.setInformation(i18n("Loading C")); + if(bUseCurrentEncoding == true) + m_sd3.readAndPreprocess(m_sd3.getEncoding(), false); + else + m_sd3.readAndPreprocess(m_pOptions->m_pEncodingC, m_pOptions->m_bAutoDetectUnicodeC); + pp.step(); + } + + pTotalDiffStatus->bBinaryAEqB = m_sd1.isBinaryEqualWith(m_sd2); + pTotalDiffStatus->bBinaryAEqC = m_sd1.isBinaryEqualWith(m_sd3); + pTotalDiffStatus->bBinaryBEqC = m_sd3.isBinaryEqualWith(m_sd2); + + pp.setInformation(i18n("Diff: A <-> B")); + runDiff(m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_diffList12, 1, 2, + &m_manualDiffHelpList, &m_pOptionDialog->m_options); + pp.step(); + pp.setInformation(i18n("Diff: B <-> C")); + runDiff(m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_sd3.getLineDataForDiff(), m_sd3.getSizeLines(), m_diffList23, 2, 3, + &m_manualDiffHelpList, &m_pOptionDialog->m_options); + pp.step(); + pp.setInformation(i18n("Diff: A <-> C")); + runDiff(m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd3.getLineDataForDiff(), m_sd3.getSizeLines(), m_diffList13, 1, 3, + &m_manualDiffHelpList, &m_pOptionDialog->m_options); + pp.step(); + + calcDiff3LineListUsingAB(&m_diffList12, m_diff3LineList); + calcDiff3LineListUsingAC(&m_diffList13, m_diff3LineList); + correctManualDiffAlignment(m_diff3LineList, &m_manualDiffHelpList); + calcDiff3LineListTrim(m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff(), &m_manualDiffHelpList); + + if(m_pOptions->m_bDiff3AlignBC) + { + calcDiff3LineListUsingBC(&m_diffList23, m_diff3LineList); + correctManualDiffAlignment(m_diff3LineList, &m_manualDiffHelpList); + calcDiff3LineListTrim(m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff(), &m_manualDiffHelpList); + } + debugLineCheck(m_diff3LineList, m_sd1.getSizeLines(), 1); + debugLineCheck(m_diff3LineList, m_sd2.getSizeLines(), 2); + debugLineCheck(m_diff3LineList, m_sd3.getSizeLines(), 3); + + pp.setInformation(i18n("Linediff: A <-> B")); + pTotalDiffStatus->bTextAEqB = fineDiff(m_diff3LineList, 1, m_sd1.getLineDataForDisplay(), m_sd2.getLineDataForDisplay()); + pp.step(); + pp.setInformation(i18n("Linediff: B <-> C")); + pTotalDiffStatus->bTextBEqC = fineDiff(m_diff3LineList, 2, m_sd2.getLineDataForDisplay(), m_sd3.getLineDataForDisplay()); + pp.step(); + pp.setInformation(i18n("Linediff: A <-> C")); + pTotalDiffStatus->bTextAEqC = fineDiff(m_diff3LineList, 3, m_sd3.getLineDataForDisplay(), m_sd1.getLineDataForDisplay()); + pp.step(); + if(m_sd1.getSizeBytes() == 0) { + pTotalDiffStatus->bTextAEqB = false; + pTotalDiffStatus->bTextAEqC = false; + } + if(m_sd2.getSizeBytes() == 0) { + pTotalDiffStatus->bTextAEqB = false; + pTotalDiffStatus->bTextBEqC = false; + } + } + m_diffBufferInfo.init(&m_diff3LineList, &m_diff3LineVector, + m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), + m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), + m_sd3.getLineDataForDiff(), m_sd3.getSizeLines()); + calcWhiteDiff3Lines(m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff()); + calcDiff3LineVector(m_diff3LineList, m_diff3LineVector); + + // Calc needed lines for display + m_neededLines = m_diff3LineList.size(); + + QList oldHeights; + if(m_pDirectoryMergeSplitter->isVisible()) + oldHeights = m_pMainSplitter->sizes(); + + initView(); + + 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]; + } + if(oldHeights[0] == 0 && oldHeights[1] == 0) + { + oldHeights[1] = 100; + oldHeights[0] = 100; + } + m_pMainSplitter->setSizes(oldHeights); + } + + m_pMainWidget->setVisible(bGUI); + + m_bTripleDiff = !m_sd3.isEmpty(); + + m_pMergeResultWindowTitle->setEncodings(m_sd1.getEncoding(), m_sd2.getEncoding(), m_sd3.getEncoding()); + if(!m_pOptions->m_bAutoSelectOutEncoding) + m_pMergeResultWindowTitle->setEncoding(m_pOptions->m_pEncodingOut); + + m_pMergeResultWindowTitle->setLineEndStyles(m_sd1.getLineEndStyle(), m_sd2.getLineEndStyle(), m_sd3.getLineEndStyle()); + + if(bGUI) + { + const ManualDiffHelpList* pMDHL = &m_manualDiffHelpList; + m_pDiffTextWindow1->init(m_sd1.getAliasName(), m_sd1.getEncoding(), m_sd1.getLineEndStyle(), + m_sd1.getLineDataForDisplay(), m_sd1.getSizeLines(), &m_diff3LineVector, pMDHL, m_bTripleDiff); + m_pDiffTextWindow2->init(m_sd2.getAliasName(), m_sd2.getEncoding(), m_sd2.getLineEndStyle(), + m_sd2.getLineDataForDisplay(), m_sd2.getSizeLines(), &m_diff3LineVector, pMDHL, m_bTripleDiff); + m_pDiffTextWindow3->init(m_sd3.getAliasName(), m_sd3.getEncoding(), m_sd3.getLineEndStyle(), + m_sd3.getLineDataForDisplay(), m_sd3.getSizeLines(), &m_diff3LineVector, pMDHL, m_bTripleDiff); + + m_pDiffTextWindowFrame3->setVisible(m_bTripleDiff); + } + + m_bOutputModified = bVisibleMergeResultWindow; + + m_pMergeResultWindow->init( + m_sd1.getLineDataForDisplay(), m_sd1.getSizeLines(), + m_sd2.getLineDataForDisplay(), m_sd2.getSizeLines(), + m_bTripleDiff ? m_sd3.getLineDataForDisplay() : 0, m_sd3.getSizeLines(), + &m_diff3LineList, + pTotalDiffStatus); + m_pMergeResultWindowTitle->setFileName(m_outputFilename.isEmpty() ? QString("unnamed.txt") : m_outputFilename); + + if(!bGUI) + { + // We now have all needed information. The rest below is only for GUI-activation. + m_sd1.reset(); + m_sd2.reset(); + m_sd3.reset(); + return; + } + + m_pOverview->init(&m_diff3LineList, m_bTripleDiff); + m_pDiffVScrollBar->setValue(0); + m_pHScrollBar->setValue(0); + m_pMergeVScrollBar->setValue(0); + + m_pDiffTextWindow1->setPaintingAllowed(true); + m_pDiffTextWindow2->setPaintingAllowed(true); + m_pDiffTextWindow3->setPaintingAllowed(true); + m_pOverview->setPaintingAllowed(true); + m_pMergeResultWindow->setPaintingAllowed(true); + + if(!bVisibleMergeResultWindow) + m_pMergeWindowFrame->hide(); + else + m_pMergeWindowFrame->show(); + + // Try to create a meaningful but not too long caption + if(!isPart()) + { + // 1. If the filenames are equal then show only one filename + QString caption; + QString f1 = m_sd1.getAliasName(); + QString f2 = m_sd2.getAliasName(); + QString f3 = m_sd3.getAliasName(); + int p; + if((p = f1.indexOf("@@")) >= 0) + f1 = f1.left(p); + if((p = f2.indexOf("@@")) >= 0) + f2 = f2.left(p); + if((p = f3.indexOf("@@")) >= 0) + f3 = f3.left(p); + + if((p = f1.lastIndexOf('/')) >= 0 || (p = f1.lastIndexOf('\\')) >= 0) + f1 = f1.mid(p + 1); + if((p = f2.lastIndexOf('/')) >= 0 || (p = f2.lastIndexOf('\\')) >= 0) + f2 = f2.mid(p + 1); + if((p = f3.lastIndexOf('/')) >= 0 || (p = f3.lastIndexOf('\\')) >= 0) + f3 = f3.mid(p + 1); + + if(!f1.isEmpty()) + { + if((f2.isEmpty() && f3.isEmpty()) || + (f2.isEmpty() && f1 == f3) || (f3.isEmpty() && f1 == f2) || (f1 == f2 && f1 == f3)) + caption = f1; + } + else if(!f2.isEmpty()) + { + if(f3.isEmpty() || f2 == f3) + caption = f2; + } + else if(!f3.isEmpty()) + caption = f3; + + // 2. If the files don't have the same name then show all names + if(caption.isEmpty() && (!f1.isEmpty() || !f2.isEmpty() || !f3.isEmpty())) + { + caption = (f1.isEmpty() ? QString("") : f1); + caption += QString(caption.isEmpty() || f2.isEmpty() ? "" : " <-> ") + (f2.isEmpty() ? QString("") : f2); + caption += QString(caption.isEmpty() || f3.isEmpty() ? "" : " <-> ") + (f3.isEmpty() ? QString("") : f3); + } + + m_pKDiff3Shell->setWindowTitle(caption.isEmpty() ? QString("KDiff3") : caption + QString(" - KDiff3")); + } + + //initialize wheel tracking to zero + m_iCumulativeWheelDelta = 0; + + m_bFinishMainInit = true; // call slotFinishMainInit after finishing the word wrap + m_bLoadFiles = bLoadFiles; + postRecalcWordWrap(); } - void KDiff3App::setHScrollBarRange() { - int w1 = m_pDiffTextWindow1!=0 && m_pDiffTextWindow1->isVisible() ? m_pDiffTextWindow1->getMaxTextWidth() : 0; - int w2 = m_pDiffTextWindow2!=0 && m_pDiffTextWindow2->isVisible() ? m_pDiffTextWindow2->getMaxTextWidth() : 0; - int w3 = m_pDiffTextWindow3!=0 && m_pDiffTextWindow3->isVisible() ? m_pDiffTextWindow3->getMaxTextWidth() : 0; - - int wm = m_pMergeResultWindow!=0 && m_pMergeResultWindow->isVisible() ? m_pMergeResultWindow->getMaxTextWidth() : 0; - - int v1 = m_pDiffTextWindow1!=0 && m_pDiffTextWindow1->isVisible() ? m_pDiffTextWindow1->getVisibleTextAreaWidth() : 0; - int v2 = m_pDiffTextWindow2!=0 && m_pDiffTextWindow2->isVisible() ? m_pDiffTextWindow2->getVisibleTextAreaWidth() : 0; - int v3 = m_pDiffTextWindow3!=0 && m_pDiffTextWindow3->isVisible() ? m_pDiffTextWindow3->getVisibleTextAreaWidth() : 0; - int vm = m_pMergeResultWindow!=0 && m_pMergeResultWindow->isVisible() ? m_pMergeResultWindow->getVisibleTextAreaWidth() : 0; - - // Find the minimum, but don't consider 0. - static int pageStep = 0; - if ( (pageStep==0 || pageStep>v1) && v1>0 ) - pageStep = v1; - if ( (pageStep==0 || pageStep>v2) && v2>0 ) - pageStep = v2; - if ( (pageStep==0 || pageStep>v3) && v3>0 ) - pageStep = v3; - if ( (pageStep==0 || pageStep>vm) && vm>0 ) - pageStep = vm; - - static int rangeMax = 0; - if ( w1>v1 && w1-v1>rangeMax && v1>0 ) - rangeMax = w1-v1; - if ( w2>v2 && w2-v2>rangeMax && v2>0 ) - rangeMax = w2-v2; - if ( w3>v3 && w3-v3>rangeMax && v3>0 ) - rangeMax = w3-v3; - if ( wm>vm && wm-vm>rangeMax && vm>0 ) - rangeMax = wm-vm; - - m_pHScrollBar->setRange(0, rangeMax ); - m_pHScrollBar->setPageStep( pageStep ); + int w1 = m_pDiffTextWindow1 != 0 && m_pDiffTextWindow1->isVisible() ? m_pDiffTextWindow1->getMaxTextWidth() : 0; + int w2 = m_pDiffTextWindow2 != 0 && m_pDiffTextWindow2->isVisible() ? m_pDiffTextWindow2->getMaxTextWidth() : 0; + int w3 = m_pDiffTextWindow3 != 0 && m_pDiffTextWindow3->isVisible() ? m_pDiffTextWindow3->getMaxTextWidth() : 0; + + int wm = m_pMergeResultWindow != 0 && m_pMergeResultWindow->isVisible() ? m_pMergeResultWindow->getMaxTextWidth() : 0; + + int v1 = m_pDiffTextWindow1 != 0 && m_pDiffTextWindow1->isVisible() ? m_pDiffTextWindow1->getVisibleTextAreaWidth() : 0; + int v2 = m_pDiffTextWindow2 != 0 && m_pDiffTextWindow2->isVisible() ? m_pDiffTextWindow2->getVisibleTextAreaWidth() : 0; + int v3 = m_pDiffTextWindow3 != 0 && m_pDiffTextWindow3->isVisible() ? m_pDiffTextWindow3->getVisibleTextAreaWidth() : 0; + int vm = m_pMergeResultWindow != 0 && m_pMergeResultWindow->isVisible() ? m_pMergeResultWindow->getVisibleTextAreaWidth() : 0; + + // Find the minimum, but don't consider 0. + static int pageStep = 0; + if((pageStep == 0 || pageStep > v1) && v1 > 0) + pageStep = v1; + if((pageStep == 0 || pageStep > v2) && v2 > 0) + pageStep = v2; + if((pageStep == 0 || pageStep > v3) && v3 > 0) + pageStep = v3; + if((pageStep == 0 || pageStep > vm) && vm > 0) + pageStep = vm; + + static int rangeMax = 0; + if(w1 > v1 && w1 - v1 > rangeMax && v1 > 0) + rangeMax = w1 - v1; + if(w2 > v2 && w2 - v2 > rangeMax && v2 > 0) + rangeMax = w2 - v2; + if(w3 > v3 && w3 - v3 > rangeMax && v3 > 0) + rangeMax = w3 - v3; + if(wm > vm && wm - vm > rangeMax && vm > 0) + rangeMax = wm - vm; + + m_pHScrollBar->setRange(0, rangeMax); + m_pHScrollBar->setPageStep(pageStep); } void KDiff3App::resizeDiffTextWindowHeight(int newHeight) { - m_DTWHeight = 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() ); + m_pDiffVScrollBar->setRange(0, max2(0, m_neededLines + 1 - newHeight)); + m_pDiffVScrollBar->setPageStep(newHeight); + m_pOverview->setRange(m_pDiffVScrollBar->value(), m_pDiffVScrollBar->pageStep()); - setHScrollBarRange(); + setHScrollBarRange(); } void KDiff3App::resizeMergeResultWindow() { - MergeResultWindow* p = m_pMergeResultWindow; - m_pMergeVScrollBar->setRange(0, max2(0, p->getNofLines() - p->getNofVisibleLines()) ); - m_pMergeVScrollBar->setPageStep( p->getNofVisibleLines() ); + MergeResultWindow* p = m_pMergeResultWindow; + m_pMergeVScrollBar->setRange(0, max2(0, p->getNofLines() - p->getNofVisibleLines())); + m_pMergeVScrollBar->setPageStep(p->getNofVisibleLines()); - setHScrollBarRange(); + setHScrollBarRange(); } -void KDiff3App::scrollDiffTextWindow( int deltaX, int deltaY ) +void KDiff3App::scrollDiffTextWindow(int deltaX, int deltaY) { - if ( deltaY!= 0 ) - { - m_pDiffVScrollBar->setValue( m_pDiffVScrollBar->value() + deltaY ); - m_pOverview->setRange( m_pDiffVScrollBar->value(), m_pDiffVScrollBar->pageStep() ); - } - if ( deltaX!= 0) - m_pHScrollBar->QScrollBar::setValue( m_pHScrollBar->value() + deltaX ); + if(deltaY != 0) + { + m_pDiffVScrollBar->setValue(m_pDiffVScrollBar->value() + deltaY); + m_pOverview->setRange(m_pDiffVScrollBar->value(), m_pDiffVScrollBar->pageStep()); + } + if(deltaX != 0) + m_pHScrollBar->QScrollBar::setValue(m_pHScrollBar->value() + deltaX); } -void KDiff3App::scrollMergeResultWindow( int deltaX, int deltaY ) +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 ); + 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 ) +void KDiff3App::setDiff3Line(int line) { - m_pDiffVScrollBar->setValue( line ); + m_pDiffVScrollBar->setValue(line); } -void KDiff3App::sourceMask( int srcMask, int enabledMask ) +void KDiff3App::sourceMask(int srcMask, int enabledMask) { - chooseA->blockSignals(true); - chooseB->blockSignals(true); - chooseC->blockSignals(true); - chooseA->setChecked( (srcMask & 1) != 0 ); - chooseB->setChecked( (srcMask & 2) != 0 ); - chooseC->setChecked( (srcMask & 4) != 0 ); - chooseA->blockSignals(false); - chooseB->blockSignals(false); - chooseC->blockSignals(false); - chooseA->setEnabled( (enabledMask & 1) != 0 ); - chooseB->setEnabled( (enabledMask & 2) != 0 ); - chooseC->setEnabled( (enabledMask & 4) != 0 ); + chooseA->blockSignals(true); + chooseB->blockSignals(true); + chooseC->blockSignals(true); + chooseA->setChecked((srcMask & 1) != 0); + chooseB->setChecked((srcMask & 2) != 0); + chooseC->setChecked((srcMask & 4) != 0); + chooseA->blockSignals(false); + chooseB->blockSignals(false); + chooseC->blockSignals(false); + 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) +void addWidget(L* layout, W* widget) { - QSize s = widget->sizeHint(); - widget->setMinimumSize( QSize(max2(s.width(),0),max2(s.height(),0) ) ); - layout->addWidget( 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 - if ( m_pMainWidget != 0 ) - { - return; - //delete m_pMainWidget; - } - m_pMainWidget = new QWidget(); // Contains vertical splitter and horiz scrollbar - m_pMainSplitter->addWidget( m_pMainWidget ); - m_pMainWidget->setObjectName("MainWidget"); - QVBoxLayout* pVLayout = new QVBoxLayout(m_pMainWidget); - pVLayout->setMargin(0); - pVLayout->setSpacing(0); - - QSplitter* pVSplitter = new QSplitter(); - pVSplitter->setObjectName("VSplitter"); - pVSplitter->setOpaqueResize(false); - pVSplitter->setOrientation( Qt::Vertical ); - pVLayout->addWidget( pVSplitter ); - - QWidget* pDiffWindowFrame = new QWidget(); // Contains diff windows, overview and vert scrollbar - pDiffWindowFrame->setObjectName("DiffWindowFrame"); - QHBoxLayout* pDiffHLayout = new QHBoxLayout( pDiffWindowFrame ); - pDiffHLayout->setMargin(0); - pDiffHLayout->setSpacing(0); - pVSplitter->addWidget(pDiffWindowFrame); - - m_pDiffWindowSplitter = new QSplitter(); - m_pDiffWindowSplitter->setObjectName("DiffWindowSplitter"); - m_pDiffWindowSplitter->setOpaqueResize(false); - - m_pDiffWindowSplitter->setOrientation( m_pOptions->m_bHorizDiffWindowSplitting ? Qt::Horizontal : Qt::Vertical ); - pDiffHLayout->addWidget( m_pDiffWindowSplitter ); - - m_pOverview = new Overview( &m_pOptionDialog->m_options ); - m_pOverview->setObjectName("Overview"); - pDiffHLayout->addWidget(m_pOverview); - connect( m_pOverview, SIGNAL(setLine(int)), this, SLOT(setDiff3Line(int)) ); - - m_pDiffVScrollBar = new QScrollBar( Qt::Vertical, pDiffWindowFrame ); - pDiffHLayout->addWidget( m_pDiffVScrollBar ); - - m_pDiffTextWindowFrame1 = new DiffTextWindowFrame( m_pDiffWindowSplitter, statusBar(), &m_pOptionDialog->m_options, 1, &m_sd1); - m_pDiffWindowSplitter->addWidget(m_pDiffTextWindowFrame1); - m_pDiffTextWindowFrame2 = new DiffTextWindowFrame( m_pDiffWindowSplitter, statusBar(), &m_pOptionDialog->m_options, 2, &m_sd2); - m_pDiffWindowSplitter->addWidget(m_pDiffTextWindowFrame2); - m_pDiffTextWindowFrame3 = new DiffTextWindowFrame( m_pDiffWindowSplitter, statusBar(), &m_pOptionDialog->m_options, 3, &m_sd3); - m_pDiffWindowSplitter->addWidget(m_pDiffTextWindowFrame3); - m_pDiffTextWindow1 = m_pDiffTextWindowFrame1->getDiffTextWindow(); - m_pDiffTextWindow2 = m_pDiffTextWindowFrame2->getDiffTextWindow(); - m_pDiffTextWindow3 = m_pDiffTextWindowFrame3->getDiffTextWindow(); - connect(m_pDiffTextWindowFrame1, SIGNAL(fileNameChanged(const QString&,int)), this, SLOT(slotFileNameChanged(const QString&,int))); - connect(m_pDiffTextWindowFrame2, SIGNAL(fileNameChanged(const QString&,int)), this, SLOT(slotFileNameChanged(const QString&,int))); - connect(m_pDiffTextWindowFrame3, SIGNAL(fileNameChanged(const QString&,int)), this, SLOT(slotFileNameChanged(const QString&,int))); - - connect(m_pDiffTextWindowFrame1, SIGNAL(encodingChanged(QTextCodec*)), this, SLOT(slotEncodingChangedA(QTextCodec*))); - connect(m_pDiffTextWindowFrame2, SIGNAL(encodingChanged(QTextCodec*)), this, SLOT(slotEncodingChangedB(QTextCodec*))); - connect(m_pDiffTextWindowFrame3, SIGNAL(encodingChanged(QTextCodec*)), this, SLOT(slotEncodingChangedC(QTextCodec*))); - - // Merge window - m_pMergeWindowFrame = new QWidget( pVSplitter ); - m_pMergeWindowFrame->setObjectName("MergeWindowFrame"); - pVSplitter->addWidget(m_pMergeWindowFrame); - QHBoxLayout* pMergeHLayout = new QHBoxLayout( m_pMergeWindowFrame ); - pMergeHLayout->setMargin(0); - pMergeHLayout->setSpacing(0); - QVBoxLayout* pMergeVLayout = new QVBoxLayout(); - pMergeHLayout->addLayout( pMergeVLayout, 1 ); - - m_pMergeResultWindowTitle = new WindowTitleWidget(&m_pOptionDialog->m_options); - pMergeVLayout->addWidget( m_pMergeResultWindowTitle ); - - m_pMergeResultWindow = new MergeResultWindow( m_pMergeWindowFrame, &m_pOptionDialog->m_options, statusBar() ); - pMergeVLayout->addWidget( m_pMergeResultWindow, 1 ); - - m_pMergeVScrollBar = new QScrollBar( Qt::Vertical, m_pMergeWindowFrame ); - pMergeHLayout->addWidget( m_pMergeVScrollBar ); - - m_pMainSplitter->addWidget(m_pMainWidget); - - autoAdvance->setEnabled(true); - - QList sizes = pVSplitter->sizes(); - int total = sizes[0] + sizes[1]; - if ( total<10 ) - total = 100; - sizes[0]=total/2; sizes[1]=total/2; - pVSplitter->setSizes( sizes ); - - QList hSizes; - hSizes << 1 << 1 << 1; - m_pDiffWindowSplitter->setSizes( hSizes ); - - m_pMergeResultWindow->installEventFilter( this ); // for Cut/Copy/Paste-shortcuts - m_pMergeResultWindow->installEventFilter( m_pMergeResultWindowTitle ); // for focus tracking - - QHBoxLayout* pHScrollBarLayout = new QHBoxLayout(); - pVLayout->addLayout( pHScrollBarLayout ); - m_pHScrollBar = new ReversibleScrollBar( Qt::Horizontal, &m_pOptions->m_bRightToLeftLanguage ); - pHScrollBarLayout->addWidget( m_pHScrollBar ); - m_pCornerWidget = new QWidget( m_pMainWidget ); - pHScrollBarLayout->addWidget( m_pCornerWidget ); - - - connect(m_pDiffVScrollBar, &QScrollBar::valueChanged, m_pOverview, &Overview::setFirstLine); - connect( m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pDiffTextWindow1, SLOT(setFirstLine(int))); - connect( m_pHScrollBar, SIGNAL(valueChanged2(int)), m_pDiffTextWindow1, SLOT(setHorizScrollOffset(int))); - connect( m_pDiffTextWindow1, SIGNAL(newSelection()), this, SLOT(slotSelectionStart())); - connect( m_pDiffTextWindow1, SIGNAL(selectionEnd()), this, SLOT(slotSelectionEnd())); - connect( m_pDiffTextWindow1, SIGNAL(scroll(int,int)), this, SLOT(scrollDiffTextWindow(int,int))); - m_pDiffTextWindow1->installEventFilter( this ); - - connect( m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pDiffTextWindow2, SLOT(setFirstLine(int))); - connect( m_pHScrollBar, SIGNAL(valueChanged2(int)), m_pDiffTextWindow2, SLOT(setHorizScrollOffset(int))); - connect( m_pDiffTextWindow2, SIGNAL(newSelection()), this, SLOT(slotSelectionStart())); - connect( m_pDiffTextWindow2, SIGNAL(selectionEnd()), this, SLOT(slotSelectionEnd())); - connect( m_pDiffTextWindow2, SIGNAL(scroll(int,int)), this, SLOT(scrollDiffTextWindow(int,int))); - m_pDiffTextWindow2->installEventFilter( this ); - - connect( m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pDiffTextWindow3, SLOT(setFirstLine(int))); - connect( m_pHScrollBar, SIGNAL(valueChanged2(int)), m_pDiffTextWindow3, SLOT(setHorizScrollOffset(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, &QScrollBar::valueChanged, p, &MergeResultWindow::setFirstLine); - - connect(m_pHScrollBar, &ReversibleScrollBar::valueChanged2, p, &MergeResultWindow::setHorizScrollOffset); - connect( p, SIGNAL(scroll(int,int)), this, SLOT(scrollMergeResultWindow(int,int))); - connect( p, SIGNAL(sourceMask(int,int)), this, SLOT(sourceMask(int,int))); - connect( p, SIGNAL( resizeSignal() ),this, SLOT(resizeMergeResultWindow())); - connect( p, SIGNAL( selectionEnd() ), this, SLOT( slotSelectionEnd() ) ); - connect( p, SIGNAL( newSelection() ), this, SLOT( slotSelectionStart() ) ); - connect( p, SIGNAL( modifiedChanged(bool) ), this, SLOT( slotOutputModified(bool) ) ); - connect(p, &MergeResultWindow::modifiedChanged, m_pMergeResultWindowTitle, &WindowTitleWidget::slotSetModified); - connect( p, SIGNAL( updateAvailabilities() ), this, SLOT( slotUpdateAvailabilities() ) ); - connect( p, SIGNAL( showPopupMenu(const QPoint&) ), this, SLOT(showPopupMenu(const QPoint&))); - connect( p, SIGNAL( noRelevantChangesDetected() ), this, SLOT(slotNoRelevantChangesDetected())); - sourceMask(0,0); - - - connect( p, SIGNAL(setFastSelectorRange(int,int)), m_pDiffTextWindow1, SLOT(setFastSelectorRange(int,int))); - connect( p, SIGNAL(setFastSelectorRange(int,int)), m_pDiffTextWindow2, SLOT(setFastSelectorRange(int,int))); - connect( p, SIGNAL(setFastSelectorRange(int,int)), m_pDiffTextWindow3, SLOT(setFastSelectorRange(int,int))); - connect(m_pDiffTextWindow1, SIGNAL(setFastSelectorLine(int)), p, SLOT(slotSetFastSelectorLine(int))); - connect(m_pDiffTextWindow2, SIGNAL(setFastSelectorLine(int)), p, SLOT(slotSetFastSelectorLine(int))); - connect(m_pDiffTextWindow3, SIGNAL(setFastSelectorLine(int)), p, SLOT(slotSetFastSelectorLine(int))); - connect(m_pDiffTextWindow1, SIGNAL(gotFocus()), p, SLOT(updateSourceMask())); - connect(m_pDiffTextWindow2, SIGNAL(gotFocus()), p, SLOT(updateSourceMask())); - connect(m_pDiffTextWindow3, SIGNAL(gotFocus()), p, SLOT(updateSourceMask())); - connect(m_pDirectoryMergeInfo, SIGNAL(gotFocus()), p, SLOT(updateSourceMask())); - - connect( m_pDiffTextWindow1, SIGNAL( resizeHeightChangedSignal(int) ),this, SLOT(resizeDiffTextWindowHeight(int))); - // The following two connects cause the wordwrap to be recalced thrice, just to make sure. Better than forgetting one. - connect(m_pDiffTextWindow1, SIGNAL(resizeWidthChangedSignal(int)), this, SLOT(postRecalcWordWrap())); - connect(m_pDiffTextWindow2, SIGNAL(resizeWidthChangedSignal(int)), this, SLOT(postRecalcWordWrap())); - connect(m_pDiffTextWindow3, SIGNAL(resizeWidthChangedSignal(int)), this, SLOT(postRecalcWordWrap())); - - m_pDiffTextWindow1->setFocus(); - m_pMainWidget->setMinimumSize(50,50); - m_pCornerWidget->setFixedSize( m_pDiffVScrollBar->width(), m_pHScrollBar->height() ); - showWindowA->setChecked( true ); - showWindowB->setChecked( true ); - showWindowC->setChecked( true ); -} - -static int calcManualDiffFirstDiff3LineIdx( const Diff3LineVector& d3lv, const ManualDiffHelpEntry& mdhe ) -{ - int i; - for( i = 0; i=0 && mdhe.lineA1==d3l.lineA) || - (mdhe.lineB1>=0 && mdhe.lineB1==d3l.lineB) || - (mdhe.lineC1>=0 && mdhe.lineC1==d3l.lineC) ) - return i; - } - return -1; + // set the main widget here + if(m_pMainWidget != 0) + { + return; + //delete m_pMainWidget; + } + m_pMainWidget = new QWidget(); // Contains vertical splitter and horiz scrollbar + m_pMainSplitter->addWidget(m_pMainWidget); + m_pMainWidget->setObjectName("MainWidget"); + QVBoxLayout* pVLayout = new QVBoxLayout(m_pMainWidget); + pVLayout->setMargin(0); + pVLayout->setSpacing(0); + + QSplitter* pVSplitter = new QSplitter(); + pVSplitter->setObjectName("VSplitter"); + pVSplitter->setOpaqueResize(false); + pVSplitter->setOrientation(Qt::Vertical); + pVLayout->addWidget(pVSplitter); + + QWidget* pDiffWindowFrame = new QWidget(); // Contains diff windows, overview and vert scrollbar + pDiffWindowFrame->setObjectName("DiffWindowFrame"); + QHBoxLayout* pDiffHLayout = new QHBoxLayout(pDiffWindowFrame); + pDiffHLayout->setMargin(0); + pDiffHLayout->setSpacing(0); + pVSplitter->addWidget(pDiffWindowFrame); + + m_pDiffWindowSplitter = new QSplitter(); + m_pDiffWindowSplitter->setObjectName("DiffWindowSplitter"); + m_pDiffWindowSplitter->setOpaqueResize(false); + + m_pDiffWindowSplitter->setOrientation(m_pOptions->m_bHorizDiffWindowSplitting ? Qt::Horizontal : Qt::Vertical); + pDiffHLayout->addWidget(m_pDiffWindowSplitter); + + m_pOverview = new Overview(&m_pOptionDialog->m_options); + m_pOverview->setObjectName("Overview"); + pDiffHLayout->addWidget(m_pOverview); + connect(m_pOverview, SIGNAL(setLine(int)), this, SLOT(setDiff3Line(int))); + + m_pDiffVScrollBar = new QScrollBar(Qt::Vertical, pDiffWindowFrame); + pDiffHLayout->addWidget(m_pDiffVScrollBar); + + m_pDiffTextWindowFrame1 = new DiffTextWindowFrame(m_pDiffWindowSplitter, statusBar(), &m_pOptionDialog->m_options, 1, &m_sd1); + m_pDiffWindowSplitter->addWidget(m_pDiffTextWindowFrame1); + m_pDiffTextWindowFrame2 = new DiffTextWindowFrame(m_pDiffWindowSplitter, statusBar(), &m_pOptionDialog->m_options, 2, &m_sd2); + m_pDiffWindowSplitter->addWidget(m_pDiffTextWindowFrame2); + m_pDiffTextWindowFrame3 = new DiffTextWindowFrame(m_pDiffWindowSplitter, statusBar(), &m_pOptionDialog->m_options, 3, &m_sd3); + m_pDiffWindowSplitter->addWidget(m_pDiffTextWindowFrame3); + m_pDiffTextWindow1 = m_pDiffTextWindowFrame1->getDiffTextWindow(); + m_pDiffTextWindow2 = m_pDiffTextWindowFrame2->getDiffTextWindow(); + m_pDiffTextWindow3 = m_pDiffTextWindowFrame3->getDiffTextWindow(); + connect(m_pDiffTextWindowFrame1, SIGNAL(fileNameChanged(const QString&, int)), this, SLOT(slotFileNameChanged(const QString&, int))); + connect(m_pDiffTextWindowFrame2, SIGNAL(fileNameChanged(const QString&, int)), this, SLOT(slotFileNameChanged(const QString&, int))); + connect(m_pDiffTextWindowFrame3, SIGNAL(fileNameChanged(const QString&, int)), this, SLOT(slotFileNameChanged(const QString&, int))); + + connect(m_pDiffTextWindowFrame1, SIGNAL(encodingChanged(QTextCodec*)), this, SLOT(slotEncodingChangedA(QTextCodec*))); + connect(m_pDiffTextWindowFrame2, SIGNAL(encodingChanged(QTextCodec*)), this, SLOT(slotEncodingChangedB(QTextCodec*))); + connect(m_pDiffTextWindowFrame3, SIGNAL(encodingChanged(QTextCodec*)), this, SLOT(slotEncodingChangedC(QTextCodec*))); + + // Merge window + m_pMergeWindowFrame = new QWidget(pVSplitter); + m_pMergeWindowFrame->setObjectName("MergeWindowFrame"); + pVSplitter->addWidget(m_pMergeWindowFrame); + QHBoxLayout* pMergeHLayout = new QHBoxLayout(m_pMergeWindowFrame); + pMergeHLayout->setMargin(0); + pMergeHLayout->setSpacing(0); + QVBoxLayout* pMergeVLayout = new QVBoxLayout(); + pMergeHLayout->addLayout(pMergeVLayout, 1); + + m_pMergeResultWindowTitle = new WindowTitleWidget(&m_pOptionDialog->m_options); + pMergeVLayout->addWidget(m_pMergeResultWindowTitle); + + m_pMergeResultWindow = new MergeResultWindow(m_pMergeWindowFrame, &m_pOptionDialog->m_options, statusBar()); + pMergeVLayout->addWidget(m_pMergeResultWindow, 1); + + m_pMergeVScrollBar = new QScrollBar(Qt::Vertical, m_pMergeWindowFrame); + pMergeHLayout->addWidget(m_pMergeVScrollBar); + + m_pMainSplitter->addWidget(m_pMainWidget); + + autoAdvance->setEnabled(true); + + QList sizes = pVSplitter->sizes(); + int total = sizes[0] + sizes[1]; + if(total < 10) + total = 100; + sizes[0] = total / 2; + sizes[1] = total / 2; + pVSplitter->setSizes(sizes); + + QList hSizes; + hSizes << 1 << 1 << 1; + m_pDiffWindowSplitter->setSizes(hSizes); + + m_pMergeResultWindow->installEventFilter(this); // for Cut/Copy/Paste-shortcuts + m_pMergeResultWindow->installEventFilter(m_pMergeResultWindowTitle); // for focus tracking + + QHBoxLayout* pHScrollBarLayout = new QHBoxLayout(); + pVLayout->addLayout(pHScrollBarLayout); + m_pHScrollBar = new ReversibleScrollBar(Qt::Horizontal, &m_pOptions->m_bRightToLeftLanguage); + pHScrollBarLayout->addWidget(m_pHScrollBar); + m_pCornerWidget = new QWidget(m_pMainWidget); + pHScrollBarLayout->addWidget(m_pCornerWidget); + + connect(m_pDiffVScrollBar, &QScrollBar::valueChanged, m_pOverview, &Overview::setFirstLine); + connect(m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pDiffTextWindow1, SLOT(setFirstLine(int))); + connect(m_pHScrollBar, SIGNAL(valueChanged2(int)), m_pDiffTextWindow1, SLOT(setHorizScrollOffset(int))); + connect(m_pDiffTextWindow1, SIGNAL(newSelection()), this, SLOT(slotSelectionStart())); + connect(m_pDiffTextWindow1, SIGNAL(selectionEnd()), this, SLOT(slotSelectionEnd())); + connect(m_pDiffTextWindow1, SIGNAL(scroll(int, int)), this, SLOT(scrollDiffTextWindow(int, int))); + m_pDiffTextWindow1->installEventFilter(this); + + connect(m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pDiffTextWindow2, SLOT(setFirstLine(int))); + connect(m_pHScrollBar, SIGNAL(valueChanged2(int)), m_pDiffTextWindow2, SLOT(setHorizScrollOffset(int))); + connect(m_pDiffTextWindow2, SIGNAL(newSelection()), this, SLOT(slotSelectionStart())); + connect(m_pDiffTextWindow2, SIGNAL(selectionEnd()), this, SLOT(slotSelectionEnd())); + connect(m_pDiffTextWindow2, SIGNAL(scroll(int, int)), this, SLOT(scrollDiffTextWindow(int, int))); + m_pDiffTextWindow2->installEventFilter(this); + + connect(m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pDiffTextWindow3, SLOT(setFirstLine(int))); + connect(m_pHScrollBar, SIGNAL(valueChanged2(int)), m_pDiffTextWindow3, SLOT(setHorizScrollOffset(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, &QScrollBar::valueChanged, p, &MergeResultWindow::setFirstLine); + + connect(m_pHScrollBar, &ReversibleScrollBar::valueChanged2, p, &MergeResultWindow::setHorizScrollOffset); + connect(p, SIGNAL(scroll(int, int)), this, SLOT(scrollMergeResultWindow(int, int))); + connect(p, SIGNAL(sourceMask(int, int)), this, SLOT(sourceMask(int, int))); + connect(p, SIGNAL(resizeSignal()), this, SLOT(resizeMergeResultWindow())); + connect(p, SIGNAL(selectionEnd()), this, SLOT(slotSelectionEnd())); + connect(p, SIGNAL(newSelection()), this, SLOT(slotSelectionStart())); + connect(p, SIGNAL(modifiedChanged(bool)), this, SLOT(slotOutputModified(bool))); + connect(p, &MergeResultWindow::modifiedChanged, m_pMergeResultWindowTitle, &WindowTitleWidget::slotSetModified); + connect(p, SIGNAL(updateAvailabilities()), this, SLOT(slotUpdateAvailabilities())); + connect(p, SIGNAL(showPopupMenu(const QPoint&)), this, SLOT(showPopupMenu(const QPoint&))); + connect(p, SIGNAL(noRelevantChangesDetected()), this, SLOT(slotNoRelevantChangesDetected())); + sourceMask(0, 0); + + connect(p, SIGNAL(setFastSelectorRange(int, int)), m_pDiffTextWindow1, SLOT(setFastSelectorRange(int, int))); + connect(p, SIGNAL(setFastSelectorRange(int, int)), m_pDiffTextWindow2, SLOT(setFastSelectorRange(int, int))); + connect(p, SIGNAL(setFastSelectorRange(int, int)), m_pDiffTextWindow3, SLOT(setFastSelectorRange(int, int))); + connect(m_pDiffTextWindow1, SIGNAL(setFastSelectorLine(int)), p, SLOT(slotSetFastSelectorLine(int))); + connect(m_pDiffTextWindow2, SIGNAL(setFastSelectorLine(int)), p, SLOT(slotSetFastSelectorLine(int))); + connect(m_pDiffTextWindow3, SIGNAL(setFastSelectorLine(int)), p, SLOT(slotSetFastSelectorLine(int))); + connect(m_pDiffTextWindow1, SIGNAL(gotFocus()), p, SLOT(updateSourceMask())); + connect(m_pDiffTextWindow2, SIGNAL(gotFocus()), p, SLOT(updateSourceMask())); + connect(m_pDiffTextWindow3, SIGNAL(gotFocus()), p, SLOT(updateSourceMask())); + connect(m_pDirectoryMergeInfo, SIGNAL(gotFocus()), p, SLOT(updateSourceMask())); + + connect(m_pDiffTextWindow1, SIGNAL(resizeHeightChangedSignal(int)), this, SLOT(resizeDiffTextWindowHeight(int))); + // The following two connects cause the wordwrap to be recalced thrice, just to make sure. Better than forgetting one. + connect(m_pDiffTextWindow1, SIGNAL(resizeWidthChangedSignal(int)), this, SLOT(postRecalcWordWrap())); + connect(m_pDiffTextWindow2, SIGNAL(resizeWidthChangedSignal(int)), this, SLOT(postRecalcWordWrap())); + connect(m_pDiffTextWindow3, SIGNAL(resizeWidthChangedSignal(int)), this, SLOT(postRecalcWordWrap())); + + m_pDiffTextWindow1->setFocus(); + m_pMainWidget->setMinimumSize(50, 50); + m_pCornerWidget->setFixedSize(m_pDiffVScrollBar->width(), m_pHScrollBar->height()); + showWindowA->setChecked(true); + showWindowB->setChecked(true); + showWindowC->setChecked(true); +} + +static int calcManualDiffFirstDiff3LineIdx(const Diff3LineVector& d3lv, const ManualDiffHelpEntry& mdhe) +{ + int i; + for(i = 0; i < d3lv.size(); ++i) + { + const Diff3Line& d3l = *d3lv[i]; + if((mdhe.lineA1 >= 0 && mdhe.lineA1 == d3l.lineA) || + (mdhe.lineB1 >= 0 && mdhe.lineB1 == d3l.lineB) || + (mdhe.lineC1 >= 0 && mdhe.lineC1 == d3l.lineC)) + return i; + } + return -1; } // called after word wrap is complete void KDiff3App::slotFinishMainInit() { - setHScrollBarRange(); - - 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() ); - - int d3l=-1; - if ( ! m_manualDiffHelpList.empty() ) - d3l = calcManualDiffFirstDiff3LineIdx( m_diff3LineVector, m_manualDiffHelpList.front() ); - if ( d3l>=0 && m_pDiffTextWindow1 ) - { - int line = m_pDiffTextWindow1->convertDiff3LineIdxToLine( d3l ); - m_pDiffVScrollBar->setValue( max2(0,line-1) ); - } - else - { - m_pMergeResultWindow->slotGoTop(); - if ( ! m_outputFilename.isEmpty() && ! m_pMergeResultWindow->isUnsolvedConflictAtCurrent() ) - m_pMergeResultWindow->slotGoNextUnsolvedConflict(); - } - - if (m_pCornerWidget) - m_pCornerWidget->setFixedSize( m_pDiffVScrollBar->width(), m_pHScrollBar->height() ); - - slotUpdateAvailabilities(); - setUpdatesEnabled(true); - // Workaround for a Qt-bug - QList treeViews = findChildren(); - foreach( QTreeView* pTreeView, treeViews ) - { - pTreeView->setUpdatesEnabled(true); - } - - bool bVisibleMergeResultWindow = !m_outputFilename.isEmpty(); - TotalDiffStatus* pTotalDiffStatus = &m_totalDiffStatus; - - if (m_bLoadFiles) - { - - if (bVisibleMergeResultWindow) - m_pMergeResultWindow->showNrOfConflicts(); - else if ( - // Avoid showing this message during startup without parameters. - !(m_sd1.getAliasName().isEmpty() && m_sd2.getAliasName().isEmpty() && m_sd3.getAliasName().isEmpty()) && - (m_sd1.isValid() && m_sd2.isValid() && m_sd3.isValid()) - ) - { - QString totalInfo; - if (pTotalDiffStatus->bBinaryAEqB && pTotalDiffStatus->bBinaryAEqC) - totalInfo += i18n("All input files are binary equal."); - else if (pTotalDiffStatus->bTextAEqB && pTotalDiffStatus->bTextAEqC) - totalInfo += i18n("All input files contain the same text, but are not binary equal."); - else { - if (pTotalDiffStatus->bBinaryAEqB) totalInfo += i18n("Files %1 and %2 are binary equal.\n", QString("A"), QString("B")); - else if (pTotalDiffStatus->bTextAEqB) totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n", QString("A"), QString("B")); - if (pTotalDiffStatus->bBinaryAEqC) totalInfo += i18n("Files %1 and %2 are binary equal.\n", QString("A"), QString("C")); - else if (pTotalDiffStatus->bTextAEqC) totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n", QString("A"), QString("C")); - if (pTotalDiffStatus->bBinaryBEqC) totalInfo += i18n("Files %1 and %2 are binary equal.\n", QString("B"), QString("C")); - else if (pTotalDiffStatus->bTextBEqC) totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n", QString("B"), QString("C")); - } - - if (!totalInfo.isEmpty()) - KMessageBox::information(this, totalInfo); - } - - if (bVisibleMergeResultWindow && (!m_sd1.isText() || !m_sd2.isText() || !m_sd3.isText())) - { - KMessageBox::information(this, i18n( - "Some inputfiles don't seem to be pure textfiles.\n" - "Note that the KDiff3-merge was not meant for binary data.\n" - "Continue at your own risk.")); - } - if (m_sd1.isIncompleteConversion() || m_sd2.isIncompleteConversion() || m_sd3.isIncompleteConversion()) - { - QString files; - if (m_sd1.isIncompleteConversion()) - files += "A"; - if (m_sd2.isIncompleteConversion()) - files += files.isEmpty() ? "B" : ", B"; - if (m_sd3.isIncompleteConversion()) - files += files.isEmpty() ? "C" : ", C"; - - KMessageBox::information(this, i18n( - "Some input characters could not be converted to valid unicode.\n" - "You might be using the wrong codec. (e.g. UTF-8 for non UTF-8 files).\n" - "Don't save the result if unsure. Continue at your own risk.\n" - "Affected input files are in %1.").arg(files)); - } - } - - if (bVisibleMergeResultWindow && m_pMergeResultWindow) - { - m_pMergeResultWindow->setFocus(); - } - else if (m_pDiffTextWindow1) - { - m_pDiffTextWindow1->setFocus(); - } + setHScrollBarRange(); + + 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()); + + int d3l = -1; + if(!m_manualDiffHelpList.empty()) + d3l = calcManualDiffFirstDiff3LineIdx(m_diff3LineVector, m_manualDiffHelpList.front()); + if(d3l >= 0 && m_pDiffTextWindow1) + { + int line = m_pDiffTextWindow1->convertDiff3LineIdxToLine(d3l); + m_pDiffVScrollBar->setValue(max2(0, line - 1)); + } + else + { + m_pMergeResultWindow->slotGoTop(); + if(!m_outputFilename.isEmpty() && !m_pMergeResultWindow->isUnsolvedConflictAtCurrent()) + m_pMergeResultWindow->slotGoNextUnsolvedConflict(); + } + + if(m_pCornerWidget) + m_pCornerWidget->setFixedSize(m_pDiffVScrollBar->width(), m_pHScrollBar->height()); + + slotUpdateAvailabilities(); + setUpdatesEnabled(true); + // Workaround for a Qt-bug + QList treeViews = findChildren(); + foreach(QTreeView* pTreeView, treeViews) + { + pTreeView->setUpdatesEnabled(true); + } + + bool bVisibleMergeResultWindow = !m_outputFilename.isEmpty(); + TotalDiffStatus* pTotalDiffStatus = &m_totalDiffStatus; + + if(m_bLoadFiles) + { + + if(bVisibleMergeResultWindow) + m_pMergeResultWindow->showNrOfConflicts(); + else if( + // Avoid showing this message during startup without parameters. + !(m_sd1.getAliasName().isEmpty() && m_sd2.getAliasName().isEmpty() && m_sd3.getAliasName().isEmpty()) && + (m_sd1.isValid() && m_sd2.isValid() && m_sd3.isValid())) + { + QString totalInfo; + if(pTotalDiffStatus->bBinaryAEqB && pTotalDiffStatus->bBinaryAEqC) + totalInfo += i18n("All input files are binary equal."); + else if(pTotalDiffStatus->bTextAEqB && pTotalDiffStatus->bTextAEqC) + totalInfo += i18n("All input files contain the same text, but are not binary equal."); + else + { + if(pTotalDiffStatus->bBinaryAEqB) + totalInfo += i18n("Files %1 and %2 are binary equal.\n", QString("A"), QString("B")); + else if(pTotalDiffStatus->bTextAEqB) + totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n", QString("A"), QString("B")); + if(pTotalDiffStatus->bBinaryAEqC) + totalInfo += i18n("Files %1 and %2 are binary equal.\n", QString("A"), QString("C")); + else if(pTotalDiffStatus->bTextAEqC) + totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n", QString("A"), QString("C")); + if(pTotalDiffStatus->bBinaryBEqC) + totalInfo += i18n("Files %1 and %2 are binary equal.\n", QString("B"), QString("C")); + else if(pTotalDiffStatus->bTextBEqC) + totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n", QString("B"), QString("C")); + } + + if(!totalInfo.isEmpty()) + KMessageBox::information(this, totalInfo); + } + + if(bVisibleMergeResultWindow && (!m_sd1.isText() || !m_sd2.isText() || !m_sd3.isText())) + { + KMessageBox::information(this, i18n( + "Some inputfiles don't seem to be pure textfiles.\n" + "Note that the KDiff3-merge was not meant for binary data.\n" + "Continue at your own risk.")); + } + if(m_sd1.isIncompleteConversion() || m_sd2.isIncompleteConversion() || m_sd3.isIncompleteConversion()) + { + QString files; + if(m_sd1.isIncompleteConversion()) + files += "A"; + if(m_sd2.isIncompleteConversion()) + files += files.isEmpty() ? "B" : ", B"; + if(m_sd3.isIncompleteConversion()) + files += files.isEmpty() ? "C" : ", C"; + + KMessageBox::information(this, i18n("Some input characters could not be converted to valid unicode.\n" + "You might be using the wrong codec. (e.g. UTF-8 for non UTF-8 files).\n" + "Don't save the result if unsure. Continue at your own risk.\n" + "Affected input files are in %1.") + .arg(files)); + } + } + + if(bVisibleMergeResultWindow && m_pMergeResultWindow) + { + m_pMergeResultWindow->setFocus(); + } + else if(m_pDiffTextWindow1) + { + m_pDiffTextWindow1->setFocus(); + } } void KDiff3App::resizeEvent(QResizeEvent* e) { - QSplitter::resizeEvent(e); - if (m_pCornerWidget) - m_pCornerWidget->setFixedSize( m_pDiffVScrollBar->width(), m_pHScrollBar->height() ); + QSplitter::resizeEvent(e); + if(m_pCornerWidget) + m_pCornerWidget->setFixedSize(m_pDiffVScrollBar->width(), m_pHScrollBar->height()); } -void KDiff3App::childEvent(QChildEvent *c) +void KDiff3App::childEvent(QChildEvent* c) { - // Workaround for a bug in several Qt versions. When a child is added to QSplitter, don't - // add it to the splitter if it is a window. - if ( c->child()->isWidgetType()) - { - QWidget *w = static_cast(c->child()); - if ( w->isWindow() ) - return; - } - QSplitter::childEvent(c); + // Workaround for a bug in several Qt versions. When a child is added to QSplitter, don't + // add it to the splitter if it is a window. + if(c->child()->isWidgetType()) + { + QWidget* w = static_cast(c->child()); + if(w->isWindow()) + return; + } + QSplitter::childEvent(c); } -bool KDiff3App::eventFilter( QObject* o, QEvent* e ) +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->QInputEvent::modifiers() & Qt::ControlModifier)!=0 ) - { + if(o == m_pMergeResultWindow) + { + if(e->type() == QEvent::KeyPress) + { // key press + QKeyEvent* k = (QKeyEvent*)e; + if(k->key() == Qt::Key_Insert && (k->QInputEvent::modifiers() & Qt::ControlModifier) != 0) + { + slotEditCopy(); + return true; + } + if(k->key() == Qt::Key_Insert && (k->QInputEvent::modifiers() & Qt::ShiftModifier) != 0) + { + slotEditPaste(); + return true; + } + if(k->key() == Qt::Key_Delete && (k->QInputEvent::modifiers() & Qt::ShiftModifier) != 0) + { + slotEditCut(); + return true; + } + if(k->key() == Qt::Key_Escape && m_pKDiff3Shell && m_pOptions->m_bEscapeKeyQuits) + { + m_pKDiff3Shell->close(); + return true; + } + } + return QSplitter::eventFilter(o, e); // standard event processing + } + + if(e->type() == QEvent::KeyPress) // key press + { + QKeyEvent* k = (QKeyEvent*)e; + if(k->key() == Qt::Key_Escape && m_pKDiff3Shell && m_pOptions->m_bEscapeKeyQuits) + { + m_pKDiff3Shell->close(); + return true; + } + + bool bCtrl = (k->QInputEvent::modifiers() & Qt::ControlModifier) != 0; + if(k->key() == Qt::Key_Insert && bCtrl) + { slotEditCopy(); return true; - } - if (k->key()==Qt::Key_Insert && (k->QInputEvent::modifiers() & Qt::ShiftModifier)!=0 ) - { + } + if(k->key() == Qt::Key_Insert && (k->QInputEvent::modifiers() & Qt::ShiftModifier) != 0) + { slotEditPaste(); return true; - } - if (k->key()==Qt::Key_Delete && (k->QInputEvent::modifiers() & Qt::ShiftModifier)!=0 ) - { - slotEditCut(); - return true; - } - if ( k->key()==Qt::Key_Escape && m_pKDiff3Shell && m_pOptions->m_bEscapeKeyQuits ) - { - m_pKDiff3Shell->close(); - return true; - } - } - return QSplitter::eventFilter( o, e ); // standard event processing - } - - if ( e->type() == QEvent::KeyPress ) // key press - { - QKeyEvent *k = (QKeyEvent*)e; - if ( k->key()==Qt::Key_Escape && m_pKDiff3Shell && m_pOptions->m_bEscapeKeyQuits ) - { - m_pKDiff3Shell->close(); - return true; - } - - bool bCtrl = (k->QInputEvent::modifiers() & Qt::ControlModifier) != 0; - if (k->key()==Qt::Key_Insert && bCtrl ) - { - slotEditCopy(); - return true; - } - if (k->key()==Qt::Key_Insert && (k->QInputEvent::modifiers() & Qt::ShiftModifier)!=0 ) - { - slotEditPaste(); - return true; - } - int deltaX=0; - int deltaY=0; - int pageSize = m_DTWHeight; - switch( k->key() ) - { - case Qt::Key_Down: if (!bCtrl) ++deltaY; break; - case Qt::Key_Up: if (!bCtrl) --deltaY; break; - case Qt::Key_PageDown: if (!bCtrl) deltaY+=pageSize; break; - case Qt::Key_PageUp: if (!bCtrl) deltaY-=pageSize; break; - case Qt::Key_Left: if (!bCtrl) --deltaX; break; - case Qt::Key_Right: if (!bCtrl) ++deltaX; break; - case Qt::Key_Home: if ( bCtrl ) m_pDiffVScrollBar->setValue( 0 ); - else m_pHScrollBar->setValue( 0 ); - break; - case Qt::Key_End: if ( bCtrl ) m_pDiffVScrollBar->setValue( m_pDiffVScrollBar->maximum() ); - else m_pHScrollBar->setValue( m_pHScrollBar->maximum() ); - 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(); - - //As per QT documentation, some mice/OS combos send delta values - //less than 120 units(15 degrees) - d = d + m_iCumulativeWheelDelta; - if ( d > -120 && d < 120) - { - //not enough for a full step in either direction, add it up - //to use on a successive call - m_iCumulativeWheelDelta = d; - } - else - { - //reset cumulative tracking of the wheel since we have enough - //for a 15 degree movement - m_iCumulativeWheelDelta= 0; - } - - 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 ( pDropEvent->mimeData()->hasUrls() ) - { - QList urlList = pDropEvent->mimeData()->urls(); - if ( canContinue() && !urlList.isEmpty() ) - { - raise(); - QString filename = urlList.first().toLocalFile(); - 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 ); - mainInit(); - } - } - else if ( pDropEvent->mimeData()->hasText() ) - { - QString text = pDropEvent->mimeData()->text(); - if ( canContinue() ) - { - QStringList errors; - - raise(); - if ( o == m_pDiffTextWindow1 ) errors = m_sd1.setData(text); - else if ( o == m_pDiffTextWindow2 ) errors = m_sd2.setData(text); - else if ( o == m_pDiffTextWindow3 ) errors = m_sd3.setData(text); - foreach(const QString &error, errors) + } + int deltaX = 0; + int deltaY = 0; + int pageSize = m_DTWHeight; + switch(k->key()) + { + case Qt::Key_Down: + if(!bCtrl) ++deltaY; + break; + case Qt::Key_Up: + if(!bCtrl) --deltaY; + break; + case Qt::Key_PageDown: + if(!bCtrl) deltaY += pageSize; + break; + case Qt::Key_PageUp: + if(!bCtrl) deltaY -= pageSize; + break; + case Qt::Key_Left: + if(!bCtrl) --deltaX; + break; + case Qt::Key_Right: + if(!bCtrl) ++deltaX; + break; + case Qt::Key_Home: + if(bCtrl) + m_pDiffVScrollBar->setValue(0); + else + m_pHScrollBar->setValue(0); + break; + case Qt::Key_End: + if(bCtrl) + m_pDiffVScrollBar->setValue(m_pDiffVScrollBar->maximum()); + else + m_pHScrollBar->setValue(m_pHScrollBar->maximum()); + 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(); + + //As per QT documentation, some mice/OS combos send delta values + //less than 120 units(15 degrees) + d = d + m_iCumulativeWheelDelta; + if(d > -120 && d < 120) + { + //not enough for a full step in either direction, add it up + //to use on a successive call + m_iCumulativeWheelDelta = d; + } + else + { + //reset cumulative tracking of the wheel since we have enough + //for a 15 degree movement + m_iCumulativeWheelDelta = 0; + } + + 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(pDropEvent->mimeData()->hasUrls()) + { + QList urlList = pDropEvent->mimeData()->urls(); + if(canContinue() && !urlList.isEmpty()) { - KMessageBox::error( m_pOptionDialog, error ); + raise(); + QString filename = urlList.first().toLocalFile(); + 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); + mainInit(); } - mainInit(); - } - } + } + else if(pDropEvent->mimeData()->hasText()) + { + QString text = pDropEvent->mimeData()->text(); + if(canContinue()) + { + QStringList errors; + + raise(); + if(o == m_pDiffTextWindow1) + errors = m_sd1.setData(text); + else if(o == m_pDiffTextWindow2) + errors = m_sd2.setData(text); + else if(o == m_pDiffTextWindow3) + errors = m_sd3.setData(text); + foreach(const QString& error, errors) + { + KMessageBox::error(m_pOptionDialog, error); + } + mainInit(); + } + } - return true; - } - return QSplitter::eventFilter( o, e ); // standard event processing + return true; + } + return QSplitter::eventFilter(o, e); // standard event processing } - - - void KDiff3App::slotFileOpen() { - if ( !canContinue() ) return; - - if ( m_pDirectoryMergeWindow->isDirectoryMergeInProgress() ) - { - int result = KMessageBox::warningYesNo(this, - i18n("You are currently doing a directory merge. Are you sure, you want to abort?"), - i18n("Warning"), - KGuiItem( i18n("Abort") ), - KGuiItem( i18n("Continue Merging") ) ); - if ( result!=KMessageBox::Yes ) - return; - } - - - slotStatusMsg(i18n("Opening files...")); - - for(;;) - { - OpenDialog d(this, - QDir::toNativeSeparators( m_bDirCompare ? m_pDirectoryMergeWindow->getDirNameA() : m_sd1.isFromBuffer() ? QString("") : m_sd1.getAliasName() ), - QDir::toNativeSeparators( m_bDirCompare ? m_pDirectoryMergeWindow->getDirNameB() : m_sd2.isFromBuffer() ? QString("") : m_sd2.getAliasName() ), - QDir::toNativeSeparators( m_bDirCompare ? m_pDirectoryMergeWindow->getDirNameC() : m_sd3.isFromBuffer() ? QString("") : m_sd3.getAliasName() ), - m_bDirCompare ? ! m_pDirectoryMergeWindow->getDirNameDest().isEmpty() : !m_outputFilename.isEmpty(), - QDir::toNativeSeparators( m_bDirCompare ? m_pDirectoryMergeWindow->getDirNameDest() : m_bDefaultFilename ? QString("") : m_outputFilename ), - SLOT(slotConfigure()), &m_pOptionDialog->m_options ); - int status = d.exec(); - if ( status == QDialog::Accepted ) - { - m_sd1.setFilename( d.m_pLineA->currentText() ); - m_sd2.setFilename( d.m_pLineB->currentText() ); - m_sd3.setFilename( d.m_pLineC->currentText() ); - - if( d.m_pMerge->isChecked() ) - { - if ( d.m_pLineOut->currentText().isEmpty() ) + 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"), + KGuiItem(i18n("Abort")), + KGuiItem(i18n("Continue Merging"))); + if(result != KMessageBox::Yes) + return; + } + + slotStatusMsg(i18n("Opening files...")); + + for(;;) + { + OpenDialog d(this, + QDir::toNativeSeparators(m_bDirCompare ? m_pDirectoryMergeWindow->getDirNameA() : m_sd1.isFromBuffer() ? QString("") : m_sd1.getAliasName()), + QDir::toNativeSeparators(m_bDirCompare ? m_pDirectoryMergeWindow->getDirNameB() : m_sd2.isFromBuffer() ? QString("") : m_sd2.getAliasName()), + QDir::toNativeSeparators(m_bDirCompare ? m_pDirectoryMergeWindow->getDirNameC() : m_sd3.isFromBuffer() ? QString("") : m_sd3.getAliasName()), + m_bDirCompare ? !m_pDirectoryMergeWindow->getDirNameDest().isEmpty() : !m_outputFilename.isEmpty(), + QDir::toNativeSeparators(m_bDirCompare ? m_pDirectoryMergeWindow->getDirNameDest() : m_bDefaultFilename ? QString("") : m_outputFilename), + SLOT(slotConfigure()), &m_pOptionDialog->m_options); + int status = d.exec(); + if(status == QDialog::Accepted) + { + m_sd1.setFilename(d.m_pLineA->currentText()); + m_sd2.setFilename(d.m_pLineB->currentText()); + m_sd3.setFilename(d.m_pLineC->currentText()); + + if(d.m_pMerge->isChecked()) { - m_outputFilename = "unnamed.txt"; - m_bDefaultFilename = true; + if(d.m_pLineOut->currentText().isEmpty()) + { + m_outputFilename = "unnamed.txt"; + m_bDefaultFilename = true; + } + else + { + m_outputFilename = d.m_pLineOut->currentText(); + m_bDefaultFilename = false; + } } else - { - m_outputFilename = d.m_pLineOut->currentText(); - m_bDefaultFilename = false; - } - } - else - m_outputFilename = ""; + m_outputFilename = ""; - bool bSuccess = improveFilenames(false); - if ( !bSuccess ) - continue; + bool bSuccess = improveFilenames(false); + if(!bSuccess) + continue; - if ( m_bDirCompare ) - { - m_pDirectoryMergeSplitter->show(); - if ( m_pMainWidget!=0 ) + if(m_bDirCompare) { - m_pMainWidget->hide(); + m_pDirectoryMergeSplitter->show(); + if(m_pMainWidget != 0) + { + m_pMainWidget->hide(); + } + break; } - break; - } - else - { - m_pDirectoryMergeSplitter->hide(); - mainInit(); - - if ( (! m_sd1.isEmpty() && !m_sd1.hasData()) || - (! m_sd2.isEmpty() && !m_sd2.hasData()) || - (! m_sd3.isEmpty() && !m_sd3.hasData()) ) + else { - QString text( i18n("Opening of these files failed:") ); - text += "\n\n"; - if ( ! m_sd1.isEmpty() && !m_sd1.hasData() ) - text += " - " + m_sd1.getAliasName() + "\n"; - if ( ! m_sd2.isEmpty() && !m_sd2.hasData() ) - text += " - " + m_sd2.getAliasName() + "\n"; - if ( ! m_sd3.isEmpty() && !m_sd3.hasData() ) - text += " - " + m_sd3.getAliasName() + "\n"; - - KMessageBox::sorry( this, text, i18n("File open error") ); - continue; + m_pDirectoryMergeSplitter->hide(); + mainInit(); + + if((!m_sd1.isEmpty() && !m_sd1.hasData()) || + (!m_sd2.isEmpty() && !m_sd2.hasData()) || + (!m_sd3.isEmpty() && !m_sd3.hasData())) + { + QString text(i18n("Opening of these files failed:")); + text += "\n\n"; + if(!m_sd1.isEmpty() && !m_sd1.hasData()) + text += " - " + m_sd1.getAliasName() + "\n"; + if(!m_sd2.isEmpty() && !m_sd2.hasData()) + text += " - " + m_sd2.getAliasName() + "\n"; + if(!m_sd3.isEmpty() && !m_sd3.hasData()) + text += " - " + m_sd3.getAliasName() + "\n"; + + KMessageBox::sorry(this, text, i18n("File open error")); + continue; + } } - } - } - break; - } + } + break; + } - slotUpdateAvailabilities(); - slotStatusMsg(i18n("Ready.")); + slotUpdateAvailabilities(); + slotStatusMsg(i18n("Ready.")); } void KDiff3App::slotFileOpen2(QString fn1, QString fn2, QString fn3, QString ofn, - QString an1, QString an2, QString an3, TotalDiffStatus* pTotalDiffStatus ) -{ - if ( !canContinue() ) return; - - if(fn1=="" && fn2=="" && fn3=="" && ofn=="" && m_pMainWidget!=0 ) - { - m_pMainWidget->hide(); - return; - } - - slotStatusMsg(i18n("Opening files...")); - - m_sd1.setFilename( fn1 ); - m_sd2.setFilename( fn2 ); - m_sd3.setFilename( fn3 ); - - m_sd1.setAliasName( an1 ); - m_sd2.setAliasName( an2 ); - m_sd3.setAliasName( an3 ); - - if ( ! ofn.isEmpty() ) - { - m_outputFilename = ofn; - m_bDefaultFilename = false; - } - else - { - m_outputFilename = ""; - m_bDefaultFilename = true; - } - - bool bDirCompare = m_bDirCompare; - improveFilenames(true); // Create new window for KDiff3 for directory comparison. - - if( m_bDirCompare ) - { - } - else - { - m_bDirCompare = bDirCompare; // Don't allow this to change here. - mainInit( pTotalDiffStatus ); - - if ( pTotalDiffStatus!=0 ) - return; - - if ( (! m_sd1.isEmpty() && ! m_sd1.hasData()) || - (! m_sd2.isEmpty() && ! m_sd2.hasData()) || - (! m_sd3.isEmpty() && ! m_sd3.hasData()) ) - { - QString text( i18n("Opening of these files failed:") ); - text += "\n\n"; - if ( ! m_sd1.isEmpty() && !m_sd1.hasData() ) - text += " - " + m_sd1.getAliasName() + "\n"; - if ( ! m_sd2.isEmpty() && !m_sd2.hasData() ) - text += " - " + m_sd2.getAliasName() + "\n"; - if ( ! m_sd3.isEmpty() && !m_sd3.hasData() ) - text += " - " + m_sd3.getAliasName() + "\n"; - - KMessageBox::sorry( this, text, i18n("File open error") ); - } - else - { - if ( m_pDirectoryMergeWindow!=0 && m_pDirectoryMergeWindow->isVisible() && ! dirShowBoth->isChecked() ) - { - slotDirViewToggle(); - } - } - } - slotStatusMsg(i18n("Ready.")); + QString an1, QString an2, QString an3, TotalDiffStatus* pTotalDiffStatus) +{ + if(!canContinue()) return; + + if(fn1 == "" && fn2 == "" && fn3 == "" && ofn == "" && m_pMainWidget != 0) + { + m_pMainWidget->hide(); + return; + } + + slotStatusMsg(i18n("Opening files...")); + + m_sd1.setFilename(fn1); + m_sd2.setFilename(fn2); + m_sd3.setFilename(fn3); + + m_sd1.setAliasName(an1); + m_sd2.setAliasName(an2); + m_sd3.setAliasName(an3); + + if(!ofn.isEmpty()) + { + m_outputFilename = ofn; + m_bDefaultFilename = false; + } + else + { + m_outputFilename = ""; + m_bDefaultFilename = true; + } + + bool bDirCompare = m_bDirCompare; + improveFilenames(true); // Create new window for KDiff3 for directory comparison. + + if(m_bDirCompare) + { + } + else + { + m_bDirCompare = bDirCompare; // Don't allow this to change here. + mainInit(pTotalDiffStatus); + + if(pTotalDiffStatus != 0) + return; + + if((!m_sd1.isEmpty() && !m_sd1.hasData()) || + (!m_sd2.isEmpty() && !m_sd2.hasData()) || + (!m_sd3.isEmpty() && !m_sd3.hasData())) + { + QString text(i18n("Opening of these files failed:")); + text += "\n\n"; + if(!m_sd1.isEmpty() && !m_sd1.hasData()) + text += " - " + m_sd1.getAliasName() + "\n"; + if(!m_sd2.isEmpty() && !m_sd2.hasData()) + text += " - " + m_sd2.getAliasName() + "\n"; + if(!m_sd3.isEmpty() && !m_sd3.hasData()) + text += " - " + m_sd3.getAliasName() + "\n"; + + KMessageBox::sorry(this, text, i18n("File open error")); + } + else + { + if(m_pDirectoryMergeWindow != 0 && m_pDirectoryMergeWindow->isVisible() && !dirShowBoth->isChecked()) + { + slotDirViewToggle(); + } + } + } + slotStatusMsg(i18n("Ready.")); } - void KDiff3App::slotFileNameChanged(const QString& fileName, int winIdx) { - QString fn1 = m_sd1.getFilename(); - QString an1 = m_sd1.getAliasName(); - QString fn2 = m_sd2.getFilename(); - QString an2 = m_sd2.getAliasName(); - QString fn3 = m_sd3.getFilename(); - QString an3 = m_sd3.getAliasName(); - if (winIdx==1) { fn1 = fileName; an1 = ""; } - if (winIdx==2) { fn2 = fileName; an2 = ""; } - if (winIdx==3) { fn3 = fileName; an3 = ""; } - - slotFileOpen2( fn1, fn2, fn3, m_outputFilename, an1, an2, an3, 0 ); + QString fn1 = m_sd1.getFilename(); + QString an1 = m_sd1.getAliasName(); + QString fn2 = m_sd2.getFilename(); + QString an2 = m_sd2.getAliasName(); + QString fn3 = m_sd3.getFilename(); + QString an3 = m_sd3.getAliasName(); + if(winIdx == 1) { + fn1 = fileName; + an1 = ""; + } + if(winIdx == 2) { + fn2 = fileName; + an2 = ""; + } + if(winIdx == 3) { + fn3 = fileName; + an3 = ""; + } + + slotFileOpen2(fn1, fn2, fn3, m_outputFilename, an1, an2, an3, 0); } - void KDiff3App::slotEditCut() { - slotStatusMsg(i18n("Cutting selection...")); + slotStatusMsg(i18n("Cutting selection...")); - QString s; - if ( m_pMergeResultWindow!=0 ) - { - s = m_pMergeResultWindow->getSelection(); - m_pMergeResultWindow->deleteSelection(); + QString s; + if(m_pMergeResultWindow != 0) + { + s = m_pMergeResultWindow->getSelection(); + m_pMergeResultWindow->deleteSelection(); - m_pMergeResultWindow->update(); - } + m_pMergeResultWindow->update(); + } - if ( !s.isEmpty() ) - { - QApplication::clipboard()->setText( s, QClipboard::Clipboard ); - } + if(!s.isEmpty()) + { + QApplication::clipboard()->setText(s, QClipboard::Clipboard); + } - slotStatusMsg(i18n("Ready.")); + slotStatusMsg(i18n("Ready.")); } void KDiff3App::slotEditCopy() { - slotStatusMsg(i18n("Copying selection to clipboard...")); - QString s; - if ( m_pDiffTextWindow1!=0 ) s = m_pDiffTextWindow1->getSelection(); - if ( s.isEmpty() && m_pDiffTextWindow2!=0 ) s = m_pDiffTextWindow2->getSelection(); - if ( s.isEmpty() && m_pDiffTextWindow3!=0 ) s = m_pDiffTextWindow3->getSelection(); - if ( s.isEmpty() && m_pMergeResultWindow!=0 ) s = m_pMergeResultWindow->getSelection(); - if ( !s.isEmpty() ) - { - QApplication::clipboard()->setText( s, QClipboard::Clipboard ); - } + slotStatusMsg(i18n("Copying selection to clipboard...")); + QString s; + if(m_pDiffTextWindow1 != 0) s = m_pDiffTextWindow1->getSelection(); + if(s.isEmpty() && m_pDiffTextWindow2 != 0) s = m_pDiffTextWindow2->getSelection(); + if(s.isEmpty() && m_pDiffTextWindow3 != 0) s = m_pDiffTextWindow3->getSelection(); + if(s.isEmpty() && m_pMergeResultWindow != 0) s = m_pMergeResultWindow->getSelection(); + if(!s.isEmpty()) + { + QApplication::clipboard()->setText(s, QClipboard::Clipboard); + } - slotStatusMsg(i18n("Ready.")); + slotStatusMsg(i18n("Ready.")); } void KDiff3App::slotEditPaste() { - slotStatusMsg(i18n("Inserting clipboard contents...")); - - if ( m_pMergeResultWindow!=0 && m_pMergeResultWindow->isVisible() ) - { - m_pMergeResultWindow->pasteClipboard(false); - } - else if ( canContinue() ) - { - QStringList errors; - bool do_init = false; - - if ( m_pDiffTextWindow1->hasFocus() ) - { - errors = m_sd1.setData( QApplication::clipboard()->text(QClipboard::Clipboard) ); - do_init = true; - } - else if ( m_pDiffTextWindow2->hasFocus() ) - { - errors = m_sd2.setData( QApplication::clipboard()->text(QClipboard::Clipboard) ); - do_init = true; - } - else if ( m_pDiffTextWindow3->hasFocus() ) - { - errors = m_sd3.setData( QApplication::clipboard()->text(QClipboard::Clipboard) ); - do_init = true; - } - - foreach(const QString &error, errors) - { - KMessageBox::error( m_pOptionDialog, error ); - } - - if(do_init) - { - mainInit(); - } - } + slotStatusMsg(i18n("Inserting clipboard contents...")); + + if(m_pMergeResultWindow != 0 && m_pMergeResultWindow->isVisible()) + { + m_pMergeResultWindow->pasteClipboard(false); + } + else if(canContinue()) + { + QStringList errors; + bool do_init = false; + + if(m_pDiffTextWindow1->hasFocus()) + { + errors = m_sd1.setData(QApplication::clipboard()->text(QClipboard::Clipboard)); + do_init = true; + } + else if(m_pDiffTextWindow2->hasFocus()) + { + errors = m_sd2.setData(QApplication::clipboard()->text(QClipboard::Clipboard)); + do_init = true; + } + else if(m_pDiffTextWindow3->hasFocus()) + { + errors = m_sd3.setData(QApplication::clipboard()->text(QClipboard::Clipboard)); + do_init = true; + } + + foreach(const QString& error, errors) + { + KMessageBox::error(m_pOptionDialog, error); + } + + if(do_init) + { + mainInit(); + } + } - slotStatusMsg(i18n("Ready.")); + slotStatusMsg(i18n("Ready.")); } void KDiff3App::slotEditSelectAll() { - int l=0,p=0; // needed as dummy return values - if ( m_pMergeResultWindow && m_pMergeResultWindow->hasFocus() ) { m_pMergeResultWindow->setSelection( 0,0,m_pMergeResultWindow->getNofLines(),0); } - else if ( m_pDiffTextWindow1 && m_pDiffTextWindow1->hasFocus() ) { m_pDiffTextWindow1 ->setSelection( 0,0,m_pDiffTextWindow1->getNofLines(),0,l,p); } - else if ( m_pDiffTextWindow2 && m_pDiffTextWindow2->hasFocus() ) { m_pDiffTextWindow2 ->setSelection( 0,0,m_pDiffTextWindow2->getNofLines(),0,l,p); } - else if ( m_pDiffTextWindow3 && m_pDiffTextWindow3->hasFocus() ) { m_pDiffTextWindow3 ->setSelection( 0,0,m_pDiffTextWindow3->getNofLines(),0,l,p); } - - slotStatusMsg(i18n("Ready.")); + int l = 0, p = 0; // needed as dummy return values + if(m_pMergeResultWindow && m_pMergeResultWindow->hasFocus()) { + m_pMergeResultWindow->setSelection(0, 0, m_pMergeResultWindow->getNofLines(), 0); + } + else if(m_pDiffTextWindow1 && m_pDiffTextWindow1->hasFocus()) + { + m_pDiffTextWindow1->setSelection(0, 0, m_pDiffTextWindow1->getNofLines(), 0, l, p); + } + else if(m_pDiffTextWindow2 && m_pDiffTextWindow2->hasFocus()) + { + m_pDiffTextWindow2->setSelection(0, 0, m_pDiffTextWindow2->getNofLines(), 0, l, p); + } + else if(m_pDiffTextWindow3 && m_pDiffTextWindow3->hasFocus()) + { + m_pDiffTextWindow3->setSelection(0, 0, m_pDiffTextWindow3->getNofLines(), 0, l, p); + } + + slotStatusMsg(i18n("Ready.")); } void KDiff3App::slotGoCurrent() { - if (m_pMergeResultWindow) m_pMergeResultWindow->slotGoCurrent(); + if(m_pMergeResultWindow) m_pMergeResultWindow->slotGoCurrent(); } void KDiff3App::slotGoTop() { - if (m_pMergeResultWindow) m_pMergeResultWindow->slotGoTop(); + if(m_pMergeResultWindow) m_pMergeResultWindow->slotGoTop(); } void KDiff3App::slotGoBottom() { - if (m_pMergeResultWindow) m_pMergeResultWindow->slotGoBottom(); + if(m_pMergeResultWindow) m_pMergeResultWindow->slotGoBottom(); } void KDiff3App::slotGoPrevUnsolvedConflict() { - if (m_pMergeResultWindow) m_pMergeResultWindow->slotGoPrevUnsolvedConflict(); + if(m_pMergeResultWindow) m_pMergeResultWindow->slotGoPrevUnsolvedConflict(); } void KDiff3App::slotGoNextUnsolvedConflict() { - m_bTimerBlock = false; - if (m_pMergeResultWindow) m_pMergeResultWindow->slotGoNextUnsolvedConflict(); + m_bTimerBlock = false; + if(m_pMergeResultWindow) m_pMergeResultWindow->slotGoNextUnsolvedConflict(); } void KDiff3App::slotGoPrevConflict() { - if (m_pMergeResultWindow) m_pMergeResultWindow->slotGoPrevConflict(); + if(m_pMergeResultWindow) m_pMergeResultWindow->slotGoPrevConflict(); } void KDiff3App::slotGoNextConflict() { - m_bTimerBlock = false; - if (m_pMergeResultWindow) m_pMergeResultWindow->slotGoNextConflict(); + m_bTimerBlock = false; + if(m_pMergeResultWindow) m_pMergeResultWindow->slotGoNextConflict(); } void KDiff3App::slotGoPrevDelta() { - if (m_pMergeResultWindow) m_pMergeResultWindow->slotGoPrevDelta(); + if(m_pMergeResultWindow) m_pMergeResultWindow->slotGoPrevDelta(); } void KDiff3App::slotGoNextDelta() { - if (m_pMergeResultWindow) m_pMergeResultWindow->slotGoNextDelta(); -} - -void KDiff3App::choose( int choice ) -{ - if (!m_bTimerBlock ) - { - if ( m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->hasFocus() ) - { - if (choice==A) m_pDirectoryMergeWindow->slotCurrentChooseA(); - if (choice==B) m_pDirectoryMergeWindow->slotCurrentChooseB(); - if (choice==C) m_pDirectoryMergeWindow->slotCurrentChooseC(); - - chooseA->setChecked(false); - chooseB->setChecked(false); - chooseC->setChecked(false); - } - else if ( m_pMergeResultWindow ) - { - m_pMergeResultWindow->choose( choice ); - if ( autoAdvance->isChecked() ) - { - m_bTimerBlock = true; - QTimer::singleShot( m_pOptions->m_autoAdvanceDelay, this, SLOT( slotGoNextUnsolvedConflict() ) ); - } - } - } -} - -void KDiff3App::slotChooseA() { choose( A ); } -void KDiff3App::slotChooseB() { choose( B ); } -void KDiff3App::slotChooseC() { choose( C ); } + if(m_pMergeResultWindow) m_pMergeResultWindow->slotGoNextDelta(); +} -// bConflictsOnly automatically choose for conflicts only (true) or for everywhere -static void mergeChooseGlobal( MergeResultWindow* pMRW, int selector, bool bConflictsOnly, bool bWhiteSpaceOnly ) +void KDiff3App::choose(int choice) { - if ( pMRW ) - { - pMRW->chooseGlobal(selector, bConflictsOnly, bWhiteSpaceOnly ); - } + if(!m_bTimerBlock) + { + if(m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->hasFocus()) + { + if(choice == A) m_pDirectoryMergeWindow->slotCurrentChooseA(); + if(choice == B) m_pDirectoryMergeWindow->slotCurrentChooseB(); + if(choice == C) m_pDirectoryMergeWindow->slotCurrentChooseC(); + + chooseA->setChecked(false); + chooseB->setChecked(false); + chooseC->setChecked(false); + } + else if(m_pMergeResultWindow) + { + m_pMergeResultWindow->choose(choice); + if(autoAdvance->isChecked()) + { + m_bTimerBlock = true; + QTimer::singleShot(m_pOptions->m_autoAdvanceDelay, this, SLOT(slotGoNextUnsolvedConflict())); + } + } + } } -void KDiff3App::slotChooseAEverywhere() { mergeChooseGlobal( m_pMergeResultWindow, A, false, false ); } -void KDiff3App::slotChooseBEverywhere() { mergeChooseGlobal( m_pMergeResultWindow, B, false, false ); } -void KDiff3App::slotChooseCEverywhere() { mergeChooseGlobal( m_pMergeResultWindow, C, false, false ); } -void KDiff3App::slotChooseAForUnsolvedConflicts() { mergeChooseGlobal( m_pMergeResultWindow, A, true, false ); } -void KDiff3App::slotChooseBForUnsolvedConflicts() { mergeChooseGlobal( m_pMergeResultWindow, B, true, false ); } -void KDiff3App::slotChooseCForUnsolvedConflicts() { mergeChooseGlobal( m_pMergeResultWindow, C, true, false ); } -void KDiff3App::slotChooseAForUnsolvedWhiteSpaceConflicts() { mergeChooseGlobal( m_pMergeResultWindow, A, true, true ); } -void KDiff3App::slotChooseBForUnsolvedWhiteSpaceConflicts() { mergeChooseGlobal( m_pMergeResultWindow, B, true, true ); } -void KDiff3App::slotChooseCForUnsolvedWhiteSpaceConflicts() { mergeChooseGlobal( m_pMergeResultWindow, C, true, true ); } +void KDiff3App::slotChooseA() { choose(A); } +void KDiff3App::slotChooseB() { choose(B); } +void KDiff3App::slotChooseC() { choose(C); } + +// bConflictsOnly automatically choose for conflicts only (true) or for everywhere +static void mergeChooseGlobal(MergeResultWindow* pMRW, int selector, bool bConflictsOnly, bool bWhiteSpaceOnly) +{ + if(pMRW) + { + pMRW->chooseGlobal(selector, bConflictsOnly, bWhiteSpaceOnly); + } +} +void KDiff3App::slotChooseAEverywhere() { mergeChooseGlobal(m_pMergeResultWindow, A, false, false); } +void KDiff3App::slotChooseBEverywhere() { mergeChooseGlobal(m_pMergeResultWindow, B, false, false); } +void KDiff3App::slotChooseCEverywhere() { mergeChooseGlobal(m_pMergeResultWindow, C, false, false); } +void KDiff3App::slotChooseAForUnsolvedConflicts() { mergeChooseGlobal(m_pMergeResultWindow, A, true, false); } +void KDiff3App::slotChooseBForUnsolvedConflicts() { mergeChooseGlobal(m_pMergeResultWindow, B, true, false); } +void KDiff3App::slotChooseCForUnsolvedConflicts() { mergeChooseGlobal(m_pMergeResultWindow, C, true, false); } +void KDiff3App::slotChooseAForUnsolvedWhiteSpaceConflicts() { mergeChooseGlobal(m_pMergeResultWindow, A, true, true); } +void KDiff3App::slotChooseBForUnsolvedWhiteSpaceConflicts() { mergeChooseGlobal(m_pMergeResultWindow, B, true, true); } +void KDiff3App::slotChooseCForUnsolvedWhiteSpaceConflicts() { mergeChooseGlobal(m_pMergeResultWindow, C, true, true); } void KDiff3App::slotAutoSolve() { - if (m_pMergeResultWindow ) - { - m_pMergeResultWindow->slotAutoSolve(); - // m_pMergeWindowFrame->show(); incompatible with bPreserveCarriageReturn - m_pMergeResultWindow->showNrOfConflicts(); - slotUpdateAvailabilities(); - } + if(m_pMergeResultWindow) + { + m_pMergeResultWindow->slotAutoSolve(); + // m_pMergeWindowFrame->show(); incompatible with bPreserveCarriageReturn + m_pMergeResultWindow->showNrOfConflicts(); + slotUpdateAvailabilities(); + } } void KDiff3App::slotUnsolve() { - if (m_pMergeResultWindow ) - { - m_pMergeResultWindow->slotUnsolve(); - } + if(m_pMergeResultWindow) + { + m_pMergeResultWindow->slotUnsolve(); + } } void KDiff3App::slotMergeHistory() { - if (m_pMergeResultWindow ) - { - m_pMergeResultWindow->slotMergeHistory(); - } + if(m_pMergeResultWindow) + { + m_pMergeResultWindow->slotMergeHistory(); + } } void KDiff3App::slotRegExpAutoMerge() { - if (m_pMergeResultWindow ) - { - m_pMergeResultWindow->slotRegExpAutoMerge(); - } + if(m_pMergeResultWindow) + { + m_pMergeResultWindow->slotRegExpAutoMerge(); + } } void KDiff3App::slotSplitDiff() { - int firstLine = -1; - int lastLine = -1; - DiffTextWindow* pDTW=0; - if ( m_pDiffTextWindow1 ) { pDTW=m_pDiffTextWindow1; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); } - if ( firstLine<0 && m_pDiffTextWindow2 ) { pDTW=m_pDiffTextWindow2; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); } - if ( firstLine<0 && m_pDiffTextWindow3 ) { pDTW=m_pDiffTextWindow3; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); } - if ( pDTW && firstLine>=0 && m_pMergeResultWindow) - { - pDTW->resetSelection(); - - m_pMergeResultWindow->slotSplitDiff( firstLine, lastLine ); - } + int firstLine = -1; + int lastLine = -1; + DiffTextWindow* pDTW = 0; + if(m_pDiffTextWindow1) { + pDTW = m_pDiffTextWindow1; + pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); + } + if(firstLine < 0 && m_pDiffTextWindow2) { + pDTW = m_pDiffTextWindow2; + pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); + } + if(firstLine < 0 && m_pDiffTextWindow3) { + pDTW = m_pDiffTextWindow3; + pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); + } + if(pDTW && firstLine >= 0 && m_pMergeResultWindow) + { + pDTW->resetSelection(); + + m_pMergeResultWindow->slotSplitDiff(firstLine, lastLine); + } } void KDiff3App::slotJoinDiffs() { - int firstLine = -1; - int lastLine = -1; - DiffTextWindow* pDTW=0; - if ( m_pDiffTextWindow1 ) { pDTW=m_pDiffTextWindow1; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); } - if ( firstLine<0 && m_pDiffTextWindow2 ) { pDTW=m_pDiffTextWindow2; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); } - if ( firstLine<0 && m_pDiffTextWindow3 ) { pDTW=m_pDiffTextWindow3; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); } - if ( pDTW && firstLine>=0 && m_pMergeResultWindow) - { - pDTW->resetSelection(); - - m_pMergeResultWindow->slotJoinDiffs( firstLine, lastLine ); - } + int firstLine = -1; + int lastLine = -1; + DiffTextWindow* pDTW = 0; + if(m_pDiffTextWindow1) { + pDTW = m_pDiffTextWindow1; + pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); + } + if(firstLine < 0 && m_pDiffTextWindow2) { + pDTW = m_pDiffTextWindow2; + pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); + } + if(firstLine < 0 && m_pDiffTextWindow3) { + pDTW = m_pDiffTextWindow3; + pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); + } + if(pDTW && firstLine >= 0 && m_pMergeResultWindow) + { + pDTW->resetSelection(); + + m_pMergeResultWindow->slotJoinDiffs(firstLine, lastLine); + } } void KDiff3App::slotConfigure() { - m_pOptionDialog->setState(); - m_pOptionDialog->setMinimumHeight(m_pOptionDialog->minimumHeight() + 40); - m_pOptionDialog->exec(); - slotRefresh(); + m_pOptionDialog->setState(); + m_pOptionDialog->setMinimumHeight(m_pOptionDialog->minimumHeight() + 40); + m_pOptionDialog->exec(); + slotRefresh(); } void KDiff3App::slotConfigureKeys() { KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, this); } void KDiff3App::slotRefresh() { - QApplication::setFont( m_pOptions->m_appFont ); - if (m_pDiffTextWindow1!=0) - { - m_pDiffTextWindow1->setFont(m_pOptions->m_font); - m_pDiffTextWindow1->update(); - } - if (m_pDiffTextWindow2!=0) - { - m_pDiffTextWindow2->setFont(m_pOptions->m_font); - m_pDiffTextWindow2->update(); - } - if (m_pDiffTextWindow3!=0) - { - m_pDiffTextWindow3->setFont(m_pOptions->m_font); - m_pDiffTextWindow3->update(); - } - if (m_pMergeResultWindow!=0) - { - m_pMergeResultWindow->setFont(m_pOptions->m_font); - m_pMergeResultWindow->update(); - } - if (m_pHScrollBar!=0) - { - m_pHScrollBar->setAgain(); - } - if ( m_pDiffWindowSplitter!=0 ) - { - m_pDiffWindowSplitter->setOrientation( m_pOptions->m_bHorizDiffWindowSplitting ? Qt::Horizontal : Qt::Vertical ); - } - if ( m_pDirectoryMergeWindow ) - { - m_pDirectoryMergeWindow->updateFileVisibilities(); - } + QApplication::setFont(m_pOptions->m_appFont); + if(m_pDiffTextWindow1 != 0) + { + m_pDiffTextWindow1->setFont(m_pOptions->m_font); + m_pDiffTextWindow1->update(); + } + if(m_pDiffTextWindow2 != 0) + { + m_pDiffTextWindow2->setFont(m_pOptions->m_font); + m_pDiffTextWindow2->update(); + } + if(m_pDiffTextWindow3 != 0) + { + m_pDiffTextWindow3->setFont(m_pOptions->m_font); + m_pDiffTextWindow3->update(); + } + if(m_pMergeResultWindow != 0) + { + m_pMergeResultWindow->setFont(m_pOptions->m_font); + m_pMergeResultWindow->update(); + } + if(m_pHScrollBar != 0) + { + m_pHScrollBar->setAgain(); + } + if(m_pDiffWindowSplitter != 0) + { + m_pDiffWindowSplitter->setOrientation(m_pOptions->m_bHorizDiffWindowSplitting ? Qt::Horizontal : Qt::Vertical); + } + if(m_pDirectoryMergeWindow) + { + m_pDirectoryMergeWindow->updateFileVisibilities(); + } } void KDiff3App::slotSelectionStart() { - //editCopy->setEnabled( false ); - //editCut->setEnabled( false ); + //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(); + 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_pOptions->m_bAutoCopySelection ) - { - slotEditCopy(); - } - else - { - QClipboard *clipBoard = QApplication::clipboard(); - - if (clipBoard->supportsSelection ()) - { - QString s; - if ( m_pDiffTextWindow1!=0 ) s = m_pDiffTextWindow1->getSelection(); - if ( s.isEmpty() && m_pDiffTextWindow2!=0 ) s = m_pDiffTextWindow2->getSelection(); - if ( s.isEmpty() && m_pDiffTextWindow3!=0 ) s = m_pDiffTextWindow3->getSelection(); - if ( s.isEmpty() && m_pMergeResultWindow!=0 ) s = m_pMergeResultWindow->getSelection(); - if ( !s.isEmpty() ) - { - clipBoard->setText( s, QClipboard::Selection ); - } - } - } + //const QObject* s = sender(); + //editCopy->setEnabled(true); + //editCut->setEnabled( s==m_pMergeResultWindow ); + if(m_pOptions->m_bAutoCopySelection) + { + slotEditCopy(); + } + else + { + QClipboard* clipBoard = QApplication::clipboard(); + + if(clipBoard->supportsSelection()) + { + QString s; + if(m_pDiffTextWindow1 != 0) s = m_pDiffTextWindow1->getSelection(); + if(s.isEmpty() && m_pDiffTextWindow2 != 0) s = m_pDiffTextWindow2->getSelection(); + if(s.isEmpty() && m_pDiffTextWindow3 != 0) s = m_pDiffTextWindow3->getSelection(); + if(s.isEmpty() && m_pMergeResultWindow != 0) s = m_pMergeResultWindow->getSelection(); + if(!s.isEmpty()) + { + clipBoard->setText(s, QClipboard::Selection); + } + } + } } void KDiff3App::slotClipboardChanged() { - QString s = QApplication::clipboard()->text(); - //editPaste->setEnabled(!s.isEmpty()); + QString s = QApplication::clipboard()->text(); + //editPaste->setEnabled(!s.isEmpty()); } void KDiff3App::slotOutputModified(bool bModified) { - if ( bModified && !m_bOutputModified ) - { - m_bOutputModified=true; - slotUpdateAvailabilities(); - } + if(bModified && !m_bOutputModified) + { + m_bOutputModified = true; + slotUpdateAvailabilities(); + } } void KDiff3App::slotAutoAdvanceToggled() { - m_pOptions->m_bAutoAdvance = autoAdvance->isChecked(); + m_pOptions->m_bAutoAdvance = autoAdvance->isChecked(); } void KDiff3App::slotWordWrapToggled() { - m_pOptions->m_bWordWrap = wordWrap->isChecked(); - postRecalcWordWrap(); + m_pOptions->m_bWordWrap = wordWrap->isChecked(); + postRecalcWordWrap(); } // Enable or disable all widgets except the status bar widget. static void mainWindowEnable(QWidget* pWidget, bool bEnable) { - if (QMainWindow* pWindow = dynamic_cast(pWidget->window())) - { - QWidget* pStatusBarWidget = pWindow->statusBar(); - QList children = pWindow->children(); - for (int i = 0; i < children.count(); ++i) - { - if (children[i]->isWidgetType()) - { - QWidget* pChildWidget = (QWidget*)children[i]; - if (pChildWidget != pStatusBarWidget) + if(QMainWindow* pWindow = dynamic_cast(pWidget->window())) + { + QWidget* pStatusBarWidget = pWindow->statusBar(); + QList children = pWindow->children(); + for(int i = 0; i < children.count(); ++i) + { + if(children[i]->isWidgetType()) { - pChildWidget->setEnabled(bEnable); + QWidget* pChildWidget = (QWidget*)children[i]; + if(pChildWidget != pStatusBarWidget) + { + pChildWidget->setEnabled(bEnable); + } } - } - } - } + } + } } void KDiff3App::postRecalcWordWrap() { - if ( ! m_bRecalcWordWrapPosted ) - { - m_bRecalcWordWrapPosted = true; - mainWindowEnable(window(), false); - m_firstD3LIdx = -1; - QTimer::singleShot( 1 /* ms */, this, SLOT(slotRecalcWordWrap()) ); - } - else - { - g_pProgressDialog->cancel(ProgressDialog::eResize); - } + if(!m_bRecalcWordWrapPosted) + { + m_bRecalcWordWrapPosted = true; + mainWindowEnable(window(), false); + m_firstD3LIdx = -1; + QTimer::singleShot(1 /* ms */, this, SLOT(slotRecalcWordWrap())); + } + else + { + g_pProgressDialog->cancel(ProgressDialog::eResize); + } } void KDiff3App::slotRecalcWordWrap() { - recalcWordWrap(); + recalcWordWrap(); } // visibleTextWidthForPrinting is >=0 only for printing, otherwise the really visible width is used void KDiff3App::recalcWordWrap(int visibleTextWidthForPrinting) { - m_bRecalcWordWrapPosted = true; - mainWindowEnable(window(), false); - - m_visibleTextWidthForPrinting = visibleTextWidthForPrinting; - if (m_firstD3LIdx < 0) - { - m_firstD3LIdx = 0; - if (m_pDiffTextWindow1) - m_firstD3LIdx = m_pDiffTextWindow1->convertLineToDiff3LineIdx(m_pDiffTextWindow1->getFirstLine()); - } - - // Convert selection to D3L-coords (converting back happens in DiffTextWindow::recalcWordWrap() - if ( m_pDiffTextWindow1 ) - m_pDiffTextWindow1->convertSelectionToD3LCoords(); - if ( m_pDiffTextWindow2 ) - m_pDiffTextWindow2->convertSelectionToD3LCoords(); - if ( m_pDiffTextWindow3 ) - m_pDiffTextWindow3->convertSelectionToD3LCoords(); - - g_pProgressDialog->clearCancelState(); // clear cancelled state if previously set - - if (!m_diff3LineList.empty()) - { - if (m_pOptions->m_bWordWrap) - { - Diff3LineList::iterator i; - int sumOfLines = 0; - for (i = m_diff3LineList.begin(); i != m_diff3LineList.end(); ++i) - { - Diff3Line& d3l = *i; - d3l.linesNeededForDisplay = 1; - d3l.sumLinesNeededForDisplay = sumOfLines; - sumOfLines += d3l.linesNeededForDisplay; - } - - // Let every window calc how many lines will be needed. - if (m_pDiffTextWindow1) - { - m_pDiffTextWindow1->recalcWordWrap(true, 0, m_visibleTextWidthForPrinting); - } - if (m_pDiffTextWindow2) - { - m_pDiffTextWindow2->recalcWordWrap(true, 0, m_visibleTextWidthForPrinting); - } - if (m_pDiffTextWindow3) - { - m_pDiffTextWindow3->recalcWordWrap(true, 0, m_visibleTextWidthForPrinting); - } - } - else - { - m_neededLines = m_diff3LineVector.size(); - if (m_pDiffTextWindow1) - m_pDiffTextWindow1->recalcWordWrap(false, 0, 0); - if (m_pDiffTextWindow2) - m_pDiffTextWindow2->recalcWordWrap(false, 0, 0); - if (m_pDiffTextWindow3) - m_pDiffTextWindow3->recalcWordWrap(false, 0, 0); - } - bool bRunnablesStarted = startRunnables(); - if (!bRunnablesStarted) - slotFinishRecalcWordWrap(); - else - { - g_pProgressDialog->setInformation(m_pOptions->m_bWordWrap - ? i18n("Word wrap (Cancel disables word wrap)") : i18n("Calculating max width for horizontal scrollbar"), false); - } - } + m_bRecalcWordWrapPosted = true; + mainWindowEnable(window(), false); + + m_visibleTextWidthForPrinting = visibleTextWidthForPrinting; + if(m_firstD3LIdx < 0) + { + m_firstD3LIdx = 0; + if(m_pDiffTextWindow1) + m_firstD3LIdx = m_pDiffTextWindow1->convertLineToDiff3LineIdx(m_pDiffTextWindow1->getFirstLine()); + } + + // Convert selection to D3L-coords (converting back happens in DiffTextWindow::recalcWordWrap() + if(m_pDiffTextWindow1) + m_pDiffTextWindow1->convertSelectionToD3LCoords(); + if(m_pDiffTextWindow2) + m_pDiffTextWindow2->convertSelectionToD3LCoords(); + if(m_pDiffTextWindow3) + m_pDiffTextWindow3->convertSelectionToD3LCoords(); + + g_pProgressDialog->clearCancelState(); // clear cancelled state if previously set + + if(!m_diff3LineList.empty()) + { + if(m_pOptions->m_bWordWrap) + { + Diff3LineList::iterator i; + int sumOfLines = 0; + for(i = m_diff3LineList.begin(); i != m_diff3LineList.end(); ++i) + { + Diff3Line& d3l = *i; + d3l.linesNeededForDisplay = 1; + d3l.sumLinesNeededForDisplay = sumOfLines; + sumOfLines += d3l.linesNeededForDisplay; + } + + // Let every window calc how many lines will be needed. + if(m_pDiffTextWindow1) + { + m_pDiffTextWindow1->recalcWordWrap(true, 0, m_visibleTextWidthForPrinting); + } + if(m_pDiffTextWindow2) + { + m_pDiffTextWindow2->recalcWordWrap(true, 0, m_visibleTextWidthForPrinting); + } + if(m_pDiffTextWindow3) + { + m_pDiffTextWindow3->recalcWordWrap(true, 0, m_visibleTextWidthForPrinting); + } + } + else + { + m_neededLines = m_diff3LineVector.size(); + if(m_pDiffTextWindow1) + m_pDiffTextWindow1->recalcWordWrap(false, 0, 0); + if(m_pDiffTextWindow2) + m_pDiffTextWindow2->recalcWordWrap(false, 0, 0); + if(m_pDiffTextWindow3) + m_pDiffTextWindow3->recalcWordWrap(false, 0, 0); + } + bool bRunnablesStarted = startRunnables(); + if(!bRunnablesStarted) + slotFinishRecalcWordWrap(); + else + { + g_pProgressDialog->setInformation(m_pOptions->m_bWordWrap + ? i18n("Word wrap (Cancel disables word wrap)") + : i18n("Calculating max width for horizontal scrollbar"), + false); + } + } } void KDiff3App::slotFinishRecalcWordWrap() { - g_pProgressDialog->pop(); - - if ( m_pOptions->m_bWordWrap && g_pProgressDialog->wasCancelled()) - { - if (g_pProgressDialog->cancelReason() == ProgressDialog::eUserAbort) - { - wordWrap->setChecked(false); - m_pOptions->m_bWordWrap = wordWrap->isChecked(); - QTimer::singleShot(1 /* ms */, this, SLOT(slotRecalcWordWrap())); // do it again - } - else // eResize - { - QTimer::singleShot(1 /* ms */, this, SLOT(slotRecalcWordWrap())); // do it again - } - return; - } - else - { - m_bRecalcWordWrapPosted = false; - } - - g_pProgressDialog->setStayHidden(false); - - bool bPrinting = m_visibleTextWidthForPrinting >= 0; - - if (!m_diff3LineList.empty()) - { - if (m_pOptions->m_bWordWrap) - { - Diff3LineList::iterator i; - int sumOfLines = 0; - for (i = m_diff3LineList.begin(); i != m_diff3LineList.end(); ++i) - { - Diff3Line& d3l = *i; - d3l.sumLinesNeededForDisplay = sumOfLines; - sumOfLines += d3l.linesNeededForDisplay; - } - - // Finish the word wrap - if (m_pDiffTextWindow1) - m_pDiffTextWindow1->recalcWordWrap(true, sumOfLines, m_visibleTextWidthForPrinting); - if (m_pDiffTextWindow2) - m_pDiffTextWindow2->recalcWordWrap(true, sumOfLines, m_visibleTextWidthForPrinting); - if (m_pDiffTextWindow3) - m_pDiffTextWindow3->recalcWordWrap(true, sumOfLines, m_visibleTextWidthForPrinting); - - m_neededLines = sumOfLines; - } - else - { - if (m_pDiffTextWindow1) - m_pDiffTextWindow1->recalcWordWrap(false, 1, 0); - if (m_pDiffTextWindow2) - m_pDiffTextWindow2->recalcWordWrap(false, 1, 0); - if (m_pDiffTextWindow3) - m_pDiffTextWindow3->recalcWordWrap(false, 1, 0); - } - slotStatusMsg(QString()); - } - - if (!bPrinting) - { - if (m_pOverview) - m_pOverview->slotRedraw(); - if (m_pDiffVScrollBar) - m_pDiffVScrollBar->setRange(0, max2(0, m_neededLines + 1 - m_DTWHeight)); - if (m_pDiffTextWindow1) - { - m_pDiffVScrollBar->setValue(m_pDiffTextWindow1->convertDiff3LineIdxToLine(m_firstD3LIdx)); - - setHScrollBarRange(); - m_pHScrollBar->setValue(0); - } - } - mainWindowEnable(window(), true); - - if (m_bFinishMainInit) - { - m_bFinishMainInit = false; - slotFinishMainInit(); - } - if (m_pEventLoopForPrinting) - m_pEventLoopForPrinting->quit(); + g_pProgressDialog->pop(); + + if(m_pOptions->m_bWordWrap && g_pProgressDialog->wasCancelled()) + { + if(g_pProgressDialog->cancelReason() == ProgressDialog::eUserAbort) + { + wordWrap->setChecked(false); + m_pOptions->m_bWordWrap = wordWrap->isChecked(); + QTimer::singleShot(1 /* ms */, this, SLOT(slotRecalcWordWrap())); // do it again + } + else // eResize + { + QTimer::singleShot(1 /* ms */, this, SLOT(slotRecalcWordWrap())); // do it again + } + return; + } + else + { + m_bRecalcWordWrapPosted = false; + } + + g_pProgressDialog->setStayHidden(false); + + bool bPrinting = m_visibleTextWidthForPrinting >= 0; + + if(!m_diff3LineList.empty()) + { + if(m_pOptions->m_bWordWrap) + { + Diff3LineList::iterator i; + int sumOfLines = 0; + for(i = m_diff3LineList.begin(); i != m_diff3LineList.end(); ++i) + { + Diff3Line& d3l = *i; + d3l.sumLinesNeededForDisplay = sumOfLines; + sumOfLines += d3l.linesNeededForDisplay; + } + + // Finish the word wrap + if(m_pDiffTextWindow1) + m_pDiffTextWindow1->recalcWordWrap(true, sumOfLines, m_visibleTextWidthForPrinting); + if(m_pDiffTextWindow2) + m_pDiffTextWindow2->recalcWordWrap(true, sumOfLines, m_visibleTextWidthForPrinting); + if(m_pDiffTextWindow3) + m_pDiffTextWindow3->recalcWordWrap(true, sumOfLines, m_visibleTextWidthForPrinting); + + m_neededLines = sumOfLines; + } + else + { + if(m_pDiffTextWindow1) + m_pDiffTextWindow1->recalcWordWrap(false, 1, 0); + if(m_pDiffTextWindow2) + m_pDiffTextWindow2->recalcWordWrap(false, 1, 0); + if(m_pDiffTextWindow3) + m_pDiffTextWindow3->recalcWordWrap(false, 1, 0); + } + slotStatusMsg(QString()); + } + + if(!bPrinting) + { + if(m_pOverview) + m_pOverview->slotRedraw(); + if(m_pDiffVScrollBar) + m_pDiffVScrollBar->setRange(0, max2(0, m_neededLines + 1 - m_DTWHeight)); + if(m_pDiffTextWindow1) + { + m_pDiffVScrollBar->setValue(m_pDiffTextWindow1->convertDiff3LineIdxToLine(m_firstD3LIdx)); + + setHScrollBarRange(); + m_pHScrollBar->setValue(0); + } + } + mainWindowEnable(window(), true); + + if(m_bFinishMainInit) + { + m_bFinishMainInit = false; + slotFinishMainInit(); + } + if(m_pEventLoopForPrinting) + m_pEventLoopForPrinting->quit(); } void KDiff3App::slotShowWhiteSpaceToggled() { - m_pOptions->m_bShowWhiteSpaceCharacters = showWhiteSpaceCharacters->isChecked(); - m_pOptions->m_bShowWhiteSpace = showWhiteSpace->isChecked(); + m_pOptions->m_bShowWhiteSpaceCharacters = showWhiteSpaceCharacters->isChecked(); + m_pOptions->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(); - if ( m_pMergeResultWindow !=0 ) - m_pMergeResultWindow->update(); - if ( m_pOverview!=0 ) - m_pOverview->slotRedraw(); + 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(); + if(m_pOverview != 0) + m_pOverview->slotRedraw(); } void KDiff3App::slotShowLineNumbersToggled() { - m_pOptions->m_bShowLineNumbers = showLineNumbers->isChecked(); - - if ( wordWrap->isChecked() ) - recalcWordWrap(); + m_pOptions->m_bShowLineNumbers = showLineNumbers->isChecked(); - if ( m_pDiffTextWindow1!=0 ) - m_pDiffTextWindow1->update(); - if ( m_pDiffTextWindow2!=0 ) - m_pDiffTextWindow2->update(); + if(wordWrap->isChecked()) + recalcWordWrap(); - if ( m_pDiffTextWindow3!=0 ) - m_pDiffTextWindow3->update(); - } + if(m_pDiffTextWindow1 != 0) + m_pDiffTextWindow1->update(); + if(m_pDiffTextWindow2 != 0) + m_pDiffTextWindow2->update(); + + if(m_pDiffTextWindow3 != 0) + m_pDiffTextWindow3->update(); +} /// Return true for success, else false -bool KDiff3App::improveFilenames( bool bCreateNewInstance ) -{ - m_bDirCompare = false; - - FileAccess f1(m_sd1.getFilename()); - FileAccess f2(m_sd2.getFilename()); - FileAccess f3(m_sd3.getFilename()); - FileAccess f4(m_outputFilename); - - if ( f1.isFile() && f1.exists() ) - { - if ( f2.isDir() ) - { - f2.addPath( f1.fileName() ); - if ( f2.isFile() && f2.exists() ) - m_sd2.setFileAccess( f2 ); - } - if ( f3.isDir() ) - { - f3.addPath( f1.fileName() ); - if ( f3.isFile() && f3.exists() ) - m_sd3.setFileAccess( f3 ); - } - if ( f4.isDir() ) - { - f4.addPath( f1.fileName() ); - if ( f4.isFile() && f4.exists() ) - m_outputFilename = f4.absoluteFilePath(); - } - } - else if ( f1.isDir() ) - { - m_bDirCompare = true; - if (bCreateNewInstance) - { - emit createNewInstance( f1.absoluteFilePath(), f2.absoluteFilePath(), f3.absoluteFilePath() ); - } - else - { - FileAccess destDir; - if (!m_bDefaultFilename) destDir = f4; - m_pDirectoryMergeSplitter->show(); - if (m_pMainWidget!=0) m_pMainWidget->hide(); - setUpdatesEnabled(true); - - bool bSuccess = m_pDirectoryMergeWindow->init( - f1, f2, f3, - destDir, // Destdirname - !m_outputFilename.isEmpty() - ); - - m_bDirCompare = true; // This seems redundant but it might have been reset during full analysis. - - if (bSuccess) - { - m_sd1.reset(); - if (m_pDiffTextWindow1!=0) m_pDiffTextWindow1->init(0,0,eLineEndStyleDos,0,0,0,0,false); - m_sd2.reset(); - if (m_pDiffTextWindow2!=0) m_pDiffTextWindow2->init(0,0,eLineEndStyleDos,0,0,0,0,false); - m_sd3.reset(); - if (m_pDiffTextWindow3!=0) m_pDiffTextWindow3->init(0,0,eLineEndStyleDos,0,0,0,0,false); - } - slotUpdateAvailabilities(); - return bSuccess; - } - } - return true; +bool KDiff3App::improveFilenames(bool bCreateNewInstance) +{ + m_bDirCompare = false; + + FileAccess f1(m_sd1.getFilename()); + FileAccess f2(m_sd2.getFilename()); + FileAccess f3(m_sd3.getFilename()); + FileAccess f4(m_outputFilename); + + if(f1.isFile() && f1.exists()) + { + if(f2.isDir()) + { + f2.addPath(f1.fileName()); + if(f2.isFile() && f2.exists()) + m_sd2.setFileAccess(f2); + } + if(f3.isDir()) + { + f3.addPath(f1.fileName()); + if(f3.isFile() && f3.exists()) + m_sd3.setFileAccess(f3); + } + if(f4.isDir()) + { + f4.addPath(f1.fileName()); + if(f4.isFile() && f4.exists()) + m_outputFilename = f4.absoluteFilePath(); + } + } + else if(f1.isDir()) + { + m_bDirCompare = true; + if(bCreateNewInstance) + { + emit createNewInstance(f1.absoluteFilePath(), f2.absoluteFilePath(), f3.absoluteFilePath()); + } + else + { + FileAccess destDir; + if(!m_bDefaultFilename) destDir = f4; + m_pDirectoryMergeSplitter->show(); + if(m_pMainWidget != 0) m_pMainWidget->hide(); + setUpdatesEnabled(true); + + bool bSuccess = m_pDirectoryMergeWindow->init( + f1, f2, f3, + destDir, // Destdirname + !m_outputFilename.isEmpty()); + + m_bDirCompare = true; // This seems redundant but it might have been reset during full analysis. + + if(bSuccess) + { + m_sd1.reset(); + if(m_pDiffTextWindow1 != 0) m_pDiffTextWindow1->init(0, 0, eLineEndStyleDos, 0, 0, 0, 0, false); + m_sd2.reset(); + if(m_pDiffTextWindow2 != 0) m_pDiffTextWindow2->init(0, 0, eLineEndStyleDos, 0, 0, 0, 0, false); + m_sd3.reset(); + if(m_pDiffTextWindow3 != 0) m_pDiffTextWindow3->init(0, 0, eLineEndStyleDos, 0, 0, 0, 0, false); + } + slotUpdateAvailabilities(); + return bSuccess; + } + } + return true; } void KDiff3App::slotReload() { - if ( !canContinue() ) return; + if(!canContinue()) return; - mainInit(); + mainInit(); } 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"), - KGuiItem( i18n("Save && Continue") ), - KGuiItem( 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") ); + // 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"), + KGuiItem(i18n("Save && Continue")), + KGuiItem(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; + m_bOutputModified = false; + return true; } -void KDiff3App::slotCheckIfCanContinue( bool* pbContinue ) +void KDiff3App::slotCheckIfCanContinue(bool* pbContinue) { - if (pbContinue!=0) *pbContinue = canContinue(); + if(pbContinue != 0) *pbContinue = canContinue(); } - void KDiff3App::slotDirShowBoth() { - if( dirShowBoth->isChecked() ) - { - if ( m_pDirectoryMergeSplitter ) - m_pDirectoryMergeSplitter->setVisible( m_bDirCompare ); + if(dirShowBoth->isChecked()) + { + if(m_pDirectoryMergeSplitter) + m_pDirectoryMergeSplitter->setVisible(m_bDirCompare); - if ( m_pMainWidget!=0 ) - m_pMainWidget->show(); - } - else - { - bool bTextDataAvailable = ( m_sd1.hasData() || m_sd2.hasData() || m_sd3.hasData() ); - if ( m_pMainWidget!=0 && bTextDataAvailable ) - { - m_pMainWidget->show(); - m_pDirectoryMergeSplitter->hide(); - } - else if ( m_bDirCompare ) - { - m_pDirectoryMergeSplitter->show(); - } - } + if(m_pMainWidget != 0) + m_pMainWidget->show(); + } + else + { + bool bTextDataAvailable = (m_sd1.hasData() || m_sd2.hasData() || m_sd3.hasData()); + if(m_pMainWidget != 0 && bTextDataAvailable) + { + m_pMainWidget->show(); + m_pDirectoryMergeSplitter->hide(); + } + else if(m_bDirCompare) + { + m_pDirectoryMergeSplitter->show(); + } + } - slotUpdateAvailabilities(); + 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(); + 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 ) - { - m_pDiffTextWindowFrame1->setVisible( showWindowA->isChecked() ); - slotUpdateAvailabilities(); - } + if(m_pDiffTextWindow1 != 0) + { + m_pDiffTextWindowFrame1->setVisible(showWindowA->isChecked()); + slotUpdateAvailabilities(); + } } void KDiff3App::slotShowWindowBToggled() { - if ( m_pDiffTextWindow2!=0 ) - { - m_pDiffTextWindowFrame2->setVisible( showWindowB->isChecked() ); - slotUpdateAvailabilities(); - } + if(m_pDiffTextWindow2 != 0) + { + m_pDiffTextWindowFrame2->setVisible(showWindowB->isChecked()); + slotUpdateAvailabilities(); + } } void KDiff3App::slotShowWindowCToggled() { - if ( m_pDiffTextWindow3!=0 ) - { - m_pDiffTextWindowFrame3->setVisible( showWindowC->isChecked() ); - slotUpdateAvailabilities(); - } + if(m_pDiffTextWindow3 != 0) + { + m_pDiffTextWindowFrame3->setVisible(showWindowC->isChecked()); + slotUpdateAvailabilities(); + } } void KDiff3App::slotEditFind() { - m_pFindDialog->currentLine = 0; - m_pFindDialog->currentPos = 0; - m_pFindDialog->currentWindow = 1; - - // Use currently selected text: - QString s; - if ( m_pDiffTextWindow1!=0 ) s = m_pDiffTextWindow1->getSelection(); - if ( s.isEmpty() && m_pDiffTextWindow2!=0 ) s = m_pDiffTextWindow2->getSelection(); - if ( s.isEmpty() && m_pDiffTextWindow3!=0 ) s = m_pDiffTextWindow3->getSelection(); - if ( s.isEmpty() && m_pMergeResultWindow!=0 ) s = m_pMergeResultWindow->getSelection(); - if ( !s.isEmpty() && !s.contains('\n') ) - { - m_pFindDialog->m_pSearchString->setText( s ); - } - - if ( QDialog::Accepted == m_pFindDialog->exec() ) - { - slotEditFindNext(); - } + m_pFindDialog->currentLine = 0; + m_pFindDialog->currentPos = 0; + m_pFindDialog->currentWindow = 1; + + // Use currently selected text: + QString s; + if(m_pDiffTextWindow1 != 0) s = m_pDiffTextWindow1->getSelection(); + if(s.isEmpty() && m_pDiffTextWindow2 != 0) s = m_pDiffTextWindow2->getSelection(); + if(s.isEmpty() && m_pDiffTextWindow3 != 0) s = m_pDiffTextWindow3->getSelection(); + if(s.isEmpty() && m_pMergeResultWindow != 0) s = m_pMergeResultWindow->getSelection(); + if(!s.isEmpty() && !s.contains('\n')) + { + m_pFindDialog->m_pSearchString->setText(s); + } + + if(QDialog::Accepted == m_pFindDialog->exec()) + { + slotEditFindNext(); + } } void KDiff3App::slotEditFindNext() { - QString s = m_pFindDialog->m_pSearchString->text(); - if ( s.isEmpty() ) - { - slotEditFind(); - return; - } - - bool bDirDown = true; - bool bCaseSensitive = m_pFindDialog->m_pCaseSensitive->isChecked(); - - int d3vLine = m_pFindDialog->currentLine; - int posInLine = m_pFindDialog->currentPos; - int l=0; - int p=0; - if ( m_pFindDialog->currentWindow == 1 ) - { - if ( m_pFindDialog->m_pSearchInA->isChecked() && m_pDiffTextWindow1!=0 && - m_pDiffTextWindow1->findString( s, d3vLine, posInLine, bDirDown, bCaseSensitive ) ) - { - m_pDiffTextWindow1->setSelection( d3vLine, posInLine, d3vLine, posInLine+s.length(), l, p ); - m_pDiffVScrollBar->setValue(l-m_pDiffVScrollBar->pageStep()/2); - m_pHScrollBar->setValue( max2( 0, p+(int)s.length()-m_pHScrollBar->pageStep()) ); - m_pFindDialog->currentLine = d3vLine; - m_pFindDialog->currentPos = posInLine + 1; - return; - } - m_pFindDialog->currentWindow = 2; - m_pFindDialog->currentLine = 0; - m_pFindDialog->currentPos = 0; - } - - d3vLine = m_pFindDialog->currentLine; - posInLine = m_pFindDialog->currentPos; - if ( m_pFindDialog->currentWindow == 2 ) - { - if ( m_pFindDialog->m_pSearchInB->isChecked() && m_pDiffTextWindow2!=0 && - m_pDiffTextWindow2->findString( s, d3vLine, posInLine, bDirDown, bCaseSensitive ) ) - { - m_pDiffTextWindow2->setSelection( d3vLine, posInLine, d3vLine, posInLine+s.length(),l,p ); - m_pDiffVScrollBar->setValue(l-m_pDiffVScrollBar->pageStep()/2); - m_pHScrollBar->setValue( max2( 0, p+(int)s.length()-m_pHScrollBar->pageStep()) ); - m_pFindDialog->currentLine = d3vLine; - m_pFindDialog->currentPos = posInLine + 1; - return; - } - m_pFindDialog->currentWindow = 3; - m_pFindDialog->currentLine = 0; - m_pFindDialog->currentPos = 0; - } - - d3vLine = m_pFindDialog->currentLine; - posInLine = m_pFindDialog->currentPos; - if ( m_pFindDialog->currentWindow == 3 ) - { - if ( m_pFindDialog->m_pSearchInC->isChecked() && m_pDiffTextWindow3!=0 && - m_pDiffTextWindow3->findString( s, d3vLine, posInLine, bDirDown, bCaseSensitive ) ) - { - m_pDiffTextWindow3->setSelection( d3vLine, posInLine, d3vLine, posInLine+s.length(),l,p ); - m_pDiffVScrollBar->setValue(l-m_pDiffVScrollBar->pageStep()/2); - m_pHScrollBar->setValue( max2( 0, p+(int)s.length()-m_pHScrollBar->pageStep()) ); - m_pFindDialog->currentLine = d3vLine; - m_pFindDialog->currentPos = posInLine + 1; - return; - } - m_pFindDialog->currentWindow = 4; - m_pFindDialog->currentLine = 0; - m_pFindDialog->currentPos = 0; - } - - d3vLine = m_pFindDialog->currentLine; - posInLine = m_pFindDialog->currentPos; - if ( m_pFindDialog->currentWindow == 4 ) - { - if ( m_pFindDialog->m_pSearchInOutput->isChecked() && m_pMergeResultWindow!=0 && m_pMergeResultWindow->isVisible() && - m_pMergeResultWindow->findString( s, d3vLine, posInLine, bDirDown, bCaseSensitive ) ) - { - m_pMergeResultWindow->setSelection( d3vLine, posInLine, d3vLine, posInLine+s.length() ); - m_pMergeVScrollBar->setValue(d3vLine - m_pMergeVScrollBar->pageStep()/2); - m_pHScrollBar->setValue( max2( 0, posInLine+(int)s.length()-m_pHScrollBar->pageStep()) ); - m_pFindDialog->currentLine = d3vLine; - m_pFindDialog->currentPos = posInLine + 1; - return; - } - m_pFindDialog->currentWindow = 5; - m_pFindDialog->currentLine = 0; - m_pFindDialog->currentPos = 0; - } - - KMessageBox::information(this,i18n("Search complete."),i18n("Search Complete")); - m_pFindDialog->currentWindow = 1; - m_pFindDialog->currentLine = 0; - m_pFindDialog->currentPos = 0; + QString s = m_pFindDialog->m_pSearchString->text(); + if(s.isEmpty()) + { + slotEditFind(); + return; + } + + bool bDirDown = true; + bool bCaseSensitive = m_pFindDialog->m_pCaseSensitive->isChecked(); + + int d3vLine = m_pFindDialog->currentLine; + int posInLine = m_pFindDialog->currentPos; + int l = 0; + int p = 0; + if(m_pFindDialog->currentWindow == 1) + { + if(m_pFindDialog->m_pSearchInA->isChecked() && m_pDiffTextWindow1 != 0 && + m_pDiffTextWindow1->findString(s, d3vLine, posInLine, bDirDown, bCaseSensitive)) + { + m_pDiffTextWindow1->setSelection(d3vLine, posInLine, d3vLine, posInLine + s.length(), l, p); + m_pDiffVScrollBar->setValue(l - m_pDiffVScrollBar->pageStep() / 2); + m_pHScrollBar->setValue(max2(0, p + (int)s.length() - m_pHScrollBar->pageStep())); + m_pFindDialog->currentLine = d3vLine; + m_pFindDialog->currentPos = posInLine + 1; + return; + } + m_pFindDialog->currentWindow = 2; + m_pFindDialog->currentLine = 0; + m_pFindDialog->currentPos = 0; + } + + d3vLine = m_pFindDialog->currentLine; + posInLine = m_pFindDialog->currentPos; + if(m_pFindDialog->currentWindow == 2) + { + if(m_pFindDialog->m_pSearchInB->isChecked() && m_pDiffTextWindow2 != 0 && + m_pDiffTextWindow2->findString(s, d3vLine, posInLine, bDirDown, bCaseSensitive)) + { + m_pDiffTextWindow2->setSelection(d3vLine, posInLine, d3vLine, posInLine + s.length(), l, p); + m_pDiffVScrollBar->setValue(l - m_pDiffVScrollBar->pageStep() / 2); + m_pHScrollBar->setValue(max2(0, p + (int)s.length() - m_pHScrollBar->pageStep())); + m_pFindDialog->currentLine = d3vLine; + m_pFindDialog->currentPos = posInLine + 1; + return; + } + m_pFindDialog->currentWindow = 3; + m_pFindDialog->currentLine = 0; + m_pFindDialog->currentPos = 0; + } + + d3vLine = m_pFindDialog->currentLine; + posInLine = m_pFindDialog->currentPos; + if(m_pFindDialog->currentWindow == 3) + { + if(m_pFindDialog->m_pSearchInC->isChecked() && m_pDiffTextWindow3 != 0 && + m_pDiffTextWindow3->findString(s, d3vLine, posInLine, bDirDown, bCaseSensitive)) + { + m_pDiffTextWindow3->setSelection(d3vLine, posInLine, d3vLine, posInLine + s.length(), l, p); + m_pDiffVScrollBar->setValue(l - m_pDiffVScrollBar->pageStep() / 2); + m_pHScrollBar->setValue(max2(0, p + (int)s.length() - m_pHScrollBar->pageStep())); + m_pFindDialog->currentLine = d3vLine; + m_pFindDialog->currentPos = posInLine + 1; + return; + } + m_pFindDialog->currentWindow = 4; + m_pFindDialog->currentLine = 0; + m_pFindDialog->currentPos = 0; + } + + d3vLine = m_pFindDialog->currentLine; + posInLine = m_pFindDialog->currentPos; + if(m_pFindDialog->currentWindow == 4) + { + if(m_pFindDialog->m_pSearchInOutput->isChecked() && m_pMergeResultWindow != 0 && m_pMergeResultWindow->isVisible() && + m_pMergeResultWindow->findString(s, d3vLine, posInLine, bDirDown, bCaseSensitive)) + { + m_pMergeResultWindow->setSelection(d3vLine, posInLine, d3vLine, posInLine + s.length()); + m_pMergeVScrollBar->setValue(d3vLine - m_pMergeVScrollBar->pageStep() / 2); + m_pHScrollBar->setValue(max2(0, posInLine + (int)s.length() - m_pHScrollBar->pageStep())); + m_pFindDialog->currentLine = d3vLine; + m_pFindDialog->currentPos = posInLine + 1; + return; + } + m_pFindDialog->currentWindow = 5; + m_pFindDialog->currentLine = 0; + m_pFindDialog->currentPos = 0; + } + + KMessageBox::information(this, i18n("Search complete."), i18n("Search Complete")); + m_pFindDialog->currentWindow = 1; + m_pFindDialog->currentLine = 0; + m_pFindDialog->currentPos = 0; } void KDiff3App::slotMergeCurrentFile() { - if ( m_bDirCompare && m_pDirectoryMergeWindow->isVisible() && m_pDirectoryMergeWindow->isFileSelected() ) - { - m_pDirectoryMergeWindow->mergeCurrentFile(); - } - else if ( m_pMainWidget != 0 && m_pMainWidget->isVisible() ) - { - if ( !canContinue() ) return; - if ( m_outputFilename.isEmpty() ) - { - if ( !m_sd3.isEmpty() && !m_sd3.isFromBuffer() ) - { - m_outputFilename = m_sd3.getFilename(); - } - else if ( !m_sd2.isEmpty() && !m_sd2.isFromBuffer() ) - { - m_outputFilename = m_sd2.getFilename(); - } - else if ( !m_sd1.isEmpty() && !m_sd1.isFromBuffer() ) - { - m_outputFilename = m_sd1.getFilename(); - } - else - { - m_outputFilename = "unnamed.txt"; - m_bDefaultFilename = true; - } - } - mainInit(); - } + if(m_bDirCompare && m_pDirectoryMergeWindow->isVisible() && m_pDirectoryMergeWindow->isFileSelected()) + { + m_pDirectoryMergeWindow->mergeCurrentFile(); + } + else if(m_pMainWidget != 0 && m_pMainWidget->isVisible()) + { + if(!canContinue()) return; + if(m_outputFilename.isEmpty()) + { + if(!m_sd3.isEmpty() && !m_sd3.isFromBuffer()) + { + m_outputFilename = m_sd3.getFilename(); + } + else if(!m_sd2.isEmpty() && !m_sd2.isFromBuffer()) + { + m_outputFilename = m_sd2.getFilename(); + } + else if(!m_sd1.isEmpty() && !m_sd1.isFromBuffer()) + { + m_outputFilename = m_sd1.getFilename(); + } + else + { + m_outputFilename = "unnamed.txt"; + m_bDefaultFilename = true; + } + } + mainInit(); + } } void KDiff3App::slotWinFocusNext() { - QWidget* focus = qApp->focusWidget(); - if ( focus == m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->isVisible() && ! dirShowBoth->isChecked() ) - { - slotDirViewToggle(); - } - - std::list visibleWidgetList; - if ( m_pDiffTextWindow1 && m_pDiffTextWindow1->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow1); - if ( m_pDiffTextWindow2 && m_pDiffTextWindow2->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow2); - if ( m_pDiffTextWindow3 && m_pDiffTextWindow3->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow3); - if ( m_pMergeResultWindow && m_pMergeResultWindow->isVisible() ) visibleWidgetList.push_back(m_pMergeResultWindow); - if ( m_bDirCompare /*m_pDirectoryMergeWindow->isVisible()*/ ) visibleWidgetList.push_back(m_pDirectoryMergeWindow); - //if ( m_pDirectoryMergeInfo->isVisible() ) visibleWidgetList.push_back(m_pDirectoryMergeInfo->getInfoList()); - - std::list::iterator i = std::find( visibleWidgetList.begin(), visibleWidgetList.end(), focus); - ++i; - if ( i==visibleWidgetList.end() ) - i = visibleWidgetList.begin(); - if ( i!=visibleWidgetList.end() ) - { - if ( *i == m_pDirectoryMergeWindow && ! dirShowBoth->isChecked() ) - { - slotDirViewToggle(); - } - (*i)->setFocus(); - } + QWidget* focus = qApp->focusWidget(); + if(focus == m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->isVisible() && !dirShowBoth->isChecked()) + { + slotDirViewToggle(); + } + + std::list visibleWidgetList; + if(m_pDiffTextWindow1 && m_pDiffTextWindow1->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow1); + if(m_pDiffTextWindow2 && m_pDiffTextWindow2->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow2); + if(m_pDiffTextWindow3 && m_pDiffTextWindow3->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow3); + if(m_pMergeResultWindow && m_pMergeResultWindow->isVisible()) visibleWidgetList.push_back(m_pMergeResultWindow); + if(m_bDirCompare /*m_pDirectoryMergeWindow->isVisible()*/) visibleWidgetList.push_back(m_pDirectoryMergeWindow); + //if ( m_pDirectoryMergeInfo->isVisible() ) visibleWidgetList.push_back(m_pDirectoryMergeInfo->getInfoList()); + + std::list::iterator i = std::find(visibleWidgetList.begin(), visibleWidgetList.end(), focus); + ++i; + if(i == visibleWidgetList.end()) + i = visibleWidgetList.begin(); + if(i != visibleWidgetList.end()) + { + if(*i == m_pDirectoryMergeWindow && !dirShowBoth->isChecked()) + { + slotDirViewToggle(); + } + (*i)->setFocus(); + } } void KDiff3App::slotWinFocusPrev() { - QWidget* focus = qApp->focusWidget(); - if ( focus == m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->isVisible() && ! dirShowBoth->isChecked() ) - { - slotDirViewToggle(); - } - - std::list visibleWidgetList; - if ( m_pDiffTextWindow1 && m_pDiffTextWindow1->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow1); - if ( m_pDiffTextWindow2 && m_pDiffTextWindow2->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow2); - if ( m_pDiffTextWindow3 && m_pDiffTextWindow3->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow3); - if ( m_pMergeResultWindow && m_pMergeResultWindow->isVisible() ) visibleWidgetList.push_back(m_pMergeResultWindow); - if (m_bDirCompare /* m_pDirectoryMergeWindow->isVisible() */ ) visibleWidgetList.push_back(m_pDirectoryMergeWindow); - //if ( m_pDirectoryMergeInfo->isVisible() ) visibleWidgetList.push_back(m_pDirectoryMergeInfo->getInfoList()); - - std::list::iterator i = std::find( visibleWidgetList.begin(), visibleWidgetList.end(), focus); - if ( i==visibleWidgetList.begin() ) - i=visibleWidgetList.end(); - --i; - if ( i!=visibleWidgetList.end() ) - { - if ( *i == m_pDirectoryMergeWindow && ! dirShowBoth->isChecked() ) - { - slotDirViewToggle(); - } - (*i)->setFocus(); - } + QWidget* focus = qApp->focusWidget(); + if(focus == m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->isVisible() && !dirShowBoth->isChecked()) + { + slotDirViewToggle(); + } + + std::list visibleWidgetList; + if(m_pDiffTextWindow1 && m_pDiffTextWindow1->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow1); + if(m_pDiffTextWindow2 && m_pDiffTextWindow2->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow2); + if(m_pDiffTextWindow3 && m_pDiffTextWindow3->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow3); + if(m_pMergeResultWindow && m_pMergeResultWindow->isVisible()) visibleWidgetList.push_back(m_pMergeResultWindow); + if(m_bDirCompare /* m_pDirectoryMergeWindow->isVisible() */) visibleWidgetList.push_back(m_pDirectoryMergeWindow); + //if ( m_pDirectoryMergeInfo->isVisible() ) visibleWidgetList.push_back(m_pDirectoryMergeInfo->getInfoList()); + + std::list::iterator i = std::find(visibleWidgetList.begin(), visibleWidgetList.end(), focus); + if(i == visibleWidgetList.begin()) + i = visibleWidgetList.end(); + --i; + if(i != visibleWidgetList.end()) + { + if(*i == m_pDirectoryMergeWindow && !dirShowBoth->isChecked()) + { + slotDirViewToggle(); + } + (*i)->setFocus(); + } } void KDiff3App::slotWinToggleSplitterOrientation() { - if ( m_pDiffWindowSplitter!=0 ) - { - m_pDiffWindowSplitter->setOrientation( - m_pDiffWindowSplitter->orientation()==Qt::Vertical ? Qt::Horizontal : Qt::Vertical - ); + if(m_pDiffWindowSplitter != 0) + { + m_pDiffWindowSplitter->setOrientation( + m_pDiffWindowSplitter->orientation() == Qt::Vertical ? Qt::Horizontal : Qt::Vertical); - m_pOptions->m_bHorizDiffWindowSplitting = m_pDiffWindowSplitter->orientation()==Qt::Horizontal; - } + m_pOptions->m_bHorizDiffWindowSplitting = m_pDiffWindowSplitter->orientation() == Qt::Horizontal; + } } void KDiff3App::slotOverviewNormal() { - if ( m_pOverview != 0 ) - m_pOverview->setOverviewMode( Overview::eOMNormal ); - if ( m_pMergeResultWindow !=0 ) - m_pMergeResultWindow->setOverviewMode( Overview::eOMNormal ); - slotUpdateAvailabilities(); + if(m_pOverview != 0) + m_pOverview->setOverviewMode(Overview::eOMNormal); + if(m_pMergeResultWindow != 0) + m_pMergeResultWindow->setOverviewMode(Overview::eOMNormal); + slotUpdateAvailabilities(); } void KDiff3App::slotOverviewAB() { - if ( m_pOverview != 0 ) - m_pOverview->setOverviewMode( Overview::eOMAvsB ); - m_pMergeResultWindow->setOverviewMode( Overview::eOMAvsB ); - slotUpdateAvailabilities(); + if(m_pOverview != 0) + m_pOverview->setOverviewMode(Overview::eOMAvsB); + m_pMergeResultWindow->setOverviewMode(Overview::eOMAvsB); + slotUpdateAvailabilities(); } void KDiff3App::slotOverviewAC() { - if ( m_pOverview != 0 ) - m_pOverview->setOverviewMode( Overview::eOMAvsC ); - if ( m_pMergeResultWindow !=0 ) - m_pMergeResultWindow->setOverviewMode( Overview::eOMAvsC ); - slotUpdateAvailabilities(); + if(m_pOverview != 0) + m_pOverview->setOverviewMode(Overview::eOMAvsC); + if(m_pMergeResultWindow != 0) + m_pMergeResultWindow->setOverviewMode(Overview::eOMAvsC); + slotUpdateAvailabilities(); } void KDiff3App::slotOverviewBC() { - if ( m_pOverview != 0 ) - m_pOverview->setOverviewMode( Overview::eOMBvsC ); - if ( m_pMergeResultWindow !=0 ) - m_pMergeResultWindow->setOverviewMode( Overview::eOMBvsC ); - slotUpdateAvailabilities(); + if(m_pOverview != 0) + m_pOverview->setOverviewMode(Overview::eOMBvsC); + if(m_pMergeResultWindow != 0) + m_pMergeResultWindow->setOverviewMode(Overview::eOMBvsC); + slotUpdateAvailabilities(); } void KDiff3App::slotNoRelevantChangesDetected() { - if ( m_bTripleDiff && ! m_outputFilename.isEmpty() ) - { - //KMessageBox::information( this, "No relevant changes detected", "KDiff3" ); - if (!m_pOptions->m_IrrelevantMergeCmd.isEmpty()) - { - QString cmd = m_pOptions->m_IrrelevantMergeCmd + " \"" + m_sd1.getAliasName()+ "\" \"" + m_sd2.getAliasName() + "\" \"" + m_sd3.getAliasName(); - QProcess process; - process.start( cmd ); - process.waitForFinished(-1); - //::system( cmd.local8Bit() ); - } - } -} - -static void insertManualDiffHelp( ManualDiffHelpList* pManualDiffHelpList, int winIdx, int firstLine, int lastLine ) -{ - // The manual diff help list must be sorted and compact. - // "Compact" means that upper items can't be empty if lower items contain data. - - // First insert the new item without regarding compactness. - // If the new item overlaps with previous items then the previous items will be removed. - - ManualDiffHelpEntry mdhe; - mdhe.firstLine( winIdx ) = firstLine; - mdhe.lastLine( winIdx ) = lastLine; - - ManualDiffHelpList::iterator i; - for( i=pManualDiffHelpList->begin(); i!=pManualDiffHelpList->end(); ++i ) - { - int& l1 = i->firstLine( winIdx ); - int& l2 = i->lastLine( winIdx ); - if (l1>=0 && l2>=0) - { - if ( (firstLine<=l1 && lastLine>=l1) || (firstLine <=l2 && lastLine>=l2) ) - { - // overlap - l1 = -1; - l2 = -1; - } - if ( firstLineinsert( i, mdhe ); - break; - } - } - } - if ( i == pManualDiffHelpList->end() ) - { - pManualDiffHelpList->insert( i, mdhe ); - } - - // Now make the list compact - for( int wIdx=1; wIdx<=3; ++wIdx ) - { - ManualDiffHelpList::iterator iEmpty = pManualDiffHelpList->begin(); - for( i=pManualDiffHelpList->begin(); i!=pManualDiffHelpList->end(); ++i ) - { - if ( iEmpty->firstLine(wIdx) >= 0 ) - { - ++iEmpty; - continue; - } - if ( i->firstLine(wIdx)>=0 ) // Current item is not empty -> move it to the empty place - { - iEmpty->firstLine(wIdx) = i->firstLine(wIdx); - iEmpty->lastLine(wIdx) = i->lastLine(wIdx); - i->firstLine(wIdx) = -1; - i->lastLine(wIdx) = -1; - ++iEmpty; - } - } - } - pManualDiffHelpList->remove( ManualDiffHelpEntry() ); // Remove all completely empty items. + if(m_bTripleDiff && !m_outputFilename.isEmpty()) + { + //KMessageBox::information( this, "No relevant changes detected", "KDiff3" ); + if(!m_pOptions->m_IrrelevantMergeCmd.isEmpty()) + { + QString cmd = m_pOptions->m_IrrelevantMergeCmd + " \"" + m_sd1.getAliasName() + "\" \"" + m_sd2.getAliasName() + "\" \"" + m_sd3.getAliasName(); + QProcess process; + process.start(cmd); + process.waitForFinished(-1); + //::system( cmd.local8Bit() ); + } + } +} + +static void insertManualDiffHelp(ManualDiffHelpList* pManualDiffHelpList, int winIdx, int firstLine, int lastLine) +{ + // The manual diff help list must be sorted and compact. + // "Compact" means that upper items can't be empty if lower items contain data. + + // First insert the new item without regarding compactness. + // If the new item overlaps with previous items then the previous items will be removed. + + ManualDiffHelpEntry mdhe; + mdhe.firstLine(winIdx) = firstLine; + mdhe.lastLine(winIdx) = lastLine; + + ManualDiffHelpList::iterator i; + for(i = pManualDiffHelpList->begin(); i != pManualDiffHelpList->end(); ++i) + { + int& l1 = i->firstLine(winIdx); + int& l2 = i->lastLine(winIdx); + if(l1 >= 0 && l2 >= 0) + { + if((firstLine <= l1 && lastLine >= l1) || (firstLine <= l2 && lastLine >= l2)) + { + // overlap + l1 = -1; + l2 = -1; + } + if(firstLine < l1 && lastLine < l1) + { + // insert before this position + pManualDiffHelpList->insert(i, mdhe); + break; + } + } + } + if(i == pManualDiffHelpList->end()) + { + pManualDiffHelpList->insert(i, mdhe); + } + + // Now make the list compact + for(int wIdx = 1; wIdx <= 3; ++wIdx) + { + ManualDiffHelpList::iterator iEmpty = pManualDiffHelpList->begin(); + for(i = pManualDiffHelpList->begin(); i != pManualDiffHelpList->end(); ++i) + { + if(iEmpty->firstLine(wIdx) >= 0) + { + ++iEmpty; + continue; + } + if(i->firstLine(wIdx) >= 0) // Current item is not empty -> move it to the empty place + { + iEmpty->firstLine(wIdx) = i->firstLine(wIdx); + iEmpty->lastLine(wIdx) = i->lastLine(wIdx); + i->firstLine(wIdx) = -1; + i->lastLine(wIdx) = -1; + ++iEmpty; + } + } + } + pManualDiffHelpList->remove(ManualDiffHelpEntry()); // Remove all completely empty items. } void KDiff3App::slotAddManualDiffHelp() { - int firstLine = -1; - int lastLine = -1; - int winIdx = -1; - if ( m_pDiffTextWindow1 ) { m_pDiffTextWindow1->getSelectionRange(&firstLine, &lastLine, eFileCoords); winIdx=1; } - if ( firstLine<0 && m_pDiffTextWindow2 ) { m_pDiffTextWindow2->getSelectionRange(&firstLine, &lastLine, eFileCoords); winIdx=2; } - if ( firstLine<0 && m_pDiffTextWindow3 ) { m_pDiffTextWindow3->getSelectionRange(&firstLine, &lastLine, eFileCoords); winIdx=3; } - - if ( firstLine<0 || lastLine <0 || lastLinegetSelectionRange(&firstLine, &lastLine, eFileCoords); + winIdx = 1; + } + if(firstLine < 0 && m_pDiffTextWindow2) { + m_pDiffTextWindow2->getSelectionRange(&firstLine, &lastLine, eFileCoords); + winIdx = 2; + } + if(firstLine < 0 && m_pDiffTextWindow3) { + m_pDiffTextWindow3->getSelectionRange(&firstLine, &lastLine, eFileCoords); + winIdx = 3; + } + + if(firstLine < 0 || lastLine < 0 || lastLine < firstLine) + KMessageBox::information(this, i18n("Nothing is selected in either diff input window."), i18n("Error while adding manual diff range")); + else + { + /* ManualDiffHelpEntry mdhe; if (!m_manualDiffHelpList.empty()) mdhe = m_manualDiffHelpList.front(); if ( winIdx==1 ) { mdhe.lineA1 = firstLine; mdhe.lineA2 = lastLine; } if ( winIdx==2 ) { mdhe.lineB1 = firstLine; mdhe.lineB2 = lastLine; } if ( winIdx==3 ) { mdhe.lineC1 = firstLine; mdhe.lineC2 = lastLine; } m_manualDiffHelpList.clear(); m_manualDiffHelpList.push_back( mdhe ); */ - insertManualDiffHelp( &m_manualDiffHelpList, winIdx, firstLine, lastLine ); + insertManualDiffHelp(&m_manualDiffHelpList, winIdx, firstLine, lastLine); - mainInit( 0, false ); // Init without reload - slotRefresh(); - } + mainInit(0, false); // Init without reload + slotRefresh(); + } } void KDiff3App::slotClearManualDiffHelpList() { - m_manualDiffHelpList.clear(); - mainInit( 0, false ); // Init without reload - slotRefresh(); + m_manualDiffHelpList.clear(); + mainInit(0, false); // Init without reload + slotRefresh(); } void KDiff3App::slotEncodingChangedA(QTextCodec* c) { m_sd1.setEncoding(c); - mainInit( 0, true, true); // Init with reload + mainInit(0, true, true); // Init with reload slotRefresh(); } void KDiff3App::slotEncodingChangedB(QTextCodec* c) { m_sd2.setEncoding(c); - mainInit( 0, true, true); // Init with reload + mainInit(0, true, true); // Init with reload slotRefresh(); } void KDiff3App::slotEncodingChangedC(QTextCodec* c) { m_sd3.setEncoding(c); - mainInit( 0, true, true ); // Init with reload + mainInit(0, true, true); // Init with reload slotRefresh(); } void KDiff3App::slotUpdateAvailabilities() { - if (m_pMainSplitter==0) - return; - - bool bTextDataAvailable = ( m_sd1.hasData() || m_sd2.hasData() || m_sd3.hasData() ); - - if( dirShowBoth->isChecked() ) - { - if ( m_pDirectoryMergeSplitter!=0 ) - m_pDirectoryMergeSplitter->setVisible( m_bDirCompare ); - - if ( m_pMainWidget!=0 && !m_pMainWidget->isVisible() && - bTextDataAvailable && !m_pDirectoryMergeWindow->isScanning() - ) - m_pMainWidget->show(); - } - - - bool bDiffWindowVisible = m_pMainWidget != 0 && m_pMainWidget->isVisible(); - bool bMergeEditorVisible = m_pMergeWindowFrame !=0 && m_pMergeWindowFrame->isVisible(); - - m_pDirectoryMergeWindow->updateAvailabilities( m_bDirCompare, bDiffWindowVisible, chooseA, chooseB, chooseC ); - - dirShowBoth->setEnabled( m_bDirCompare ); - dirViewToggle->setEnabled( - m_bDirCompare && - ((!m_pDirectoryMergeSplitter->isVisible() && m_pMainWidget!=0 && m_pMainWidget->isVisible()) || - (m_pDirectoryMergeSplitter->isVisible() && m_pMainWidget!=0 && !m_pMainWidget->isVisible() && bTextDataAvailable) ) - ); - - bool bDirWindowHasFocus = m_pDirectoryMergeSplitter->isVisible() && m_pDirectoryMergeWindow->hasFocus(); - - showWhiteSpaceCharacters->setEnabled( bDiffWindowVisible ); - autoAdvance->setEnabled( bMergeEditorVisible ); - autoSolve->setEnabled( bMergeEditorVisible && m_bTripleDiff ); - unsolve->setEnabled( bMergeEditorVisible ); - if ( !bDirWindowHasFocus ) - { - chooseA->setEnabled( bMergeEditorVisible ); - chooseB->setEnabled( bMergeEditorVisible ); - chooseC->setEnabled( bMergeEditorVisible && m_bTripleDiff ); - } - chooseAEverywhere->setEnabled( bMergeEditorVisible ); - chooseBEverywhere->setEnabled( bMergeEditorVisible ); - chooseCEverywhere->setEnabled( bMergeEditorVisible && m_bTripleDiff ); - chooseAForUnsolvedConflicts->setEnabled( bMergeEditorVisible ); - chooseBForUnsolvedConflicts->setEnabled( bMergeEditorVisible ); - chooseCForUnsolvedConflicts->setEnabled( bMergeEditorVisible && m_bTripleDiff ); - chooseAForUnsolvedWhiteSpaceConflicts->setEnabled( bMergeEditorVisible ); - chooseBForUnsolvedWhiteSpaceConflicts->setEnabled( bMergeEditorVisible ); - chooseCForUnsolvedWhiteSpaceConflicts->setEnabled( bMergeEditorVisible && m_bTripleDiff ); - mergeHistory->setEnabled( bMergeEditorVisible ); - mergeRegExp->setEnabled( bMergeEditorVisible ); - showWindowA->setEnabled( bDiffWindowVisible && ( m_pDiffTextWindow2->isVisible() || m_pDiffTextWindow3->isVisible() ) ); - showWindowB->setEnabled( bDiffWindowVisible && ( m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow3->isVisible() )); - showWindowC->setEnabled( bDiffWindowVisible && m_bTripleDiff && ( m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow2->isVisible() ) ); - editFind->setEnabled( bDiffWindowVisible ); - editFindNext->setEnabled( bDiffWindowVisible ); - m_pFindDialog->m_pSearchInC->setEnabled( m_bTripleDiff ); - m_pFindDialog->m_pSearchInOutput->setEnabled( bMergeEditorVisible ); - - bool bSavable = bMergeEditorVisible && m_pMergeResultWindow->getNrOfUnsolvedConflicts()==0; - fileSave->setEnabled( m_bOutputModified && bSavable ); - fileSaveAs->setEnabled( bSavable ); - - goTop->setEnabled( bDiffWindowVisible && m_pMergeResultWindow->isDeltaAboveCurrent() ); - goBottom->setEnabled( bDiffWindowVisible && m_pMergeResultWindow->isDeltaBelowCurrent() ); - goCurrent->setEnabled( bDiffWindowVisible ); - goPrevUnsolvedConflict->setEnabled( bMergeEditorVisible && m_pMergeResultWindow->isUnsolvedConflictAboveCurrent() ); - goNextUnsolvedConflict->setEnabled( bMergeEditorVisible && m_pMergeResultWindow->isUnsolvedConflictBelowCurrent() ); - goPrevConflict->setEnabled( bDiffWindowVisible && m_pMergeResultWindow->isConflictAboveCurrent() ); - goNextConflict->setEnabled( bDiffWindowVisible && m_pMergeResultWindow->isConflictBelowCurrent() ); - goPrevDelta->setEnabled( bDiffWindowVisible && m_pMergeResultWindow->isDeltaAboveCurrent() ); - goNextDelta->setEnabled( bDiffWindowVisible && m_pMergeResultWindow->isDeltaBelowCurrent() ); - - overviewModeNormal->setEnabled( m_bTripleDiff && bDiffWindowVisible ); - overviewModeAB->setEnabled( m_bTripleDiff && bDiffWindowVisible ); - overviewModeAC->setEnabled( m_bTripleDiff && bDiffWindowVisible ); - overviewModeBC->setEnabled( m_bTripleDiff && bDiffWindowVisible ); - Overview::e_OverviewMode overviewMode = m_pOverview==0 ? Overview::eOMNormal : m_pOverview->getOverviewMode(); - overviewModeNormal->setChecked( overviewMode == Overview::eOMNormal ); - overviewModeAB->setChecked( overviewMode == Overview::eOMAvsB ); - overviewModeAC->setChecked( overviewMode == Overview::eOMAvsC ); - overviewModeBC->setChecked( overviewMode == Overview::eOMBvsC ); - - winToggleSplitOrientation->setEnabled( bDiffWindowVisible && m_pDiffWindowSplitter!=0 ); + if(m_pMainSplitter == 0) + return; + + bool bTextDataAvailable = (m_sd1.hasData() || m_sd2.hasData() || m_sd3.hasData()); + + if(dirShowBoth->isChecked()) + { + if(m_pDirectoryMergeSplitter != 0) + m_pDirectoryMergeSplitter->setVisible(m_bDirCompare); + + if(m_pMainWidget != 0 && !m_pMainWidget->isVisible() && + bTextDataAvailable && !m_pDirectoryMergeWindow->isScanning()) + m_pMainWidget->show(); + } + + bool bDiffWindowVisible = m_pMainWidget != 0 && m_pMainWidget->isVisible(); + bool bMergeEditorVisible = m_pMergeWindowFrame != 0 && m_pMergeWindowFrame->isVisible(); + + m_pDirectoryMergeWindow->updateAvailabilities(m_bDirCompare, bDiffWindowVisible, chooseA, chooseB, chooseC); + + dirShowBoth->setEnabled(m_bDirCompare); + dirViewToggle->setEnabled( + m_bDirCompare && + ((!m_pDirectoryMergeSplitter->isVisible() && m_pMainWidget != 0 && m_pMainWidget->isVisible()) || + (m_pDirectoryMergeSplitter->isVisible() && m_pMainWidget != 0 && !m_pMainWidget->isVisible() && bTextDataAvailable))); + + bool bDirWindowHasFocus = m_pDirectoryMergeSplitter->isVisible() && m_pDirectoryMergeWindow->hasFocus(); + + showWhiteSpaceCharacters->setEnabled(bDiffWindowVisible); + autoAdvance->setEnabled(bMergeEditorVisible); + autoSolve->setEnabled(bMergeEditorVisible && m_bTripleDiff); + unsolve->setEnabled(bMergeEditorVisible); + if(!bDirWindowHasFocus) + { + chooseA->setEnabled(bMergeEditorVisible); + chooseB->setEnabled(bMergeEditorVisible); + chooseC->setEnabled(bMergeEditorVisible && m_bTripleDiff); + } + chooseAEverywhere->setEnabled(bMergeEditorVisible); + chooseBEverywhere->setEnabled(bMergeEditorVisible); + chooseCEverywhere->setEnabled(bMergeEditorVisible && m_bTripleDiff); + chooseAForUnsolvedConflicts->setEnabled(bMergeEditorVisible); + chooseBForUnsolvedConflicts->setEnabled(bMergeEditorVisible); + chooseCForUnsolvedConflicts->setEnabled(bMergeEditorVisible && m_bTripleDiff); + chooseAForUnsolvedWhiteSpaceConflicts->setEnabled(bMergeEditorVisible); + chooseBForUnsolvedWhiteSpaceConflicts->setEnabled(bMergeEditorVisible); + chooseCForUnsolvedWhiteSpaceConflicts->setEnabled(bMergeEditorVisible && m_bTripleDiff); + mergeHistory->setEnabled(bMergeEditorVisible); + mergeRegExp->setEnabled(bMergeEditorVisible); + showWindowA->setEnabled(bDiffWindowVisible && (m_pDiffTextWindow2->isVisible() || m_pDiffTextWindow3->isVisible())); + showWindowB->setEnabled(bDiffWindowVisible && (m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow3->isVisible())); + showWindowC->setEnabled(bDiffWindowVisible && m_bTripleDiff && (m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow2->isVisible())); + editFind->setEnabled(bDiffWindowVisible); + editFindNext->setEnabled(bDiffWindowVisible); + m_pFindDialog->m_pSearchInC->setEnabled(m_bTripleDiff); + m_pFindDialog->m_pSearchInOutput->setEnabled(bMergeEditorVisible); + + bool bSavable = bMergeEditorVisible && m_pMergeResultWindow->getNrOfUnsolvedConflicts() == 0; + fileSave->setEnabled(m_bOutputModified && bSavable); + fileSaveAs->setEnabled(bSavable); + + goTop->setEnabled(bDiffWindowVisible && m_pMergeResultWindow->isDeltaAboveCurrent()); + goBottom->setEnabled(bDiffWindowVisible && m_pMergeResultWindow->isDeltaBelowCurrent()); + goCurrent->setEnabled(bDiffWindowVisible); + goPrevUnsolvedConflict->setEnabled(bMergeEditorVisible && m_pMergeResultWindow->isUnsolvedConflictAboveCurrent()); + goNextUnsolvedConflict->setEnabled(bMergeEditorVisible && m_pMergeResultWindow->isUnsolvedConflictBelowCurrent()); + goPrevConflict->setEnabled(bDiffWindowVisible && m_pMergeResultWindow->isConflictAboveCurrent()); + goNextConflict->setEnabled(bDiffWindowVisible && m_pMergeResultWindow->isConflictBelowCurrent()); + goPrevDelta->setEnabled(bDiffWindowVisible && m_pMergeResultWindow->isDeltaAboveCurrent()); + goNextDelta->setEnabled(bDiffWindowVisible && m_pMergeResultWindow->isDeltaBelowCurrent()); + + overviewModeNormal->setEnabled(m_bTripleDiff && bDiffWindowVisible); + overviewModeAB->setEnabled(m_bTripleDiff && bDiffWindowVisible); + overviewModeAC->setEnabled(m_bTripleDiff && bDiffWindowVisible); + overviewModeBC->setEnabled(m_bTripleDiff && bDiffWindowVisible); + Overview::e_OverviewMode overviewMode = m_pOverview == 0 ? Overview::eOMNormal : m_pOverview->getOverviewMode(); + overviewModeNormal->setChecked(overviewMode == Overview::eOMNormal); + overviewModeAB->setChecked(overviewMode == Overview::eOMAvsB); + overviewModeAC->setChecked(overviewMode == Overview::eOMAvsC); + overviewModeBC->setChecked(overviewMode == Overview::eOMBvsC); + + winToggleSplitOrientation->setEnabled(bDiffWindowVisible && m_pDiffWindowSplitter != 0); } diff --git a/src/progress.cpp b/src/progress.cpp index 3e8294b..b3c9dd8 100644 --- a/src/progress.cpp +++ b/src/progress.cpp @@ -1,544 +1,540 @@ /*************************************************************************** * Copyright (C) 2003-2011 by Joachim Eibl * * joachim.eibl at gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "progress.h" #include "common.h" +#include +#include #include -#include #include -#include -#include -#include #include +#include +#include #include #include -ProgressDialog* g_pProgressDialog=0; - -ProgressDialog::ProgressDialog( QWidget* pParent, QStatusBar* pStatusBar ) -: QDialog(pParent), m_pStatusBar(pStatusBar) -{ - m_pGuiThread = QThread::currentThread(); - - setObjectName("ProgressDialog"); - m_bStayHidden = false; - setModal(true); - QVBoxLayout* layout = new QVBoxLayout(this); - - m_pInformation = new QLabel( " ", this ); - layout->addWidget( m_pInformation ); - - m_pProgressBar = new QProgressBar(); - m_pProgressBar->setRange(0,1000); - layout->addWidget( m_pProgressBar ); - - m_pSubInformation = new QLabel( " ", this); - layout->addWidget( m_pSubInformation ); - - m_pSubProgressBar = new QProgressBar(); - m_pSubProgressBar->setRange(0,1000); - layout->addWidget( m_pSubProgressBar ); - - m_pSlowJobInfo = new QLabel( " ", this); - layout->addWidget( m_pSlowJobInfo ); - - QHBoxLayout* hlayout = new QHBoxLayout(); - layout->addLayout(hlayout); - hlayout->addStretch(1); - m_pAbortButton = new QPushButton( i18n("&Cancel"), this); - hlayout->addWidget( m_pAbortButton ); - connect(m_pAbortButton, &QPushButton::clicked, this, &ProgressDialog::slotAbort); - if (m_pStatusBar) - { - m_pStatusBarWidget = new QWidget; - QHBoxLayout* pStatusBarLayout = new QHBoxLayout(m_pStatusBarWidget); - pStatusBarLayout->setMargin(0); - pStatusBarLayout->setSpacing(3); - m_pStatusProgressBar = new QProgressBar; - m_pStatusProgressBar->setRange(0, 1000); - m_pStatusProgressBar->setTextVisible(false); - m_pStatusAbortButton = new QPushButton( i18n("&Cancel") ); - connect(m_pStatusAbortButton, SIGNAL(clicked()), this, SLOT(slotAbort())); - pStatusBarLayout->addWidget(m_pStatusProgressBar); - pStatusBarLayout->addWidget(m_pStatusAbortButton); - m_pStatusBar->addPermanentWidget(m_pStatusBarWidget,0); - m_pStatusBarWidget->setFixedHeight(m_pStatusBar->height()); - m_pStatusBarWidget->hide(); - } - else - { - m_pStatusProgressBar = 0; - m_pStatusAbortButton = 0; - } - - m_progressDelayTimer = 0; - m_delayedHideTimer = 0; - m_delayedHideStatusBarWidgetTimer = 0; - resize(400, 100); - m_t1.start(); - m_t2.start(); - m_bWasCancelled = false; - m_eCancelReason = eUserAbort; - m_pJob = 0; -} - -void ProgressDialog::setStayHidden( bool bStayHidden ) -{ - if (m_bStayHidden != bStayHidden) - { - m_bStayHidden = bStayHidden; - if (m_pStatusBarWidget) - { - if (m_bStayHidden) - { - if (m_delayedHideStatusBarWidgetTimer) +ProgressDialog* g_pProgressDialog = 0; + +ProgressDialog::ProgressDialog(QWidget* pParent, QStatusBar* pStatusBar) + : QDialog(pParent), m_pStatusBar(pStatusBar) +{ + m_pGuiThread = QThread::currentThread(); + + setObjectName("ProgressDialog"); + m_bStayHidden = false; + setModal(true); + QVBoxLayout* layout = new QVBoxLayout(this); + + m_pInformation = new QLabel(" ", this); + layout->addWidget(m_pInformation); + + m_pProgressBar = new QProgressBar(); + m_pProgressBar->setRange(0, 1000); + layout->addWidget(m_pProgressBar); + + m_pSubInformation = new QLabel(" ", this); + layout->addWidget(m_pSubInformation); + + m_pSubProgressBar = new QProgressBar(); + m_pSubProgressBar->setRange(0, 1000); + layout->addWidget(m_pSubProgressBar); + + m_pSlowJobInfo = new QLabel(" ", this); + layout->addWidget(m_pSlowJobInfo); + + QHBoxLayout* hlayout = new QHBoxLayout(); + layout->addLayout(hlayout); + hlayout->addStretch(1); + m_pAbortButton = new QPushButton(i18n("&Cancel"), this); + hlayout->addWidget(m_pAbortButton); + connect(m_pAbortButton, &QPushButton::clicked, this, &ProgressDialog::slotAbort); + if(m_pStatusBar) + { + m_pStatusBarWidget = new QWidget; + QHBoxLayout* pStatusBarLayout = new QHBoxLayout(m_pStatusBarWidget); + pStatusBarLayout->setMargin(0); + pStatusBarLayout->setSpacing(3); + m_pStatusProgressBar = new QProgressBar; + m_pStatusProgressBar->setRange(0, 1000); + m_pStatusProgressBar->setTextVisible(false); + m_pStatusAbortButton = new QPushButton(i18n("&Cancel")); + connect(m_pStatusAbortButton, SIGNAL(clicked()), this, SLOT(slotAbort())); + pStatusBarLayout->addWidget(m_pStatusProgressBar); + pStatusBarLayout->addWidget(m_pStatusAbortButton); + m_pStatusBar->addPermanentWidget(m_pStatusBarWidget, 0); + m_pStatusBarWidget->setFixedHeight(m_pStatusBar->height()); + m_pStatusBarWidget->hide(); + } + else + { + m_pStatusProgressBar = 0; + m_pStatusAbortButton = 0; + } + + m_progressDelayTimer = 0; + m_delayedHideTimer = 0; + m_delayedHideStatusBarWidgetTimer = 0; + resize(400, 100); + m_t1.start(); + m_t2.start(); + m_bWasCancelled = false; + m_eCancelReason = eUserAbort; + m_pJob = 0; +} + +void ProgressDialog::setStayHidden(bool bStayHidden) +{ + if(m_bStayHidden != bStayHidden) + { + m_bStayHidden = bStayHidden; + if(m_pStatusBarWidget) + { + if(m_bStayHidden) { - killTimer(m_delayedHideStatusBarWidgetTimer); - m_delayedHideStatusBarWidgetTimer = 0; + if(m_delayedHideStatusBarWidgetTimer) + { + killTimer(m_delayedHideStatusBarWidgetTimer); + m_delayedHideStatusBarWidgetTimer = 0; + } + m_pStatusBarWidget->show(); } - m_pStatusBarWidget->show(); - } - else - hideStatusBarWidget(); // delayed - } - if ( isVisible() && m_bStayHidden ) - hide(); // delayed hide - } + else + hideStatusBarWidget(); // delayed + } + if(isVisible() && m_bStayHidden) + hide(); // delayed hide + } } void ProgressDialog::push() { - ProgressLevelData pld; - if ( !m_progressStack.empty() ) - { - pld.m_dRangeMax = m_progressStack.back().m_dSubRangeMax; - pld.m_dRangeMin = m_progressStack.back().m_dSubRangeMin; - } - else - { - m_bWasCancelled = false; - m_t1.restart(); - m_t2.restart(); - if ( !m_bStayHidden ) - show(); - } - - m_progressStack.push_back( pld ); -} - -void ProgressDialog::pop( bool bRedrawUpdate ) -{ - if ( !m_progressStack.empty() ) - { - m_progressStack.pop_back(); - if(m_progressStack.empty()) - { - hide(); - } - else - recalc(bRedrawUpdate); - } -} - -void ProgressDialog::setInformation(const QString& info, int current, bool bRedrawUpdate ) -{ - if ( m_progressStack.empty() ) - return; - ProgressLevelData& pld = m_progressStack.back(); - pld.m_current = current; - int level = m_progressStack.size(); - if ( level==1 ) - { - m_pInformation->setText( info ); - m_pSubInformation->setText(""); - if (m_pStatusBar && m_bStayHidden) - m_pStatusBar->showMessage(info); - } - else if ( level==2 ) - { - m_pSubInformation->setText( info ); - } - recalc(bRedrawUpdate); -} - -void ProgressDialog::setInformation(const QString& info, bool bRedrawUpdate ) -{ - if ( m_progressStack.empty() ) - return; - //ProgressLevelData& pld = m_progressStack.back(); - int level = m_progressStack.size(); - if ( level==1 ) - { - m_pInformation->setText( info ); - m_pSubInformation->setText( "" ); - if (m_pStatusBar && m_bStayHidden) - m_pStatusBar->showMessage(info); - } - else if ( level==2 ) - { - m_pSubInformation->setText( info ); - } - recalc(bRedrawUpdate); -} - -void ProgressDialog::setMaxNofSteps( int maxNofSteps ) -{ - if ( m_progressStack.empty() ) - return; - ProgressLevelData& pld = m_progressStack.back(); - pld.m_maxNofSteps = maxNofSteps; - pld.m_current = 0; -} - -void ProgressDialog::addNofSteps( int nofSteps ) -{ - if ( m_progressStack.empty() ) - return; - ProgressLevelData& pld = m_progressStack.back(); - pld.m_maxNofSteps.fetchAndAddRelaxed( nofSteps ); -} - -void ProgressDialog::step( bool bRedrawUpdate ) -{ - if ( m_progressStack.empty() ) - return; - ProgressLevelData& pld = m_progressStack.back(); - pld.m_current.fetchAndAddRelaxed(1); - recalc(bRedrawUpdate); -} - -void ProgressDialog::setCurrent( int subCurrent, bool bRedrawUpdate ) -{ - if ( m_progressStack.empty() ) - return; - ProgressLevelData& pld = m_progressStack.back(); - pld.m_current = subCurrent; - recalc( bRedrawUpdate ); + ProgressLevelData pld; + if(!m_progressStack.empty()) + { + pld.m_dRangeMax = m_progressStack.back().m_dSubRangeMax; + pld.m_dRangeMin = m_progressStack.back().m_dSubRangeMin; + } + else + { + m_bWasCancelled = false; + m_t1.restart(); + m_t2.restart(); + if(!m_bStayHidden) + show(); + } + + m_progressStack.push_back(pld); +} + +void ProgressDialog::pop(bool bRedrawUpdate) +{ + if(!m_progressStack.empty()) + { + m_progressStack.pop_back(); + if(m_progressStack.empty()) + { + hide(); + } + else + recalc(bRedrawUpdate); + } +} + +void ProgressDialog::setInformation(const QString& info, int current, bool bRedrawUpdate) +{ + if(m_progressStack.empty()) + return; + ProgressLevelData& pld = m_progressStack.back(); + pld.m_current = current; + int level = m_progressStack.size(); + if(level == 1) + { + m_pInformation->setText(info); + m_pSubInformation->setText(""); + if(m_pStatusBar && m_bStayHidden) + m_pStatusBar->showMessage(info); + } + else if(level == 2) + { + m_pSubInformation->setText(info); + } + recalc(bRedrawUpdate); +} + +void ProgressDialog::setInformation(const QString& info, bool bRedrawUpdate) +{ + if(m_progressStack.empty()) + return; + //ProgressLevelData& pld = m_progressStack.back(); + int level = m_progressStack.size(); + if(level == 1) + { + m_pInformation->setText(info); + m_pSubInformation->setText(""); + if(m_pStatusBar && m_bStayHidden) + m_pStatusBar->showMessage(info); + } + else if(level == 2) + { + m_pSubInformation->setText(info); + } + recalc(bRedrawUpdate); +} + +void ProgressDialog::setMaxNofSteps(int maxNofSteps) +{ + if(m_progressStack.empty()) + return; + ProgressLevelData& pld = m_progressStack.back(); + pld.m_maxNofSteps = maxNofSteps; + pld.m_current = 0; +} + +void ProgressDialog::addNofSteps(int nofSteps) +{ + if(m_progressStack.empty()) + return; + ProgressLevelData& pld = m_progressStack.back(); + pld.m_maxNofSteps.fetchAndAddRelaxed(nofSteps); +} + +void ProgressDialog::step(bool bRedrawUpdate) +{ + if(m_progressStack.empty()) + return; + ProgressLevelData& pld = m_progressStack.back(); + pld.m_current.fetchAndAddRelaxed(1); + recalc(bRedrawUpdate); +} + +void ProgressDialog::setCurrent(int subCurrent, bool bRedrawUpdate) +{ + if(m_progressStack.empty()) + return; + ProgressLevelData& pld = m_progressStack.back(); + pld.m_current = subCurrent; + recalc(bRedrawUpdate); } // The progressbar goes from 0 to 1 usually. // By supplying a subrange transformation the subCurrent-values // 0 to 1 will be transformed to dMin to dMax instead. // Requirement: 0 < dMin < dMax < 1 -void ProgressDialog::setRangeTransformation( double dMin, double dMax ) +void ProgressDialog::setRangeTransformation(double dMin, double dMax) { - if ( m_progressStack.empty() ) - return; - ProgressLevelData& pld = m_progressStack.back(); - pld.m_dRangeMin = dMin; - pld.m_dRangeMax = dMax; - pld.m_current = 0; + if(m_progressStack.empty()) + return; + ProgressLevelData& pld = m_progressStack.back(); + pld.m_dRangeMin = dMin; + pld.m_dRangeMax = dMax; + pld.m_current = 0; } -void ProgressDialog::setSubRangeTransformation( double dMin, double dMax ) +void ProgressDialog::setSubRangeTransformation(double dMin, double dMax) { - if ( m_progressStack.empty() ) - return; - ProgressLevelData& pld = m_progressStack.back(); - pld.m_dSubRangeMin = dMin; - pld.m_dSubRangeMax = dMax; + if(m_progressStack.empty()) + return; + ProgressLevelData& pld = m_progressStack.back(); + pld.m_dSubRangeMin = dMin; + pld.m_dSubRangeMax = dMax; } void qt_enter_modal(QWidget*); void qt_leave_modal(QWidget*); -void ProgressDialog::enterEventLoop( KJob* pJob, const QString& jobInfo ) +void ProgressDialog::enterEventLoop(KJob* pJob, const QString& jobInfo) { - m_pJob = pJob; - m_currentJobInfo = jobInfo; - m_pSlowJobInfo->setText( m_currentJobInfo ); - if ( m_progressDelayTimer ) - killTimer( m_progressDelayTimer ); - m_progressDelayTimer = startTimer( 3000 ); /* 3 s delay */ + m_pJob = pJob; + m_currentJobInfo = jobInfo; + m_pSlowJobInfo->setText(m_currentJobInfo); + if(m_progressDelayTimer) + killTimer(m_progressDelayTimer); + m_progressDelayTimer = startTimer(3000); /* 3 s delay */ - // immediately show the progess dialog for KIO jobs, because some KIO jobs require password authentication, - // but if the progress dialog pops up at a later moment, this might cover the login dialog and hide it from the user. - if( m_pJob && !m_bStayHidden ) - show(); + // immediately show the progess dialog for KIO jobs, because some KIO jobs require password authentication, + // but if the progress dialog pops up at a later moment, this might cover the login dialog and hide it from the user. + if(m_pJob && !m_bStayHidden) + show(); - // instead of using exec() the eventloop is entered and exited often without hiding/showing the window. - //qt_enter_modal(this); - QEventLoop* pEventLoop = new QEventLoop(this); - m_eventLoopStack.push_back( pEventLoop ); - pEventLoop->exec(); // this function only returns after ProgressDialog::exitEventLoop() is called. - delete pEventLoop; - m_eventLoopStack.pop_back(); - //qt_leave_modal(this); + // instead of using exec() the eventloop is entered and exited often without hiding/showing the window. + //qt_enter_modal(this); + QEventLoop* pEventLoop = new QEventLoop(this); + m_eventLoopStack.push_back(pEventLoop); + pEventLoop->exec(); // this function only returns after ProgressDialog::exitEventLoop() is called. + delete pEventLoop; + m_eventLoopStack.pop_back(); + //qt_leave_modal(this); } void ProgressDialog::exitEventLoop() { - if ( m_progressDelayTimer ) - killTimer( m_progressDelayTimer ); - m_progressDelayTimer = 0; - m_pJob = 0; - if (!m_eventLoopStack.empty()) - m_eventLoopStack.back()->exit(); + if(m_progressDelayTimer) + killTimer(m_progressDelayTimer); + m_progressDelayTimer = 0; + m_pJob = 0; + if(!m_eventLoopStack.empty()) + m_eventLoopStack.back()->exit(); } void ProgressDialog::recalc(bool bUpdate) { - if (!m_bWasCancelled) - { - if (QThread::currentThread() == m_pGuiThread) - { - if (m_progressDelayTimer) - killTimer(m_progressDelayTimer); - m_progressDelayTimer = 0; - if ( ! m_bStayHidden ) - m_progressDelayTimer = startTimer(3000); /* 3 s delay */ - - int level = m_progressStack.size(); - if ((bUpdate && level == 1) || m_t1.elapsed() > 200) - { - if (m_progressStack.empty()) - { - m_pProgressBar->setValue(0); - m_pSubProgressBar->setValue(0); - } - else + if(!m_bWasCancelled) + { + if(QThread::currentThread() == m_pGuiThread) + { + if(m_progressDelayTimer) + killTimer(m_progressDelayTimer); + m_progressDelayTimer = 0; + if(!m_bStayHidden) + m_progressDelayTimer = startTimer(3000); /* 3 s delay */ + + int level = m_progressStack.size(); + if((bUpdate && level == 1) || m_t1.elapsed() > 200) { - QList::iterator i = m_progressStack.begin(); - int value = int(1000.0 * (getAtomic(i->m_current) * (i->m_dRangeMax - i->m_dRangeMin) / getAtomic(i->m_maxNofSteps) + i->m_dRangeMin)); - m_pProgressBar->setValue(value); - if (m_bStayHidden && m_pStatusProgressBar) - m_pStatusProgressBar->setValue(value); - - ++i; - if (i != m_progressStack.end()) - m_pSubProgressBar->setValue(int(1000.0 * (getAtomic(i->m_current) * (i->m_dRangeMax - i->m_dRangeMin) / getAtomic(i->m_maxNofSteps) + i->m_dRangeMin))); - else - m_pSubProgressBar->setValue(int(1000.0 * m_progressStack.front().m_dSubRangeMin)); + if(m_progressStack.empty()) + { + m_pProgressBar->setValue(0); + m_pSubProgressBar->setValue(0); + } + else + { + QList::iterator i = m_progressStack.begin(); + int value = int(1000.0 * (getAtomic(i->m_current) * (i->m_dRangeMax - i->m_dRangeMin) / getAtomic(i->m_maxNofSteps) + i->m_dRangeMin)); + m_pProgressBar->setValue(value); + if(m_bStayHidden && m_pStatusProgressBar) + m_pStatusProgressBar->setValue(value); + + ++i; + if(i != m_progressStack.end()) + m_pSubProgressBar->setValue(int(1000.0 * (getAtomic(i->m_current) * (i->m_dRangeMax - i->m_dRangeMin) / getAtomic(i->m_maxNofSteps) + i->m_dRangeMin))); + else + m_pSubProgressBar->setValue(int(1000.0 * m_progressStack.front().m_dSubRangeMin)); + } + + if(!m_bStayHidden && !isVisible()) + show(); + qApp->processEvents(); + m_t1.restart(); } - - if (!m_bStayHidden && !isVisible()) - show(); - qApp->processEvents(); - m_t1.restart(); - } - } - else - { - QMetaObject::invokeMethod(this, "recalc", Qt::QueuedConnection, Q_ARG(bool, bUpdate)); - } - } + } + else + { + QMetaObject::invokeMethod(this, "recalc", Qt::QueuedConnection, Q_ARG(bool, bUpdate)); + } + } } - #include void ProgressDialog::show() { - if ( m_progressDelayTimer ) - killTimer( m_progressDelayTimer ); - if ( m_delayedHideTimer ) - killTimer( m_delayedHideTimer ); - m_progressDelayTimer = 0; - m_delayedHideTimer = 0; - if ( !isVisible() && (parentWidget()==0 || parentWidget()->isVisible()) ) - { - QDialog::show(); - } + if(m_progressDelayTimer) + killTimer(m_progressDelayTimer); + if(m_delayedHideTimer) + killTimer(m_delayedHideTimer); + m_progressDelayTimer = 0; + m_delayedHideTimer = 0; + if(!isVisible() && (parentWidget() == 0 || parentWidget()->isVisible())) + { + QDialog::show(); + } } void ProgressDialog::hide() { - if ( m_progressDelayTimer ) - killTimer( m_progressDelayTimer ); - m_progressDelayTimer = 0; - // Calling QDialog::hide() directly doesn't always work. (?) - if (m_delayedHideTimer) - killTimer(m_delayedHideTimer); - m_delayedHideTimer = startTimer(100); + if(m_progressDelayTimer) + killTimer(m_progressDelayTimer); + m_progressDelayTimer = 0; + // Calling QDialog::hide() directly doesn't always work. (?) + if(m_delayedHideTimer) + killTimer(m_delayedHideTimer); + m_delayedHideTimer = startTimer(100); } void ProgressDialog::delayedHide() { - if (m_pJob!=0) - { - m_pJob->kill( KJob::Quietly ); - m_pJob = 0; - } - QDialog::hide(); - m_pInformation->setText( "" ); + if(m_pJob != 0) + { + m_pJob->kill(KJob::Quietly); + m_pJob = 0; + } + QDialog::hide(); + m_pInformation->setText(""); - //m_progressStack.clear(); + //m_progressStack.clear(); - m_pProgressBar->setValue( 0 ); - m_pSubProgressBar->setValue( 0 ); - m_pSubInformation->setText(""); - m_pSlowJobInfo->setText(""); + m_pProgressBar->setValue(0); + m_pSubProgressBar->setValue(0); + m_pSubInformation->setText(""); + m_pSlowJobInfo->setText(""); } void ProgressDialog::hideStatusBarWidget() { - if (m_delayedHideStatusBarWidgetTimer) - killTimer(m_delayedHideStatusBarWidgetTimer); - m_delayedHideStatusBarWidgetTimer = startTimer(100); + if(m_delayedHideStatusBarWidgetTimer) + killTimer(m_delayedHideStatusBarWidgetTimer); + m_delayedHideStatusBarWidgetTimer = startTimer(100); } void ProgressDialog::delayedHideStatusBarWidget() { - if (m_progressDelayTimer) - killTimer(m_progressDelayTimer); - m_progressDelayTimer = 0; - if (m_pStatusBarWidget) - { - m_pStatusBarWidget->hide(); - m_pStatusProgressBar->setValue(0); - m_pStatusBar->clearMessage(); - } + if(m_progressDelayTimer) + killTimer(m_progressDelayTimer); + m_progressDelayTimer = 0; + if(m_pStatusBarWidget) + { + m_pStatusBarWidget->hide(); + m_pStatusProgressBar->setValue(0); + m_pStatusBar->clearMessage(); + } } - void ProgressDialog::reject() { - cancel(eUserAbort); - QDialog::reject(); + cancel(eUserAbort); + QDialog::reject(); } void ProgressDialog::slotAbort() { - reject(); + reject(); } bool ProgressDialog::wasCancelled() { - if ( QThread::currentThread() == m_pGuiThread ) - { - if( m_t2.elapsed()>100 ) - { - qApp->processEvents(); - m_t2.restart(); - } - } - return m_bWasCancelled; + if(QThread::currentThread() == m_pGuiThread) + { + if(m_t2.elapsed() > 100) + { + qApp->processEvents(); + m_t2.restart(); + } + } + return m_bWasCancelled; } void ProgressDialog::clearCancelState() { - m_bWasCancelled = false; + m_bWasCancelled = false; } void ProgressDialog::cancel(e_CancelReason eCancelReason) { - if ( !m_bWasCancelled) - { - m_bWasCancelled = true; - m_eCancelReason = eCancelReason; - } + if(!m_bWasCancelled) + { + m_bWasCancelled = true; + m_eCancelReason = eCancelReason; + } } ProgressDialog::e_CancelReason ProgressDialog::cancelReason() { - return m_eCancelReason; + return m_eCancelReason; +} + +void ProgressDialog::timerEvent(QTimerEvent* te) +{ + if(te->timerId() == m_progressDelayTimer) + { + if(!isVisible() && !m_bStayHidden) + { + show(); + } + m_pSlowJobInfo->setText(m_currentJobInfo); + } + else if(te->timerId() == m_delayedHideTimer) + { + killTimer(m_delayedHideTimer); + m_delayedHideTimer = 0; + delayedHide(); + } + else if(te->timerId() == m_delayedHideStatusBarWidgetTimer) + { + killTimer(m_delayedHideStatusBarWidgetTimer); + m_delayedHideStatusBarWidgetTimer = 0; + delayedHideStatusBarWidget(); + } } -void ProgressDialog::timerEvent(QTimerEvent* te ) -{ - if ( te->timerId() == m_progressDelayTimer ) - { - if( !isVisible() && !m_bStayHidden ) - { - show(); - } - m_pSlowJobInfo->setText( m_currentJobInfo ); - } - else if (te->timerId() == m_delayedHideTimer) - { - killTimer(m_delayedHideTimer); - m_delayedHideTimer = 0; - delayedHide(); - } - else if (te->timerId() == m_delayedHideStatusBarWidgetTimer) - { - killTimer(m_delayedHideStatusBarWidgetTimer); - m_delayedHideStatusBarWidgetTimer = 0; - delayedHideStatusBarWidget(); - } -} - - ProgressProxy::ProgressProxy() { - g_pProgressDialog->push(); + g_pProgressDialog->push(); } ProgressProxy::~ProgressProxy() { - g_pProgressDialog->pop(false); + g_pProgressDialog->pop(false); } -void ProgressProxy::enterEventLoop( KJob* pJob, const QString& jobInfo ) +void ProgressProxy::enterEventLoop(KJob* pJob, const QString& jobInfo) { - g_pProgressDialog->enterEventLoop(pJob, jobInfo); + g_pProgressDialog->enterEventLoop(pJob, jobInfo); } void ProgressProxy::exitEventLoop() { - g_pProgressDialog->exitEventLoop(); + g_pProgressDialog->exitEventLoop(); } -QDialog *ProgressProxy::getDialog() +QDialog* ProgressProxy::getDialog() { - return g_pProgressDialog; + return g_pProgressDialog; } -void ProgressProxy::setInformation( const QString& info, bool bRedrawUpdate ) +void ProgressProxy::setInformation(const QString& info, bool bRedrawUpdate) { - g_pProgressDialog->setInformation( info, bRedrawUpdate ); + g_pProgressDialog->setInformation(info, bRedrawUpdate); } -void ProgressProxy::setInformation( const QString& info, int current, bool bRedrawUpdate ) +void ProgressProxy::setInformation(const QString& info, int current, bool bRedrawUpdate) { - g_pProgressDialog->setInformation( info, current, bRedrawUpdate ); + g_pProgressDialog->setInformation(info, current, bRedrawUpdate); } -void ProgressProxy::setCurrent( int current, bool bRedrawUpdate ) +void ProgressProxy::setCurrent(int current, bool bRedrawUpdate) { - g_pProgressDialog->setCurrent( current, bRedrawUpdate ); + g_pProgressDialog->setCurrent(current, bRedrawUpdate); } -void ProgressProxy::step( bool bRedrawUpdate ) +void ProgressProxy::step(bool bRedrawUpdate) { - g_pProgressDialog->step( bRedrawUpdate ); + g_pProgressDialog->step(bRedrawUpdate); } -void ProgressProxy::setMaxNofSteps( int maxNofSteps ) +void ProgressProxy::setMaxNofSteps(int maxNofSteps) { - g_pProgressDialog->setMaxNofSteps( maxNofSteps ); + g_pProgressDialog->setMaxNofSteps(maxNofSteps); } -void ProgressProxy::addNofSteps( int nofSteps ) +void ProgressProxy::addNofSteps(int nofSteps) { - g_pProgressDialog->addNofSteps( nofSteps ); + g_pProgressDialog->addNofSteps(nofSteps); } bool ProgressProxy::wasCancelled() { - return g_pProgressDialog->wasCancelled(); + return g_pProgressDialog->wasCancelled(); } -void ProgressProxy::setRangeTransformation( double dMin, double dMax ) +void ProgressProxy::setRangeTransformation(double dMin, double dMax) { - g_pProgressDialog->setRangeTransformation( dMin, dMax ); + g_pProgressDialog->setRangeTransformation(dMin, dMax); } -void ProgressProxy::setSubRangeTransformation( double dMin, double dMax ) +void ProgressProxy::setSubRangeTransformation(double dMin, double dMax) { - g_pProgressDialog->setSubRangeTransformation( dMin, dMax ); + g_pProgressDialog->setSubRangeTransformation(dMin, dMax); } void ProgressProxy::recalc() { - g_pProgressDialog->recalc(true); + g_pProgressDialog->recalc(true); } - diff --git a/src/smalldialogs.cpp b/src/smalldialogs.cpp index 7db668e..b614275 100644 --- a/src/smalldialogs.cpp +++ b/src/smalldialogs.cpp @@ -1,615 +1,639 @@ /*************************************************************************** * Copyright (C) 2005-2007 by Joachim Eibl * * joachim.eibl at gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "smalldialogs.h" -#include "options.h" #include "diff.h" +#include "options.h" -#include #include -#include -#include -#include -#include -#include +#include #include #include +#include +#include +#include +#include #include -#include #include -#include +#include +#include +#include #include // OpenDialog ************************************************************** OpenDialog::OpenDialog( - QWidget* pParent, const QString& n1, const QString& n2, const QString& n3, - bool bMerge, const QString& outputName, const char* slotConfigure, Options* pOptions ) -: QDialog( pParent ) + QWidget* pParent, const QString& n1, const QString& n2, const QString& n3, + bool bMerge, const QString& outputName, const char* slotConfigure, Options* pOptions) + : QDialog(pParent) { - setObjectName("OpenDialog"); - setModal(true); - m_pOptions = pOptions; - - QVBoxLayout* v = new QVBoxLayout( this ); - v->setMargin(5); - QGridLayout* h = new QGridLayout(); - v->addLayout(h); - h->setSpacing( 5 ); - h->setColumnStretch( 1, 10 ); - - QLabel* label = new QLabel( i18n("A (Base):"), this ); - - m_pLineA = new QComboBox(); - m_pLineA->setEditable(true); - m_pLineA->insertItems( 0, m_pOptions->m_recentAFiles ); - m_pLineA->setEditText( QUrl(n1).toDisplayString() ); - m_pLineA->setMinimumWidth( 200 ); - QPushButton * button = new QPushButton(QIcon::fromTheme("document-new"), i18n("File..."), this); - connect(button, &QPushButton::clicked, this, &OpenDialog::selectFileA); - QPushButton * button2 = new QPushButton(QIcon::fromTheme("document-open-folder"), i18n("Dir..."), this); - connect(button2, &QPushButton::clicked, this, &OpenDialog::selectDirA); - connect(m_pLineA, &QComboBox::editTextChanged, this, &OpenDialog::inputFilenameChanged); - - h->addWidget( label, 0, 0 ); - h->addWidget( m_pLineA, 0, 1 ); - h->addWidget( button, 0, 2 ); - h->addWidget( button2, 0, 3 ); - - label = new QLabel( "B:", this ); - m_pLineB = new QComboBox(); - m_pLineB->setEditable(true); - m_pLineB->insertItems( 0, m_pOptions->m_recentBFiles ); - m_pLineB->setEditText( QUrl(n2).toDisplayString() ); - m_pLineB->setMinimumWidth( 200 ); - button = new QPushButton(QIcon::fromTheme("document-new"), i18n("File..."), this ); - connect(button, &QPushButton::clicked, this, &OpenDialog::selectFileB); - button2 = new QPushButton(QIcon::fromTheme("document-open-folder"), i18n("Dir..."), this); - connect(button2, &QPushButton::clicked, this, &OpenDialog::selectDirB); - connect(m_pLineB, &QComboBox::editTextChanged, this, &OpenDialog::inputFilenameChanged); - - h->addWidget( label, 1, 0 ); - h->addWidget( m_pLineB, 1, 1 ); - h->addWidget( button, 1, 2 ); - h->addWidget( button2, 1, 3 ); - - label = new QLabel( i18n("C (Optional):"), this ); - m_pLineC= new QComboBox(); - m_pLineC->setEditable(true); - m_pLineC->insertItems( 0, m_pOptions->m_recentCFiles ); - m_pLineC->setEditText( QUrl(n3).toDisplayString() ); - m_pLineC->setMinimumWidth( 200 ); - button = new QPushButton(QIcon::fromTheme("document-new"), i18n("File..."), this); - connect(button, &QPushButton::clicked, this, &OpenDialog::selectFileC); - button2 = new QPushButton(QIcon::fromTheme("document-open-folder"), i18n("Dir..."), this); - connect(button2, &QPushButton::clicked, this, &OpenDialog::selectDirC); - connect(m_pLineC, &QComboBox::editTextChanged, this, &OpenDialog::inputFilenameChanged); - - h->addWidget( label, 2, 0 ); - h->addWidget( m_pLineC, 2, 1 ); - h->addWidget( button, 2, 2 ); - h->addWidget( button2, 2, 3 ); - - m_pMerge = new QCheckBox( i18n("Merge"), this ); - h->addWidget( m_pMerge, 3, 0 ); - - QHBoxLayout* hl = new QHBoxLayout(); - h->addLayout( hl, 3, 1 ); - hl->addStretch(2); - button = new QPushButton(i18n("Swap/Copy Names ..."), this); - //button->setToggleButton(false); - hl->addWidget( button ); - - QMenu* m = new QMenu(this); - m->addAction( i18n("Swap %1<->%2", QString("A"),QString("B") )); - m->addAction( i18n("Swap %1<->%2",QString("B"),QString("C") )); - m->addAction( i18n("Swap %1<->%2",QString("C"),QString("A") )); - m->addAction( i18n("Copy %1->Output",QString("A") )); - m->addAction( i18n("Copy %1->Output",QString("B") )); - m->addAction( i18n("Copy %1->Output",QString("C") )); - m->addAction( i18n("Swap %1<->Output",QString("A") )); - m->addAction( i18n("Swap %1<->Output",QString("B") )); - m->addAction( i18n("Swap %1<->Output",QString("C") )); - connect(m, &QMenu::triggered, this, &OpenDialog::slotSwapCopyNames); - button->setMenu(m); - - - hl->addStretch(2); - - label = new QLabel( i18n("Output (optional):"), this ); - m_pLineOut = new QComboBox(); - m_pLineOut->setEditable(true); - m_pLineOut->insertItems( 0, m_pOptions->m_recentOutputFiles ); - m_pLineOut->setEditText( QUrl(outputName).toDisplayString() ); - m_pLineOut->setMinimumWidth( 200 ); - button = new QPushButton(QIcon::fromTheme("document-new"), i18n("File..."), this); - connect(button, &QPushButton::clicked, this, &OpenDialog::selectOutputName); - button2 = new QPushButton(QIcon::fromTheme("document-open-folder"), i18n("Dir..."), this); - connect(button2, &QPushButton::clicked, this, &OpenDialog::selectOutputDir); - connect(m_pMerge, &QCheckBox::stateChanged, this, &OpenDialog::internalSlot); - connect(this, &OpenDialog::internalSignal, m_pLineOut, &QComboBox::setEnabled); - connect(this, &OpenDialog::internalSignal, button, &QPushButton::setEnabled); - connect(this, &OpenDialog::internalSignal, button2, &QPushButton::setEnabled); - - m_pMerge->setChecked( !bMerge ); - m_pMerge->setChecked( bMerge ); -// m_pLineOutput->setEnabled( bMerge ); - -// button->setEnabled( bMerge ); - - h->addWidget( label, 4, 0 ); - h->addWidget( m_pLineOut, 4, 1 ); - h->addWidget( button, 4, 2 ); - h->addWidget( button2, 4, 3 ); - - h->addItem(new QSpacerItem(200, 0), 0, 1); - - QHBoxLayout* l = new QHBoxLayout(); - v->addLayout( l ); - l->setSpacing(5); - - button = new QPushButton(QIcon::fromTheme("configure"), i18n("Configure..."), this); - connect( button, SIGNAL(clicked()), pParent, slotConfigure ); - l->addWidget( button, 1 ); - - l->addStretch(1); - - button = new QPushButton( i18n("&OK"), this ); - button->setDefault( true ); - connect(button, &QPushButton::clicked, this, &OpenDialog::accept); - l->addWidget( button, 1 ); - - button = new QPushButton( i18n("&Cancel"), this ); - connect(button, &QPushButton::clicked, this, &OpenDialog::reject); - l->addWidget( button,1 ); - - QSize sh = sizeHint(); - setFixedHeight( sh.height() ); - m_bInputFileNameChanged = false; + setObjectName("OpenDialog"); + setModal(true); + m_pOptions = pOptions; + + QVBoxLayout* v = new QVBoxLayout(this); + v->setMargin(5); + QGridLayout* h = new QGridLayout(); + v->addLayout(h); + h->setSpacing(5); + h->setColumnStretch(1, 10); + + QLabel* label = new QLabel(i18n("A (Base):"), this); + + m_pLineA = new QComboBox(); + m_pLineA->setEditable(true); + m_pLineA->insertItems(0, m_pOptions->m_recentAFiles); + m_pLineA->setEditText(QUrl(n1).toDisplayString()); + m_pLineA->setMinimumWidth(200); + QPushButton* button = new QPushButton(QIcon::fromTheme("document-new"), i18n("File..."), this); + connect(button, &QPushButton::clicked, this, &OpenDialog::selectFileA); + QPushButton* button2 = new QPushButton(QIcon::fromTheme("document-open-folder"), i18n("Dir..."), this); + connect(button2, &QPushButton::clicked, this, &OpenDialog::selectDirA); + connect(m_pLineA, &QComboBox::editTextChanged, this, &OpenDialog::inputFilenameChanged); + + h->addWidget(label, 0, 0); + h->addWidget(m_pLineA, 0, 1); + h->addWidget(button, 0, 2); + h->addWidget(button2, 0, 3); + + label = new QLabel("B:", this); + m_pLineB = new QComboBox(); + m_pLineB->setEditable(true); + m_pLineB->insertItems(0, m_pOptions->m_recentBFiles); + m_pLineB->setEditText(QUrl(n2).toDisplayString()); + m_pLineB->setMinimumWidth(200); + button = new QPushButton(QIcon::fromTheme("document-new"), i18n("File..."), this); + connect(button, &QPushButton::clicked, this, &OpenDialog::selectFileB); + button2 = new QPushButton(QIcon::fromTheme("document-open-folder"), i18n("Dir..."), this); + connect(button2, &QPushButton::clicked, this, &OpenDialog::selectDirB); + connect(m_pLineB, &QComboBox::editTextChanged, this, &OpenDialog::inputFilenameChanged); + + h->addWidget(label, 1, 0); + h->addWidget(m_pLineB, 1, 1); + h->addWidget(button, 1, 2); + h->addWidget(button2, 1, 3); + + label = new QLabel(i18n("C (Optional):"), this); + m_pLineC = new QComboBox(); + m_pLineC->setEditable(true); + m_pLineC->insertItems(0, m_pOptions->m_recentCFiles); + m_pLineC->setEditText(QUrl(n3).toDisplayString()); + m_pLineC->setMinimumWidth(200); + button = new QPushButton(QIcon::fromTheme("document-new"), i18n("File..."), this); + connect(button, &QPushButton::clicked, this, &OpenDialog::selectFileC); + button2 = new QPushButton(QIcon::fromTheme("document-open-folder"), i18n("Dir..."), this); + connect(button2, &QPushButton::clicked, this, &OpenDialog::selectDirC); + connect(m_pLineC, &QComboBox::editTextChanged, this, &OpenDialog::inputFilenameChanged); + + h->addWidget(label, 2, 0); + h->addWidget(m_pLineC, 2, 1); + h->addWidget(button, 2, 2); + h->addWidget(button2, 2, 3); + + m_pMerge = new QCheckBox(i18n("Merge"), this); + h->addWidget(m_pMerge, 3, 0); + + QHBoxLayout* hl = new QHBoxLayout(); + h->addLayout(hl, 3, 1); + hl->addStretch(2); + button = new QPushButton(i18n("Swap/Copy Names ..."), this); + //button->setToggleButton(false); + hl->addWidget(button); + + QMenu* m = new QMenu(this); + m->addAction(i18n("Swap %1<->%2", QString("A"), QString("B"))); + m->addAction(i18n("Swap %1<->%2", QString("B"), QString("C"))); + m->addAction(i18n("Swap %1<->%2", QString("C"), QString("A"))); + m->addAction(i18n("Copy %1->Output", QString("A"))); + m->addAction(i18n("Copy %1->Output", QString("B"))); + m->addAction(i18n("Copy %1->Output", QString("C"))); + m->addAction(i18n("Swap %1<->Output", QString("A"))); + m->addAction(i18n("Swap %1<->Output", QString("B"))); + m->addAction(i18n("Swap %1<->Output", QString("C"))); + connect(m, &QMenu::triggered, this, &OpenDialog::slotSwapCopyNames); + button->setMenu(m); + + hl->addStretch(2); + + label = new QLabel(i18n("Output (optional):"), this); + m_pLineOut = new QComboBox(); + m_pLineOut->setEditable(true); + m_pLineOut->insertItems(0, m_pOptions->m_recentOutputFiles); + m_pLineOut->setEditText(QUrl(outputName).toDisplayString()); + m_pLineOut->setMinimumWidth(200); + button = new QPushButton(QIcon::fromTheme("document-new"), i18n("File..."), this); + connect(button, &QPushButton::clicked, this, &OpenDialog::selectOutputName); + button2 = new QPushButton(QIcon::fromTheme("document-open-folder"), i18n("Dir..."), this); + connect(button2, &QPushButton::clicked, this, &OpenDialog::selectOutputDir); + connect(m_pMerge, &QCheckBox::stateChanged, this, &OpenDialog::internalSlot); + connect(this, &OpenDialog::internalSignal, m_pLineOut, &QComboBox::setEnabled); + connect(this, &OpenDialog::internalSignal, button, &QPushButton::setEnabled); + connect(this, &OpenDialog::internalSignal, button2, &QPushButton::setEnabled); + + m_pMerge->setChecked(!bMerge); + m_pMerge->setChecked(bMerge); + // m_pLineOutput->setEnabled( bMerge ); + + // button->setEnabled( bMerge ); + + h->addWidget(label, 4, 0); + h->addWidget(m_pLineOut, 4, 1); + h->addWidget(button, 4, 2); + h->addWidget(button2, 4, 3); + + h->addItem(new QSpacerItem(200, 0), 0, 1); + + QHBoxLayout* l = new QHBoxLayout(); + v->addLayout(l); + l->setSpacing(5); + + button = new QPushButton(QIcon::fromTheme("configure"), i18n("Configure..."), this); + connect(button, SIGNAL(clicked()), pParent, slotConfigure); + l->addWidget(button, 1); + + l->addStretch(1); + + button = new QPushButton(i18n("&OK"), this); + button->setDefault(true); + connect(button, &QPushButton::clicked, this, &OpenDialog::accept); + l->addWidget(button, 1); + + button = new QPushButton(i18n("&Cancel"), this); + connect(button, &QPushButton::clicked, this, &OpenDialog::reject); + l->addWidget(button, 1); + + QSize sh = sizeHint(); + setFixedHeight(sh.height()); + m_bInputFileNameChanged = false; #ifdef _WIN32 - m_pLineA->lineEdit()->installEventFilter( this ); - m_pLineB->lineEdit()->installEventFilter( this ); - m_pLineC->lineEdit()->installEventFilter( this ); - m_pLineOut->lineEdit()->installEventFilter( this ); + m_pLineA->lineEdit()->installEventFilter(this); + m_pLineB->lineEdit()->installEventFilter(this); + m_pLineC->lineEdit()->installEventFilter(this); + m_pLineOut->lineEdit()->installEventFilter(this); #endif } // Eventfilter: Only needed under Windows. // Without this, files dropped in the line edit have URL-encoding. // This eventfilter decodes the filenames as needed by KDiff3. bool OpenDialog::eventFilter(QObject* o, QEvent* e) { - if ( e->type()==QEvent::DragEnter ) - { - QDragEnterEvent* d = static_cast(e); - d->setAccepted( d->mimeData()->hasUrls() ); - return true; - } - if (e->type()==QEvent::Drop) - { - QDropEvent* d = static_cast(e); - - if ( !d->mimeData()->hasUrls() ) - return false; - - QList lst = d->mimeData()->urls(); - - if ( lst.count() > 0 ) - { - static_cast(o)->setText( QDir::toNativeSeparators( lst[0].toLocalFile() ) ); - static_cast(o)->setFocus(); - } - - return true; - } - return false; -} + if(e->type() == QEvent::DragEnter) + { + QDragEnterEvent* d = static_cast(e); + d->setAccepted(d->mimeData()->hasUrls()); + return true; + } + if(e->type() == QEvent::Drop) + { + QDropEvent* d = static_cast(e); + + if(!d->mimeData()->hasUrls()) + return false; + + QList lst = d->mimeData()->urls(); + if(lst.count() > 0) + { + static_cast(o)->setText(QDir::toNativeSeparators(lst[0].toLocalFile())); + static_cast(o)->setFocus(); + } -void OpenDialog::selectURL( QComboBox* pLine, bool bDir, int i, bool bSave ) + return true; + } + return false; +} + +void OpenDialog::selectURL(QComboBox* pLine, bool bDir, int i, bool bSave) { QString current = pLine->currentText(); QUrl currentUrl; - if( current.isEmpty() && i > 3 ) { + if(current.isEmpty() && i > 3) { current = m_pLineC->currentText(); } - if( current.isEmpty() ) { + if(current.isEmpty()) { current = m_pLineB->currentText(); } - if( current.isEmpty() ) { + if(current.isEmpty()) { current = m_pLineA->currentText(); } currentUrl = QUrl::fromUserInput(current, QString(), QUrl::AssumeLocalFile); - QUrl newURL = bDir ? QFileDialog::getExistingDirectoryUrl( this, i18n("Open Directory"), currentUrl) - : bSave ? QFileDialog::getSaveFileUrl( this, i18n("Select Output File"), currentUrl, QLatin1Literal("all/allfiles") ) - : QFileDialog::getOpenFileUrl( this, i18n("Open File"), currentUrl, QLatin1Literal("all/allfiles") ); - if( !newURL.isEmpty() ) { + QUrl newURL = bDir ? QFileDialog::getExistingDirectoryUrl(this, i18n("Open Directory"), currentUrl) + : bSave ? QFileDialog::getSaveFileUrl(this, i18n("Select Output File"), currentUrl, QLatin1Literal("all/allfiles")) + : QFileDialog::getOpenFileUrl(this, i18n("Open File"), currentUrl, QLatin1Literal("all/allfiles")); + if(!newURL.isEmpty()) { /* Since we are selecting a directory open in the parent directory not the one selected. */ //QFileDialog::setStartDir( KIO::upUrl( newURL ) ); - pLine->setEditText( newURL.url() ); + pLine->setEditText(newURL.url()); } - // newURL won't be modified if nothing was selected. + // newURL won't be modified if nothing was selected. } -void OpenDialog::selectFileA() { selectURL( m_pLineA, false, 1, false ); } -void OpenDialog::selectFileB() { selectURL( m_pLineB, false, 2, false ); } -void OpenDialog::selectFileC() { selectURL( m_pLineC, false, 3, false ); } -void OpenDialog::selectOutputName(){ selectURL( m_pLineOut, false, 4, true ); } -void OpenDialog::selectDirA() { selectURL( m_pLineA, true, 1, false ); } -void OpenDialog::selectDirB() { selectURL( m_pLineB, true, 2, false ); } -void OpenDialog::selectDirC() { selectURL( m_pLineC, true, 3, false ); } -void OpenDialog::selectOutputDir() { selectURL( m_pLineOut, true, 4, true ); } +void OpenDialog::selectFileA() { selectURL(m_pLineA, false, 1, false); } +void OpenDialog::selectFileB() { selectURL(m_pLineB, false, 2, false); } +void OpenDialog::selectFileC() { selectURL(m_pLineC, false, 3, false); } +void OpenDialog::selectOutputName() { selectURL(m_pLineOut, false, 4, true); } +void OpenDialog::selectDirA() { selectURL(m_pLineA, true, 1, false); } +void OpenDialog::selectDirB() { selectURL(m_pLineB, true, 2, false); } +void OpenDialog::selectDirC() { selectURL(m_pLineC, true, 3, false); } +void OpenDialog::selectOutputDir() { selectURL(m_pLineOut, true, 4, true); } void OpenDialog::internalSlot(int i) { - emit internalSignal(i!=0); + emit internalSignal(i != 0); } -// Clear the output-filename when any input-filename changed, +// Clear the output-filename when any input-filename changed, // because users forgot to change the output and accidently overwrote it with // wrong data during a merge. void OpenDialog::inputFilenameChanged() { - if(!m_bInputFileNameChanged) - { - m_bInputFileNameChanged=true; - m_pLineOut->clearEditText(); - } + if(!m_bInputFileNameChanged) + { + m_bInputFileNameChanged = true; + m_pLineOut->clearEditText(); + } } -static void fixCurrentText( QComboBox* pCB ) +static void fixCurrentText(QComboBox* pCB) { - QString s = pCB->currentText(); + QString s = pCB->currentText(); - int pos = s.indexOf( '\n' ); - if ( pos>=0 ) - s=s.left(pos); - pos = s.indexOf( '\r' ); - if ( pos>=0 ) - s=s.left(pos); + int pos = s.indexOf('\n'); + if(pos >= 0) + s = s.left(pos); + pos = s.indexOf('\r'); + if(pos >= 0) + s = s.left(pos); - pCB->setEditText( s ); + pCB->setEditText(s); } void OpenDialog::accept() { - int maxNofRecentFiles = 10; - fixCurrentText( m_pLineA ); - - QString s = m_pLineA->currentText(); - s = QUrl::fromUserInput(s, QString(), QUrl::AssumeLocalFile).toLocalFile(); - QStringList* sl = &m_pOptions->m_recentAFiles; - // If an item exist, remove it from the list and reinsert it at the beginning. - sl->removeAll(s); - if ( !s.isEmpty() ) sl->prepend( s ); - if (sl->count()>maxNofRecentFiles) sl->erase( sl->begin()+maxNofRecentFiles, sl->end() ); - - fixCurrentText( m_pLineB ); - s = m_pLineB->currentText(); - s = QUrl::fromUserInput(s, QString(), QUrl::AssumeLocalFile).toLocalFile(); - sl = &m_pOptions->m_recentBFiles; - sl->removeAll(s); - if ( !s.isEmpty() ) sl->prepend( s ); - if (sl->count()>maxNofRecentFiles) sl->erase( sl->begin()+maxNofRecentFiles, sl->end() ); - - fixCurrentText( m_pLineC ); - s = m_pLineC->currentText(); - s = QUrl::fromUserInput(s, QString(), QUrl::AssumeLocalFile).toLocalFile(); - sl = &m_pOptions->m_recentCFiles; - sl->removeAll(s); - if ( !s.isEmpty() ) sl->prepend( s ); - if (sl->count()>maxNofRecentFiles) sl->erase( sl->begin()+maxNofRecentFiles, sl->end() ); - - fixCurrentText( m_pLineOut ); - s = m_pLineOut->currentText(); - s = QUrl::fromUserInput(s, QString(), QUrl::AssumeLocalFile).toLocalFile(); - sl = &m_pOptions->m_recentOutputFiles; - sl->removeAll(s); - if ( !s.isEmpty() ) sl->prepend( s ); - if (sl->count()>maxNofRecentFiles) sl->erase( sl->begin()+maxNofRecentFiles, sl->end() ); - - QDialog::accept(); + int maxNofRecentFiles = 10; + fixCurrentText(m_pLineA); + + QString s = m_pLineA->currentText(); + s = QUrl::fromUserInput(s, QString(), QUrl::AssumeLocalFile).toLocalFile(); + QStringList* sl = &m_pOptions->m_recentAFiles; + // If an item exist, remove it from the list and reinsert it at the beginning. + sl->removeAll(s); + if(!s.isEmpty()) sl->prepend(s); + if(sl->count() > maxNofRecentFiles) sl->erase(sl->begin() + maxNofRecentFiles, sl->end()); + + fixCurrentText(m_pLineB); + s = m_pLineB->currentText(); + s = QUrl::fromUserInput(s, QString(), QUrl::AssumeLocalFile).toLocalFile(); + sl = &m_pOptions->m_recentBFiles; + sl->removeAll(s); + if(!s.isEmpty()) sl->prepend(s); + if(sl->count() > maxNofRecentFiles) sl->erase(sl->begin() + maxNofRecentFiles, sl->end()); + + fixCurrentText(m_pLineC); + s = m_pLineC->currentText(); + s = QUrl::fromUserInput(s, QString(), QUrl::AssumeLocalFile).toLocalFile(); + sl = &m_pOptions->m_recentCFiles; + sl->removeAll(s); + if(!s.isEmpty()) sl->prepend(s); + if(sl->count() > maxNofRecentFiles) sl->erase(sl->begin() + maxNofRecentFiles, sl->end()); + + fixCurrentText(m_pLineOut); + s = m_pLineOut->currentText(); + s = QUrl::fromUserInput(s, QString(), QUrl::AssumeLocalFile).toLocalFile(); + sl = &m_pOptions->m_recentOutputFiles; + sl->removeAll(s); + if(!s.isEmpty()) sl->prepend(s); + if(sl->count() > maxNofRecentFiles) sl->erase(sl->begin() + maxNofRecentFiles, sl->end()); + + QDialog::accept(); } -void OpenDialog::slotSwapCopyNames( QAction* pAction ) // id selected in the popup menu +void OpenDialog::slotSwapCopyNames(QAction* pAction) // id selected in the popup menu { - int id = pAction->parentWidget()->actions().indexOf(pAction); - QComboBox* cb1=0; - QComboBox* cb2=0; - switch(id) - { - case 0: cb1=m_pLineA; cb2=m_pLineB; break; - case 1: cb1=m_pLineB; cb2=m_pLineC; break; - case 2: cb1=m_pLineC; cb2=m_pLineA; break; - case 3: cb1=m_pLineA; cb2=m_pLineOut; break; - case 4: cb1=m_pLineB; cb2=m_pLineOut; break; - case 5: cb1=m_pLineC; cb2=m_pLineOut; break; - case 6: cb1=m_pLineA; cb2=m_pLineOut; break; - case 7: cb1=m_pLineB; cb2=m_pLineOut; break; - case 8: cb1=m_pLineC; cb2=m_pLineOut; break; - } - if ( cb1 && cb2 ) - { - QString t1 = cb1->currentText(); - QString t2 = cb2->currentText(); - cb2->setEditText(t1); - if ( id<=2 || id>=6 ) - { - cb1->setEditText( t2 ); - } - } + int id = pAction->parentWidget()->actions().indexOf(pAction); + QComboBox* cb1 = 0; + QComboBox* cb2 = 0; + switch(id) + { + case 0: + cb1 = m_pLineA; + cb2 = m_pLineB; + break; + case 1: + cb1 = m_pLineB; + cb2 = m_pLineC; + break; + case 2: + cb1 = m_pLineC; + cb2 = m_pLineA; + break; + case 3: + cb1 = m_pLineA; + cb2 = m_pLineOut; + break; + case 4: + cb1 = m_pLineB; + cb2 = m_pLineOut; + break; + case 5: + cb1 = m_pLineC; + cb2 = m_pLineOut; + break; + case 6: + cb1 = m_pLineA; + cb2 = m_pLineOut; + break; + case 7: + cb1 = m_pLineB; + cb2 = m_pLineOut; + break; + case 8: + cb1 = m_pLineC; + cb2 = m_pLineOut; + break; + } + if(cb1 && cb2) + { + QString t1 = cb1->currentText(); + QString t2 = cb2->currentText(); + cb2->setEditText(t1); + if(id <= 2 || id >= 6) + { + cb1->setEditText(t2); + } + } } // FindDialog ********************************************* FindDialog::FindDialog(QWidget* pParent) -: QDialog( pParent ) + : QDialog(pParent) { - QGridLayout* layout = new QGridLayout( this ); - layout->setMargin(5); - layout->setSpacing(5); - - int line=0; - layout->addWidget( new QLabel(i18n("Search text:"),this), line, 0, 1, 2 ); - ++line; - - m_pSearchString = new QLineEdit( this ); - layout->addWidget( m_pSearchString, line, 0, 1, 2 ); - ++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, &QPushButton::clicked, this, &FindDialog::accept); - - pButton = new QPushButton( i18n("&Cancel"), this ); - layout->addWidget( pButton, line, 1 ); - connect(pButton, &QPushButton::clicked, this, &FindDialog::reject); - - hide(); + QGridLayout* layout = new QGridLayout(this); + layout->setMargin(5); + layout->setSpacing(5); + + int line = 0; + layout->addWidget(new QLabel(i18n("Search text:"), this), line, 0, 1, 2); + ++line; + + m_pSearchString = new QLineEdit(this); + layout->addWidget(m_pSearchString, line, 0, 1, 2); + ++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, &QPushButton::clicked, this, &FindDialog::accept); + + pButton = new QPushButton(i18n("&Cancel"), this); + layout->addWidget(pButton, line, 1); + connect(pButton, &QPushButton::clicked, this, &FindDialog::reject); + + hide(); } -void FindDialog::setVisible( bool bVisible ) +void FindDialog::setVisible(bool bVisible) { - QDialog::setVisible( bVisible ); - m_pSearchString->selectAll(); - m_pSearchString->setFocus(); + QDialog::setVisible(bVisible); + m_pSearchString->selectAll(); + m_pSearchString->setFocus(); } -RegExpTester::RegExpTester( QWidget* pParent, const QString& autoMergeRegExpToolTip, - const QString& historyStartRegExpToolTip, const QString& historyEntryStartRegExpToolTip, const QString& historySortKeyOrderToolTip ) -: QDialog( pParent) +RegExpTester::RegExpTester(QWidget* pParent, const QString& autoMergeRegExpToolTip, + const QString& historyStartRegExpToolTip, const QString& historyEntryStartRegExpToolTip, const QString& historySortKeyOrderToolTip) + : QDialog(pParent) { - int line=0; - setWindowTitle(i18n("Regular Expression Tester")); - QGridLayout* pGrid = new QGridLayout( this ); - pGrid->setSpacing(5); - pGrid->setMargin(5); - - QLabel* l = new QLabel(i18n("Auto merge regular expression:"), this); - pGrid->addWidget(l,line,0); - l->setToolTip( autoMergeRegExpToolTip ); - m_pAutoMergeRegExpEdit = new QLineEdit(this); - pGrid->addWidget(m_pAutoMergeRegExpEdit,line,1); - connect(m_pAutoMergeRegExpEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); - ++line; - - l = new QLabel(i18n("Example auto merge line:"), this); - pGrid->addWidget(l,line,0); - l->setToolTip( i18n("To test auto merge, copy a line as used in your files.") ); - m_pAutoMergeExampleEdit = new QLineEdit(this); - pGrid->addWidget(m_pAutoMergeExampleEdit,line,1); - connect(m_pAutoMergeExampleEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); - ++line; - - l = new QLabel(i18n("Match result:"), this); - pGrid->addWidget(l,line,0); - m_pAutoMergeMatchResult = new QLineEdit(this); - m_pAutoMergeMatchResult->setReadOnly(true); - pGrid->addWidget(m_pAutoMergeMatchResult,line,1); - ++line; - - pGrid->addItem( new QSpacerItem(100,20), line, 0 ); - pGrid->setRowStretch( line, 5); - ++line; - - l = new QLabel(i18n("History start regular expression:"), this); - pGrid->addWidget(l,line,0); - l->setToolTip( historyStartRegExpToolTip ); - m_pHistoryStartRegExpEdit = new QLineEdit(this); - pGrid->addWidget(m_pHistoryStartRegExpEdit,line,1); - connect(m_pHistoryStartRegExpEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); - ++line; - - l = new QLabel(i18n("Example history start line (with leading comment):"), this); - pGrid->addWidget(l,line,0); - l->setToolTip( i18n("Copy a history start line as used in your files,\n" - "including the leading comment.") ); - m_pHistoryStartExampleEdit = new QLineEdit(this); - pGrid->addWidget(m_pHistoryStartExampleEdit,line,1); - connect(m_pHistoryStartExampleEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); - ++line; - - l = new QLabel(i18n("Match result:"), this); - pGrid->addWidget(l,line,0); - m_pHistoryStartMatchResult = new QLineEdit(this); - m_pHistoryStartMatchResult->setReadOnly(true); - pGrid->addWidget(m_pHistoryStartMatchResult,line,1); - ++line; - - pGrid->addItem( new QSpacerItem(100,20), line, 0 ); - pGrid->setRowStretch( line, 5); - ++line; - - l = new QLabel(i18n("History entry start regular expression:"), this); - pGrid->addWidget(l,line,0); - l->setToolTip( historyEntryStartRegExpToolTip ); - m_pHistoryEntryStartRegExpEdit = new QLineEdit(this); - pGrid->addWidget(m_pHistoryEntryStartRegExpEdit,line,1); - connect(m_pHistoryEntryStartRegExpEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); - ++line; - - l = new QLabel(i18n("History sort key order:"), this); - pGrid->addWidget(l,line,0); - l->setToolTip( historySortKeyOrderToolTip ); - m_pHistorySortKeyOrderEdit = new QLineEdit(this); - pGrid->addWidget(m_pHistorySortKeyOrderEdit,line,1); - connect(m_pHistorySortKeyOrderEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); - ++line; - - l = new QLabel(i18n("Example history entry start line (without leading comment):"), this); - pGrid->addWidget(l,line,0); - l->setToolTip( i18n("Copy a history entry start line as used in your files,\n" - "but omit the leading comment.") ); - m_pHistoryEntryStartExampleEdit = new QLineEdit(this); - pGrid->addWidget(m_pHistoryEntryStartExampleEdit,line,1); - connect(m_pHistoryEntryStartExampleEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); - ++line; - - l = new QLabel(i18n("Match result:"), this); - pGrid->addWidget(l,line,0); - m_pHistoryEntryStartMatchResult = new QLineEdit(this); - m_pHistoryEntryStartMatchResult->setReadOnly(true); - pGrid->addWidget(m_pHistoryEntryStartMatchResult,line,1); - ++line; - - l = new QLabel(i18n("Sort key result:"), this); - pGrid->addWidget(l,line,0); - m_pHistorySortKeyResult = new QLineEdit(this); - m_pHistorySortKeyResult->setReadOnly(true); - pGrid->addWidget(m_pHistorySortKeyResult,line,1); - ++line; - - QPushButton* pButton = new QPushButton(i18n("OK"), this); - pGrid->addWidget(pButton,line,0); - connect(pButton, &QPushButton::clicked, this, &RegExpTester::accept); - - pButton = new QPushButton(i18n("Cancel"), this); - pGrid->addWidget(pButton,line,1); - connect(pButton, &QPushButton::clicked, this, &RegExpTester::reject); - - resize( 800, sizeHint().height() ); + int line = 0; + setWindowTitle(i18n("Regular Expression Tester")); + QGridLayout* pGrid = new QGridLayout(this); + pGrid->setSpacing(5); + pGrid->setMargin(5); + + QLabel* l = new QLabel(i18n("Auto merge regular expression:"), this); + pGrid->addWidget(l, line, 0); + l->setToolTip(autoMergeRegExpToolTip); + m_pAutoMergeRegExpEdit = new QLineEdit(this); + pGrid->addWidget(m_pAutoMergeRegExpEdit, line, 1); + connect(m_pAutoMergeRegExpEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); + ++line; + + l = new QLabel(i18n("Example auto merge line:"), this); + pGrid->addWidget(l, line, 0); + l->setToolTip(i18n("To test auto merge, copy a line as used in your files.")); + m_pAutoMergeExampleEdit = new QLineEdit(this); + pGrid->addWidget(m_pAutoMergeExampleEdit, line, 1); + connect(m_pAutoMergeExampleEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); + ++line; + + l = new QLabel(i18n("Match result:"), this); + pGrid->addWidget(l, line, 0); + m_pAutoMergeMatchResult = new QLineEdit(this); + m_pAutoMergeMatchResult->setReadOnly(true); + pGrid->addWidget(m_pAutoMergeMatchResult, line, 1); + ++line; + + pGrid->addItem(new QSpacerItem(100, 20), line, 0); + pGrid->setRowStretch(line, 5); + ++line; + + l = new QLabel(i18n("History start regular expression:"), this); + pGrid->addWidget(l, line, 0); + l->setToolTip(historyStartRegExpToolTip); + m_pHistoryStartRegExpEdit = new QLineEdit(this); + pGrid->addWidget(m_pHistoryStartRegExpEdit, line, 1); + connect(m_pHistoryStartRegExpEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); + ++line; + + l = new QLabel(i18n("Example history start line (with leading comment):"), this); + pGrid->addWidget(l, line, 0); + l->setToolTip(i18n("Copy a history start line as used in your files,\n" + "including the leading comment.")); + m_pHistoryStartExampleEdit = new QLineEdit(this); + pGrid->addWidget(m_pHistoryStartExampleEdit, line, 1); + connect(m_pHistoryStartExampleEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); + ++line; + + l = new QLabel(i18n("Match result:"), this); + pGrid->addWidget(l, line, 0); + m_pHistoryStartMatchResult = new QLineEdit(this); + m_pHistoryStartMatchResult->setReadOnly(true); + pGrid->addWidget(m_pHistoryStartMatchResult, line, 1); + ++line; + + pGrid->addItem(new QSpacerItem(100, 20), line, 0); + pGrid->setRowStretch(line, 5); + ++line; + + l = new QLabel(i18n("History entry start regular expression:"), this); + pGrid->addWidget(l, line, 0); + l->setToolTip(historyEntryStartRegExpToolTip); + m_pHistoryEntryStartRegExpEdit = new QLineEdit(this); + pGrid->addWidget(m_pHistoryEntryStartRegExpEdit, line, 1); + connect(m_pHistoryEntryStartRegExpEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); + ++line; + + l = new QLabel(i18n("History sort key order:"), this); + pGrid->addWidget(l, line, 0); + l->setToolTip(historySortKeyOrderToolTip); + m_pHistorySortKeyOrderEdit = new QLineEdit(this); + pGrid->addWidget(m_pHistorySortKeyOrderEdit, line, 1); + connect(m_pHistorySortKeyOrderEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); + ++line; + + l = new QLabel(i18n("Example history entry start line (without leading comment):"), this); + pGrid->addWidget(l, line, 0); + l->setToolTip(i18n("Copy a history entry start line as used in your files,\n" + "but omit the leading comment.")); + m_pHistoryEntryStartExampleEdit = new QLineEdit(this); + pGrid->addWidget(m_pHistoryEntryStartExampleEdit, line, 1); + connect(m_pHistoryEntryStartExampleEdit, &QLineEdit::textChanged, this, &RegExpTester::slotRecalc); + ++line; + + l = new QLabel(i18n("Match result:"), this); + pGrid->addWidget(l, line, 0); + m_pHistoryEntryStartMatchResult = new QLineEdit(this); + m_pHistoryEntryStartMatchResult->setReadOnly(true); + pGrid->addWidget(m_pHistoryEntryStartMatchResult, line, 1); + ++line; + + l = new QLabel(i18n("Sort key result:"), this); + pGrid->addWidget(l, line, 0); + m_pHistorySortKeyResult = new QLineEdit(this); + m_pHistorySortKeyResult->setReadOnly(true); + pGrid->addWidget(m_pHistorySortKeyResult, line, 1); + ++line; + + QPushButton* pButton = new QPushButton(i18n("OK"), this); + pGrid->addWidget(pButton, line, 0); + connect(pButton, &QPushButton::clicked, this, &RegExpTester::accept); + + pButton = new QPushButton(i18n("Cancel"), this); + pGrid->addWidget(pButton, line, 1); + connect(pButton, &QPushButton::clicked, this, &RegExpTester::reject); + + resize(800, sizeHint().height()); } -void RegExpTester::init( const QString& autoMergeRegExp, const QString& historyStartRegExp, const QString& historyEntryStartRegExp, const QString historySortKeyOrder ) +void RegExpTester::init(const QString& autoMergeRegExp, const QString& historyStartRegExp, const QString& historyEntryStartRegExp, const QString historySortKeyOrder) { - m_pAutoMergeRegExpEdit->setText( autoMergeRegExp ); - m_pHistoryStartRegExpEdit->setText( historyStartRegExp ); - m_pHistoryEntryStartRegExpEdit->setText( historyEntryStartRegExp ); - m_pHistorySortKeyOrderEdit->setText( historySortKeyOrder ); + m_pAutoMergeRegExpEdit->setText(autoMergeRegExp); + m_pHistoryStartRegExpEdit->setText(historyStartRegExp); + m_pHistoryEntryStartRegExpEdit->setText(historyEntryStartRegExp); + m_pHistorySortKeyOrderEdit->setText(historySortKeyOrder); } QString RegExpTester::autoMergeRegExp() { - return m_pAutoMergeRegExpEdit->text(); + return m_pAutoMergeRegExpEdit->text(); } QString RegExpTester::historyStartRegExp() { - return m_pHistoryStartRegExpEdit->text(); + return m_pHistoryStartRegExpEdit->text(); } QString RegExpTester::historyEntryStartRegExp() { - return m_pHistoryEntryStartRegExpEdit->text(); + return m_pHistoryEntryStartRegExpEdit->text(); } QString RegExpTester::historySortKeyOrder() { - return m_pHistorySortKeyOrderEdit->text(); + return m_pHistorySortKeyOrderEdit->text(); } void RegExpTester::slotRecalc() { - QRegExp autoMergeRegExp( m_pAutoMergeRegExpEdit->text() ); - if ( autoMergeRegExp.exactMatch( m_pAutoMergeExampleEdit->text() ) ) - { - m_pAutoMergeMatchResult->setText( i18n("Match success.") ); - } - else - { - m_pAutoMergeMatchResult->setText( i18n("Match failed.") ); - } - - QRegExp historyStartRegExp( m_pHistoryStartRegExpEdit->text() ); - if ( historyStartRegExp.exactMatch( m_pHistoryStartExampleEdit->text() ) ) - { - m_pHistoryStartMatchResult->setText( i18n("Match success.") ); - } - else - { - m_pHistoryStartMatchResult->setText( i18n("Match failed.") ); - } - - - QStringList parenthesesGroups; - bool bSuccess = findParenthesesGroups( m_pHistoryEntryStartRegExpEdit->text(), parenthesesGroups ); - if ( ! bSuccess ) - { - m_pHistoryEntryStartMatchResult->setText( i18n("Opening and closing parentheses do not match in regular expression.") ); - m_pHistorySortKeyResult->setText( "" ); - return; - } - QRegExp historyEntryStartRegExp( m_pHistoryEntryStartRegExpEdit->text() ); - QString s = m_pHistoryEntryStartExampleEdit->text(); - - if ( historyEntryStartRegExp.exactMatch( s ) ) - { - m_pHistoryEntryStartMatchResult->setText( i18n("Match success.") ); - QString key = calcHistorySortKey( m_pHistorySortKeyOrderEdit->text(),historyEntryStartRegExp,parenthesesGroups); - m_pHistorySortKeyResult->setText(key); - } - else - { - m_pHistoryEntryStartMatchResult->setText( i18n("Match failed.") ); - m_pHistorySortKeyResult->setText( "" ); - } + QRegExp autoMergeRegExp(m_pAutoMergeRegExpEdit->text()); + if(autoMergeRegExp.exactMatch(m_pAutoMergeExampleEdit->text())) + { + m_pAutoMergeMatchResult->setText(i18n("Match success.")); + } + else + { + m_pAutoMergeMatchResult->setText(i18n("Match failed.")); + } + + QRegExp historyStartRegExp(m_pHistoryStartRegExpEdit->text()); + if(historyStartRegExp.exactMatch(m_pHistoryStartExampleEdit->text())) + { + m_pHistoryStartMatchResult->setText(i18n("Match success.")); + } + else + { + m_pHistoryStartMatchResult->setText(i18n("Match failed.")); + } + + QStringList parenthesesGroups; + bool bSuccess = findParenthesesGroups(m_pHistoryEntryStartRegExpEdit->text(), parenthesesGroups); + if(!bSuccess) + { + m_pHistoryEntryStartMatchResult->setText(i18n("Opening and closing parentheses do not match in regular expression.")); + m_pHistorySortKeyResult->setText(""); + return; + } + QRegExp historyEntryStartRegExp(m_pHistoryEntryStartRegExpEdit->text()); + QString s = m_pHistoryEntryStartExampleEdit->text(); + + if(historyEntryStartRegExp.exactMatch(s)) + { + m_pHistoryEntryStartMatchResult->setText(i18n("Match success.")); + QString key = calcHistorySortKey(m_pHistorySortKeyOrderEdit->text(), historyEntryStartRegExp, parenthesesGroups); + m_pHistorySortKeyResult->setText(key); + } + else + { + m_pHistoryEntryStartMatchResult->setText(i18n("Match failed.")); + m_pHistorySortKeyResult->setText(""); + } } //#include "smalldialogs.moc"