...
 
Commits (50)
......@@ -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.8.2 VARIABLE_PREFIX KDIFF3 VERSION_HEADER ${CMAKE_BINARY_DIR}/src/version.h)
find_package(
Qt5 ${QT_MIN_VERSION}
......@@ -49,6 +49,7 @@ find_package(
IconThemes
)
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 )
......@@ -89,6 +90,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
......
......@@ -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.
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
......@@ -34,141 +34,6 @@
#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 +130,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 +142,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);
......
......@@ -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;
......
......@@ -41,10 +41,6 @@
#include <initguid.h>
#include <KLocalizedString>
//#include <log/log.h>
//#include <log/log_message.h>
//#include <log/file_sink.h>
//#include <debug/trace.h>
#include "server.h"
#include "class_factory.h"
......
......@@ -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.08.02</releaseinfo>
<abstract>
......
......@@ -49,7 +49,7 @@ private Q_SLOTS:
private:
QList<QUrl> m_list;
QWidget* m_pParentWidget;
QWidget* m_pParentWidget = nullptr;
//KFileItemListProperties m_fileItemInfos;
};
#endif
......@@ -15,6 +15,7 @@
"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 +24,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"
......
......@@ -49,6 +49,8 @@ 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} )
......@@ -66,4 +68,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)
......@@ -20,3 +20,4 @@
#include "Logging.h"
Q_LOGGING_CATEGORY(kdeMain, "org.kde.kdiff3")
Q_LOGGING_CATEGORY(kdiffFileAccess, "org.kde.kdiff3.fileAccess")
......@@ -22,4 +22,5 @@
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(kdeMain)
Q_DECLARE_LOGGING_CATEGORY(kdiffFileAccess)
#endif // !LOGGING_H
......@@ -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,7 +89,9 @@ 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)
{
......@@ -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)
};
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)
};
......
......@@ -193,7 +193,7 @@ const QString& SourceData::getText() const
bool SourceData::isText()
{
return m_normalData.isText();
return m_normalData.isText() || m_normalData.isEmpty();
}
bool SourceData::isIncompleteConversion()
......@@ -220,7 +220,7 @@ void SourceData::FileData::reset()
m_v.clear();
m_size = 0;
m_vSize = 0;
m_bIsText = true;
m_bIsText = false;
m_bIncompleteConversion = false;
m_eLineEndStyle = eLineEndStyleUndefined;
}
......@@ -501,6 +501,11 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
m_lmppData.copyBufFrom(m_normalData);
}
}
else
{
//exit early for non-existant files
return errors;
}
if(!m_lmppData.preprocess(false, pEncoding2))
{
......@@ -597,6 +602,9 @@ bool SourceData::FileData::preprocess(bool bPreserveCR, QTextCodec* pEncoding)
{
if(i >= ucSize || p[i] == '\n')
{
if(lines >= INT_MAX - 5)
return false;
++lines;
}
if(p[i].isNull())
......
......@@ -111,11 +111,11 @@ class SourceData
bool isEmpty() { return m_size == 0; }
bool isText() { return m_bIsText; }
bool isText() { return m_bIsText || isEmpty(); }
};
FileData m_normalData;
FileData m_lmppData;
QTextCodec* m_pEncoding;
QTextCodec* m_pEncoding = nullptr;
};
#endif // !SOURCEDATA_H
......@@ -21,6 +21,7 @@
#ifndef UTILS_H
#define UTILS_H
#include <QFontMetrics>
#include <QStringList>
#include <QString>
......@@ -28,6 +29,27 @@ class Utils{
public:
static bool wildcardMultiMatch(const QString& wildcard, const QString& testString, bool bCaseSensitive);
static QString getArguments(QString cmd, QString& program, QStringList& args);
//Where posiable use QTextLayout in place of these functions especially when dealing with non-latin scripts.
inline static int getHorizontalAdvance(const QFontMetrics &metrics, const QString& s, int len = -1)
{
//Warning: The Qt API used here is not accurate for some non-latin characters.
#if QT_VERSION < QT_VERSION_CHECK(5,12,0)
return metrics.width(s, len);
#else
return metrics.horizontalAdvance(s, len);
#endif
}
inline static int getHorizontalAdvance(const QFontMetrics &metrics, const QChar& c)
{
//Warning: The Qt API used here is not accurate for some non-latin characters.
#if QT_VERSION < QT_VERSION_CHECK(5,12,0)
return metrics.width(c);
#else
return metrics.horizontalAdvance(c);
#endif
}
};
#endif
......@@ -36,7 +36,7 @@ void CvsIgnoreList::init(FileAccess& dir, const t_DirectoryList* pDirList)
FileAccess file(dir);
file.addPath(".cvsignore");
qint64 size = file.exists() ? file.sizeForReading() : 0;
if(size > 0)
if(size > 0 && size <= (qint64)std::numeric_limits<int>::max())
{
char* buf = new char[size];
if(buf != nullptr)
......
......@@ -234,7 +234,7 @@ class Diff3LineList : public std::list<Diff3Line>
void calcWhiteDiff3Lines(const LineData* pldA, const LineData* pldB, const LineData* pldC);
//TODO: Add safety guards to prevent list from getting too large. Same problem as with QLinkedList.
int size() const {
if(std::list<Diff3Line>::size() > std::numeric_limits<int>::max())
if(std::list<Diff3Line>::size() > (size_t)std::numeric_limits<int>::max())//explicit cast insure correct results
{
qCDebug(kdeMain) << "Diff3Line: List too large. size=" << std::list<Diff3Line>::size();
Q_ASSERT(false);//Unsupported size
......
......@@ -18,6 +18,7 @@
#include "options.h"
#include "FileNameLineEdit.h"
#include "RLPainter.h"
#include "Utils.h"
#include <algorithm>
#include <cmath>
......@@ -288,7 +289,7 @@ int DiffTextWindow::getFirstLine()
void DiffTextWindow::setHorizScrollOffset(int horizScrollOffset)
{
int fontWidth = fontMetrics().width('0');
int fontWidth = Utils::getHorizontalAdvance(fontMetrics(), '0');
int xOffset = d->leftInfoWidth() * fontWidth;
int deltaX = d->m_horizScrollOffset - std::max(0, horizScrollOffset);
......@@ -433,7 +434,7 @@ void DiffTextWindow::mousePressEvent(QMouseEvent* e)
int pos;
convertToLinePos(e->x(), e->y(), line, pos);
int fontWidth = fontMetrics().width('0');
int fontWidth = Utils::getHorizontalAdvance(fontMetrics(), '0');
int xOffset = d->leftInfoWidth() * fontWidth;
if((!d->m_pOptions->m_bRightToLeftLanguage && e->x() < xOffset) || (d->m_pOptions->m_bRightToLeftLanguage && e->x() > width() - xOffset))
......@@ -563,7 +564,7 @@ void DiffTextWindow::mouseMoveEvent(QMouseEvent* e)
// Scroll because mouse moved out of the window
const QFontMetrics& fm = fontMetrics();
int fontWidth = fm.width('0');
int fontWidth = Utils::getHorizontalAdvance(fm, '0');
int deltaX = 0;
int deltaY = 0;
if(!d->m_pOptions->m_bRightToLeftLanguage)
......@@ -756,7 +757,7 @@ void DiffTextWindowData::prepareTextLayout(QTextLayout& textLayout, bool /*bFirs
int leading = m_pDiffTextWindow->fontMetrics().leading();
int height = 0;
int fontWidth = m_pDiffTextWindow->fontMetrics().width('0');
int fontWidth = Utils::getHorizontalAdvance(m_pDiffTextWindow->fontMetrics(), '0');
int xOffset = leftInfoWidth() * fontWidth - m_horizScrollOffset;
int textWidth = visibleTextWidth;
if(textWidth < 0)
......@@ -813,7 +814,7 @@ void DiffTextWindowData::writeLine(
const QFontMetrics& fm = p.fontMetrics();
int fontHeight = fm.lineSpacing();
int fontAscent = fm.ascent();
int fontWidth = fm.width('0');
int fontWidth = Utils::getHorizontalAdvance(fm, '0');
int xOffset = leftInfoWidth() * fontWidth - m_horizScrollOffset;
int yOffset = (line - m_firstLine) * fontHeight;
......@@ -1027,7 +1028,7 @@ void DiffTextWindow::paintEvent(QPaintEvent* e)
int endLine = std::min(d->m_firstLine + getNofVisibleLines() + 2, getNofLines());
RLPainter p(this, d->m_pOptions->m_bRightToLeftLanguage, width(), fontMetrics().width('0'));
RLPainter p(this, d->m_pOptions->m_bRightToLeftLanguage, width(), Utils::getHorizontalAdvance(fontMetrics(), '0'));
p.setFont(font());
p.QPainter::fillRect(invalidRect, d->m_pOptions->m_bgColor);
......@@ -1182,7 +1183,7 @@ 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();
int visibleColumns = s.width() / Utils::getHorizontalAdvance(fm, '0') - d->leftInfoWidth();
if(e->size().height() != e->oldSize().height())
emit resizeHeightChangedSignal(visibleLines);
if(e->size().width() != e->oldSize().width())
......@@ -1201,7 +1202,7 @@ int DiffTextWindow::getNofVisibleLines()
int DiffTextWindow::getVisibleTextAreaWidth()
{
QFontMetrics fm = fontMetrics();
return width() - d->leftInfoWidth() * fm.width('0');
return width() - d->leftInfoWidth() * Utils::getHorizontalAdvance(fm, '0');
}
QString DiffTextWindow::getSelection()
......@@ -1576,7 +1577,7 @@ void DiffTextWindow::recalcWordWrapHelper(int wrapLineVectorSize, int visibleTex
if(visibleTextWidth < 0)
visibleTextWidth = getVisibleTextAreaWidth();
else
visibleTextWidth -= d->leftInfoWidth() * fontMetrics().width('0');
visibleTextWidth -= d->leftInfoWidth() * Utils::getHorizontalAdvance(fontMetrics(), '0');
int i;
int wrapLineIdx = 0;
int size = d->m_pDiff3LineVector->size();
......@@ -1837,8 +1838,7 @@ void DiffTextWindowFrame::setFirstLine(int firstLine)
int l = pDTW->calcTopLineInFile(firstLine);
int w = d->m_pTopLine->fontMetrics().width(
s + ' ' + QString().fill('0', lineNumberWidth));
int w = Utils::getHorizontalAdvance(d->m_pTopLine->fontMetrics(), s + ' ' + QString().fill('0', lineNumberWidth));
d->m_pTopLine->setMinimumWidth(w);
if(l == -1)
......
......@@ -556,7 +556,7 @@ class DirectoryMergeWindow::DirMergeItemDelegate : public QStyledItemDelegate
: QStyledItemDelegate(pParent), m_pDMW(pParent), d(pParent->d)
{
}
void paint(QPainter* p, const QStyleOptionViewItem& option, const QModelIndex& index) const override
void paint(QPainter* thePainter, const QStyleOptionViewItem& option, const QModelIndex& index) const override
{
int column = index.column();
if(column == s_ACol || column == s_BCol || column == s_CCol)
......@@ -584,27 +584,28 @@ class DirectoryMergeWindow::DirMergeItemDelegate : public QStyledItemDelegate
if(!icon.isNull())
{
int yOffset = (sizeHint(option, index).height() - icon.height()) / 2;
p->drawPixmap(x + 2, y + yOffset, icon);
thePainter->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);
thePainter->setPen(c); // highlight() );
thePainter->drawRect(x + 2, y + yOffset, icon.width(), icon.height());
thePainter->setPen(QPen(c, 0, Qt::DotLine));
thePainter->drawRect(x + 1, y + yOffset - 1, icon.width() + 2, icon.height() + 2);
thePainter->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,
thePainter->drawText(x + 2 + (icon.width() - Utils::getHorizontalAdvance(thePainter->fontMetrics(), s)) / 2,
y + yOffset + (icon.height() + thePainter->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);
thePainter->setPen(m_pDMW->palette().window().color());
thePainter->drawRect(x + 1, y + yOffset - 1, icon.width() + 2, icon.height() + 2);
}
return;
}
......@@ -614,7 +615,7 @@ class DirectoryMergeWindow::DirMergeItemDelegate : public QStyledItemDelegate
{
option2.displayAlignment = Qt::AlignRight;
}
QStyledItemDelegate::paint(p, option2, index);
QStyledItemDelegate::paint(thePainter, option2, index);
}
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override
{
......@@ -741,6 +742,7 @@ bool DirectoryMergeWindow::DirectoryMergeWindowPrivate::fastFileComparison(
if(!fi2.open(QIODevice::ReadOnly))
{
fi1.close();
status = fi2.errorString();
return bEqual;
}
......@@ -758,17 +760,23 @@ bool DirectoryMergeWindow::DirectoryMergeWindowPrivate::fastFileComparison(
if(len != fi1.read(&buf1[0], len))
{
status = fi1.errorString();
fi1.close();
fi2.close();
return bEqual;
}
if(len != fi2.read(&buf2[0], len))
{
status = fi2.errorString();;
status = fi2.errorString();
fi1.close();
fi2.close();
return bEqual;
}
if(memcmp(&buf1[0], &buf2[0], len) != 0)
{
fi1.close();
fi2.close();
bError = false;
return bEqual;
}
......@@ -780,6 +788,9 @@ bool DirectoryMergeWindow::DirectoryMergeWindowPrivate::fastFileComparison(
// If the program really arrives here, then the files are really equal.
bError = false;
bEqual = true;
fi1.close();
fi2.close();
return bEqual;
}
......@@ -2507,7 +2518,6 @@ void DirectoryMergeWindow::DirectoryMergeWindowPrivate::prepareMergeStart(const
}
m_currentIndexForOperation = m_mergeItemList.begin();
return;
}
void DirectoryMergeWindow::slotRunOperationForCurrentItem()
......
......@@ -10,6 +10,7 @@
#include "fileaccess.h"
#include "cvsignorelist.h"
#include "common.h"
#include "Logging.h"
#include "progress.h"
#include "Utils.h"
......@@ -62,7 +63,6 @@ void FileAccess::reset()
m_linkTarget = "";
//m_fileType = -1;
m_pParent = nullptr;
tmpFile.clear();
tmpFile = QSharedPointer<QTemporaryFile>::create();
realFile = nullptr;
......@@ -101,6 +101,7 @@ void FileAccess::setFile(const QString& name, bool bWantToWrite)
void FileAccess::setFile(const QUrl& url, bool bWantToWrite)
{
reset();
Q_ASSERT(parent() == nullptr || url != parent()->url());
m_url = url;
//QUrl::isLocalFile assumes the scheme is set.
......@@ -131,7 +132,7 @@ void FileAccess::loadData()
m_fileInfo.setCaching(true);
if(parent() == nullptr)
m_baseDir = m_fileInfo.absoluteFilePath();
m_baseDir.setPath(m_fileInfo.absoluteFilePath());
else
m_baseDir = m_pParent->m_baseDir;
......@@ -158,7 +159,7 @@ void FileAccess::loadData()
if(isLocal() && m_bSymLink)
{
m_linkTarget = m_fileInfo.readLink();
m_linkTarget = m_fileInfo.symLinkTarget();
#ifndef Q_OS_WIN
// Unfortunately Qt5 symLinkTarget/readLink always returns an absolute path, even if the link is relative
char* s = (char*)malloc(PATH_MAX + 1);
......@@ -281,7 +282,24 @@ void FileAccess::setFromUdsEntry(const KIO::UDSEntry& e, FileAccess *parent)
m_fileInfo = QFileInfo(filePath);
m_fileInfo.setCaching(true);
if(m_url.isEmpty())
m_url = QUrl::fromUserInput(filePath);
{
if(parent != nullptr)
{
m_url = parent->url().resolved(QUrl(filePath));
//Verify that the scheme doesn't change.
Q_ASSERT(m_url.scheme() == parent->url().scheme());
}
else
{
/*
Invalid entry we don't know the full url because KIO didn't tell us and there is no parent
node supplied.
This is a bug if it happens and should be logged . However it is a recoverable error.
*/
qCWarning(kdiffFileAccess) << i18n("Unable to determine full url. No parent specified.");
return;
}
}
m_name = m_fileInfo.fileName();
if(isLocal() && m_name.isEmpty())
......@@ -473,6 +491,7 @@ bool FileAccess::interruptableReadFile(void* pDestBuffer, qint64 maxLength)
bool FileAccess::readFile(void* pDestBuffer, qint64 maxLength)
{
bool success = false;
//Avoid hang on linux for special files.
if(!isNormal())
return true;
......@@ -480,14 +499,20 @@ bool FileAccess::readFile(void* pDestBuffer, qint64 maxLength)
if(isLocal() || !m_localCopy.isEmpty())
{
if(open(QIODevice::ReadOnly))//krazy:exclude=syscalls
return interruptableReadFile(pDestBuffer, maxLength); // maxLength == f.read( (char*)pDestBuffer, maxLength );
{
success = interruptableReadFile(pDestBuffer, maxLength); // maxLength == f.read( (char*)pDestBuffer, maxLength )
close();
}
}
else
{
FileAccessJobHandler jh(this);
return jh.get(pDestBuffer, maxLength);
success = jh.get(pDestBuffer, maxLength);
}
return false;
close();
Q_ASSERT(!realFile->isOpen() && !tmpFile->isOpen());
return success;
}
bool FileAccess::writeFile(const void* pSrcBuffer, qint64 length)
......@@ -495,8 +520,7 @@ bool FileAccess::writeFile(const void* pSrcBuffer, qint64 length)
ProgressProxy pp;
if(isLocal())
{
QFile f(absoluteFilePath());
if(f.open(QIODevice::WriteOnly))
if(realFile->open(QIODevice::WriteOnly))
{
const qint64 maxChunkSize = 100000;
pp.setMaxNofSteps(length / maxChunkSize + 1);
......@@ -504,33 +528,44 @@ bool FileAccess::writeFile(const void* pSrcBuffer, qint64 length)
while(i < length)
{
qint64 nextLength = std::min(length - i, maxChunkSize);
qint64 reallyWritten = f.write((char*)pSrcBuffer + i, nextLength);
qint64 reallyWritten = realFile->write((char*)pSrcBuffer + i, nextLength);
if(reallyWritten != nextLength)
{
realFile->close();
return false;
}
i += reallyWritten;
pp.step();
if(pp.wasCancelled())
{
realFile->close();
return false;
}
f.close();
}
if(isExecutable()) // value is true if the old file was executable
{
// Preserve attributes
f.setPermissions(f.permissions() | QFile::ExeUser);
realFile->setPermissions(realFile->permissions() | QFile::ExeUser);
}
realFile->close();
return true;
}
}
else
{
FileAccessJobHandler jh(this);
return jh.put(pSrcBuffer, length, true /*overwrite*/);
bool success = jh.put(pSrcBuffer, length, true /*overwrite*/);
close();
Q_ASSERT(!realFile->isOpen() && !tmpFile->isOpen());
return success;
}
close();
Q_ASSERT(!realFile->isOpen() && !tmpFile->isOpen());
return false;
}
......@@ -815,7 +850,7 @@ FileAccessJobHandler::FileAccessJobHandler(FileAccess* pFileAccess)
m_bSuccess = false;
}
bool FileAccessJobHandler::stat(int detail, bool bWantToWrite)
bool FileAccessJobHandler::stat(short detail, bool bWantToWrite)
{
m_bSuccess = false;
m_pFileAccess->setStatusText(QString());
......@@ -1121,8 +1156,11 @@ bool FileAccessJobHandler::listDir(t_DirectoryList* pDirList, bool bRecursive, b
QFileInfoList fiList = dir.entryInfoList();
if(fiList.isEmpty())
{
// No Permission to read directory or other error.
m_bSuccess = false;
/*
Sadly Qt provides no error information making this case ambigious.
A readablity check is the best we can do.
*/
m_bSuccess = dir.isReadable();
}
else
{
......@@ -1203,7 +1241,8 @@ void FileAccessJobHandler::slotListDirProcessNewEntries(KIO::Job*, const KIO::UD
//must be manually filtered KDE does not supply API for ignoring these.
if(fa.fileName() != "." && fa.fileName() != "..")
{
fa.addPath(fa.fileName());
//quick fix to preserve behavoir without creating invalid urls. TODO: look for altertive machanism for use with next major release.
fa.setFile(fa.url());
m_pDirList->push_back(fa);
}
......
......@@ -120,7 +120,7 @@ class FileAccess
bool m_bValidData;
//long m_fileType; // for testing only
FileAccess* m_pParent;
FileAccess* m_pParent = nullptr;
QDir m_baseDir;
QFileInfo m_fileInfo;
......@@ -156,7 +156,7 @@ class FileAccessJobHandler : public QObject
bool get(void* pDestBuffer, long maxLength);
bool put(const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume = false, int permissions = -1);
bool stat(int detailLevel = 2, bool bWantToWrite = false);
bool stat(short detailLevel = 2, bool bWantToWrite = false);
bool copyFile(const QString& dest);
bool rename(const FileAccess& dest);
bool listDir(t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden,
......
......@@ -318,9 +318,9 @@ struct change *find_change (struct change *);
struct change *find_reverse_change (struct change *);
void *zalloc (size_t);
enum changes analyze_hunk (struct change *, LineRef *, LineRef *, LineRef *, LineRef *);
void begin_output (void);
void begin_output ();
void debug_script (struct change *);
void finish_output (void);
void finish_output ();
void message (const QChar *, const QChar *, const QChar *);
void message5 (const QChar *, const QChar *, const QChar *, const QChar *, const QChar *);
void output_1_line (const QChar *, const QChar *, const QChar *, const QChar *);
......@@ -348,7 +348,7 @@ private:
// gnudiff_xmalloc.cpp
void *xmalloc (size_t n);
void *xrealloc(void *p, size_t n);
void xalloc_die (void);
void xalloc_die ();
inline bool isWhite( QChar c )
{
......
......@@ -30,9 +30,9 @@
#include "gnudiff_diff.h"
/* If non NULL, call this function when memory is exhausted. */
void (*xalloc_fail_func)(void) = nullptr;
void (*xalloc_fail_func)() = nullptr;
void GnuDiff::xalloc_die(void)
void GnuDiff::xalloc_die()
{
if(xalloc_fail_func)
(*xalloc_fail_func)();
......
......@@ -129,6 +129,98 @@ namespace GuiUtils {
theAction->setIconText( iconText );
return theAction;
}
//Allow actions to be created without connecting them immediately.
template <class T>
inline typename std::enable_if<std::is_same<T, QAction>::value, QAction>::type* createAction(
const QString& text,
KActionCollection* ac,
const QString& actionName)
{
Q_ASSERT(ac != nullptr);
QAction* theAction;
theAction = ac->addAction(actionName);
theAction->setText(text);
return theAction;
}
template <class T>
inline typename std::enable_if<std::is_same<T, KToggleAction>::value, KToggleAction>::type* createAction(
const QString& text,
KActionCollection* ac,
const QString &actionName) {
Q_ASSERT( ac != nullptr );
KToggleAction* theAction = new KToggleAction(ac);
ac->addAction( actionName, theAction );
theAction->setText( text );
return theAction;
}
template <class T>
T* createAction(
const QString& text,
const QKeySequence& shortcut,
KActionCollection* ac,
const QString &actionName)
{
T* theAction = createAction<T>( text, ac, actionName );
ac->setDefaultShortcut(theAction, shortcut);
return theAction;
}
template <class T>
T* createAction(
const QString& text,
const QIcon& icon,
KActionCollection* ac,
const QString &actionName)
{
T* theAction = createAction<T>( text, ac, actionName );
theAction->setIcon( icon );
return theAction;
}
template <class T>
T* createAction(
const QString& text,
const QIcon& icon,
const QString& iconText,
KActionCollection* ac,
const QString &actionName)
{
T* theAction = createAction<T>( text, ac, actionName );
theAction->setIcon( icon );
theAction->setIconText( iconText );
return theAction;
}
template <class T>
T* createAction(
const QString& text,
const QIcon& icon,
const QKeySequence& shortcut,
KActionCollection* ac,
const QString &actionName)
{
T* theAction = createAction<T>( text, shortcut, ac, actionName );
theAction->setIcon( icon );
return theAction;
}
template <class T>
T* createAction(
const QString& text,
const QIcon& icon,
const QString& iconText,
const QKeySequence& shortcut,
KActionCollection* ac,
const QString &actionName)
{
T* theAction = createAction<T>( text, shortcut, ac, actionName );
theAction->setIcon( icon );
theAction->setIconText( iconText );
return theAction;
}
}
#endif
set(KDIFF3_PNG_ICONS
icons/16-apps-kdiff3.png
icons/22-apps-kdiff3.png
icons/32-apps-kdiff3.png
icons/48-apps-kdiff3.png
icons/64-apps-kdiff3.png
icons/128-apps-kdiff3.png
icons/256-apps-kdiff3.png)
set(KDIFF3_ICONS
${KDIFF3_PNG_ICONS}
icons/sc-apps-kdiff3.svgz
)
# add icons to application sources, to have them bundled -- must be in same scope as src/CMakeLists.txt
ecm_add_app_icon(kdiff3_SRCS ICONS ${KDIFF3_PNG_ICONS})
ecm_install_icons(
ICONS
16-apps-kdiff3.png
22-apps-kdiff3.png
32-apps-kdiff3.png
48-apps-kdiff3.png
64-apps-kdiff3.png
128-apps-kdiff3.png
256-apps-kdiff3.png
sc-apps-kdiff3.svgz
${KDIFF3_ICONS}
DESTINATION ${KDE_INSTALL_ICONDIR}
THEME hicolor
)
......@@ -23,6 +23,7 @@
#include "difftextwindow.h"
#include "mergeresultwindow.h"
#include "RLPainter.h"
#include "Utils.h"
#ifndef Q_OS_WIN
#include <unistd.h>
......@@ -222,7 +223,12 @@ KDiff3App::KDiff3App(QWidget* pParent, const QString& name, KDiff3Part* pKDiff3P
m_sd2.setOptions(m_pOptions);
m_sd3.setOptions(m_pOptions);
m_bAutoFlag = false; //disable --auto option git hard codes this unwanted flag.
#ifdef ENABLE_AUTO
m_bAutoFlag = hasArgs && KDiff3Shell::getParser()->isSet("auto");
#else
m_bAutoFlag = false;
#endif
m_bAutoMode = m_bAutoFlag || m_pOptions->m_bAutoSaveAndQuitOnMergeWithoutConflicts;
if(hasArgs) {
m_outputFilename = KDiff3Shell::getParser()->value("output");
......@@ -266,8 +272,10 @@ KDiff3App::KDiff3App(QWidget* pParent, const QString& name, KDiff3Part* pKDiff3P
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" );
//Set m_bDirCompare flag
m_bDirCompare = FileAccess(m_sd1.getFilename()).isDir();
QStringList aliasList = KDiff3Shell::getParser()->values( "fname" );
QStringList::Iterator ali = aliasList.begin();
QString an1 = KDiff3Shell::getParser()->value("L1");
......@@ -310,6 +318,8 @@ KDiff3App::KDiff3App(QWidget* pParent, const QString& name, KDiff3Part* pKDiff3P
///////////////////////////////////////////////////////////////////
// call inits to invoke all other construction parts
initActions(actionCollection());
MergeResultWindow::initActions(actionCollection());
initStatusBar();
m_pFindDialog = new FindDialog(this);
......@@ -791,7 +801,7 @@ void printDiffTextWindow(RLPainter& painter, const QRect& view, const QString& h
QString s = headerText.mid(p);
int i;
for(i = 2; i < s.length(); ++i)
if(fm.width(s, i) > view.width())
if(Utils::getHorizontalAdvance(fm, s, i) > view.width())
{
--i;
break;
......@@ -807,7 +817,7 @@ void printDiffTextWindow(RLPainter& painter, const QRect& view, const QString& h
painter.translate(0, view.top());
pDiffTextWindow->print(painter, view, line, linesPerPage);
painter.resetMatrix();
painter.resetTransform();
}
void KDiff3App::slotFilePrint()
......@@ -854,7 +864,7 @@ void KDiff3App::slotFilePrint()
{
slotStatusMsg(i18n("Printing..."));
// create a painter to paint on the printer object
RLPainter painter(&printer, m_pOptions->m_bRightToLeftLanguage, width(), fontMetrics().width('W'));
RLPainter painter(&printer, m_pOptions->m_bRightToLeftLanguage, width(), Utils::getHorizontalAdvance(fontMetrics(),'W'));
QPaintDevice* pPaintDevice = painter.device();
int dpiy = pPaintDevice->logicalDpiY();
......@@ -871,7 +881,7 @@ void KDiff3App::slotFilePrint()
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 = Utils::getHorizontalAdvance(fm, m_sd1.getAliasName() + ", " + topLineText + ": 01234567") / columnWidth + 1;
int headerMargin = headerLines * fm.height() + 3; // Text + one horizontal line
int footerMargin = fm.height() + 3;
......@@ -996,7 +1006,7 @@ void KDiff3App::slotFilePrint()
QString s = bPrintCurrentPage ? QString("")
: QString::number(page) + '/' + QString::number(totalNofPages);
if(bPrintSelection) s += i18n(" (Selection)");
painter.drawText((view.right() - painter.fontMetrics().width(s)) / 2,
painter.drawText((view.right() - Utils::getHorizontalAdvance(painter.fontMetrics(), s)) / 2,
view.bottom() + painter.fontMetrics().ascent() + 5, s);
bFirstPrintedPage = true;
......
......@@ -318,8 +318,8 @@ class KDiff3App : public QSplitter
QSplitter* m_pMainSplitter;
QWidget* m_pMainWidget;
QWidget* m_pMergeWindowFrame;
ReversibleScrollBar* m_pHScrollBar;
QScrollBar* m_pDiffVScrollBar;
ReversibleScrollBar* m_pHScrollBar = nullptr;
QScrollBar* m_pDiffVScrollBar = nullptr;
QScrollBar* m_pMergeVScrollBar;
DiffTextWindow* m_pDiffTextWindow1;
......@@ -395,8 +395,8 @@ class KDiff3App : public QSplitter
KToolBar* toolBar(QLatin1String);
KDiff3Part* m_pKDiff3Part;
KParts::MainWindow* m_pKDiff3Shell;
bool m_bAutoFlag;
bool m_bAutoMode;
bool m_bAutoFlag = false;
bool m_bAutoMode = false;
void recalcWordWrap(int visibleTextWidthForPrinting = -1);
bool m_bRecalcWordWrapPosted;
void setHScrollBarRange();
......
......@@ -113,12 +113,16 @@ int main(int argc, char* argv[])
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")));
#ifdef ENABLE_AUTO
cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("auto"), i18n("No GUI if all conflicts are auto-solvable. (Needs -o file)")));
#else
cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("auto"), i18n("Ignored.")));
#endif
cmdLineParser->addOption(QCommandLineOption(QStringList() << QLatin1String("qall"), i18n("Do not 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("L") << QLatin1String("fname"), i18n("Alternative visible name replacement. Supply this once for every input."), QLatin1String("alias")));
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")));
......@@ -144,7 +148,7 @@ int main(int argc, char* argv[])
else
{
/*
There is no terminal connected so don't just exit mysteriously exit on error.
There is no terminal connected so don't just exit mysteriously on error.
*/
if(!cmdLineParser->parse(QCoreApplication::arguments()))
{
......
......@@ -13,6 +13,7 @@
#include "options.h"
#include "RLPainter.h"
#include "guiutils.h"
#include "Utils.h"
#include <QApplication>
#include <QClipboard>
......@@ -55,6 +56,16 @@ int g_bAutoSolve = true;
#undef leftInfoWidth
QAction* MergeResultWindow::chooseAEverywhere = nullptr;
QAction* MergeResultWindow::chooseBEverywhere = nullptr;
QAction* MergeResultWindow::chooseCEverywhere = nullptr;
QAction* MergeResultWindow::chooseAForUnsolvedConflicts = nullptr;
QAction* MergeResultWindow::chooseBForUnsolvedConflicts = nullptr;
QAction* MergeResultWindow::chooseCForUnsolvedConflicts = nullptr;
QAction* MergeResultWindow::chooseAForUnsolvedWhiteSpaceConflicts = nullptr;
QAction* MergeResultWindow::chooseBForUnsolvedWhiteSpaceConflicts = nullptr;
QAction* MergeResultWindow::chooseCForUnsolvedWhiteSpaceConflicts = nullptr;
MergeResultWindow::MergeResultWindow(
QWidget* pParent,
Options* pOptions,
......@@ -148,6 +159,8 @@ void MergeResultWindow::init(
showUnsolvedConflictsStatusMessage();
}
//This must be called before KXMLGui::SetXMLFile and friends or the actions will not be shown in the menu.
//At that point in startup we don't have a MergeResultWindow object so we cannot connect the signals yet.
void MergeResultWindow::initActions(KActionCollection* ac)
{
if(ac == nullptr){
......@@ -155,15 +168,30 @@ void MergeResultWindow::initActions(KActionCollection* ac)
exit(-1);//we cannot recover from this.
}
chooseAEverywhere = GuiUtils::createAction<QAction>(i18n("Choose A Everywhere"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_1), this, &MergeResultWindow::slotChooseAEverywhere, ac, "merge_choose_a_everywhere");
chooseBEverywhere = GuiUtils::createAction<QAction>(i18n("Choose B Everywhere"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_2), this, &MergeResultWindow::slotChooseBEverywhere, ac, "merge_choose_b_everywhere");
chooseCEverywhere = GuiUtils::createAction<QAction>(i18n("Choose C Everywhere"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_3), this, &MergeResultWindow::slotChooseCEverywhere, ac, "merge_choose_c_everywhere");
chooseAForUnsolvedConflicts = GuiUtils::createAction<QAction>(i18n("Choose A for All Unsolved Conflicts"), this, &MergeResultWindow::slotChooseAForUnsolvedConflicts, ac, "merge_choose_a_for_unsolved_conflicts");
chooseBForUnsolvedConflicts = GuiUtils::createAction<QAction>(i18n("Choose B for All Unsolved Conflicts"), this, &MergeResultWindow::slotChooseBForUnsolvedConflicts, ac, "merge_choose_b_for_unsolved_conflicts");
chooseCForUnsolvedConflicts = GuiUtils::createAction<QAction>(i18n("Choose C for All Unsolved Conflicts"), this, &MergeResultWindow::slotChooseCForUnsolvedConflicts, ac, "merge_choose_c_for_unsolved_conflicts");
chooseAForUnsolvedWhiteSpaceConflicts = GuiUtils::createAction<QAction>(i18n("Choose A for All Unsolved Whitespace Conflicts"), this, &MergeResultWindow::slotChooseAForUnsolvedWhiteSpaceConflicts, ac, "merge_choose_a_for_unsolved_whitespace_conflicts");
chooseBForUnsolvedWhiteSpaceConflicts = GuiUtils::createAction<QAction>(i18n("Choose B for All Unsolved Whitespace Conflicts"), this, &MergeResultWindow::slotChooseBForUnsolvedWhiteSpaceConflicts, ac, "merge_choose_b_for_unsolved_whitespace_conflicts");
chooseCForUnsolvedWhiteSpaceConflicts = GuiUtils::createAction<QAction>(i18n("Choose C for All Unsolved Whitespace Conflicts"), this, &MergeResultWindow::slotChooseCForUnsolvedWhiteSpaceConflicts, ac, "merge_choose_c_for_unsolved_whitespace_conflicts");
chooseAEverywhere = GuiUtils::createAction<QAction>(i18n("Choose A Everywhere"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_1), ac, "merge_choose_a_everywhere");
chooseBEverywhere = GuiUtils::createAction<QAction>(i18n("Choose B Everywhere"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_2), ac, "merge_choose_b_everywhere");
chooseCEverywhere = GuiUtils::createAction<QAction>(i18n("Choose C Everywhere"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_3), ac, "merge_choose_c_everywhere");
chooseAForUnsolvedConflicts = GuiUtils::createAction<QAction>(i18n("Choose A for All Unsolved Conflicts"), ac, "merge_choose_a_for_unsolved_conflicts");
chooseBForUnsolvedConflicts = GuiUtils::createAction<QAction>(i18n("Choose B for All Unsolved Conflicts"), ac, "merge_choose_b_for_unsolved_conflicts");
chooseCForUnsolvedConflicts = GuiUtils::createAction<QAction>(i18n("Choose C for All Unsolved Conflicts"), ac, "merge_choose_c_for_unsolved_conflicts");
chooseAForUnsolvedWhiteSpaceConflicts = GuiUtils::createAction<QAction>(i18n("Choose A for All Unsolved Whitespace Conflicts"), ac, "merge_choose_a_for_unsolved_whitespace_conflicts");
chooseBForUnsolvedWhiteSpaceConflicts = GuiUtils::createAction<QAction>(i18n("Choose B for All Unsolved Whitespace Conflicts"), ac, "merge_choose_b_for_unsolved_whitespace_conflicts");
chooseCForUnsolvedWhiteSpaceConflicts = GuiUtils::createAction<QAction>(i18n("Choose C for All Unsolved Whitespace Conflicts"), ac, "merge_choose_c_for_unsolved_whitespace_conflicts");
}
void MergeResultWindow::connectActions()
{
QObject::connect(chooseAEverywhere, &QAction::triggered, this, &MergeResultWindow::slotChooseAEverywhere);
QObject::connect(chooseBEverywhere, &QA