...
 
Commits (111)
stages:
- build
- test
build_ubuntu_18_04:
stage: build
image: reporter123/cmake:bionic
before_script:
- apt-get update
- apt-get install -y libqt5test5 gettext qtbase5-dev extra-cmake-modules libkf5i18n-dev libkf5coreaddons-dev libkf5iconthemes-dev libkf5parts-dev libkf5doctools-dev libkf5crash-dev
script:
- cmake -DBUILD_TESTING=YES .
- make
artifacts:
untracked: true
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure
ubuntu_18_04_test:
stage: test
needs: ["build_ubuntu_18_04"]
image: reporter123/cmake:bionic
before_script:
- apt-get update
- apt-get install -y libqt5test5
script:
- make ARGS="-V -E appstreamtest" test #exclude appstreamtest this does not run properly in my image
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure
EXCLUDE copyright,license
......@@ -3,11 +3,12 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
project(kdiff3)
set(CMAKE_CXX_EXTENSIONS OFF ) #don't use non-standard extensions
set(CMAKE_CXX_EXTENSIONS ON ) #disable trigraphs in clang/gcc -- officially removed in c++17
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(ECM_MIN_VERSION "5.10.0")
set(QT_MIN_VERSION "5.6.0")
set(KF5_MIN_VERSION "5.23.0")
#KF5 5.27 fixes a crash bug triggered on exit.
set(KF5_MIN_VERSION "5.27.0")
find_package(ECM ${ECM_MIN_VERSION} CONFIG REQUIRED)
set(
......@@ -25,7 +26,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 +50,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 )
......@@ -56,14 +58,16 @@ set(KDiff3_LIBRARIES ${Qt5PrintSupport_LIBRARIES} KF5::I18n KF5::CoreAddons KF5:
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
#Adjust clang specific warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wshadow")
set(CLANG_WARNING_FLAGS "-Wno-invalid-pp-token -Wno-comment -Wshorten-64-to-32 -Wstring-conversion -Wc++11-narrowing -fstack-protector-all")
set(CLANG_WARNING_FLAGS "-Wno-trigraphs -Wno-invalid-pp-token -Wno-comment -Wshorten-64-to-32 -Wstring-conversion -Wc++11-narrowing -fstack-protector-all")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CLANG_WARNING_FLAGS}")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_definitions(-DNOMINMAX) #Suppress MSVCs min/max macros
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-check")
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wduplicated-cond -Wduplicated-branches -Wshadow")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-trigraphs -Wduplicated-cond -Wduplicated-branches -Wshadow")
endif()
endif()
......@@ -89,6 +93,12 @@ set(
cxx_static_assert
)
if(ENABLE_AUTO)
add_definitions(
-DENABLE_AUTO
)
endif()
add_definitions(
-DQT_DEPRECATED_WARNINGS #Get warnings from QT about deprecated functions.
-DQT_NO_URL_CAST_FROM_STRING # casting from string to url does not always behave as you might think
......
Version 1.8.2 - 2020-03-29
===========================
Bug 411472 Allowing editing of blank lines and don't mark newly intserted lines as a confilict
2ba20222 - Remove broken attempt to optimize drawing on horizonal scroll.
Bug 418813 - Fix line numbers not shown. Use QString::number directly not through a format string.
11e93232 - Correcly support "Print Current Page"
64804a64 - Don't attempt to free nullptr in SourceData::FileData::reset()
f4c66ace - Make Preferance dialog panes scrollable if too large to fit on screen.
de06e561 - Fix dialog filter on windows.
e8d06774 - Switch to QElapsedTime for timing avoids explictly undefined behavior inside qt if time is changed.
05e2d6fb - Fix sync mode.
f9bd88a1 - Make matching in CvsIngnoreList always honor bCaseSensitive setting.
418ea78c - Don't use temporary with QLatin1String constructor strange things will happen.
b058c060 - ignore over size cvsignore files
Bug 410962 - Fix '-L' parameter handling
b4b2c970 - Restore acciedently deleted --auto option
Bug 411602 - Fixing missing menu items also resolves a potiential crash in MergeResultWindow::slotUpdateAvailabilities (Bug 407745).
d4239b92 - Prevent intermient crash during reload/refresh
Bug 410008 - Show diff for empty/missing files.
3bb755c5 - Don't give false error when comparing empty folders
Bug 408991 - 4ad69790,0737cc3e,0402f84a - Close files when not in use - Fixes "Too many open files" bug.
Bug 407829 - Avoid crash when recieving mouse or key events during earily startup.
cc6d76e3 - Don't try to manually build url if parent is not set.
85052379 - Fix crash when canceling by using only one event loop in ProgressDialog.
d151f151 - Don't append to already complete url.
d3cb2def - Fix manual url building in FileAccess::setFromUdsEntry - scheme should not change now.
Bug 405918 - Fix craft install instructions for windows
Bug 411586 - Fix crash in OptionDialog::slotApply()
Bug 407745 - Fix crash in MergeResultWindow::slotUpdateAvailabilities
Bug 407894,399070 - Fixed redraw for horizonal scrolling.
Version 1.8 - 2019-03-22
===========================
-Don't enable "Choose C for Everthing" on two way merge.
......
Building KDiff3 requires the fallowing minimium versions:
1)Qt 5.6 or later
2)KF5 5.14+
2)KF5 5.27+
3)CMake 3.1
4)ECM 1.8
Support compilers:
......@@ -33,14 +33,30 @@ Run the fallowing.
1)Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
2)iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/KDE/craft/master/setup/install_craft.ps1'))
You may also have exempt your craft directory from virus scans as these can interefer with the build process.
You may also have to exempt your craft directory from virus scans as these can interefer with the build process.
1)cd to your craft root
Run:
2)C:\CraftRoot\craft\craftenv.ps1
3)craft --package kdiff3
3)craft png2ico
4)craft kdiff3
If you what to build 1.8x than use:
4) craft --target 1.8 kdiff3
This will be a time consuming process on first run as craft will have download all dependencies.
Otherwise craft will use master which is the developement branch and therefor more likely to experiance breakage.
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 or craft --target 1.8 --package kdiff3
This will be a time consuming process on first run as craft will have to 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 filing a bug report regarding this process.
\ No newline at end of file
......@@ -3,18 +3,20 @@ KDiff3-Readme
Author: Joachim Eibl (joachim.eibl at gmx.de)
Port to KF5/Qt5 by Michael Reeves (reeves.87@gmail.com)
KDiff3-Version: 1.8
KDiff3-Version: 1.8.2
Now requires Qt 5.6 or later and KF5 5.14+. Legacy 0.9.98 and earlier builds are not supported.
Now requires Qt 5.6 or later and KF5 5.27+. Legacy 0.9.98 and earlier builds are not supported.
MacOSX build is untested since port. The Konqueror specific plugin is not ported and no longer maintained.
This plugin would only apply to KDE before 4.6. Support as been removed from main CMakeLists.txt.
As of 1/13/17 cmake 3.1+ is the targeted cmake version.
This plugin would only apply to KDE before 4.6. As of 1/13/17 cmake 3.1+ is the targeted cmake version.
cmake is now the only build system supported. KF5/Qt5 was big jump. A lot changed besides just the API.
I am not against a Qt5-only build variant but see no reason to maintain two separate build systems.
At present KF5 is my focus.
The current reprository is at https://invent.kde.org/kde/kdiff3
Bugs can be reported at https://bugs.kde.org
The original pre KF5/Qt5 Readme follows old build instructions have been removed to avoid confusion:
......
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 )
......
......@@ -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
......@@ -11,18 +11,24 @@
"Name[de]": "Dateien und Ordner vergleichen und zusammenführen mit KDiff3",
"Name[en_GB]": "Compare/Merge Files/Directories with KDiff3",
"Name[es]": "Comparar o fusionar archivos o directorios con KDiff3",
"Name[eu]": "Alderatu/bateratu fitxategiak/direktorioak KDiff3 erabiliz",
"Name[fi]": "Vertaa ja yhdistä tiedostoja ja kansioita KDiff3:lla",
"Name[fr]": "Comparaison et fusion de fichiers ou de dossiers à l'aide de « KDiff3 »",
"Name[gl]": "Comparar ou mesturar ficheiros ou directorios con KDiff3",
"Name[ia]": "Compara/Fusiona Files/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[nn]": "Samanlikna/flett filer/mapper med KDiff3",
"Name[pl]": "Porównuj/Scalaj pliki/katalogi z KDiff3",
"Name[pt]": "Comparar/Reunir os Ficheiros/Pastas com o KDiff3",
"Name[pt_BR]": "Comparar/Mesclar arquivos/pastas com o KDiff3",
"Name[ru]": "Сравнение и слияние файлов и каталогов с использованием приложения KDiff3",
"Name[sk]": "Porovnať/zlúčiť súbory/adresáre s KDiff3",
"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"
......
......@@ -31,6 +31,10 @@ set(kdiff3part_PART_SRCS
Logging.cpp
FileNameLineEdit.cpp )
ki18n_wrap_ui(kdiff3part_PART_SRCS
scroller.ui
)
add_library(kdiff3part MODULE ${kdiff3part_PART_SRCS})
set_target_properties(kdiff3part PROPERTIES DEFINE_SYMBOL KDIFF3_PART)
......@@ -49,12 +53,33 @@ set(kdiff3_SRCS
${kdiff3part_PART_SRCS}
)
#cann't use add_subdirectory because it changes the scope.
include(icons/CMakeLists.txt)
add_executable(kdiff3 ${kdiff3_SRCS})
target_link_libraries(kdiff3 KF5::ConfigCore KF5::ConfigGui KF5::Parts KF5::Crash ${KDiff3_LIBRARIES} )
target_compile_features(kdiff3 PRIVATE ${needed_features})
install(TARGETS kdiff3 ${INSTALL_TARGETS_DEFAULT_ARGS})
# See https://cmake.org/cmake/help/v3.15/prop_tgt/MACOSX_BUNDLE_INFO_PLIST.html
if(APPLE)
set_property(
TARGET kdiff3
PROPERTY MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/MacOSXBundleInfo.plist.in
)
# These are substituted by CMake into plist.in.
set(MACOSX_BUNDLE_DISPLAY_NAME "KDiff3")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.KDiff3")
set(MACOSX_BUNDLE_BUNDLE_NAME "KDiff3")
set(MACOSX_BUNDLE_DISPLAY_NAME "KDiff3")
set(MACOSX_BUNDLE_INFO_STRING "KDiff3 - Diff/Patch Frontend")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "KDiff3 ${KDIFF3_VERSION}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${KDIFF3_VERSION_MAJOR}.${KDIFF3_VERSION_MINOR}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${KDIFF3_VERSION}")
set(MACOSX_BUNDLE_COPYRIGHT "2003-2020 The KDiff3 Authors")
endif()
install(TARGETS kdiff3 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
########### install files ###############
......@@ -66,4 +91,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)
......@@ -49,6 +49,8 @@ class DirectoryInfo
return m_dirC.isValid() ? m_dirC : m_dirB;
}
inline bool allowSyncMode() { return !m_dirC.isValid() && !m_dirDest.isValid(); }
inline bool listDirA(const Options& options)
{
return m_dirA.listDir(&m_dirListA,
......
......@@ -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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>LSRequiresCarbon</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>LSMultipleInstancesProhibited</key>
<true/>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>LSItemContentTypes</key>
<array>
<string>*</string>
</array>
<key>CFBundleTypeName</key>
<string>NSStringPboardType</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
</dict>
</plist>
......@@ -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)
};
......
......@@ -66,6 +66,8 @@ void SourceData::reset()
m_tempFile.remove();
m_tempInputFileName = "";
}
mErrors.clear();
}
void SourceData::setFilename(const QString& filename)
......@@ -125,6 +127,8 @@ void SourceData::setFileAccess(const FileAccess& fileAccess)
m_tempFile.remove();
m_tempInputFileName = "";
}
mErrors.clear();
}
void SourceData::setEncoding(QTextCodec* pEncoding)
{
......@@ -133,8 +137,7 @@ void SourceData::setEncoding(QTextCodec* pEncoding)
QStringList SourceData::setData(const QString& data)
{
QStringList errors;
mErrors.clear();
// Create a temp file for preprocessing:
if(m_tempInputFileName.isEmpty())
{
......@@ -147,7 +150,7 @@ QStringList SourceData::setData(const QString& data)
bool bSuccess = f.writeFile(ba.constData(), ba.length());
if(!bSuccess)
{
errors.append(i18n("Writing clipboard data to temp file failed."));
mErrors.append(i18n("Writing clipboard data to temp file failed."));
}
else
{
......@@ -155,7 +158,7 @@ QStringList SourceData::setData(const QString& data)
m_fileAccess = FileAccess(""); // Effect: m_fileAccess.isValid() is false
}
return errors;
return mErrors;
}
const LineData* SourceData::getLineDataForDiff() const
......@@ -193,7 +196,7 @@ const QString& SourceData::getText() const
bool SourceData::isText()
{
return m_normalData.isText();
return m_normalData.isText() || m_normalData.isEmpty();
}
bool SourceData::isIncompleteConversion()
......@@ -215,12 +218,15 @@ bool SourceData::isBinaryEqualWith(const SourceData& other) const
void SourceData::FileData::reset()
{
if(m_pBuf != nullptr)
{
delete[](char*) m_pBuf;
m_pBuf = nullptr;
}
m_v.clear();
m_size = 0;
m_vSize = 0;
m_bIsText = true;
m_bIsText = false;
m_bIncompleteConversion = false;
m_eLineEndStyle = eLineEndStyleUndefined;
}
......@@ -249,6 +255,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;
}
......@@ -320,7 +334,7 @@ QTextCodec* SourceData::detectEncoding(const QString& fileName, QTextCodec* pFal
return pFallbackCodec;
}
QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetectUnicode)
const QStringList& SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetectUnicode)
{
m_pEncoding = pEncoding;
QTemporaryFile fileIn1, fileOut1;
......@@ -328,12 +342,11 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
QString fileNameOut1;
QString fileNameIn2;
QString fileNameOut2;
QStringList errors;
if(m_fileAccess.isValid() && !m_fileAccess.isNormal())
{
errors.append(i18n("%1 is not a normal file.", m_fileAccess.prettyAbsPath()));
return errors;
mErrors.append(i18n("%1 is not a normal file.", m_fileAccess.prettyAbsPath()));
return mErrors;
}
bool bTempFileFromClipboard = !m_fileAccess.isValid();
......@@ -382,8 +395,8 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
// No preprocessing: Read the file directly:
if(!m_normalData.readFile(faIn))
{
errors.append(faIn.getStatusText());
return errors;
mErrors.append(faIn.getStatusText());
return mErrors;
}
}
else
......@@ -423,12 +436,12 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
{
if(!m_normalData.readFile(faIn))
{
errors.append(faIn.getStatusText());
errors.append(i18n(" Temp file is: %1", fileNameIn1));
return errors;
mErrors.append(faIn.getStatusText());
mErrors.append(i18n(" Temp file is: %1", fileNameIn1));
return mErrors;
}
//Don't fail the preprocessor command if the file cann't be read.
errors.append(
mErrors.append(
i18n("Preprocessing possibly failed. Check this command:\n\n %1"
"\n\nThe preprocessing command will be disabled now.", ppCmd) +
errorReason);
......@@ -440,12 +453,12 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
if(!m_normalData.preprocess(m_pOptions->m_bPreserveCarriageReturn, pEncoding1))
{
errors.append(i18n("File %1 too large to process. Skipping.", fileNameIn1));
return errors;
mErrors.append(i18n("File %1 too large to process. Skipping.", fileNameIn1));
return mErrors;
}
//exit early for non text data further processing assumes a text file as input
if(!m_normalData.isText())
return errors;
return mErrors;
// LineMatching Preprocessor
if(!m_pOptions->m_LineMatchingPreProcessorCmd.isEmpty())
......@@ -483,15 +496,15 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
bool bSuccess = errorReason.isEmpty() && m_lmppData.readFile(fileNameOut2);
if(FileAccess(fileNameIn2).size() > 0 && (!bSuccess || m_lmppData.m_size == 0))
{
errors.append(
mErrors.append(
i18n("The line-matching-preprocessing possibly failed. Check this command:\n\n %1"
"\n\nThe line-matching-preprocessing command will be disabled now.", ppCmd) +
errorReason);
m_pOptions->m_LineMatchingPreProcessorCmd = "";
if(!m_lmppData.readFile(fileNameIn2))
{
errors.append(i18n("Failed to read file: %1", fileNameIn2));
return errors;
mErrors.append(i18n("Failed to read file: %1", fileNameIn2));
return mErrors;
}
}
}
......@@ -501,11 +514,16 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
m_lmppData.copyBufFrom(m_normalData);
}
}
else
{
//exit early for non-existant files
return mErrors;
}
if(!m_lmppData.preprocess(false, pEncoding2))
{
errors.append(i18n("File %1 too large to process. Skipping.", fileNameIn1));
return errors;
mErrors.append(i18n("File %1 too large to process. Skipping.", fileNameIn1));
return mErrors;
}
Q_ASSERT(m_lmppData.isText());
......@@ -533,7 +551,7 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
}
}
return errors;
return mErrors;
}
/** Prepare the linedata vector for every input line.*/
......@@ -597,6 +615,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())
......
......@@ -51,7 +51,7 @@ class SourceData
bool isValid(); // Either no file is specified or reading was successful
// Returns a list of error messages if anything went wrong
QStringList readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetectUnicode);
const QStringList& readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetectUnicode);
bool saveNormalDataAs(const QString& fileName);
bool isBinaryEqualWith(const SourceData& other) const;
......@@ -61,6 +61,7 @@ class SourceData
QTextCodec* getEncoding() const { return m_pEncoding; }
e_LineEndStyle getLineEndStyle() const { return m_normalData.m_eLineEndStyle; }
const QStringList& getErrors() { return mErrors; }
private:
bool convertFileEncoding(const QString& fileNameIn, QTextCodec* pCodecIn,
const QString& fileNameOut, QTextCodec* pCodecOut);
......@@ -76,6 +77,8 @@ class SourceData
QString m_tempInputFileName;
QTemporaryFile m_tempFile; //Created from clipboard content.
QStringList mErrors;
class FileData
{
private:
......@@ -111,11 +114,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
......@@ -15,6 +15,7 @@
#include <QDir>
#include <QTextStream>
#include <qregexp.h>
void CvsIgnoreList::init(FileAccess& dir, const t_DirectoryList* pDirList)
{
......@@ -36,7 +37,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)
......@@ -147,7 +148,12 @@ void CvsIgnoreList::addEntry(const QString& pattern)
bool CvsIgnoreList::matches(const QString& text, bool bCaseSensitive) const
{
if(m_exactPatterns.indexOf(text) >= 0)
/*
Don't let the compilier create a temporary QRegExp explictly create one to prevent a possiable crash
QString::indexOf and therefor QStringList::indexOf may modify the QRegExp passed to it.
*/
QRegExp regexp(text, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
if(m_exactPatterns.indexOf(regexp) >= 0)
{
return true;
}
......@@ -156,7 +162,7 @@ bool CvsIgnoreList::matches(const QString& text, bool bCaseSensitive) const
QStringList::ConstIterator itEnd;
for(it = m_startPatterns.begin(), itEnd = m_startPatterns.end(); it != itEnd; ++it)
{
if(text.startsWith(*it))
if(text.startsWith(*it, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive))
{
return true;
}
......@@ -164,7 +170,7 @@ bool CvsIgnoreList::matches(const QString& text, bool bCaseSensitive) const
for(it = m_endPatterns.begin(), itEnd = m_endPatterns.end(); it != itEnd; ++it)
{
if(text.mid(text.length() - (*it).length()) == *it) //(text.endsWith(*it))
if(text.midRef(text.length() - (*it).length()).compare(*it, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) == 0) //(text.endsWith(*it))
{
return true;
}
......
......@@ -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
......
This diff is collapsed.
......@@ -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;
......
......@@ -28,6 +28,7 @@
#include <QApplication>
#include <QDialogButtonBox>
#include <QDir>
#include <QElapsedTimer>
#include <QFileDialog>
#include <QImage>
#include <QKeyEvent>
......@@ -556,7 +557,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 +585,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 +616,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 +743,7 @@ bool DirectoryMergeWindow::DirectoryMergeWindowPrivate::fastFileComparison(
if(!fi2.open(QIODevice::ReadOnly))
{
fi1.close();
status = fi2.errorString();
return bEqual;
}
......@@ -758,17 +761,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 +789,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;
}
......@@ -1002,7 +1014,7 @@ bool DirectoryMergeWindow::DirectoryMergeWindowPrivate::init(
m_bScanning = true;
emit q->statusBarMessage(i18n("Scanning directories..."));
m_bSyncMode = m_pOptions->m_bDmSyncMode && !dirC.isValid() && !dirDest.isValid();
m_bSyncMode = m_pOptions->m_bDmSyncMode && dirInfo->allowSyncMode();
m_fileMergeMap.clear();
s_eCaseSensitivity = m_bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
......@@ -1680,7 +1692,7 @@ void DirectoryMergeWindow::DirectoryMergeWindowPrivate::prepareListView(Progress
t_fileMergeMap::iterator j;
int nrOfFiles = m_fileMergeMap.size();
int currentIdx = 1;
QTime t;
QElapsedTimer t;
t.start();
pp.setMaxNofSteps(nrOfFiles);
......@@ -2507,7 +2519,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"
......@@ -51,7 +52,9 @@ void FileAccess::reset()
m_bFile = false;
m_bDir = false;
m_bSymLink = false;
m_bReadable = false;
m_bWritable = false;
m_bExecutable = false;
m_bHidden = false;
m_size = 0;
m_modificationTime = QDateTime();
......@@ -62,7 +65,6 @@ void FileAccess::reset()
m_linkTarget = "";
//m_fileType = -1;
m_pParent = nullptr;
tmpFile.clear();
tmpFile = QSharedPointer<QTemporaryFile>::create();
realFile = nullptr;
......@@ -101,6 +103,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 +134,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 +161,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 +284,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())
......@@ -339,8 +359,8 @@ bool FileAccess::exists() const
{
if(!isLocal())
return m_bExists;
else
return m_fileInfo.exists();
else//Thank you git for being different.
return m_fileInfo.exists() && absoluteFilePath() != "/dev/null";
}
qint64 FileAccess::size() const
......@@ -473,6 +493,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 +501,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 +522,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 +530,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 +852,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 +1158,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 +1243,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);
}
......
......@@ -117,10 +117,10 @@ class FileAccess
bool interruptableReadFile(void* pDestBuffer, qint64 maxLength);
QUrl m_url;
bool m_bValidData;
bool m_bValidData = false;
//long m_fileType; // for testing only
FileAccess* m_pParent;
FileAccess* m_pParent = nullptr;
QDir m_baseDir;