...
 
Commits (43)
......@@ -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
......@@ -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>
......
......@@ -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;
}
......@@ -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,7 +111,7 @@ 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;
......
......@@ -741,6 +741,7 @@ bool DirectoryMergeWindow::DirectoryMergeWindowPrivate::fastFileComparison(
if(!fi2.open(QIODevice::ReadOnly))
{
fi1.close();
status = fi2.errorString();
return bEqual;
}
......@@ -758,17 +759,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 +787,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 +2517,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.
......@@ -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_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
)
......@@ -222,7 +222,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 +271,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 +317,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);
......
......@@ -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()))
{
......
......@@ -55,6 +55,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 +158,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 +167,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, &QAction::triggered, this, &MergeResultWindow::slotChooseBEverywhere);
QObject::connect(chooseCEverywhere, &QAction::triggered, this, &MergeResultWindow::slotChooseCEverywhere);
QObject::connect(chooseAForUnsolvedConflicts, &QAction::triggered, this, &MergeResultWindow::slotChooseAForUnsolvedConflicts);
QObject::connect(chooseBForUnsolvedConflicts, &QAction::triggered, this, &MergeResultWindow::slotChooseBForUnsolvedConflicts);
QObject::connect(chooseCForUnsolvedConflicts, &QAction::triggered, this, &MergeResultWindow::slotChooseCForUnsolvedConflicts);
QObject::connect(chooseAForUnsolvedWhiteSpaceConflicts, &QAction::triggered, this, &MergeResultWindow::slotChooseAForUnsolvedWhiteSpaceConflicts);
QObject::connect(chooseBForUnsolvedWhiteSpaceConflicts, &QAction::triggered, this, &MergeResultWindow::slotChooseBForUnsolvedWhiteSpaceConflicts);
QObject::connect(chooseCForUnsolvedWhiteSpaceConflicts, &QAction::triggered, this, &MergeResultWindow::slotChooseCForUnsolvedWhiteSpaceConflicts);
}
void MergeResultWindow::showUnsolvedConflictsStatusMessage()
......
......@@ -40,7 +40,16 @@ public:
const Diff3LineList* pDiff3LineList,
TotalDiffStatus* pTotalDiffStatus
);
void initActions(KActionCollection* ac);
inline void clearMergeList()
{
m_mergeLineList.clear();
m_totalSize = 0;
}
static void initActions(KActionCollection* ac);
void connectActions();
void reset();
bool saveDocument( const QString& fileName, QTextCodec* pEncoding, e_LineEndStyle eLineEndStyle );
......@@ -119,15 +128,15 @@ private:
void merge(bool bAutoSolve, e_SrcSelector defaultSelector, bool bConflictsOnly=false, bool bWhiteSpaceOnly=false );
QString getString( int lineIdx );
QAction* chooseAEverywhere = nullptr;
QAction* chooseBEverywhere = nullptr;
QAction* chooseCEverywhere = nullptr;
QAction* chooseAForUnsolvedConflicts = nullptr;
QAction* chooseBForUnsolvedConflicts = nullptr;
QAction* chooseCForUnsolvedConflicts = nullptr;
QAction* chooseAForUnsolvedWhiteSpaceConflicts = nullptr;
QAction* chooseBForUnsolvedWhiteSpaceConflicts = nullptr;
QAction* chooseCForUnsolvedWhiteSpaceConflicts = nullptr;
static QAction* chooseAEverywhere;
static QAction* chooseBEverywhere;
static QAction* chooseCEverywhere;
static QAction* chooseAForUnsolvedConflicts;
static QAction* chooseBForUnsolvedConflicts;
static QAction* chooseCForUnsolvedConflicts;
static QAction* chooseAForUnsolvedWhiteSpaceConflicts;
static QAction* chooseBForUnsolvedWhiteSpaceConflicts;
static QAction* chooseCForUnsolvedWhiteSpaceConflicts;
Options* m_pOptions = nullptr;
......
......@@ -47,7 +47,7 @@ class OptionDialog : public KPageDialog
public:
explicit OptionDialog( bool bShowDirMergeSettings, QWidget *parent = nullptr );
~OptionDialog( void ) override;
~OptionDialog() override;
QString parseOptions( const QStringList& optionList );
QString calcOptionHelp();
......@@ -61,9 +61,9 @@ public:
void addOptionItem(OptionItemBase*);
KKeyDialog* m_pKeyDialog;
protected Q_SLOTS:
virtual void slotDefault( void );
virtual void slotOk( void );
virtual void slotApply( void );
virtual void slotDefault();
virtual void slotOk();
virtual void slotApply();
//virtual void buttonClicked( QAbstractButton* );
virtual void helpRequested();
......
This diff is collapsed.
......@@ -150,7 +150,7 @@ Comment[tr]=Bir Dosya Ve Dizin Karşılaştırma Ve Birleştirme Aracı
Comment[ug]=ھۆججەت ۋە مۇندەرىجە سېلىشتۇرۇش ۋە بىرىكتۈرۈش قورالى
Comment[uk]=Інструмент для порівняння та з’єднання файлів та тек
Comment[x-test]=xxA File And Directory Comparison And Merge Toolxx
Comment[zh_CN]=一个文件和目录的比较和合并工具
Comment[zh_CN]=文件和文件夹比较合并工具
Comment[zh_TW]=一個檔案與目錄比較與合併的工具
Terminal=false
Categories=Qt;KDE;Development;
......@@ -142,6 +142,8 @@ void KDiff3App::mainInit(TotalDiffStatus* pTotalDiffStatus, bool bLoadFiles, boo
// so painting must be suppressed
if(bGUI) setLockPainting(true);
//insure merge result window never has stale iterators.
if(m_pMergeResultWindow) m_pMergeResultWindow->clearMergeList();
m_diff3LineList.clear();
m_diff3LineVector.clear();
......@@ -157,6 +159,7 @@ void KDiff3App::mainInit(TotalDiffStatus* pTotalDiffStatus, bool bLoadFiles, boo
// First get all input data.
pp.setInformation(i18n("Loading A"));
qCInfo(kdeMain) << i18n("Loading A: %1", m_sd1.getFilename());
if(bUseCurrentEncoding)
errors = m_sd1.readAndPreprocess(m_sd1.getEncoding(), false);
else
......@@ -170,6 +173,8 @@ void KDiff3App::mainInit(TotalDiffStatus* pTotalDiffStatus, bool bLoadFiles, boo
pp.step();
pp.setInformation(i18n("Loading B"));
qCInfo(kdeMain) << "Loading B: " << m_sd2.getFilename();
if(bUseCurrentEncoding)
errors = m_sd2.readAndPreprocess(m_sd2.getEncoding(), false);
else
......@@ -338,7 +343,7 @@ void KDiff3App::mainInit(TotalDiffStatus* pTotalDiffStatus, bool bLoadFiles, boo
oldHeights = m_pMainSplitter->sizes();
initView();
m_pMergeResultWindow->initActions(actionCollection());
m_pMergeResultWindow->connectActions();
if(m_pDirectoryMergeSplitter->isVisible())
{
......@@ -536,12 +541,12 @@ void KDiff3App::resizeMergeResultWindow()
void KDiff3App::scrollDiffTextWindow(int deltaX, int deltaY)
{
if(deltaY != 0)
if(deltaY != 0 && m_pDiffVScrollBar != nullptr)
{
m_pDiffVScrollBar->setValue(m_pDiffVScrollBar->value() + deltaY);
m_pOverview->setRange(m_pDiffVScrollBar->value(), m_pDiffVScrollBar->pageStep());
}
if(deltaX != 0)
if(deltaX != 0 && m_pHScrollBar != nullptr)
m_pHScrollBar->QScrollBar::setValue(m_pHScrollBar->value() + deltaX);
}
......@@ -953,15 +958,23 @@ void KDiff3App::keyPressEvent(QKeyEvent* keyEvent)
break;
case Qt::Key_Home:
if(bCtrl)
m_pDiffVScrollBar->setValue(0);
{
if(m_pDiffVScrollBar != nullptr) m_pDiffVScrollBar->setValue(0);
}
else
m_pHScrollBar->setValue(0);
{
if(m_pHScrollBar != nullptr) m_pHScrollBar->setValue(0);
}
break;
case Qt::Key_End:
if(bCtrl)
m_pDiffVScrollBar->setValue(m_pDiffVScrollBar->maximum());
{
if(m_pDiffVScrollBar != nullptr) m_pDiffVScrollBar->setValue(m_pDiffVScrollBar->maximum());
}
else
m_pHScrollBar->setValue(m_pHScrollBar->maximum());
{
if(m_pHScrollBar != nullptr) m_pHScrollBar->setValue(m_pHScrollBar->maximum());
}
break;
default:
break;
......@@ -2470,15 +2483,15 @@ void KDiff3App::slotUpdateAvailabilities()
fileSave->setEnabled(m_bOutputModified && bSavable);
fileSaveAs->setEnabled(bSavable);
goTop->setEnabled(bDiffWindowVisible && bMergeEditorVisible && m_pMergeResultWindow->isDeltaAboveCurrent());
goBottom->setEnabled(bDiffWindowVisible && bMergeEditorVisible && m_pMergeResultWindow->isDeltaBelowCurrent());
goTop->setEnabled(bDiffWindowVisible && m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isDeltaAboveCurrent());
goBottom->setEnabled(bDiffWindowVisible && m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isDeltaBelowCurrent());
goCurrent->setEnabled(bDiffWindowVisible);
goPrevUnsolvedConflict->setEnabled(bMergeEditorVisible && m_pMergeResultWindow->isUnsolvedConflictAboveCurrent());
goNextUnsolvedConflict->setEnabled(bMergeEditorVisible && m_pMergeResultWindow->isUnsolvedConflictBelowCurrent());
goPrevConflict->setEnabled(bDiffWindowVisible && bMergeEditorVisible && m_pMergeResultWindow->isConflictAboveCurrent());
goNextConflict->setEnabled(bDiffWindowVisible && bMergeEditorVisible && m_pMergeResultWindow->isConflictBelowCurrent());
goPrevDelta->setEnabled(bDiffWindowVisible && bMergeEditorVisible && m_pMergeResultWindow->isDeltaAboveCurrent());
goNextDelta->setEnabled(bDiffWindowVisible && bMergeEditorVisible && m_pMergeResultWindow->isDeltaBelowCurrent());
goPrevDelta->setEnabled(bDiffWindowVisible && m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isDeltaAboveCurrent());
goNextDelta->setEnabled(bDiffWindowVisible && m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isDeltaBelowCurrent());
overviewModeNormal->setEnabled(m_bTripleDiff && bDiffWindowVisible);
overviewModeAB->setEnabled(m_bTripleDiff && bDiffWindowVisible);
......
......@@ -13,11 +13,13 @@
#include "common.h"
#include <QApplication>
#include <QEventLoop>
#include <QLabel>
#include <QPointer>
#include <QProgressBar>
#include <QPushButton>
#include <QStatusBar>
#include <QTimer>
#include <QThread>
#include <QVBoxLayout>
......@@ -259,9 +261,6 @@ void ProgressDialog::setSubRangeTransformation(double dMin, double dMax)
pld.m_dSubRangeMax = dMax;
}
void qt_enter_modal(QWidget*);
void qt_leave_modal(QWidget*);
void ProgressDialog::enterEventLoop(KJob* pJob, const QString& jobInfo)
{
m_pJob = pJob;
......@@ -277,13 +276,16 @@ void ProgressDialog::enterEventLoop(KJob* pJob, const QString& jobInfo)
show();
// instead of using exec() the eventloop is entered and exited often without hiding/showing the window.
//qt_enter_modal(this);
QPointer<QEventLoop> pEventLoop = QPointer<QEventLoop>(new QEventLoop(this));
m_eventLoopStack.push_back(pEventLoop);
pEventLoop->exec(); // this function only returns after ProgressDialog::exitEventLoop() is called.
pEventLoop.clear();
m_eventLoopStack.pop_back();
//qt_leave_modal(this);
if(m_eventLoop == nullptr)
{
m_eventLoop = QPointer<QEventLoop>(new QEventLoop(this));
m_eventLoop->exec(); // this function only returns after ProgressDialog::exitEventLoop() is called.
m_eventLoop.clear();
}
else
{
m_eventLoop->processEvents(QEventLoop::WaitForMoreEvents);
}
}
void ProgressDialog::exitEventLoop()
......@@ -292,8 +294,8 @@ void ProgressDialog::exitEventLoop()
killTimer(m_progressDelayTimer);
m_progressDelayTimer = 0;
m_pJob = nullptr;
if(!m_eventLoopStack.empty())
m_eventLoopStack.back()->exit();
if( m_eventLoop != nullptr)
m_eventLoop->exit();
}
void ProgressDialog::recalc(bool bUpdate)
......@@ -344,7 +346,6 @@ void ProgressDialog::recalc(bool bUpdate)
}
}
#include <QTimer>
void ProgressDialog::show()
{
if(m_progressDelayTimer)
......@@ -443,6 +444,8 @@ void ProgressDialog::cancel(e_CancelReason eCancelReason)
{
m_bWasCancelled = true;
m_eCancelReason = eCancelReason;
if(m_eventLoop != nullptr)
m_eventLoop->exit(1);
}
}
......
......@@ -14,6 +14,7 @@
#define PROGRESS_H
#include <QDialog>
#include <QPointer>
#include <QTime>
#include <QList>
......@@ -84,7 +85,7 @@ private:
int m_progressDelayTimer;
int m_delayedHideTimer;
int m_delayedHideStatusBarWidgetTimer;
QList<QEventLoop*> m_eventLoopStack;
QPointer<QEventLoop> m_eventLoop;
QProgressBar* m_pProgressBar;
QProgressBar* m_pSubProgressBar;
......@@ -96,7 +97,7 @@ private:
QTime m_t2;
bool m_bWasCancelled;
e_CancelReason m_eCancelReason;
KJob* m_pJob;
KJob* m_pJob = nullptr;
QString m_currentJobInfo; // Needed if the job doesn't stop after a reasonable time.
bool m_bStayHidden;
QThread* m_pGuiThread;
......
......@@ -83,9 +83,9 @@ public:
QCheckBox* m_pSearchInOutput;
QCheckBox* m_pCaseSensitive;
int currentLine;
int currentPos;
int currentWindow;
int currentLine = 0;
int currentPos = 0;
int currentWindow = 0;
};
......
......@@ -3,7 +3,7 @@
;Apdapted for KDiff3 by Sebastien Fricker and Joachim Eibl
;Requires nsis_v2.19
!define KDIFF3_VERSION "1.08.00"
!define KDIFF3_VERSION "1.08.02"
!define DIFF_EXT32_CLSID "{9F8528E4-AB20-456E-84E5-3CE69D8720F3}"
!define DIFF_EXT64_CLSID "{34471FFB-4002-438b-8952-E4588D0C0FE9}"
......