...
 
Commits (57)
......@@ -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.
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
This diff is collapsed.
......@@ -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;
......
/*
* Copyright (c) 2003, Sergey Zorin. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __string_h__
#define __string_h__
#include <windows.h>
#include <tchar.h>
#include <string.h>
#include <stdlib.h>
class STRING;
inline STRING operator+( const STRING& s1, const STRING& s2);
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;
}
void resize( size_t newLength )
{
size_t oldLength = length();
if ( newLength < oldLength ) {
_str[newLength] = 0; // Just truncate the string
} else if( newLength>oldLength) {
TCHAR* p = new TCHAR[ newLength + 1 ];
lstrcpy(p, _str);
for( size_t i=oldLength; i<newLength; ++i)
p[i]=TEXT(' ');
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;
}
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 {
return length();
}
// String length in bytes. May differ from length() for Unicode or MBCS
size_t sizeInBytes() const {
return length()*sizeof(TCHAR);
}
bool empty() const
{
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;
}
STRING& replace( size_t pos, size_t num, const STRING& s )
{
*this = substr( 0, pos ) + s + substr( pos+num );
return *this;
}
bool operator ==(const STRING& s) const {
return (lstrcmp(_str, s) == 0);
}
size_t find(const STRING& s) const
{
const TCHAR* p = _tcsstr( _str, s._str );
if (p)
return p - _str;
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;
}
private:
TCHAR* _str;
};
inline STRING operator+( const STRING& s1, const STRING& s2) {
STRING tmp(s1);
tmp+=s2;
return tmp;
}
#endif // __string_h__
......@@ -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"
......
......@@ -32,8 +32,16 @@
#ifdef UNICODE
typedef std::wstring tstring;
#define toQString(s) QString::fromStdWString(s)
#define fromQString(s) (s).toStdWString()
#else
typedef std::string tstring;
#define toQString(s) { QString::fromStdString(s);}
#define fromQString(s) { (s).toStdString();}
#endif
#define MESSAGELOG( msg ) SERVER::logMessage( __FUNCTION__, __FILE__, __LINE__, msg )
......@@ -53,34 +61,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.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,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)
};
......
......@@ -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;
}
......@@ -249,6 +249,14 @@ bool SourceData::FileData::readFile(FileAccess& file)
m_pBuf = nullptr;
m_size = 0;
}
else
{
//null terminate buffer
pBuf[m_size + 1] = 0;
pBuf[m_size + 2] = 0;
pBuf[m_size + 3] = 0;
pBuf[m_size + 4] = 0;
}
return bSuccess;
}
......@@ -501,6 +509,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 +610,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
/**
* Copyright (C) 2018 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/>.
*
*
*/
#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();
......@@ -1777,7 +1778,8 @@ DiffTextWindowFrame::DiffTextWindowFrame(QWidget* pParent, QStatusBar* pStatusBa
pHL2->setMargin(0);
pHL2->setSpacing(2);
pHL2->addWidget(d->m_pTopLine, 0);
d->m_pEncoding = new EncodingLabel(i18n("Encoding:"), this, psd, pOptions);
d->m_pEncoding = new EncodingLabel(i18n("Encoding:"), psd, pOptions);
connect((EncodingLabel*) d->m_pEncoding, &EncodingLabel::encodingChanged, this, &DiffTextWindowFrame::slotEncodingChanged);
d->m_pLineEndStyle = new QLabel(i18n("Line end style:"));
pHL2->addWidget(d->m_pEncoding);
......@@ -1837,8 +1839,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)
......@@ -1908,15 +1909,9 @@ void DiffTextWindowFrame::slotBrowseButtonClicked()
}
}
void DiffTextWindowFrame::sendEncodingChangedSignal(QTextCodec* c)
{
emit encodingChanged(c);
}
EncodingLabel::EncodingLabel(const QString& text, DiffTextWindowFrame* pDiffTextWindowFrame, SourceData* pSD, Options* pOptions)
EncodingLabel::EncodingLabel(const QString& text, SourceData* pSD, Options* pOptions)
: QLabel(text)
{
m_pDiffTextWindowFrame = pDiffTextWindowFrame;
m_pOptions = pOptions;
m_pSourceData = pSD;
m_pContextEncodingMenu = nullptr;
......@@ -1983,19 +1978,21 @@ void EncodingLabel::insertCodec(const QString& visibleCodecName, QTextCodec* pCo
if(pCodec != nullptr && !codecEnumList.contains(CodecMIBEnum))
{
QAction* pAction = new QAction(pMenu); // menu takes ownership, so deleting the menu deletes the action too.
QLatin1String codecName(pCodec->name());
QByteArray nameArray = pCodec->name();
QLatin1String codecName = QLatin1String(nameArray);
pAction->setText(visibleCodecName.isEmpty() ? codecName : visibleCodecName + QLatin1String(" (") + codecName + QLatin1String(")"));
pAction->setData(CodecMIBEnum);
pAction->setCheckable(true);
if(currentTextCodecEnum == CodecMIBEnum)
pAction->setChecked(true);
pMenu->addAction(pAction);
connect(pAction, &QAction::triggered, this, &EncodingLabel::slotEncodingChanged);
connect(pAction, &QAction::triggered, this, &EncodingLabel::slotSelectEncoding);
codecEnumList.append(CodecMIBEnum);
}
}
void EncodingLabel::slotEncodingChanged()
void EncodingLabel::slotSelectEncoding()
{
QAction* pAction = qobject_cast<QAction*>(sender());
if(pAction)
......@@ -2015,6 +2012,7 @@ void EncodingLabel::slotEncodingChanged()
recentEncodings.append(s);
}
}
m_pDiffTextWindowFrame->sendEncodingChangedSignal(pCodec);
emit encodingChanged(pCodec);
}
}
......@@ -116,7 +116,6 @@ public:
DiffTextWindow* getDiffTextWindow();
void init();
void setFirstLine(int firstLine);
void sendEncodingChangedSignal(QTextCodec* c);
Q_SIGNALS:
void fileNameChanged(const QString&, e_SrcSelector);
void encodingChanged(QTextCodec*);
......@@ -126,7 +125,7 @@ protected:
private Q_SLOTS:
void slotReturnPressed();
void slotBrowseButtonClicked();
void slotEncodingChanged(QTextCodec* c) { emit encodingChanged(c); };//relay signal from encoding label
private:
DiffTextWindowFrameData* d;
};
......@@ -135,14 +134,15 @@ class EncodingLabel : public QLabel
{
Q_OBJECT
public:
EncodingLabel( const QString & text, DiffTextWindowFrame* pDiffTextWindowFrame, SourceData* psd, Options* pOptions);
EncodingLabel( const QString & text, SourceData* psd, Options* pOptions);
protected:
void mouseMoveEvent(QMouseEvent *ev) override;
void mousePressEvent(QMouseEvent *ev) override;
Q_SIGNALS:
void encodingChanged(QTextCodec*);
private Q_SLOTS:
void slotEncodingChanged();
void slotSelectEncoding();
private:
DiffTextWindowFrame* m_pDiffTextWindowFrame; //To send "EncodingChanged" signal
QMenu* m_pContextEncodingMenu;
SourceData* m_pSourceData; //SourceData to get access to "isEmpty()" and "isFromBuffer()" functions
static const int m_maxRecentEncodings = 5;
......
......@@ -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,
......
This diff is collapsed.
......@@ -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