...
 
Commits (122)
......@@ -25,7 +25,7 @@ include(ECMInstallIcons)
include(ECMAddAppIcon)
include(ECMSetupVersion)
ecm_setup_version(1.8.0 VARIABLE_PREFIX KDIFF3 VERSION_HEADER ${CMAKE_BINARY_DIR}/src/version.h)
ecm_setup_version(1.9.70 VARIABLE_PREFIX KDIFF3 VERSION_HEADER ${CMAKE_BINARY_DIR}/src/version.h)
find_package(
Qt5 ${QT_MIN_VERSION}
......@@ -45,13 +45,17 @@ find_package(
I18n
CoreAddons
Crash
DocTools
IconThemes
OPTIONAL_COMPONENTS
DocTools
)
set_package_properties(KF5DocTools PROPERTIES PURPOSE "Allows generating and installing docs.")
option(ENABLE_AUTO "Enable kdiff3's '--auto' flag" ON)
option(ENABLE_CLANG_TIDY "Run clang-tidy if available and cmake version >=3.6" OFF)
set(KDiff3_LIBRARIES ${Qt5PrintSupport_LIBRARIES} KF5::I18n KF5::CoreAddons KF5::Crash KF5::IconThemes )
set(KDiff3_LIBRARIES ${Qt5PrintSupport_LIBRARIES} KF5::I18n KF5::CoreAddons KF5::IconThemes )
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
#Adjust clang specific warnings
......@@ -89,6 +93,12 @@ set(
cxx_static_assert
)
if(ENABLE_AUTO)
add_definitions(
-DENABLE_AUTO
)
endif()
add_definitions(
-DQT_DEPRECATED_WARNINGS #Get warnings from QT about deprecated functions.
-DQT_NO_URL_CAST_FROM_STRING # casting from string to url does not always behave as you might think
......@@ -97,11 +107,15 @@ add_definitions(
)
add_subdirectory(src)
add_subdirectory(doc)
add_subdirectory(kdiff3fileitemactionplugin)
if(KF5DocTools_FOUND)
add_subdirectory(doc)
kdoctools_install(po)
else()
message(WARNING "DocTools not found.")
endif()
ki18n_install(po)
kdoctools_install(po)
add_subdirectory(kdiff3fileitemactionplugin)
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
......@@ -38,9 +38,20 @@ You may also have exempt your craft directory from virus scans as these can inte
1)cd to your craft root
Run:
2)C:\CraftRoot\craft\craftenv.ps1
3)craft --package kdiff3
3)craft png2ico
4)craft kdiff3
At this point you can run kdiff3 itself via the following:
cb kdiff3
bin/kdiff3
If you want to create an install package you would run:
5)craft nsis
6)craft --package kdiff3
This will be a time consuming process on first run as craft will have download all dependencies.
KDiff3 does not require special configuration for craft.
KDiff3 does not require special configuration for craft.
There should be an installer package generated in CraftRoot/tmp
Please contact kde-windows@kde.org before file a bug report regarding this process.
\ No newline at end of file
......@@ -24,9 +24,9 @@
*
*/
#ifndef __class_factory_h__
#define __class_factory_h__
#ifndef class_factory_h
#define class_factory_h
#include <shlobj.h>
#include <shlguid.h>
......@@ -43,9 +43,9 @@ class CLASS_FACTORY : public IClassFactory {
//ICLASS_FACTORY members
STDMETHODIMP CreateInstance(IUnknown*, REFIID, void**);
STDMETHODIMP LockServer(BOOL);
private:
ULONG _ref_count;
};
#endif //__class_factory_h__
#endif //class_factory_h
......@@ -26,149 +26,15 @@
#define _CRT_SECURE_NO_DEPRECATE
#include "diff_ext.h"
#include <assert.h>
#include <stdio.h>
#include <tchar.h>
#include "diff_ext.h"
#include <map>
#include <vector>
#ifdef UNICODE
static void parseString( const std::wstring& s, size_t& i /*pos*/, std::wstring& r /*result*/ )
{
size_t size = s.size();
++i; // Skip initial '"'
for( ; i<size; ++i )
{
if ( s[i]=='"' )
{
++i;
break;
}
else if ( s[i]==L'\\' && i+1<size )
{
++i;
switch( s[i] ) {
case L'n': r+=L'\n'; break;
case L'r': r+=L'\r'; break;
case L'\\': r+=L'\\'; break;
case L'"': r+=L'"'; break;
case L't': r+=L'\t'; break;
default: r+=L'\\'; r+=s[i]; break;
}
}
else
r+=s[i];
}
}
static std::map< std::wstring, std::wstring > s_translationMap;
static tstring s_translationFileName;
void readTranslationFile()
{
s_translationMap.clear();
FILE* pFile = _tfopen( s_translationFileName.c_str(), TEXT("rb") );
if ( pFile )
{
MESSAGELOG( TEXT( "Reading translations: " ) + s_translationFileName );
std::vector<char> buffer;
try {
if ( fseek(pFile, 0, SEEK_END)==0 )
{
size_t length = ftell(pFile); // Get the file length
buffer.resize(length);
fseek(pFile, 0, SEEK_SET );
fread(&buffer[0], 1, length, pFile );
}
}
catch(...)
{
}
fclose(pFile);
if (buffer.size()>0)
{
size_t bufferSize = buffer.size();
int offset = 0;
if ( buffer[0]=='\xEF' && buffer[1]=='\xBB' && buffer[2]=='\xBF' )
{
offset += 3;
bufferSize -= 3;
}
size_t sLength = MultiByteToWideChar(CP_UTF8,0,&buffer[offset], (int)bufferSize, 0, 0 );
std::wstring s( sLength, L' ' );
MultiByteToWideChar(CP_UTF8,0,&buffer[offset], (int)bufferSize, &s[0], (int)s.size() );
// Now analyze the file and extract translation strings
std::wstring msgid;
std::wstring msgstr;
msgid.reserve( 1000 );
msgstr.reserve( 1000 );
bool bExpectingId = true;
for( size_t i=0; i<sLength; ++i )
{
wchar_t c = s[i];
if( c == L'\n' || c == L'\r' || c==L' ' || c==L'\t' )
continue;
else if ( s[i]==L'#' ) // Comment
while( s[i]!='\n' && s[i]!=L'\r' && i<sLength )
++i;
else if ( s[i]==L'"' )
{
if ( bExpectingId ) parseString(s,i,msgid);
else parseString(s,i,msgstr);
}
else if ( sLength-i>5 && wcsncmp( &s[i], L"msgid", 5 )==0 )
{
if ( !msgid.empty() && !msgstr.empty() )
{
s_translationMap[msgid] = msgstr;
}
bExpectingId = true;
msgid.clear();
i+=4;
}
else if ( sLength-i>6 && wcsncmp( &s[i], L"msgstr", 6 )==0 )
{
bExpectingId = false;
msgstr.clear();
i+=5;
}
else
{
// Unexpected ?
}
}
}
}
else
{
ERRORLOG( TEXT( "Reading translations failed: " ) + s_translationFileName );
}
}
static tstring getTranslation( const tstring& fallback )
{
std::map< std::wstring, std::wstring >::iterator i = s_translationMap.find( fallback );
if (i!=s_translationMap.end())
return i->second;
return fallback;
}
#else
static tstring getTranslation( const tstring& fallback )
{
return fallback;
}
#endif
static void replaceArgs( tstring& s, const tstring& r1, const tstring& r2=TEXT(""), const tstring& r3=TEXT("") )
{
tstring arg1 = TEXT("%1");
......@@ -265,17 +131,6 @@ DIFF_EXT::Initialize(LPCITEMIDLIST /*folder not used*/, IDataObject* data, HKEY
{
LOG();
#ifdef UNICODE
tstring installDir = SERVER::instance()->getRegistryKeyString( TEXT(""), TEXT("InstallDir") );
tstring language = SERVER::instance()->getRegistryKeyString( TEXT(""), TEXT("Language") );
tstring translationFileName = installDir + TEXT("\\translations\\diff_ext_") + language + TEXT(".po");
if ( s_translationFileName != translationFileName )
{
s_translationFileName = translationFileName;
readTranslationFile();
}
#endif
FORMATETC format = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM medium;
medium.tymed = TYMED_HGLOBAL;
......@@ -288,8 +143,6 @@ DIFF_EXT::Initialize(LPCITEMIDLIST /*folder not used*/, IDataObject* data, HKEY
TCHAR tmp[MAX_PATH];
//initialize_language();
if (m_nrOfSelectedFiles >= 1 && m_nrOfSelectedFiles <= 3)
{
DragQueryFile(drop, 0, tmp, MAX_PATH);
......
......@@ -25,8 +25,8 @@
*/
#ifndef __diff_ext_h__
#define __diff_ext_h__
#ifndef diff_ext_h
#define diff_ext_h
#include <windows.h>
#include <windowsx.h>
......@@ -58,7 +58,6 @@ class DIFF_EXT : public IContextMenu, IShellExtInit {
void diff( const tstring& arguments );
void diff_with(unsigned int num, bool bMerge);
tstring cut_to_length(const tstring&, size_t length = 64);
void initialize_language();
private:
UINT m_nrOfSelectedFiles;
......
......@@ -25,8 +25,8 @@
*/
#ifndef __string_h__
#define __string_h__
#ifndef string_h
#define string_h
#include <windows.h>
#include <tchar.h>
......@@ -41,18 +41,18 @@ class STRING {
public:
static const int begin = 0;
static const int end = -1;
public:
STRING(const STRING& s) {
_str = new TCHAR[s.length()+1];
lstrcpy(_str, s);
}
STRING(const TCHAR* str = TEXT("")) {
_str = new TCHAR[lstrlen(str)+1];
lstrcpy(_str, str);
}
~STRING() {
delete[] _str;
}
......@@ -70,18 +70,18 @@ class STRING {
p[newLength]=0;
}
}
STRING& operator=(const STRING& s) {
delete[] _str;
_str = new TCHAR[s.length()+1];
lstrcpy(_str, s);
return *this;
}
operator TCHAR*() {
return _str;
}
operator const TCHAR*() const {
return _str;
}
......@@ -89,11 +89,11 @@ class STRING {
const TCHAR* c_str() const {
return _str;
}
size_t length() const {
return _tcslen(_str);
}
// Also returns the length. Behaviour like std::basic_string::size.
// See also sizeInBytes() below.
size_t size() const {
......@@ -109,21 +109,21 @@ class STRING {
{
return length()==0;
}
STRING substr(size_t from, size_t len=size_t(-1)) const {
STRING tmp;
size_t to = len==size_t(-1) ? length() : from + len;
if(from < to && (to <= length())) {
size_t new_len = to - from + 1;
TCHAR* new_str = new TCHAR[new_len+1];
lstrcpyn(new_str, &_str[from], int(new_len) );
new_str[new_len] = 0;
tmp = new_str;
delete[] new_str;
}
return tmp;
}
......@@ -132,7 +132,7 @@ class STRING {
*this = substr( 0, pos ) + s + substr( pos+num );
return *this;
}
bool operator ==(const STRING& s) const {
return (lstrcmp(_str, s) == 0);
}
......@@ -145,17 +145,17 @@ class STRING {
else
return size_t(-1);
}
STRING& operator +=(const STRING& s) {
TCHAR* str = new TCHAR[lstrlen(_str)+s.length()+1];
lstrcpy(str, _str);
lstrcat(str, s);
delete[] _str;
_str = str;
return *this;
}
......@@ -165,9 +165,9 @@ class STRING {
inline STRING operator+( const STRING& s1, const STRING& s2) {
STRING tmp(s1);
tmp+=s2;
return tmp;
}
......
This diff is collapsed.
......@@ -23,8 +23,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __server_h__
#define __server_h__
#ifndef server_h
#define server_h
#include <list> // std::list
//#include <log/file_sink.h>
#include <windows.h>
......@@ -53,34 +53,34 @@ class SERVER {
public:
static SERVER* instance();
void initLogging();
public:
virtual ~SERVER();
tstring getRegistryKeyString( const tstring& subKey, const tstring& value );
HINSTANCE handle() const;
HRESULT do_register();
HRESULT do_unregister();
void lock();
void release();
ULONG reference_count() const {
return _reference_count;
}
std::list< tstring >& recent_files();
void save_history() const;
static void logMessage( const char* function, const char* file, int line, const tstring& msg );
private:
SERVER();
SERVER(const SERVER&) {}
private:
LONG _reference_count;
std::list<tstring>* m_pRecentFiles;
......
......@@ -54,7 +54,7 @@ Please respect the format of the date (YYYY-MM-DD) and of the version
Do NOT change these in the translation. -->
<date>2019-02-22</date>
<releaseinfo>1.08.00</releaseinfo>
<releaseinfo>1.09.70</releaseinfo>
<abstract>
......
......@@ -254,8 +254,8 @@ void KDiff3FileItemAction::slotMergeThreeWay()
if ( m_list.count() > 0 && s_pHistory && s_pHistory->count()>=2 )
{
QStringList args;
args << (*s_pHistory).at(1);
args << (*s_pHistory).at(0);
args << s_pHistory->at(1);
args << s_pHistory->at(0);
args << m_list.first().toDisplayString(QUrl::PreferLocalFile);
args << ("-o" + m_list.first().toDisplayString(QUrl::PreferLocalFile));
KProcess::startDetached ("kdiff3", args);
......
......@@ -49,7 +49,7 @@ private Q_SLOTS:
private:
QList<QUrl> m_list;
QWidget* m_pParentWidget;
QWidget* m_pParentWidget = nullptr;
//KFileItemListProperties m_fileItemInfos;
};
#endif
......@@ -9,12 +9,14 @@
"Name[ca]": "Compara/fusiona fitxers/directoris amb el KDiff3",
"Name[cs]": "Porovnávejte/slučujte soubory/adresáře pomocí KDiff3",
"Name[de]": "Dateien und Ordner vergleichen und zusammenführen mit KDiff3",
"Name[el]": "Σύγκριση/Συγχώνευση αρχείων/καταλόγων με το KDiff3",
"Name[en_GB]": "Compare/Merge Files/Directories with KDiff3",
"Name[es]": "Comparar o fusionar archivos o directorios con KDiff3",
"Name[fi]": "Vertaa ja yhdistä tiedostoja ja kansioita KDiff3:lla",
"Name[fr]": "Comparaison et fusion de fichiers ou de dossiers à l'aide de « KDiff3 »",
"Name[gl]": "Comparar ou mesturar ficheiros ou directorios con KDiff3",
"Name[it]": "Confronta e fonde i file o le cartelle con KDiff3",
"Name[ko]": "KDiff3으로 파일과 디렉터리를 비교하거나 병합",
"Name[nl]": "Vergelijk/Voeg samen bestanden/mappen met KDiff3",
"Name[pl]": "Porównuj/Scalaj pliki/katalogi z KDiff3",
"Name[pt]": "Comparar/Reunir os Ficheiros/Pastas com o KDiff3",
......@@ -23,6 +25,7 @@
"Name[sv]": "Jämför/Sammanfoga filer/kataloger med KDiff3",
"Name[uk]": "Порівняння та об'єднання файлів та каталогів за допомогою KDiff3",
"Name[x-test]": "xxCompare/Merge Files/Directories with KDiff3xx",
"Name[zh_CN]": "使用KDiff3比较/合并文件或文件夹",
"Name[zh_TW]": "使用 KDiff3 比較/合併檔案或資料夾",
"ServiceTypes": [
"KFileItemAction/Plugin"
......
......@@ -29,7 +29,9 @@ set(kdiff3part_PART_SRCS
SourceData.cpp
Overview.cpp
Logging.cpp
FileNameLineEdit.cpp )
FileNameLineEdit.cpp
MergeEditLine.cpp
Options.cpp )
add_library(kdiff3part MODULE ${kdiff3part_PART_SRCS})
......@@ -49,12 +51,14 @@ set(kdiff3_SRCS
${kdiff3part_PART_SRCS}
)
#cann't use add_subdirectory because it changes the scope.
include(icons/CMakeLists.txt)
add_executable(kdiff3 ${kdiff3_SRCS})
target_link_libraries(kdiff3 KF5::ConfigCore KF5::ConfigGui KF5::Parts KF5::Crash ${KDiff3_LIBRARIES} )
target_compile_features(kdiff3 PRIVATE ${needed_features})
install(TARGETS kdiff3 ${INSTALL_TARGETS_DEFAULT_ARGS})
install(TARGETS kdiff3 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
########### install files ###############
......@@ -66,4 +70,3 @@ install( FILES kdiff3_shell.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/kdiff3 )
install( PROGRAMS org.kde.kdiff3.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
install( FILES org.kde.kdiff3.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} )
add_subdirectory(icons)
/**
*
* Copyright (C) 2018 Michael Reeves
*
* This file is part of Kdiff3.
*
* Kdiff3 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.
*
* Kdiff3 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 Kdiff3. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef LINEREF_H
#define LINEREF_H
#include "TypeUtils.h"
#include <stdlib.h>
#include <type_traits>
#include <QtGlobal>
class LineRef
{
public:
typedef qint32 LineType;
inline LineRef() = default;
inline LineRef(const LineType i) { mLineNumber = i; }
inline LineRef(const qint64 i)
{
if(i <= TYPE_MAX(LineType))
mLineNumber = (LineType)i;
else
mLineNumber = -1;
}
inline operator LineType() const { return mLineNumber; }
inline LineRef& operator=(const LineType lineIn) {
mLineNumber = lineIn;
return *this;
}
inline LineRef& operator+=(const LineType& inLine)
{
mLineNumber += inLine;
return *this;
};
LineRef& operator++()
{
++mLineNumber;
return *this;
};
const LineRef operator++(int)
{
LineRef line(*this);
++mLineNumber;
return line;
};
LineRef& operator--()
{
--mLineNumber;
return *this;
};
const LineRef operator--(int)
{
LineRef line(*this);
--mLineNumber;
return line;
};
inline void invalidate() { mLineNumber = -1; }
inline bool isValid() const { return mLineNumber != -1; }
private:
LineType mLineNumber = -1;
};
static_assert(std::is_copy_constructible<LineRef>::value, "LineRef must be copt constuctible.");
static_assert(std::is_copy_assignable<LineRef>::value, "LineRef must copy assignable.");
static_assert(std::is_move_constructible<LineRef>::value, "LineRef must be move constructible.");
static_assert(std::is_move_assignable<LineRef>::value, "LineRef must be move assignable.");
static_assert(std::is_convertible<LineRef, int>::value, "Can not convert LineRef to int.");
static_assert(std::is_convertible<int, LineRef>::value, "Can not convert int to LineRef.");
typedef LineRef::LineType LineCount;
typedef LineRef::LineType LineIndex;
#endif
......@@ -19,4 +19,7 @@
#include "Logging.h"
Q_LOGGING_CATEGORY(kdeMain, "org.kde.kdiff3")
Q_LOGGING_CATEGORY(kdiffMain, "org.kde.kdiff3")
Q_LOGGING_CATEGORY(kdiffFileAccess, "org.kde.kdiff3.fileAccess")
//The following is very noisey if debug is turned on and not really useful unless your making changes in the core data processing.
Q_LOGGING_CATEGORY(kdiffCore, "org.kde.kdiff3.core", QtWarningMsg)
......@@ -21,5 +21,9 @@
#define LOGGING_H
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(kdeMain)
Q_DECLARE_LOGGING_CATEGORY(kdiffMain)
Q_DECLARE_LOGGING_CATEGORY(kdiffFileAccess);
Q_DECLARE_LOGGING_CATEGORY(kdiffCore) //very noisey shows internal state information for kdiffs core.
#endif // !LOGGING_H
/***************************************************************************
* Copyright (C) 2002-2007 by Joachim Eibl <joachim.eibl at gmx.de> *
* Copyright (C) 2018 Michael Reeves reeves.87@gmail.com *
* *
* 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 "MergeEditLine.h"
QString MergeEditLine::getString(const QVector<LineData>* pLineDataA, const QVector<LineData>* pLineDataB, const QVector<LineData>* pLineDataC)
{
if(isRemoved())
{
return QString();
}
if(!isModified())
{
int src = m_src;
if(src == 0)
{
return QString();
}
const Diff3Line& d3l = *m_id3l;
const LineData* pld = nullptr;
Q_ASSERT(src == A || src == B || src == C);
if(src == A && d3l.getLineA().isValid())
pld = &(*pLineDataA)[d3l.getLineA()];
else if(src == B && d3l.getLineB().isValid())
pld = &(*pLineDataB)[d3l.getLineB()];
else if(src == C && d3l.getLineC().isValid())
pld = &(*pLineDataC)[d3l.getLineC()];
//Not an error.
if(pld == nullptr)
{
return QString();
}
return pld->getLine();
}
else
{
return m_str;
}
return QString();
}
/***************************************************************************
* Copyright (C) 2002-2007 by Joachim Eibl <joachim.eibl at gmx.de> *
* Copyright (C) 2018 Michael Reeves reeves.87@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef MERGEEDITLINE_H
#include "diff.h"
#include <QString>
class MergeResultWindow;
class MergeEditLine
{
public:
explicit MergeEditLine(const Diff3LineList::const_iterator& i, e_SrcSelector src = None)
{
m_id3l = i;
m_src = src;
m_bLineRemoved = false;
}
void setConflict()
{
m_src = None;
m_bLineRemoved = false;
m_str = QString();
}
bool isConflict() { return m_src == None && !m_bLineRemoved && m_str.isEmpty(); }
void setRemoved(e_SrcSelector src = None)
{
m_src = src;
m_bLineRemoved = true;
m_str = QString();
}
bool isRemoved() { return m_bLineRemoved; }
bool isEditableText() { return !isConflict() && !isRemoved(); }
void setString(const QString& s)
{
m_str = s;
m_bLineRemoved = false;
m_src = None;
}
QString getString(const QVector<LineData>* pLineDataA, const QVector<LineData>* pLineDataB, const QVector<LineData>* pLineDataC);
bool isModified() { return !m_str.isEmpty() || (m_bLineRemoved && m_src == None); }
void setSource(e_SrcSelector src, bool bLineRemoved)
{
m_src = src;
m_bLineRemoved = bLineRemoved;
}
e_SrcSelector src() { return m_src; }
Diff3LineList::const_iterator id3l() { return m_id3l; }
private:
Diff3LineList::const_iterator m_id3l;
e_SrcSelector m_src; // 1, 2 or 3 for A, B or C respectively, or 0 when line is from neither source.
QString m_str; // String when modified by user or null-string when orig data is used.
bool m_bLineRemoved;
};
class MergeEditLineList :public std::list<MergeEditLine>
{ // I want to know the size immediately!
private:
typedef std::list<MergeEditLine> BASE;
public:
typedef std::list<MergeEditLine>::iterator iterator;
typedef std::list<MergeEditLine>::reverse_iterator reverse_iterator;
typedef std::list<MergeEditLine>::const_iterator const_iterator;
int size()
{
return (int)BASE::size();
}
};
class MergeLine
{
public:
Diff3LineList::const_iterator id3l;
LineIndex d3lLineIdx = -1; // Needed to show the correct window pos.
LineCount srcRangeLength = 0; // how many src-lines have this properties
e_MergeDetails mergeDetails = eDefault;
bool bConflict = false;
bool bWhiteSpaceConflict = false;
bool bDelta = false;
e_SrcSelector srcSelect = None;
MergeEditLineList mergeEditLineList;
void split(MergeLine& ml2, int d3lLineIdx2) // The caller must insert the ml2 after this ml in the m_mergeLineList
{
if(d3lLineIdx2 < d3lLineIdx || d3lLineIdx2 >= d3lLineIdx + srcRangeLength)
return; //Error
ml2.mergeDetails = mergeDetails;
ml2.bConflict = bConflict;
ml2.bWhiteSpaceConflict = bWhiteSpaceConflict;
ml2.bDelta = bDelta;
ml2.srcSelect = srcSelect;
ml2.d3lLineIdx = d3lLineIdx2;
ml2.srcRangeLength = srcRangeLength - (d3lLineIdx2 - d3lLineIdx);
srcRangeLength = d3lLineIdx2 - d3lLineIdx; // current MergeLine controls fewer lines
ml2.id3l = id3l;
for(int i = 0; i < srcRangeLength; ++i)
++ml2.id3l;
ml2.mergeEditLineList.clear();
// Search for best place to splice
for(MergeEditLineList::iterator i = mergeEditLineList.begin(); i != mergeEditLineList.end(); ++i)
{
if(i->id3l() == ml2.id3l)
{
ml2.mergeEditLineList.splice(ml2.mergeEditLineList.begin(), mergeEditLineList, i, mergeEditLineList.end());
return;
}
}
ml2.mergeEditLineList.push_back(MergeEditLine(ml2.id3l));
}
void join(MergeLine& ml2) // The caller must remove the ml2 from the m_mergeLineList after this call
{
srcRangeLength += ml2.srcRangeLength;
ml2.mergeEditLineList.clear();
mergeEditLineList.clear();
mergeEditLineList.push_back(MergeEditLine(id3l)); // Create a simple conflict
if(ml2.bConflict) bConflict = true;
if(!ml2.bWhiteSpaceConflict) bWhiteSpaceConflict = false;
if(ml2.bDelta) bDelta = true;
}
};
typedef std::list<MergeLine> MergeLineList;
#endif
This diff is collapsed.
......@@ -22,20 +22,38 @@
enum e_MergeOperation
{
eTitleId,
eNoOperation,
// Operations in sync mode (with only two directories):
eCopyAToB, eCopyBToA, eDeleteA, eDeleteB, eDeleteAB, eMergeToA, eMergeToB, eMergeToAB,
// Operations in merge mode (with two or three directories)
eCopyAToDest, eCopyBToDest, eCopyCToDest, eDeleteFromDest, eMergeABCToDest,
eMergeABToDest,
eConflictingFileTypes, // Error
eChangedAndDeleted, // Error
eConflictingAges // Equal age but files are not!
eTitleId,
eNoOperation,
// Operations in sync mode (with only two directories):
eCopyAToB,
eCopyBToA,
eDeleteA,
eDeleteB,
eDeleteAB,
eMergeToA,
eMergeToB,
eMergeToAB,
// Operations in merge mode (with two or three directories)
eCopyAToDest,
eCopyBToDest,
eCopyCToDest,
eDeleteFromDest,
eMergeABCToDest,
eMergeABToDest,
eConflictingFileTypes, // Error
eChangedAndDeleted, // Error
eConflictingAges // Equal age but files are not!
};
enum e_Age { eNew, eMiddle, eOld, eNotThere, eAgeEnd };
enum e_Age
{
eNew,
eMiddle,
eOld,
eNotThere,
eAgeEnd
};
enum e_OperationStatus
{
......@@ -48,22 +66,27 @@ enum e_OperationStatus
eOpStatusToDo
};
class DirectoryMergeWindow;
class MergeFileInfos
{
public:
MergeFileInfos();
~MergeFileInfos();
//bool operator>( const MergeFileInfos& );
QString subPath() const;
QString fileName() const;
bool isDirA() const { return m_pFileInfoA ? m_pFileInfoA->isDir() : false; }
bool isDirB() const { return m_pFileInfoB ? m_pFileInfoB->isDir() : false; }
bool isDirC() 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 isDirA() const { return m_pFileInfoA != nullptr ? m_pFileInfoA->isDir() : false; }
bool isDirB() const { return m_pFileInfoB != nullptr ? m_pFileInfoB->isDir() : false; }
bool isDirC() const { return m_pFileInfoC != nullptr ? m_pFileInfoC->isDir() : false; }
bool hasDir() const { return isDirA() || isDirB() || isDirC(); }
bool isLinkA() const { return m_pFileInfoA != nullptr ? m_pFileInfoA->isSymLink() : false; }
bool isLinkB() const { return m_pFileInfoB != nullptr ? m_pFileInfoB->isSymLink() : false; }
bool isLinkC() const { return m_pFileInfoC != nullptr ? m_pFileInfoC->isSymLink() : false; }
bool hasLink() const { return isLinkA() || isLinkB() || isLinkC(); }
bool existsInA() const { return m_pFileInfoA != nullptr; }
bool existsInB() const { return m_pFileInfoB != nullptr; }
bool existsInC() const { return m_pFileInfoC != nullptr; }
......@@ -107,15 +130,29 @@ class MergeFileInfos
inline void setOpStatus(const e_OperationStatus eOpStatus) { m_eOpStatus = eOpStatus; }
inline e_Age getAgeA() const { return m_ageA; }
inline void setAgeA(const e_Age inAge) { m_ageA = inAge; }
inline e_Age getAgeB() const { return m_ageB; }
inline void setAgeB(const e_Age inAge) { m_ageB = inAge; }
inline e_Age getAgeC() const { return m_ageC; }
inline void setAgeC(const e_Age inAge) { m_ageC = inAge; }
inline bool isEqualAB() const { return m_bEqualAB; }
inline bool isEqualAC() const { return m_bEqualAC; }
inline bool isEqualBC() const { return m_bEqualBC; }
bool compareFilesAndCalcAges(QStringList& errors, QSharedPointer<Options> const pOptions, DirectoryMergeWindow* pDMW);
void updateAge();
inline void startSimOp() { m_bSimOpComplete = false; }
inline bool isSimOpRunning() const { return !m_bOperationComplete; }
inline void endSimOp() { m_bSimOpComplete = true; }
inline void startOperation() { m_bOperationComplete = false; };
inline bool isOperationRunning() const { return !m_bOperationComplete; }
inline void endOperation() { m_bOperationComplete = true; };
private:
bool fastFileComparison(FileAccess& fi1, FileAccess& fi2, bool& bError, QString& status, QSharedPointer<Options> const pOptions);
inline void setAgeA(const e_Age inAge) { m_ageA = inAge; }
inline void setAgeB(const e_Age inAge) { m_ageB = inAge; }
inline void setAgeC(const e_Age inAge) { m_ageC = inAge; }
MergeFileInfos* m_pParent;
QList<MergeFileInfos*> m_children;
......@@ -124,9 +161,8 @@ class MergeFileInfos
FileAccess* m_pFileInfoC;
QSharedPointer<DirectoryInfo> m_dirInfo;
TotalDiffStatus m_totalDiffStatus;
public:
e_MergeOperation m_eMergeOperation;
e_OperationStatus m_eOpStatus;
......@@ -134,9 +170,9 @@ class MergeFileInfos
e_Age m_ageB;
e_Age m_ageC;
public:
bool m_bOperationComplete;
bool m_bSimOpComplete;
public:
bool m_bEqualAB;
bool m_bEqualAC;
......@@ -144,6 +180,8 @@ class MergeFileInfos
bool m_bConflictingAges; // Equal age but files are not!
};
QTextStream& operator<<(QTextStream& ts, MergeFileInfos& mfi);
class MfiCompare
{
Qt::SortOrder mOrder;
......
......@@ -18,18 +18,17 @@
* along with KDiff3. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPTIONITEMS_H
#define OPTIONITEMS_H
#include "common.h"
#include <QString>
#include <QComboBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QString>
#include <QTextCodec>
#include <QLineEdit>
#include <KLocalizedString>
......@@ -50,18 +49,21 @@ class OptionItemBase
virtual void read(ValueMap*) = 0;
void doPreserve()
{
if(!m_bPreserved) {
if(!m_bPreserved)
{
m_bPreserved = true;
preserve();
}
}
void doUnpreserve()
{
if(m_bPreserved) {
if(m_bPreserved)
{
unpreserve();
}
}
QString getSaveName() { return m_saveName; }
protected:
virtual void preserve() = 0;
virtual void unpreserve() = 0;
......@@ -87,12 +89,14 @@ class Option : public OptionItemBase
explicit Option(const T& defaultVal, const QString& saveName, T* pVar)
: Option<T>(pVar, defaultVal, saveName)
{}
{
}
explicit Option(T* pVar, const T& defaultValue, const QString& saveName)
: OptionItemBase(saveName)
{
m_pVar = pVar;
m_defaultVal = defaultValue;
m_pVar = pVar;
m_defaultVal = defaultValue;
}
void setToDefault() override {};
......@@ -100,24 +104,25 @@ class Option : public OptionItemBase
const T& getDefault() const { return m_defaultVal; };
const T getCurrent() const { return *m_pVar; };
virtual void setCurrent(const T inValue) { *m_pVar= inValue; }
virtual void setCurrent(const T inValue) { *m_pVar = inValue; }
void apply() override {};
virtual void apply(const T& inValue) { *m_pVar = inValue; }
void write(ValueMap* config) override { config->writeEntry(m_saveName, *m_pVar); }
void read(ValueMap* config) override { *m_pVar = config->readEntry(m_saveName, m_defaultVal); }
protected:
void preserve() override { m_preservedVal = *m_pVar; }
void unpreserve() override { *m_pVar = m_preservedVal; }
T* m_pVar;
T m_preservedVal;
T m_defaultVal;
private:
Q_DISABLE_COPY(Option)
Q_DISABLE_COPY(Option)
};
template <class T>
class OptionNum : public Option<T>
{
......@@ -126,19 +131,15 @@ class OptionNum : public Option<T>
explicit OptionNum(T* pVar, const QString& saveName)
: Option<T>(pVar, saveName)
{
stringValue = QLocale().toString(*pVar);
}
explicit OptionNum(T* pVar, const T& defaultValue, const QString& saveName)
: Option<T>(pVar, defaultValue, saveName)
{
stringValue = QLocale().toString(*pVar);
}
void setCurrent(const T inValue) override
{
//setNum does not use locale formatting instead it always use QLocale::C.
stringValue = QLocale().toString(inValue);
Option<T>::setCurrent(inValue);
}
......@@ -147,14 +148,13 @@ class OptionNum : public Option<T>
//QString::setNum does not use locale formatting instead it always use QLocale::C.
return QLocale().toString(inValue);
}
const QString& getString() const
const QString getString() const
{
return stringValue;
//QString::setNum does not use locale formatting instead it always use QLocale::C.
return QLocale().toString(Option<T>::getCurrent());
}
private:
QString stringValue;
Q_DISABLE_COPY(OptionNum)
};
......
/**
* Copyright (C) 2019 Michael Reeves <reeves.87@gmail.com>
*
* This file is part of KDiff3.
*
* KDiff3 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.
*
* KDiff3 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 KDiff3. If not, see <http://www.gnu.org/licenses/>.
*/
#include "options.h"
#include "ConfigValueMap.h"
#include "OptionItems.h"
#include <KSharedConfig>
#define KDIFF3_CONFIG_GROUP "KDiff3 Options"
void Options::init()
{
/*
TODO manage toolbar positioning
*/
addOptionItem(new OptionNum<int>( Qt::TopToolBarArea, "ToolBarPos", (int*)&m_toolBarPos));
addOptionItem(new OptionSize(QSize(600, 400), "Geometry", &m_geometry));
addOptionItem(new OptionPoint(QPoint(0, 22), "Position", &m_position));
addOptionItem(new OptionToggleAction(false, "WindowStateMaximised", &m_bMaximised));
addOptionItem(new OptionToggleAction(true, "Show Toolbar", &m_bShowToolBar));
addOptionItem(new OptionToggleAction(true, "Show Statusbar", &m_bShowStatusBar));
}
void Options::apply()
{
std::list<OptionItemBase*>::const_iterator i;
for(i = mOptionItemList.begin(); i != mOptionItemList.end(); ++i)
{
(*i)->apply();
}
}
void Options::resetToDefaults()
{
std::list<OptionItemBase*>::const_iterator i;
for(i = mOptionItemList.begin(); i != mOptionItemList.end(); ++i)
{
(*i)->setToDefault();
}
}
void Options::setToCurrent()
{
std::list<OptionItemBase*>::const_iterator i;
for(i = mOptionItemList.begin(); i != mOptionItemList.end(); ++i)
{
(*i)->setToCurrent();
}
}
void Options::saveOptions(const KSharedConfigPtr config)
{
// No i18n()-Translations here!
ConfigValueMap cvm(config->group(KDIFF3_CONFIG_GROUP));
std::list<OptionItemBase*>::const_iterator i;
for(i = mOptionItemList.begin(); i != mOptionItemList.end(); ++i)
{
(*i)->doUnpreserve();
(*i)->write(&cvm);
}
}
void Options::readOptions(const KSharedConfigPtr config)
{
// No i18n()-Translations here!
ConfigValueMap cvm(config->group(KDIFF3_CONFIG_GROUP));
std::list<OptionItemBase*>::const_iterator i;
for(i = mOptionItemList.begin(); i != mOptionItemList.end(); ++i)
{
(*i)->read(&cvm);
}
}
QString Options::parseOptions(const QStringList& optionList)
{
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<OptionItemBase*>::iterator j;
bool bFound = false;
for(j = mOptionItemList.begin(); j != mOptionItemList.end(); ++j)
{
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;
}
QString Options::calcOptionHelp()
{
ValueMap config;
std::list<OptionItemBase*>::const_iterator it;
for(it = mOptionItemList.begin(); it != mOptionItemList.end(); ++it)
{
(*it)->write(&config);
}
return config.getAsString();
}
void Options::addOptionItem(OptionItemBase* inItem)
{
mOptionItemList.push_back(inItem);
}
......@@ -9,9 +9,10 @@
* *
***************************************************************************/
#include "Overview.h"
#include "diff.h"
#include "mergeresultwindow.h"
#include "options.h"
#include "diff.h"
#include <QColor>
#include <QMouseEvent>
......@@ -19,7 +20,7 @@
#include <QPixmap>
#include <QSize>
Overview::Overview(Options* pOptions)
Overview::Overview(const QSharedPointer<Options> &pOptions)
//: QWidget( pParent, 0, Qt::WNoAutoErase )
{
m_pDiff3LineList = nullptr;
......@@ -53,13 +54,13 @@ void Overview::slotRedraw()
update();
}
void Overview::setRange(int firstLine, int pageHeight)
void Overview::setRange(QtNumberType firstLine, QtNumberType pageHeight)
{
m_firstLine = firstLine;
m_pageHeight = pageHeight;
update();
}
void Overview::setFirstLine(int firstLine)
void Overview::setFirstLine(QtNumberType firstLine)
{
m_firstLine = firstLine;
update();
......@@ -219,13 +220,13 @@ void Overview::drawColumn(QPainter& p, e_OverviewMode eOverviewMode, int x, int
if(!m_bTripleDiff)
{
if(d3l.getLineA() == -1 && d3l.getLineB() >= 0)
if(!d3l.getLineA().isValid() && d3l.getLineB().isValid())
{
c = m_pOptions->m_colorA;
x2 = w / 2;
w2 = x2;
}
if(d3l.getLineA() >= 0 && d3l.getLineB() == -1)
if(d3l.getLineA().isValid() && !d3l.getLineB().isValid())
{
c = m_pOptions->m_colorB;
w2 = w / 2;
......
......@@ -11,46 +11,54 @@
#ifndef OVERVIEW_H
#define OVERVIEW_H
#include "options.h"
#include "diff.h"
#include "options.h"
#include <QWidget>
#include <QPixmap>
#include <QWidget>
class Overview : public QWidget
{
Q_OBJECT
public:
explicit Overview( Options* pOptions );
void init( Diff3LineList* pDiff3LineList, bool bTripleDiff );
void reset();
void setRange( int firstLine, int pageHeight );
void setPaintingAllowed( bool bAllowPainting );
enum e_OverviewMode { eOMNormal, eOMAvsB, eOMAvsC, eOMBvsC };
void setOverviewMode( e_OverviewMode eOverviewMode );
e_OverviewMode getOverviewMode();
public Q_SLOTS:
void setFirstLine(int firstLine);
void slotRedraw();
Q_SIGNALS:
void setLine(int);
private:
const Diff3LineList* m_pDiff3LineList;
Options* m_pOptions;
bool m_bTripleDiff;
int m_firstLine;
int m_pageHeight;
QPixmap m_pixmap;
e_OverviewMode m_eOverviewMode;
int m_nofLines;
void paintEvent( QPaintEvent* e ) override;
void mousePressEvent( QMouseEvent* e ) override;
void mouseMoveEvent( QMouseEvent* e ) override;
void drawColumn( QPainter& p, e_OverviewMode eOverviewMode, int x, int w, int h, int nofLines );
Q_OBJECT
public:
enum e_OverviewMode
{
eOMNormal,
eOMAvsB,
eOMAvsC,
eOMBvsC
};
explicit Overview(const QSharedPointer<Options> &pOptions);
void init(Diff3LineList* pDiff3LineList, bool bTripleDiff);
void reset();
void setRange(QtNumberType firstLine, QtNumberType pageHeight);
void setPaintingAllowed(bool bAllowPainting);
void setOverviewMode(e_OverviewMode eOverviewMode);
e_OverviewMode getOverviewMode();
public Q_SLOTS:
void setFirstLine(QtNumberType firstLine);
void slotRedraw();
Q_SIGNALS:
void setLine(LineRef);
private:
const Diff3LineList* m_pDiff3LineList;
QSharedPointer<Options> m_pOptions;
bool m_bTripleDiff;
LineRef m_firstLine;
int m_pageHeight;
QPixmap m_pixmap;
e_OverviewMode m_eOverviewMode;
int m_nofLines;