diff options
Diffstat (limited to 'src/corelib')
64 files changed, 1458 insertions, 357 deletions
diff --git a/src/corelib/.prev_CMakeLists.txt b/src/corelib/.prev_CMakeLists.txt index a6e862e1de..78b9c17b3f 100644 --- a/src/corelib/.prev_CMakeLists.txt +++ b/src/corelib/.prev_CMakeLists.txt @@ -385,6 +385,7 @@ qt_extend_target(Core CONDITION WIN32 AND NOT WINRT qt_extend_target(Core CONDITION APPLE SOURCES global/qoperatingsystemversion_darwin.mm + io/qfilesystemengine_mac.mm io/qstandardpaths_mac.mm io/qstorageinfo_mac.cpp kernel/qcfsocketnotifier.cpp kernel/qcfsocketnotifier_p.h diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 64c993fe9f..45b0033abe 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -492,6 +492,7 @@ qt_extend_target(Core CONDITION WIN32 AND NOT WINRT qt_extend_target(Core CONDITION APPLE SOURCES global/qoperatingsystemversion_darwin.mm + io/qfilesystemengine_mac.mm io/qstandardpaths_mac.mm io/qstorageinfo_mac.cpp kernel/qcfsocketnotifier.cpp kernel/qcfsocketnotifier_p.h diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 2bc97c6d12..94d270b739 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -59,7 +59,14 @@ macro(qt6_make_output_file infile prefix ext outfile ) set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${rel}") string(REPLACE ".." "__" _outfile ${_outfile}) get_filename_component(outpath ${_outfile} PATH) - get_filename_component(_outfile ${_outfile} NAME_WE) + if(CMAKE_VERSION VERSION_LESS "3.14") + get_filename_component(_outfile_ext ${_outfile} EXT) + get_filename_component(_outfile_ext ${_outfile_ext} NAME_WE) + get_filename_component(_outfile ${_outfile} NAME_WE) + string(APPEND _outfile ${_outfile_ext}) + else() + get_filename_component(_outfile ${_outfile} NAME_WLE) + endif() file(MAKE_DIRECTORY ${outpath}) set(${outfile} ${outpath}/${prefix}${_outfile}.${ext}) endmacro() diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp index a140175956..d30ad50ffc 100644 --- a/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -135,7 +135,7 @@ class Employee { public: Employee() {} - Employee(const QString &name, const QDate &dateOfBirth); + Employee(const QString &name, QDate dateOfBirth); ... private: diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp index 506022f082..145cd10d84 100644 --- a/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp @@ -151,7 +151,7 @@ class Employee { public: Employee() {} - Employee(const QString &name, const QDate &dateOfBirth); + Employee(const QString &name, QDate dateOfBirth); ... private: diff --git a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp index 84a156bb6d..879cdbe329 100644 --- a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp +++ b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp @@ -61,14 +61,13 @@ ButtonWidget::ButtonWidget(const QStringList &texts, QWidget *parent) QGridLayout *gridLayout = new QGridLayout; for (int i = 0; i < texts.size(); ++i) { QPushButton *button = new QPushButton(texts[i]); - connect(button, &QPushButton::clicked, - signalMapper, &QSignalMapper::map); + connect(button, &QPushButton::clicked, signalMapper, &QSignalMapper::map); //! [0] //! [1] signalMapper->setMapping(button, texts[i]); gridLayout->addWidget(button, i / 3, i % 3); } - connect(signalMapper, QOverload<const QString &>::of(&QSignalMapper::mapped), + connect(signalMapper, &QSignalMapper::mappedString, //! [1] //! [2] this, &ButtonWidget::clicked); diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp index 51766c9760..80a851e4e4 100644 --- a/src/corelib/global/qfloat16.cpp +++ b/src/corelib/global/qfloat16.cpp @@ -213,7 +213,7 @@ f16cextern void qFloatFromFloat16_fast(float *out, const quint16 *in, qsizetype #undef f16cextern } -#elif defined(__ARM_FP16_FORMAT_IEEE) && defined(__ARM_NEON__) +#elif defined(__ARM_FP16_FORMAT_IEEE) && defined(__ARM_NEON__) && (__ARM_FP & 2) static inline bool hasFastF16() { return true; diff --git a/src/corelib/global/qfloat16tables.cpp b/src/corelib/global/qfloat16tables.cpp index 3d764937d7..b87986d6b8 100644 --- a/src/corelib/global/qfloat16tables.cpp +++ b/src/corelib/global/qfloat16tables.cpp @@ -44,7 +44,7 @@ QT_BEGIN_NAMESPACE -#if !defined(__F16C__) && !defined(__ARM_FP16_FORMAT_IEEE) +#if !defined(__ARM_FP16_FORMAT_IEEE) const quint32 qfloat16::mantissatable[2048] = { 0, diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index ca4d8dbd11..123cc88ad6 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1669,14 +1669,34 @@ static bool android_default_message_handler(QtMsgType type, #endif //Q_OS_ANDROID #ifdef Q_OS_WIN +static void win_outputDebugString_helper(QStringView message) +{ + const int maxOutputStringLength = 32766; + static QBasicMutex m; + auto locker = qt_unique_lock(m); + // fast path: Avoid string copies if one output is enough + if (message.length() <= maxOutputStringLength) { + OutputDebugString(reinterpret_cast<const wchar_t *>(message.utf16())); + } else { + wchar_t *messagePart = new wchar_t[maxOutputStringLength + 1]; + for (int i = 0; i < message.length(); i += maxOutputStringLength ) { + const int length = std::min(message.length() - i, maxOutputStringLength ); + const int len = message.mid(i, length).toWCharArray(messagePart); + Q_ASSERT(len == length); + messagePart[len] = 0; + OutputDebugString(messagePart); + } + delete[] messagePart; + } +} + static bool win_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message) { if (shouldLogToStderr()) return false; // Leave logging up to stderr handler - QString formattedMessage = qFormatLogMessage(type, context, message); - formattedMessage.append(QLatin1Char('\n')); - OutputDebugString(reinterpret_cast<const wchar_t *>(formattedMessage.utf16())); + const QString formattedMessage = qFormatLogMessage(type, context, message).append('\n'); + win_outputDebugString_helper(formattedMessage); return true; // Prevent further output to stderr } @@ -1832,11 +1852,11 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex static void qt_message_print(const QString &message) { #if defined(Q_OS_WINRT) - OutputDebugString(reinterpret_cast<const wchar_t*>(message.utf16())); + win_outputDebugString_helper(message); return; #elif defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) if (!shouldLogToStderr()) { - OutputDebugString(reinterpret_cast<const wchar_t*>(message.utf16())); + win_outputDebugString_helper(message); return; } #endif diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index f278850ccf..57ccd308d7 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -1249,14 +1249,16 @@ namespace Qt { enum DateFormat { TextDate, // default Qt ISODate, // ISO 8601 - SystemLocaleDate, // deprecated - LocalDate = SystemLocaleDate, // deprecated - LocaleDate, // deprecated - SystemLocaleShortDate, - SystemLocaleLongDate, - DefaultLocaleShortDate, - DefaultLocaleLongDate, - RFC2822Date, // RFC 2822 (+ 850 and 1036 during parsing) +#if QT_DEPRECATED_SINCE(5, 15) + SystemLocaleDate Q_DECL_ENUMERATOR_DEPRECATED_X("Use QLocale"), + LocalDate Q_DECL_ENUMERATOR_DEPRECATED_X("Use QLocale") = 2, // i.e. SystemLocaleDate + LocaleDate Q_DECL_ENUMERATOR_DEPRECATED_X("Use QLocale"), + SystemLocaleShortDate Q_DECL_ENUMERATOR_DEPRECATED_X("Use QLocale"), + SystemLocaleLongDate Q_DECL_ENUMERATOR_DEPRECATED_X("Use QLocale"), + DefaultLocaleShortDate Q_DECL_ENUMERATOR_DEPRECATED_X("Use QLocale"), + DefaultLocaleLongDate Q_DECL_ENUMERATOR_DEPRECATED_X("Use QLocale"), +#endif + RFC2822Date = 8, // RFC 2822 (+ 850 and 1036 during parsing) ISODateWithMs }; @@ -1750,7 +1752,7 @@ namespace Qt { }; // QTBUG-48701 - enum ReturnByValue_t { ReturnByValue }; // ### Qt 7: Remove me + enum ReturnByValueConstant { ReturnByValue }; // ### Qt 7: Remove me #ifndef Q_QDOC // NOTE: Generally, do not add Q_ENUM_NS if a corresponding Q_FLAG_NS exists. diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 9acb978efc..708ecb11ab 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -709,26 +709,38 @@ \value ISODateWithMs \l{ISO 8601} extended format, including milliseconds if applicable. - \value SystemLocaleShortDate The \l{QLocale::ShortFormat}{short format} used - by the \l{QLocale::system()}{operating system}. + \value SystemLocaleShortDate \e{This enum value is deprecated and + shall be removed in Qt 6.} Use QLocale's methods for converting + dates and times to and from strings, with the + \l{QLocale::ShortFormat}{short format} of + \l{QLocale::system()}{the locale used by the operating system}. - \value SystemLocaleLongDate The \l{QLocale::LongFormat}{long format} used - by the \l{QLocale::system()}{operating system}. + \value SystemLocaleLongDate \e{This enum value is deprecated and + shall be removed in Qt 6.} Use QLocale's methods for converting + dates and times to and from strings, with the + \l{QLocale::LongFormat}{long format} of \l{QLocale::system()}{the + locale used by the operating system}. - \value DefaultLocaleShortDate The \l{QLocale::ShortFormat}{short format} specified - by the \l{QLocale::setDefault()}{application's locale}. + \value DefaultLocaleShortDate \e{This enum value is deprecated and + shall be removed in Qt 6.} Use QLocale's methods for converting + dates and times to and from strings, with the + \l{QLocale::ShortFormat}{short format} of + \l{QLocale::setDefault()}{the application's locale}. - \value DefaultLocaleLongDate The \l{QLocale::LongFormat}{long format} used - by the \l{QLocale::setDefault()}{application's locale}. + \value DefaultLocaleLongDate \e{This enum value is deprecated and + shall be removed in Qt 6.} Use QLocale's methods for converting + dates and times to and from strings, with the + \l{QLocale::LongFormat}{long format} \l{QLocale::setDefault()}{the + application's locale}. - \value SystemLocaleDate \e{This enum value is deprecated.} Use Qt::SystemLocaleShortDate - instead (or Qt::SystemLocaleLongDate if you want long dates). + \value SystemLocaleDate \e{This enum value is deprecated and shall + be removed in Qt 6.} It is equivalent to SystemLocaleShortDate. - \value LocaleDate \e{This enum value is deprecated.} Use Qt::DefaultLocaleShortDate - instead (or Qt::DefaultLocaleLongDate if you want long dates). + \value LocaleDate \e{This enum value is deprecated and shall be + removed in Qt 6.} It is equivalent to DefaultLocaleShortDate. - \value LocalDate \e{This enum value is deprecated.} Use Qt::SystemLocaleShortDate - instead (or Qt::SystemLocaleLongDate if you want long dates). + \value LocalDate \e{This enum value is deprecated and shall be + removed in Qt 6.} It is equivalent to SystemLocaleShortDate. \value RFC2822Date \l{RFC 2822}, \l{RFC 850} and \l{RFC 1036} format: either \c{[ddd,] dd MMM yyyy [hh:mm[:ss]][ ±tzoff]} @@ -1187,6 +1199,7 @@ \value WA_StyleSheetTarget Indicates that the widget appearance was modified by a \l{Qt Style Sheets}{style sheet}. WA_StyleSheet will also be set. + This value was introduced in Qt 5.12. \value WA_TabletTracking Indicates that the widget has tablet tracking enabled. See QWidget::tabletTracking. @@ -3321,7 +3334,7 @@ */ /*! - \enum Qt::ReturnByValue_t + \enum Qt::ReturnByValueConstant \since 5.15 This is a dummy type, designed to help users transition from certain deprecated APIs to their replacement APIs. diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index c4c6f41387..a33ffe75f2 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -183,7 +183,9 @@ win32 { SOURCES += io/qstorageinfo_mac.cpp qtConfig(processenvironment): \ OBJECTIVE_SOURCES += io/qprocess_darwin.mm - OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm + OBJECTIVE_SOURCES += \ + io/qstandardpaths_mac.mm \ + io/qfilesystemengine_mac.mm osx { LIBS += -framework DiskArbitration -framework IOKit } else { diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 5320ae2986..0cdc5bd6d3 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -552,6 +552,66 @@ QFile::remove(const QString &fileName) } /*! + \since 5.15 + + Moves the file specified by fileName() to the trash. Returns \c true if successful, + and sets the fileName() to the path at which the file can be found within the trash; + otherwise returns \c false. + + \note On systems where the system API doesn't report the location of the file in the + trash, fileName() will be set to the null string once the file has been moved. On + systems that don't have a trash can, this function always returns false. +*/ +bool +QFile::moveToTrash() +{ + Q_D(QFile); + if (d->fileName.isEmpty() && + !static_cast<QFSFileEngine *>(d->engine())->isUnnamedFile()) { + qWarning("QFile::remove: Empty or null file name"); + return false; + } + unsetError(); + close(); + if (error() == QFile::NoError) { + QFileSystemEntry fileEntry(d->fileName); + QFileSystemEntry trashEntry; + QSystemError error; + if (QFileSystemEngine::moveFileToTrash(fileEntry, trashEntry, error)) { + setFileName(trashEntry.filePath()); + unsetError(); + return true; + } + d->setError(QFile::RenameError, error.toString()); + } + return false; +} + +/*! + \since 5.15 + \overload + + Moves the file specified by fileName() to the trash. Returns \c true if successful, + and sets \a pathInTrash (if provided) to the path at which the file can be found within + the trash; otherwise returns \c false. + + \note On systems where the system API doesn't report the path of the file in the + trash, \a pathInTrash will be set to the null string once the file has been moved. + On systems that don't have a trash can, this function always returns false. +*/ +bool +QFile::moveToTrash(const QString &fileName, QString *pathInTrash) +{ + QFile file(fileName); + if (file.moveToTrash()) { + if (pathInTrash) + *pathInTrash = file.fileName(); + return true; + } + return false; +} + +/*! Renames the file currently specified by fileName() to \a newName. Returns \c true if successful; otherwise returns \c false. diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h index 2099b2852f..917fec4e1a 100644 --- a/src/corelib/io/qfile.h +++ b/src/corelib/io/qfile.h @@ -125,6 +125,9 @@ public: bool remove(); static bool remove(const QString &fileName); + bool moveToTrash(); + static bool moveToTrash(const QString &fileName, QString *pathInTrash = nullptr); + bool rename(const QString &newName); static bool rename(const QString &oldName, const QString &newName); diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 3fe1aec41f..64b1557231 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -1147,6 +1147,8 @@ bool QFileInfo::isShortcut() const /*! + \since 5.15 + Returns \c true if the object points to a junction; otherwise returns \c false. diff --git a/src/corelib/io/qfilesystemengine_mac.mm b/src/corelib/io/qfilesystemengine_mac.mm new file mode 100644 index 0000000000..258ae2e8e0 --- /dev/null +++ b/src/corelib/io/qfilesystemengine_mac.mm @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qfilesystemengine_p.h" +#include "qfile.h" +#include "qurl.h" + +#include <QtCore/private/qcore_mac_p.h> +#include <CoreFoundation/CoreFoundation.h> + +QT_BEGIN_NAMESPACE + +/* + This implementation does not enable the "put back" option in Finder + for the trashed object. The only way to get this is to use Finder automation, + which would query the user for permission to access Finder using a modal, + blocking dialog - which we definitely can't have in a console application. + + Using Finder would also play the trash sound, which we don't want either in + such a core API; applications that want that can play the sound themselves. +*/ +//static +bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source, + QFileSystemEntry &newLocation, QSystemError &error) +{ +#ifdef Q_OS_MACOS // desktop macOS has a trash can + QMacAutoReleasePool pool; + + QFileInfo info(source.filePath()); + NSString *filepath = info.filePath().toNSString(); + NSURL *fileurl = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()]; + NSURL *resultingUrl = nil; + NSError *nserror = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + if ([fm trashItemAtURL:fileurl resultingItemURL:&resultingUrl error:&nserror] != YES) { + error = QSystemError(nserror.code, QSystemError::NativeError); + return false; + } + newLocation = QFileSystemEntry(QUrl::fromNSURL(resultingUrl).path()); + return true; +#else // watch, tv, iOS don't have a trash can + return false; +#endif +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h index ecfdc03743..555483a972 100644 --- a/src/corelib/io/qfilesystemengine_p.h +++ b/src/corelib/io/qfilesystemengine_p.h @@ -88,7 +88,7 @@ inline bool qIsFilenameBroken(const QFileSystemEntry &entry) Q_RETURN_ON_INVALID_FILENAME("Broken filename passed to function", (result)); \ } while (false) -class QFileSystemEngine +class Q_AUTOTEST_EXPORT QFileSystemEngine { public: static bool isCaseSensitive() @@ -155,6 +155,7 @@ public: static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); static bool copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); + static bool moveFileToTrash(const QFileSystemEntry &source, QFileSystemEntry &newLocation, QSystemError &error); static bool renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); static bool renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error); static bool removeFile(const QFileSystemEntry &entry, QSystemError &error); diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 3bbebc7fe9..eaf4e2d9af 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -42,6 +42,8 @@ #include "qplatformdefs.h" #include "qfilesystemengine_p.h" #include "qfile.h" +#include "qstorageinfo.h" +#include "qtextstream.h" #include <QtCore/qoperatingsystemversion.h> #include <QtCore/private/qcore_unix_p.h> @@ -1197,6 +1199,216 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy return false; } +#ifndef Q_OS_DARWIN +/* + Implementing as per https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html +*/ + +// bootstrapped tools don't need this, and we don't want QStorageInfo +#ifndef QT_BOOTSTRAPPED +static QString freeDesktopTrashLocation(const QString &sourcePath) +{ + auto makeTrashDir = [](const QDir &topDir, const QString &trashDir) -> QString { + auto ownerPerms = QFileDevice::ReadOwner + | QFileDevice::WriteOwner + | QFileDevice::ExeOwner; + QString targetDir = topDir.filePath(trashDir); + if (topDir.mkdir(trashDir)) + QFile::setPermissions(targetDir, ownerPerms); + if (QFileInfo(targetDir).isDir()) + return targetDir; + return QString(); + }; + auto isSticky = [](const QFileInfo &fileInfo) -> bool { + struct stat st; + if (stat(QFile::encodeName(fileInfo.absoluteFilePath()).constData(), &st) == 0) + return st.st_mode & S_ISVTX; + + return false; + }; + + QString trash; + const QLatin1String dotTrash(".Trash"); + const QStorageInfo sourceStorage(sourcePath); + const QStorageInfo homeStorage(QDir::home()); + // We support trashing of files outside the users home partition + if (sourceStorage != homeStorage) { + QDir topDir(sourceStorage.rootPath()); + /* + Method 1: + "An administrator can create an $topdir/.Trash directory. The permissions on this + directories should permit all users who can trash files at all to write in it; + and the “sticky bit” in the permissions must be set, if the file system supports + it. + When trashing a file from a non-home partition/device, an implementation + (if it supports trashing in top directories) MUST check for the presence + of $topdir/.Trash." + */ + const QString userID = QString::number(::getuid()); + if (topDir.cd(dotTrash)) { + const QFileInfo trashInfo(topDir.path()); + + // we MUST check that the sticky bit is set, and that it is not a symlink + if (trashInfo.isSymLink()) { + // we SHOULD report the failed check to the administrator + qCritical("Warning: '%s' is a symlink to '%s'", + trashInfo.absoluteFilePath().toLocal8Bit().constData(), + trashInfo.symLinkTarget().toLatin1().constData()); + } else if (!isSticky(trashInfo)) { + // we SHOULD report the failed check to the administrator + qCritical("Warning: '%s' doesn't have sticky bit set!", + trashInfo.absoluteFilePath().toLocal8Bit().constData()); + } else if (trashInfo.isDir()) { + /* + "If the directory exists and passes the checks, a subdirectory of the + $topdir/.Trash directory is to be used as the user's trash directory + for this partition/device. The name of this subdirectory is the numeric + identifier of the current user ($topdir/.Trash/$uid). + When trashing a file, if this directory does not exist for the current user, + the implementation MUST immediately create it, without any warnings or + delays for the user." + */ + trash = makeTrashDir(topDir, userID); + } + } + /* + Method 2: + "If an $topdir/.Trash directory is absent, an $topdir/.Trash-$uid directory is to be + used as the user's trash directory for this device/partition. [...] When trashing a + file, if an $topdir/.Trash-$uid directory does not exist, the implementation MUST + immediately create it, without any warnings or delays for the user." + */ + if (trash.isEmpty()) { + topDir = QDir(sourceStorage.rootPath()); + const QString userTrashDir = dotTrash + QLatin1Char('-') + userID; + trash = makeTrashDir(topDir, userTrashDir); + } + } + /* + "If both (1) and (2) fail [...], the implementation MUST either trash the + file into the user's “home trash” or refuse to trash it." + + We trash the file into the user's home trash. + */ + if (trash.isEmpty()) { + QDir topDir = QDir::home(); + trash = makeTrashDir(topDir, dotTrash); + if (!QFileInfo(trash).isDir()) { + qWarning("Unable to establish trash directory %s in %s", + dotTrash.latin1(), topDir.path().toLocal8Bit().constData()); + } + } + + return trash; +} +#endif // QT_BOOTSTRAPPED + +//static +bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source, + QFileSystemEntry &newLocation, QSystemError &error) +{ +#ifdef QT_BOOTSTRAPPED + Q_UNUSED(source); + Q_UNUSED(newLocation); + error = QSystemError(ENOSYS, QSystemError::StandardLibraryError); + return false; +#else + const QFileInfo sourceInfo(source.filePath()); + if (!sourceInfo.exists()) { + error = QSystemError(ENOENT, QSystemError::StandardLibraryError); + return false; + } + const QString sourcePath = sourceInfo.absoluteFilePath(); + + QDir trashDir(freeDesktopTrashLocation(sourcePath)); + if (!trashDir.exists()) + return false; + /* + "A trash directory contains two subdirectories, named info and files." + */ + const QLatin1String filesDir("files"); + const QLatin1String infoDir("info"); + trashDir.mkdir(filesDir); + int savedErrno = errno; + trashDir.mkdir(infoDir); + if (!savedErrno) + savedErrno = errno; + if (!trashDir.exists(filesDir) || !trashDir.exists(infoDir)) { + error = QSystemError(savedErrno, QSystemError::StandardLibraryError); + return false; + } + /* + "The $trash/files directory contains the files and directories that were trashed. + The names of files in this directory are to be determined by the implementation; + the only limitation is that they must be unique within the directory. Even if a + file with the same name and location gets trashed many times, each subsequent + trashing must not overwrite a previous copy." + */ + const QString trashedName = sourceInfo.isDir() + ? QDir(sourcePath).dirName() + : sourceInfo.fileName(); + QString uniqueTrashedName = QLatin1Char('/') + trashedName; + QString infoFileName; + int counter = 0; + QFile infoFile; + auto makeUniqueTrashedName = [trashedName, &counter]() -> QString { + ++counter; + return QString(QLatin1String("/%1-%2")) + .arg(trashedName) + .arg(counter, 4, 10, QLatin1Char('0')); + }; + do { + while (QFile::exists(trashDir.filePath(filesDir) + uniqueTrashedName)) + uniqueTrashedName = makeUniqueTrashedName(); + /* + "The $trash/info directory contains an "information file" for every file and directory + in $trash/files. This file MUST have exactly the same name as the file or directory in + $trash/files, plus the extension ".trashinfo" + [...] + When trashing a file or directory, the implementation MUST create the corresponding + file in $trash/info first. Moreover, it MUST try to do this in an atomic fashion, + so that if two processes try to trash files with the same filename this will result + in two different trash files. On Unix-like systems this is done by generating a + filename, and then opening with O_EXCL. If that succeeds the creation was atomic + (at least on the same machine), if it fails you need to pick another filename." + */ + infoFileName = trashDir.filePath(infoDir) + + uniqueTrashedName + QLatin1String(".trashinfo"); + infoFile.setFileName(infoFileName); + if (!infoFile.open(QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text)) + uniqueTrashedName = makeUniqueTrashedName(); + } while (!infoFile.isOpen()); + + const QString targetPath = trashDir.filePath(filesDir) + uniqueTrashedName; + const QFileSystemEntry target(targetPath); + + /* + We might fail to rename if source and target are on different file systems. + In that case, we don't try further, i.e. copying and removing the original + is usually not what the user would expect to happen. + */ + if (!renameFile(source, target, error)) { + infoFile.close(); + infoFile.remove(); + return false; + } + + QTextStream out(&infoFile); +#if QT_CONFIG(textcodec) + out.setCodec("UTF-8"); +#endif + out << "[Trash Info]" << Qt::endl; + out << "Path=" << sourcePath << Qt::endl; + out << "DeletionDate=" + << QDateTime::currentDateTime().toString(QLatin1String("yyyy-MM-ddThh:mm:ss")) << Qt::endl; + infoFile.close(); + + newLocation = QFileSystemEntry(targetPath); + return true; +#endif // QT_BOOTSTRAPPED +} +#endif // Q_OS_DARWIN + //static bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) { diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 0579872f8d..36d43e9cb7 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -41,6 +41,7 @@ #include "qoperatingsystemversion.h" #include "qplatformdefs.h" #include "qsysinfo.h" +#include "qscopeguard.h" #include "private/qabstractfileengine_p.h" #include "private/qfsfileengine_p.h" #include <private/qsystemlibrary_p.h> @@ -59,6 +60,8 @@ #include <objbase.h> #ifndef Q_OS_WINRT # include <shlobj.h> +# include <shobjidl.h> +# include <shellapi.h> # include <lm.h> # include <accctrl.h> #endif @@ -422,6 +425,104 @@ static inline bool getFindData(QString path, WIN32_FIND_DATA &findData) return false; } +#if defined(__IFileOperation_INTERFACE_DEFINED__) +class FileOperationProgressSink : public IFileOperationProgressSink +{ +public: + FileOperationProgressSink() + : ref(1) + {} + virtual ~FileOperationProgressSink() {} + + ULONG STDMETHODCALLTYPE AddRef() + { + return ++ref; + } + ULONG STDMETHODCALLTYPE Release() + { + if (--ref == 0) { + delete this; + return 0; + } + return ref; + } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) + { + if (!ppvObject) + return E_POINTER; + + *ppvObject = nullptr; + + if (iid == __uuidof(IUnknown)) { + *ppvObject = static_cast<IUnknown*>(this); + } else if (iid == __uuidof(IFileOperationProgressSink)) { + *ppvObject = static_cast<IFileOperationProgressSink*>(this); + } + + if (*ppvObject) { + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; + } + + HRESULT STDMETHODCALLTYPE StartOperations() + { return S_OK; } + HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT) + { return S_OK; } + HRESULT STDMETHODCALLTYPE PreRenameItem(DWORD, IShellItem *, LPCWSTR) + { return S_OK; } + HRESULT STDMETHODCALLTYPE PostRenameItem(DWORD, IShellItem *, LPCWSTR, HRESULT, IShellItem *) + { return S_OK; } + HRESULT STDMETHODCALLTYPE PreMoveItem(DWORD, IShellItem *, IShellItem *, LPCWSTR) + { return S_OK; } + HRESULT STDMETHODCALLTYPE PostMoveItem(DWORD, IShellItem *, IShellItem *, LPCWSTR, HRESULT, + IShellItem *) + { return S_OK; } + HRESULT STDMETHODCALLTYPE PreCopyItem(DWORD, IShellItem *, IShellItem *, LPCWSTR ) + { return S_OK; } + HRESULT STDMETHODCALLTYPE PostCopyItem(DWORD, IShellItem *, IShellItem *, LPCWSTR, HRESULT, + IShellItem *) + { return S_OK; } + HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD dwFlags, IShellItem *) + { + // stop the operation if the file will be deleted rather than trashed + return (dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE) ? S_OK : E_FAIL; + } + HRESULT STDMETHODCALLTYPE PostDeleteItem(DWORD /* dwFlags */, IShellItem * /* psiItem */, + HRESULT /* hrDelete */, IShellItem *psiNewlyCreated) + { + if (psiNewlyCreated) { + wchar_t *pszName = nullptr; + psiNewlyCreated->GetDisplayName(SIGDN_FILESYSPATH, &pszName); + if (pszName) { + targetPath = QString::fromWCharArray(pszName); + CoTaskMemFree(pszName); + } + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE PreNewItem(DWORD, IShellItem *, LPCWSTR) + { return S_OK; } + HRESULT STDMETHODCALLTYPE PostNewItem(DWORD, IShellItem *, LPCWSTR, LPCWSTR, DWORD, HRESULT, + IShellItem *) + { return S_OK; } + HRESULT STDMETHODCALLTYPE UpdateProgress(UINT,UINT) + { return S_OK; } + HRESULT STDMETHODCALLTYPE ResetTimer() + { return S_OK; } + HRESULT STDMETHODCALLTYPE PauseTimer() + { return S_OK; } + HRESULT STDMETHODCALLTYPE ResumeTimer() + { return S_OK; } + + QString targetPath; +private: + ULONG ref; +}; +#endif + bool QFileSystemEngine::uncListSharesOnServer(const QString &server, QStringList *list) { DWORD res = ERROR_NOT_SUPPORTED; @@ -1431,6 +1532,103 @@ bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError & return ret; } +/* + If possible, we use the IFileOperation implementation, which allows us to determine + the location of the object in the trash. + If not (likely on mingw), we fall back to the old API, which won't allow us to know + that. +*/ +//static +bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source, + QFileSystemEntry &newLocation, QSystemError &error) +{ +#ifndef Q_OS_WINRT + // we need the "display name" of the file, so can't use nativeFilePath + const QString sourcePath = QDir::toNativeSeparators(source.filePath()); + + /* + Windows 7 insists on showing confirmation dialogs and ignores the respective + flags set on IFileOperation. Fall back to SHFileOperation, even if it doesn't + give us the new location of the file. + */ + if (QOperatingSystemVersion::current() > QOperatingSystemVersion::Windows7) { +# if defined(__IFileOperation_INTERFACE_DEFINED__) + CoInitialize(NULL); + IFileOperation *pfo = nullptr; + IShellItem *deleteItem = nullptr; + FileOperationProgressSink *sink = nullptr; + HRESULT hres = E_FAIL; + + auto coUninitialize = qScopeGuard([&](){ + if (sink) + sink->Release(); + if (deleteItem) + deleteItem->Release(); + if (pfo) + pfo->Release(); + CoUninitialize(); + if (!SUCCEEDED(hres)) + error = QSystemError(hres, QSystemError::NativeError); + }); + + hres = CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pfo)); + if (!pfo) + return false; + pfo->SetOperationFlags(FOF_ALLOWUNDO | FOFX_RECYCLEONDELETE | FOF_NOCONFIRMATION + | FOF_SILENT | FOF_NOERRORUI); + hres = SHCreateItemFromParsingName(reinterpret_cast<const wchar_t*>(sourcePath.utf16()), + nullptr, IID_PPV_ARGS(&deleteItem)); + if (!deleteItem) + return false; + sink = new FileOperationProgressSink; + hres = pfo->DeleteItem(deleteItem, static_cast<IFileOperationProgressSink*>(sink)); + if (!SUCCEEDED(hres)) + return false; + hres = pfo->PerformOperations(); + if (!SUCCEEDED(hres)) + return false; + newLocation = QFileSystemEntry(sink->targetPath); + +# endif // no IFileOperation in SDK (mingw, likely) - fall back to SHFileOperation + } else { + // double null termination needed, so can't use QString::utf16 + QVarLengthArray<wchar_t, MAX_PATH + 1> winFile(sourcePath.length() + 2); + sourcePath.toWCharArray(winFile.data()); + winFile[sourcePath.length()] = wchar_t{}; + winFile[sourcePath.length() + 1] = wchar_t{}; + + SHFILEOPSTRUCTW operation; + operation.hwnd = nullptr; + operation.wFunc = FO_DELETE; + operation.pFrom = winFile.constData(); + operation.pTo = nullptr; + operation.fFlags = FOF_ALLOWUNDO | FOF_NO_UI; + operation.fAnyOperationsAborted = FALSE; + operation.hNameMappings = nullptr; + operation.lpszProgressTitle = nullptr; + + int result = SHFileOperation(&operation); + if (result != 0) { + error = QSystemError(result, QSystemError::NativeError); + return false; + } + /* + This implementation doesn't let us know where the file ended up, even if + we would specify FOF_WANTMAPPINGHANDLE | FOF_RENAMEONCOLLISION, as + FOF_RENAMEONCOLLISION has no effect unless files are moved, copied, or renamed. + */ + Q_UNUSED(newLocation); + } + return true; + +#else // Q_OS_WINRT + Q_UNUSED(source); + Q_UNUSED(newLocation); + Q_UNUSED(error); + return false; +#endif +} + //static bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data) diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index f7a86c25cd..cc1d110252 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -714,7 +714,7 @@ void QIODevicePrivate::setReadChannelCount(int count) /*! \since 5.7 - Returns the the index of the current write channel. + Returns the index of the current write channel. \sa setCurrentWriteChannel(), writeChannelCount() */ diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index b2bf77c0da..ce2b7e8faa 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -58,7 +58,8 @@ #include <sys/file.h> // flock #endif -#if defined(Q_OS_RTEMS) +#if defined(Q_OS_RTEMS) || defined(Q_OS_QNX) +// flock() does not work in these OSes and produce warnings when we try to use # undef LOCK_EX # undef LOCK_NB #endif diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 37b8a60c37..698c4ddf41 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -60,6 +60,7 @@ #elif defined(Q_OS_LINUX) || defined(Q_OS_HURD) # include <mntent.h> # include <sys/statvfs.h> +# include <sys/sysmacros.h> #elif defined(Q_OS_SOLARIS) # include <sys/mnttab.h> # include <sys/statvfs.h> @@ -152,7 +153,7 @@ private: //(2) parent ID: the ID of the parent mount (or of self for the top of the mount tree). // int parent_id; //(3) major:minor: the value of st_dev for files on this filesystem (see stat(2)). -// dev_t rdev; + dev_t rdev; //(4) root: the pathname of the directory in the filesystem which forms the root of this mount. char *subvolume; //(5) mount point: the pathname of the mount point relative to the process's root directory. @@ -503,8 +504,7 @@ inline bool QStorageIterator::next() int rdevminor = qstrtoll(ptr + 1, const_cast<const char **>(&ptr), 10, &ok); if (!ptr || !ok) return false; - Q_UNUSED(rdevmajor); - Q_UNUSED(rdevminor); + mnt.rdev = makedev(rdevmajor, rdevminor); if (*ptr != ' ') return false; @@ -566,6 +566,21 @@ inline QByteArray QStorageIterator::fileSystemType() const inline QByteArray QStorageIterator::device() const { + // check that the device exists + if (mnt.mnt_fsname[0] == '/' && access(mnt.mnt_fsname, F_OK) != 0) { + // It doesn't, so let's try to resolve the dev_t from /dev/block. + // Note how strlen("4294967295") == digits10 + 1, so we need to add 1 + // for each number, plus the ':'. + char buf[sizeof("/dev/block/") + 2 * std::numeric_limits<unsigned>::digits10 + 3]; + QByteArray dev(PATH_MAX, Qt::Uninitialized); + char *devdata = dev.data(); + + snprintf(buf, sizeof(buf), "/dev/block/%u:%u", major(mnt.rdev), minor(mnt.rdev)); + if (realpath(buf, devdata)) { + dev.truncate(strlen(devdata)); + return dev; + } + } return QByteArray(mnt.mnt_fsname); } diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 0a5f9256eb..1beeb7b2a2 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -415,7 +415,7 @@ #include "qhash.h" #include "qdir.h" // for QDir::fromNativeSeparators #include "qdatastream.h" -#if QT_CONFIG(topleveldomain) +#if QT_CONFIG(topleveldomain) // ### Qt6: Remove section #include "qtldurl_p.h" #endif #include "private/qipaddress_p.h" @@ -3149,10 +3149,13 @@ bool QUrl::hasFragment() const return d->hasFragment(); } +#if QT_DEPRECATED_SINCE(5, 15) #if QT_CONFIG(topleveldomain) /*! \since 4.8 + \deprecated + Returns the TLD (Top-Level Domain) of the URL, (e.g. .co.uk, .net). Note that the return value is prefixed with a '.' unless the URL does not contain a valid TLD, in which case the function returns @@ -3185,7 +3188,7 @@ QString QUrl::topLevelDomain(ComponentFormattingOptions options) const return tld; } #endif - +#endif // QT_DEPRECATED_SINCE(5, 15) /*! Returns the result of the merge of this URL with \a relative. This URL is used as a base to convert \a relative to an absolute URL. diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index 94269e4369..eb7fb8087c 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -233,9 +233,11 @@ public: void setHost(const QString &host, ParsingMode mode = DecodedMode); QString host(ComponentFormattingOptions = FullyDecoded) const; +#if QT_DEPRECATED_SINCE(5, 15) #if QT_CONFIG(topleveldomain) - QString topLevelDomain(ComponentFormattingOptions options = FullyDecoded) const; + QT_DEPRECATED QString topLevelDomain(ComponentFormattingOptions options = FullyDecoded) const; #endif +#endif // QT_DEPRECATED_SINCE(5, 15) void setPort(int port); int port(int defaultPort = -1) const; diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index f132cba473..a5df17e386 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -108,6 +108,9 @@ void QPersistentModelIndexData::destroy(QPersistentModelIndexData *data) It is good practice to check that persistent model indexes are valid before using them. + \note You cannot store a QStandardItemModel's QPersistentModelIndex + in one of the model's items. + \sa {Model/View Programming}, QModelIndex, QAbstractItemModel */ diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index b1f3b74cd4..a042361686 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -247,7 +247,7 @@ AppleApplication *qt_apple_sharedApplication() qWarning() << "accessing the shared" << [AppleApplication class] << "is not allowed in application extensions"; - // In practice the application is actually available, but the the App + // In practice the application is actually available, but the App // review process will likely catch uses of it, so we return nil just // in case, unless we don't care about being App Store compliant. #if QT_CONFIG(appstore_compliant) diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 927bfb7667..b5a62d1aa0 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -988,6 +988,30 @@ enum IteratorCapability RandomAccessCapability = 4 }; +enum ContainerCapability +{ + ContainerIsAppendable = 1 +}; + +template<typename Container, typename T = void> +struct ContainerCapabilitiesImpl +{ + enum {ContainerCapabilities = 0}; + using appendFunction = void(*)(const void *container, const void *newElement); + static constexpr const appendFunction appendImpl = nullptr; +}; + +template<typename Container> +struct ContainerCapabilitiesImpl<Container, decltype(std::declval<Container>().push_back(std::declval<typename Container::value_type>()))> +{ + enum {ContainerCapabilities = ContainerIsAppendable}; + + // The code below invokes undefined behavior if and only if the pointer passed into QSequentialIterableImpl + // pointed to a const object to begin with + static void appendImpl(const void *container, const void *value) + { static_cast<Container *>(const_cast<void *>(container))->push_back(*static_cast<const typename Container::value_type *>(value)); } +}; + template<typename T, typename Category = typename std::iterator_traits<typename T::const_iterator>::iterator_category> struct CapabilitiesImpl; @@ -1019,6 +1043,12 @@ template<typename T> struct ContainerAPI<std::list<T> > : CapabilitiesImpl<std::list<T> > { static int size(const std::list<T> *t) { return int(t->size()); } }; +/* + revision 0: _iteratorCapabilities is simply a uint, where the bits at _revision were never set + revision 1: _iteratorCapabilties is treated as a bitfield, the remaining bits are used to introduce + _revision, _containerCapabilities and _unused. The latter contains 21 bits that are + not used yet +*/ class QSequentialIterableImpl { public: @@ -1027,19 +1057,37 @@ public: int _metaType_id; uint _metaType_flags; uint _iteratorCapabilities; + // Iterator capabilities looks actually like + // uint _iteratorCapabilities:4; + // uint _revision:3; + // uint _containerCapabilities:4; + // uint _unused:21;*/ typedef int(*sizeFunc)(const void *p); typedef const void * (*atFunc)(const void *p, int); typedef void (*moveIteratorFunc)(const void *p, void **); + enum Position { ToBegin, ToEnd }; + typedef void (*moveIteratorFunc2)(const void *p, void **, Position position); typedef void (*advanceFunc)(void **p, int); typedef VariantData (*getFunc)( void * const *p, int metaTypeId, uint flags); typedef void (*destroyIterFunc)(void **p); typedef bool (*equalIterFunc)(void * const *p, void * const *other); typedef void (*copyIterFunc)(void **, void * const *); + typedef void(*appendFunction)(const void *container, const void *newElement); + + IteratorCapability iteratorCapabilities() {return static_cast<IteratorCapability>(_iteratorCapabilities & 0xF);} + uint revision() {return _iteratorCapabilities >> 4 & 0x7;} + uint containerCapabilities() {return _iteratorCapabilities >> 7 & 0xF;} sizeFunc _size; atFunc _at; - moveIteratorFunc _moveToBegin; - moveIteratorFunc _moveToEnd; + union { + moveIteratorFunc _moveToBegin; + moveIteratorFunc2 _moveTo; + }; + union { + moveIteratorFunc _moveToEnd; + appendFunction _append; + }; advanceFunc _advance; getFunc _get; destroyIterFunc _destroyIter; @@ -1066,6 +1114,15 @@ public: static void moveToEndImpl(const void *container, void **iterator) { IteratorOwner<typename T::const_iterator>::assign(iterator, static_cast<const T*>(container)->end()); } + template<class Container> + static void moveToImpl(const void *container, void **iterator, Position position) + { + if (position == ToBegin) + moveToBeginImpl<Container>(container, iterator); + else + moveToEndImpl<Container>(container, iterator); + } + template<class T> static VariantData getImpl(void * const *iterator, int metaTypeId, uint flags) { return VariantData(metaTypeId, IteratorOwner<typename T::const_iterator>::getData(iterator), flags); } @@ -1076,11 +1133,11 @@ public: , _iterator(nullptr) , _metaType_id(qMetaTypeId<typename T::value_type>()) , _metaType_flags(QTypeInfo<typename T::value_type>::isPointer) - , _iteratorCapabilities(ContainerAPI<T>::IteratorCapabilities) + , _iteratorCapabilities(ContainerAPI<T>::IteratorCapabilities | (1 << 4) | (ContainerCapabilitiesImpl<T>::ContainerCapabilities << (4+3))) , _size(sizeImpl<T>) , _at(atImpl<T>) - , _moveToBegin(moveToBeginImpl<T>) - , _moveToEnd(moveToEndImpl<T>) + , _moveTo(moveToImpl<T>) + , _append(ContainerCapabilitiesImpl<T>::appendImpl) , _advance(IteratorOwner<typename T::const_iterator>::advance) , _get(getImpl<T>) , _destroyIter(IteratorOwner<typename T::const_iterator>::destroy) @@ -1094,7 +1151,7 @@ public: , _iterator(nullptr) , _metaType_id(QMetaType::UnknownType) , _metaType_flags(0) - , _iteratorCapabilities(0) + , _iteratorCapabilities(0 | (1 << 4) ) // no iterator capabilities, revision 1 , _size(nullptr) , _at(nullptr) , _moveToBegin(nullptr) @@ -1107,8 +1164,18 @@ public: { } - inline void moveToBegin() { _moveToBegin(_iterable, &_iterator); } - inline void moveToEnd() { _moveToEnd(_iterable, &_iterator); } + inline void moveToBegin() { + if (revision() == 0) + _moveToBegin(_iterable, &_iterator); + else + _moveTo(_iterable, &_iterator, ToBegin); + } + inline void moveToEnd() { + if (revision() == 0) + _moveToEnd(_iterable, &_iterator); + else + _moveTo(_iterable, &_iterator, ToEnd); + } inline bool equal(const QSequentialIterableImpl&other) const { return _equalIter(&_iterator, &other._iterator); } inline QSequentialIterableImpl &advance(int i) { Q_ASSERT(i > 0 || _iteratorCapabilities & BiDirectionalCapability); @@ -1116,6 +1183,11 @@ public: return *this; } + inline void append(const void *newElement) { + if (containerCapabilities() & ContainerIsAppendable) + _append(_iterable, newElement); + } + inline VariantData getCurrent() const { return _get(&_iterator, _metaType_id, _metaType_flags); } VariantData at(int idx) const diff --git a/src/corelib/kernel/qmimedata.cpp b/src/corelib/kernel/qmimedata.cpp index fca258c9e3..c38dab3e3f 100644 --- a/src/corelib/kernel/qmimedata.cpp +++ b/src/corelib/kernel/qmimedata.cpp @@ -72,40 +72,44 @@ public: QVariant retrieveTypedData(const QString &format, QMetaType::Type type) const; - QVector<QMimeDataStruct> dataList; + std::vector<QMimeDataStruct>::iterator find(const QString &format) noexcept { + const auto formatEquals = [](const QString &format) { + return [&format](const QMimeDataStruct &s) { return s.format == format; }; + }; + return std::find_if(dataList.begin(), dataList.end(), formatEquals(format)); + } + + std::vector<QMimeDataStruct>::const_iterator find(const QString &format) const noexcept { + return const_cast<QMimeDataPrivate*>(this)->find(format); + } + + std::vector<QMimeDataStruct> dataList; }; void QMimeDataPrivate::removeData(const QString &format) { - for (int i=0; i<dataList.size(); i++) { - if (dataList.at(i).format == format) { - dataList.removeAt(i); - return; - } - } + const auto it = find(format); + if (it != dataList.end()) + dataList.erase(it); } void QMimeDataPrivate::setData(const QString &format, const QVariant &data) { - // remove it first if the format is already here. - removeData(format); - QMimeDataStruct mimeData; - mimeData.format = format; - mimeData.data = data; - dataList += mimeData; + const auto it = find(format); + if (it == dataList.end()) + dataList.push_back({format, data}); + else + it->data = data; } QVariant QMimeDataPrivate::getData(const QString &format) const { - QVariant data; - for (int i=0; i<dataList.size(); i++) { - if (dataList.at(i).format == format) { - data = dataList.at(i).data; - break; - } - } - return data; + const auto it = find(format); + if (it == dataList.cend()) + return {}; + else + return it->data; } QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QMetaType::Type type) const @@ -635,10 +639,9 @@ QStringList QMimeData::formats() const { Q_D(const QMimeData); QStringList list; - const int size = d->dataList.size(); - list.reserve(size); - for (int i = 0; i < size; ++i) - list += d->dataList.at(i).format; + list.reserve(static_cast<int>(d->dataList.size())); + for (auto &e : d->dataList) + list += e.format; return list; } diff --git a/src/corelib/kernel/qsignalmapper.cpp b/src/corelib/kernel/qsignalmapper.cpp index 24b174972f..dc0dfe8f40 100644 --- a/src/corelib/kernel/qsignalmapper.cpp +++ b/src/corelib/kernel/qsignalmapper.cpp @@ -53,11 +53,36 @@ public: Q_Q(QSignalMapper); q->removeMappings(q->sender()); } + + template <class Signal, class Container> + void emitMappedValue(QObject *sender, Signal signal, const Container &mappedValues) + { + Q_Q(QSignalMapper); + + auto it = mappedValues.find(sender); + if (it != mappedValues.end()) { +#if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + Q_EMIT q->mapped(*it); +QT_WARNING_POP +#endif + Q_EMIT (q->*signal)(*it); + } + } + + void emitMappedValues(QObject *sender) + { + emitMappedValue(sender, &QSignalMapper::mappedInt, intHash); + emitMappedValue(sender, &QSignalMapper::mappedString, stringHash); + emitMappedValue(sender, &QSignalMapper::mappedWidget, widgetHash); + emitMappedValue(sender, &QSignalMapper::mappedObject, objectHash); + } + QHash<QObject *, int> intHash; QHash<QObject *, QString> stringHash; QHash<QObject *, QWidget*> widgetHash; QHash<QObject *, QObject*> objectHash; - }; /*! @@ -74,11 +99,12 @@ public: use lambdas for passing custom parameters to slots. This is less costly and will simplify the code. - The class supports the mapping of particular strings or integers - with particular objects using setMapping(). The objects' signals - can then be connected to the map() slot which will emit the - mapped() signal with the string or integer associated with the - original signalling object. Mappings can be removed later using + The class supports the mapping of particular strings, integers, + objects and widgets with particular objects using setMapping(). + The objects' signals can then be connected to the map() slot which + will emit a signal (it could be mappedInt(), mappedString(), + mappedWidget() and mappedObject()) with a value associated with + the original signalling object. Mappings can be removed later using removeMappings(). Example: Suppose we want to create a custom widget that contains @@ -106,8 +132,8 @@ public: created. We connect each button's \c clicked() signal to the signal mapper's map() slot, and create a mapping in the signal mapper from each button to the button's text. Finally we connect - the signal mapper's mapped() signal to the custom widget's \c - clicked() signal. When the user clicks a button, the custom + the signal mapper's mappedString() signal to the custom widget's + \c clicked() signal. When the user clicks a button, the custom widget will emit a single \c clicked() signal whose argument is the text of the button the user clicked. @@ -137,7 +163,7 @@ QSignalMapper::~QSignalMapper() /*! Adds a mapping so that when map() is signalled from the given \a - sender, the signal mapped(\a id) is emitted. + sender, the signal mappedInt(\a id) is emitted. There may be at most one integer ID for each sender. @@ -152,7 +178,7 @@ void QSignalMapper::setMapping(QObject *sender, int id) /*! Adds a mapping so that when map() is signalled from the \a sender, - the signal mapped(\a text ) is emitted. + the signal mappedString(\a text ) is emitted. There may be at most one text for each sender. */ @@ -165,7 +191,7 @@ void QSignalMapper::setMapping(QObject *sender, const QString &text) /*! Adds a mapping so that when map() is signalled from the \a sender, - the signal mapped(\a widget ) is emitted. + the signal mappedWidget(\a widget ) is emitted. There may be at most one widget for each sender. */ @@ -178,7 +204,7 @@ void QSignalMapper::setMapping(QObject *sender, QWidget *widget) /*! Adds a mapping so that when map() is signalled from the \a sender, - the signal mapped(\a object ) is emitted. + the signal mappedObject(\a object ) is emitted. There may be at most one object for each sender. */ @@ -259,20 +285,14 @@ void QSignalMapper::map() { map(sender()); } */ void QSignalMapper::map(QObject *sender) { - Q_D(QSignalMapper); - if (d->intHash.contains(sender)) - emit mapped(d->intHash.value(sender)); - if (d->stringHash.contains(sender)) - emit mapped(d->stringHash.value(sender)); - if (d->widgetHash.contains(sender)) - emit mapped(d->widgetHash.value(sender)); - if (d->objectHash.contains(sender)) - emit mapped(d->objectHash.value(sender)); + d_func()->emitMappedValues(sender); } - +#if QT_DEPRECATED_SINCE(5, 15) /*! \fn void QSignalMapper::mapped(int i) + \obsolete + \overload This signal is emitted when map() is signalled from an object that has an integer mapping set. The object's mapped integer is passed @@ -283,6 +303,8 @@ void QSignalMapper::map(QObject *sender) /*! \fn void QSignalMapper::mapped(const QString &text) + \obsolete + \overload This signal is emitted when map() is signalled from an object that has a string mapping set. The object's mapped string is passed in @@ -293,6 +315,8 @@ void QSignalMapper::map(QObject *sender) /*! \fn void QSignalMapper::mapped(QWidget *widget) + \obsolete + \overload This signal is emitted when map() is signalled from an object that has a widget mapping set. The object's mapped widget is passed in @@ -303,6 +327,53 @@ void QSignalMapper::map(QObject *sender) /*! \fn void QSignalMapper::mapped(QObject *object) + \obsolete + \overload + + This signal is emitted when map() is signalled from an object that + has an object mapping set. The object provided by the map is passed in + \a object. + + \sa setMapping() +*/ +#endif + +/*! + \fn void QSignalMapper::mappedInt(int i) + \since 5.15 + + This signal is emitted when map() is signalled from an object that + has an integer mapping set. The object's mapped integer is passed + in \a i. + + \sa setMapping() +*/ + +/*! + \fn void QSignalMapper::mappedString(const QString &text) + \since 5.15 + + This signal is emitted when map() is signalled from an object that + has a string mapping set. The object's mapped string is passed in + \a text. + + \sa setMapping() +*/ + +/*! + \fn void QSignalMapper::mappedWidget(QWidget *widget) + \since 5.15 + + This signal is emitted when map() is signalled from an object that + has a widget mapping set. The object's mapped widget is passed in + \a widget. + + \sa setMapping() +*/ + +/*! + \fn void QSignalMapper::mappedObject(QObject *object) + \since 5.15 This signal is emitted when map() is signalled from an object that has an object mapping set. The object provided by the map is passed in diff --git a/src/corelib/kernel/qsignalmapper.h b/src/corelib/kernel/qsignalmapper.h index 0da1e8f87d..592986e6a5 100644 --- a/src/corelib/kernel/qsignalmapper.h +++ b/src/corelib/kernel/qsignalmapper.h @@ -66,10 +66,20 @@ public: QObject *mapping(QObject *object) const; Q_SIGNALS: +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_VERSION_X_5_15("Use QSignalMapper::mappedInt(int) instead") void mapped(int); + QT_DEPRECATED_VERSION_X_5_15("Use QSignalMapper::mappedString(const QString&) instead") void mapped(const QString &); + QT_DEPRECATED_VERSION_X_5_15("Use QSignalMapper::mappedWidget(QWidget *) instead") void mapped(QWidget *); + QT_DEPRECATED_VERSION_X_5_15("Use QSignalMapper::mappedObject(QObject *) instead") void mapped(QObject *); +#endif + void mappedInt(int); + void mappedString(const QString &); + void mappedWidget(QWidget *); + void mappedObject(QObject *); public Q_SLOTS: void map(); diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 4bd8874630..5767d52f6a 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -283,7 +283,7 @@ class QTranslatorPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QTranslator) public: - enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88, Dependencies = 0x96 }; + enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88, Dependencies = 0x96, Language = 0xa7 }; QTranslatorPrivate() : #if defined(QT_USE_MMAP) @@ -316,6 +316,9 @@ public: uint contextLength; uint numerusRulesLength; + QString language; + QString filePath; + bool do_load(const QString &filename, const QString &directory); bool do_load(const uchar *data, qsizetype len, const QString &directory); QString do_translate(const char *context, const char *sourceText, const char *comment, @@ -597,8 +600,10 @@ bool QTranslatorPrivate::do_load(const QString &realname, const QString &directo } } - if (ok && d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength, directory)) + if (ok && d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength, directory)) { + d->filePath = realname; return true; + } #if defined(QT_USE_MMAP) if (used_mmap) { @@ -829,7 +834,9 @@ bool QTranslatorPrivate::do_load(const uchar *data, qsizetype len, const QString break; } - if (tag == QTranslatorPrivate::Contexts) { + if (tag == QTranslatorPrivate::Language) { + language = QString::fromUtf8((const char*)data, blockLen); + } else if (tag == QTranslatorPrivate::Contexts) { contextArray = data; contextLength = blockLen; } else if (tag == QTranslatorPrivate::Hashes) { @@ -1091,6 +1098,9 @@ void QTranslatorPrivate::clear() qDeleteAll(subTranslators); subTranslators.clear(); + language.clear(); + filePath.clear(); + if (QCoreApplicationPrivate::isTranslatorInstalled(q)) QCoreApplication::postEvent(QCoreApplication::instance(), new QEvent(QEvent::LanguageChange)); @@ -1132,6 +1142,32 @@ bool QTranslator::isEmpty() const && d->subTranslators.isEmpty(); } +/*! + \since 5.15 + + Returns the target language as stored in the translation file. + */ +QString QTranslator::language() const +{ + Q_D(const QTranslator); + return d->language; +} + +/*! + \since 5.15 + + Returns the path of the loaded translation file. + + The file path is empty if no translation was loaded yet, + the loading failed, or if the translation was not loaded + from a file. + */ +QString QTranslator::filePath() const +{ + Q_D(const QTranslator); + return d->filePath; +} + QT_END_NAMESPACE #include "moc_qtranslator.cpp" diff --git a/src/corelib/kernel/qtranslator.h b/src/corelib/kernel/qtranslator.h index e7c39191e7..61a39c4089 100644 --- a/src/corelib/kernel/qtranslator.h +++ b/src/corelib/kernel/qtranslator.h @@ -63,6 +63,9 @@ public: virtual bool isEmpty() const; + QString language() const; + QString filePath() const; + bool load(const QString & filename, const QString & directory = QString(), const QString & search_delimiters = QString(), diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 4ac26e3048..e3d565f185 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -662,7 +662,7 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) # endif #endif case QMetaType::QDate: - *dt = QDateTime(*v_cast<QDate>(d)); + *dt = v_cast<QDate>(d)->startOfDay(); break; default: return false; @@ -1229,7 +1229,7 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *static_cast<QCborValue *>(result) = *v_cast<QByteArray>(d); break; case QMetaType::QDate: - *static_cast<QCborValue *>(result) = QCborValue(QDateTime(*v_cast<QDate>(d))); + *static_cast<QCborValue *>(result) = QCborValue(v_cast<QDate>(d)->startOfDay()); break; case QMetaType::QDateTime: *static_cast<QCborValue *>(result) = QCborValue(*v_cast<QDateTime>(d)); diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 6eb84b327b..4a092abb3e 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2018 Intel Corporation +** Copyright (C) 2020 Intel Corporation ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -218,6 +218,8 @@ bool QLibraryPrivate::load_sys() for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) { if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix))) continue; + if (path.isEmpty() && prefixes.at(prefix).contains(QLatin1Char('/'))) + continue; if (!suffixes.at(suffix).isEmpty() && name.endsWith(suffixes.at(suffix))) continue; if (loadHints & QLibrary::LoadArchiveMemberHint) { diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp index aed1704d5f..f34578ea81 100644 --- a/src/corelib/plugin/qpluginloader.cpp +++ b/src/corelib/plugin/qpluginloader.cpp @@ -342,7 +342,7 @@ static QString locatePlugin(const QString& fileName) QPluginLoader will automatically look for the file with the appropriate suffix (see QLibrary::isLibrary()). - When loading the plugin, QPluginLoader searches in the current directory and + When loading the plugin, QPluginLoader searches in all plugin locations specified by QCoreApplication::libraryPaths(), unless the file name has an absolute path. After loading the plugin successfully, fileName() returns the fully-qualified file name of diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index fb551d5197..c1fa700959 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -3185,6 +3185,26 @@ QStateMachine::WrappedEvent::~WrappedEvent() \sa QStateMachine::running */ +/*! + \fn QStateMachine::postDelayedEvent(QEvent *event, std::chrono::milliseconds delay) + \since 5.15 + \overload + \threadsafe + + Posts the given \a event for processing by this state machine, with the + given \a delay in milliseconds. Returns an identifier associated with the + delayed event, or -1 if the event could not be posted. + + This function returns immediately. When the delay has expired, the event + will be added to the state machine's event queue for processing. The state + machine takes ownership of the event and deletes it once it has been + processed. + + You can only post events when the state machine is running. + + \sa cancelDelayedEvent(), postEvent() +*/ + QT_END_NAMESPACE #include "qstatemachine.moc" diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index 07781d09a4..b3c87a959b 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -48,6 +48,10 @@ #include <QtCore/qset.h> #include <QtCore/qvariant.h> +#if __has_include(<chrono>) +# include <chrono> +#endif + QT_REQUIRE_CONFIG(statemachine); QT_BEGIN_NAMESPACE @@ -145,6 +149,13 @@ public: bool eventFilter(QObject *watched, QEvent *event) override; #endif +#if __has_include(<chrono>) || defined(Q_QDOC) + int postDelayedEvent(QEvent *event, std::chrono::milliseconds delay) + { + return postDelayedEvent(event, int(delay.count())); + } +#endif + public Q_SLOTS: void start(); void stop(); diff --git a/src/corelib/text/qcollator_icu.cpp b/src/corelib/text/qcollator_icu.cpp index 8acda45070..0dca1ee9c9 100644 --- a/src/corelib/text/qcollator_icu.cpp +++ b/src/corelib/text/qcollator_icu.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org> ** Contact: https://www.qt.io/licensing/ ** @@ -109,6 +109,11 @@ void QCollatorPrivate::cleanup() int QCollator::compare(QStringView s1, QStringView s2) const { + if (!s1.size()) + return s2.size() ? -1 : 0; + if (!s2.size()) + return +1; + if (d->dirty) d->init(); diff --git a/src/corelib/text/qcollator_macx.cpp b/src/corelib/text/qcollator_macx.cpp index 071d7c048f..cb8e073d4a 100644 --- a/src/corelib/text/qcollator_macx.cpp +++ b/src/corelib/text/qcollator_macx.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org> +** Copyright (C) 2020 Aleix Pol Gonzalez <aleixpol@kde.org> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -94,6 +94,11 @@ void QCollatorPrivate::cleanup() int QCollator::compare(QStringView s1, QStringView s2) const { + if (!s1.size()) + return s2.size() ? -1 : 0; + if (!s2.size()) + return +1; + if (d->dirty) d->init(); if (!d->collator) diff --git a/src/corelib/text/qcollator_posix.cpp b/src/corelib/text/qcollator_posix.cpp index 9cbc539ebe..ffcd214cfb 100644 --- a/src/corelib/text/qcollator_posix.cpp +++ b/src/corelib/text/qcollator_posix.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org> +** Copyright (C) 2020 Aleix Pol Gonzalez <aleixpol@kde.org> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -75,6 +75,11 @@ static void stringToWCharArray(QVarLengthArray<wchar_t> &ret, QStringView string int QCollator::compare(QStringView s1, QStringView s2) const { + if (!s1.size()) + return s2.size() ? -1 : 0; + if (!s2.size()) + return +1; + if (d->isC()) return s1.compare(s2, caseSensitivity()); if (d->dirty) diff --git a/src/corelib/text/qcollator_win.cpp b/src/corelib/text/qcollator_win.cpp index 9d81de882f..54f57f1d24 100644 --- a/src/corelib/text/qcollator_win.cpp +++ b/src/corelib/text/qcollator_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org> +** Copyright (C) 2020 Aleix Pol Gonzalez <aleixpol@kde.org> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -89,6 +89,11 @@ void QCollatorPrivate::cleanup() int QCollator::compare(QStringView s1, QStringView s2) const { + if (!s1.size()) + return s2.size() ? -1 : 0; + if (!s2.size()) + return +1; + if (d->isC()) return s1.compare(s2, d->caseSensitivity); diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index 05fe638f46..268e96bfd2 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -660,6 +660,11 @@ static QLocalePrivate *c_private() return &c_locale; } +static const QLocaleData *systemData(); +static QLocale::NumberOptions system_number_options = QLocale::DefaultNumberOptions; +Q_GLOBAL_STATIC_WITH_ARGS(QExplicitlySharedDataPointer<QLocalePrivate>, systemLocalePrivate, + (QLocalePrivate::create(systemData(), system_number_options))) + #ifndef QT_NO_SYSTEMLOCALE /****************************************************************************** ** Default system locale behavior @@ -711,6 +716,7 @@ static void updateSystemPrivate() { // This function is NOT thread-safe! // It *should not* be called by anything but systemData() + // It *is* called before {system,default}LocalePrivate exist. const QSystemLocale *sys_locale = systemLocale(); // tell the object that the system locale has changed. @@ -718,11 +724,14 @@ static void updateSystemPrivate() // Populate global with fallback as basis: globalLocaleData = *sys_locale->fallbackUiLocaleData(); + system_number_options = QLocale::DefaultNumberOptions; QVariant res = sys_locale->query(QSystemLocale::LanguageId, QVariant()); if (!res.isNull()) { globalLocaleData.m_language_id = res.toInt(); globalLocaleData.m_script_id = QLocale::AnyScript; // default for compatibility + if (globalLocaleData.m_language_id == QLocale::C) + system_number_options = QLocale::OmitGroupSeparator; } res = sys_locale->query(QSystemLocale::CountryId, QVariant()); if (!res.isNull()) { @@ -737,9 +746,26 @@ static void updateSystemPrivate() if (!res.isNull() && !res.toString().isEmpty()) globalLocaleData.m_decimal = res.toString().at(0).unicode(); + // System may supply empty group separator to say we should omit grouping; + // and it makes no sense to use the same separator for decimal and grouping + // (which might happen by system supplying, as decimal, what CLDR has given + // us for grouping; or the other way round). Assume, at least, that each of + // system and CLDR has decimal != group, all the same. res = sys_locale->query(QSystemLocale::GroupSeparator, QVariant()); - if (!res.isNull() && !res.toString().isEmpty()) - globalLocaleData.m_group = res.toString().at(0).unicode(); + if (res.isNull()) { + // The case where system over-rides decimal but not group, and its + // decimal clashes with CLDR's group. + if (globalLocaleData.m_group == globalLocaleData.m_decimal) + system_number_options |= QLocale::OmitGroupSeparator; + } else if (res.toString().isEmpty()) { + system_number_options |= QLocale::OmitGroupSeparator; + } else { + const ushort group = res.toString().at(0).unicode(); + if (group != globalLocaleData.m_decimal) + globalLocaleData.m_group = group; + else if (group == globalLocaleData.m_group) + qWarning("System-supplied decimal and grouping character are both 0x%hx", group); + } res = sys_locale->query(QSystemLocale::ZeroDigit, QVariant()); if (!res.isNull() && !res.toString().isEmpty()) @@ -752,6 +778,10 @@ static void updateSystemPrivate() res = sys_locale->query(QSystemLocale::PositiveSign, QVariant()); if (!res.isNull() && !res.toString().isEmpty()) globalLocaleData.m_plus = res.toString().at(0).unicode(); + + if (systemLocalePrivate.exists()) + systemLocalePrivate->data()->m_numberOptions = system_number_options; + // else: system_number_options will be passed to create() when constructing. } #endif // !QT_NO_SYSTEMLOCALE @@ -812,8 +842,6 @@ static const int locale_data_size = sizeof(locale_data)/sizeof(QLocaleData) - 1; Q_GLOBAL_STATIC_WITH_ARGS(QSharedDataPointer<QLocalePrivate>, defaultLocalePrivate, (QLocalePrivate::create(defaultData()))) -Q_GLOBAL_STATIC_WITH_ARGS(QExplicitlySharedDataPointer<QLocalePrivate>, systemLocalePrivate, - (QLocalePrivate::create(systemData()))) static QLocalePrivate *localePrivateByName(const QString &name) { @@ -1996,6 +2024,9 @@ QString QLocale::toString(const QDate &date, QStringView format) const /*! Returns a localized string representation of the given \a date according to the specified \a format. + + \note Some locales may use formats that limit the range of years they can + represent. */ QString QLocale::toString(const QDate &date, FormatType format) const @@ -2150,6 +2181,9 @@ QString QLocale::toString(const QDateTime &dateTime, QStringView format, QCalend Returns a localized string representation of the given \a dateTime according to the specified \a format. + + \note Some locales may use formats that limit the range of years they can + represent. */ QString QLocale::toString(const QDateTime &dateTime, FormatType format) const @@ -2302,14 +2336,19 @@ QTime QLocale::toTime(const QString &string, FormatType format) const return toTime(string, timeFormat(format)); } +#if QT_DEPRECATED_SINCE(5, 15) /*! \since 5.14 \overload + \deprecated */ QTime QLocale::toTime(const QString &string, FormatType format, QCalendar cal) const { +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED return toTime(string, timeFormat(format), cal); +QT_WARNING_POP } +#endif /*! \since 4.4 @@ -2374,12 +2413,24 @@ QDateTime QLocale::toDateTime(const QString &string, FormatType format, QCalenda */ QTime QLocale::toTime(const QString &string, const QString &format) const { - return toTime(string, format, QCalendar()); + QTime time; +#if QT_CONFIG(datetimeparser) + QDateTimeParser dt(QMetaType::QTime, QDateTimeParser::FromString, QCalendar()); + dt.setDefaultLocale(*this); + if (dt.parseFormat(format)) + dt.fromString(string, nullptr, &time); +#else + Q_UNUSED(string); + Q_UNUSED(format); +#endif + return time; } +#if QT_DEPRECATED_SINCE(5, 15) /*! \since 5.14 \overload + \deprecated */ QTime QLocale::toTime(const QString &string, const QString &format, QCalendar cal) const { @@ -2396,6 +2447,7 @@ QTime QLocale::toTime(const QString &string, const QString &format, QCalendar ca #endif return time; } +#endif /*! \since 4.4 diff --git a/src/corelib/text/qlocale.h b/src/corelib/text/qlocale.h index cbdcebc57d..a9933bbb2e 100644 --- a/src/corelib/text/qlocale.h +++ b/src/corelib/text/qlocale.h @@ -1038,11 +1038,15 @@ public: QDateTime toDateTime(const QString &string, const QString &format) const; // Calendar-aware API QDate toDate(const QString &string, FormatType format, QCalendar cal) const; - QTime toTime(const QString &string, FormatType format, QCalendar cal) const; QDateTime toDateTime(const QString &string, FormatType format, QCalendar cal) const; QDate toDate(const QString &string, const QString &format, QCalendar cal) const; - QTime toTime(const QString &string, const QString &format, QCalendar cal) const; QDateTime toDateTime(const QString &string, const QString &format, QCalendar cal) const; +# if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_X("Calendar is ignored when parsing times") + QTime toTime(const QString &string, FormatType format, QCalendar cal) const; + QT_DEPRECATED_X("Calendar is ignored when parsing times") + QTime toTime(const QString &string, const QString &format, QCalendar cal) const; +# endif // 5.15 #endif // ### Qt 6: We need to return QString from these function since diff --git a/src/corelib/text/qlocale_mac.mm b/src/corelib/text/qlocale_mac.mm index 31ede1352b..5381f0f975 100644 --- a/src/corelib/text/qlocale_mac.mm +++ b/src/corelib/text/qlocale_mac.mm @@ -119,7 +119,7 @@ static QString macDayName(int day, bool short_format) return QString(); } -static QString macDateToString(const QDate &date, bool short_format) +static QString macDateToString(QDate date, bool short_format) { QCFType<CFDateRef> myDate = QDateTime(date, QTime()).toCFDate(); QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent(); @@ -131,7 +131,7 @@ static QString macDateToString(const QDate &date, bool short_format) return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate)); } -static QString macTimeToString(const QTime &time, bool short_format) +static QString macTimeToString(QTime time, bool short_format) { QCFType<CFDateRef> myDate = QDateTime(QDate::currentDate(), time).toCFDate(); QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent(); @@ -283,10 +283,12 @@ static QString getMacTimeFormat(CFDateFormatterStyle style) return macToQtFormat(QString::fromCFString(CFDateFormatterGetFormat(formatter))); } -static QString getCFLocaleValue(CFStringRef key) +static QVariant getCFLocaleValue(CFStringRef key) { QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent(); CFTypeRef value = CFLocaleGetValue(locale, key); + if (!value) + return QVariant(); return QString::fromCFString(CFStringRef(static_cast<CFTypeRef>(value))); } @@ -411,14 +413,10 @@ QVariant QSystemLocale::query(QueryType type, QVariant in) const switch(type) { // case Name: // return getMacLocaleName(); - case DecimalPoint: { - QString value = getCFLocaleValue(kCFLocaleDecimalSeparator); - return value.isEmpty() ? QVariant() : value; - } - case GroupSeparator: { - QString value = getCFLocaleValue(kCFLocaleGroupingSeparator); - return value.isEmpty() ? QVariant() : value; - } + case DecimalPoint: + return getCFLocaleValue(kCFLocaleDecimalSeparator); + case GroupSeparator: + return getCFLocaleValue(kCFLocaleGroupingSeparator); case DateFormatLong: case DateFormatShort: return getMacDateFormat(type == DateFormatShort diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h index a7c15d08fb..11a42b7fee 100644 --- a/src/corelib/text/qlocale_p.h +++ b/src/corelib/text/qlocale_p.h @@ -87,7 +87,7 @@ public: LanguageId, // uint CountryId, // uint DecimalPoint, // QString - GroupSeparator, // QString + GroupSeparator, // QString (empty QString means: don't group digits) ZeroDigit, // QString NegativeSign, // QString DateFormatLong, // QString diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp index 4b4152c519..4a38adf309 100644 --- a/src/corelib/text/qlocale_win.cpp +++ b/src/corelib/text/qlocale_win.cpp @@ -106,11 +106,11 @@ struct QSystemLocalePrivate { QSystemLocalePrivate(); - QString zeroDigit(); - QString decimalPoint(); - QString groupSeparator(); - QString negativeSign(); - QString positiveSign(); + QVariant zeroDigit(); + QVariant decimalPoint(); + QVariant groupSeparator(); + QVariant negativeSign(); + QVariant positiveSign(); QVariant dateFormat(QLocale::FormatType); QVariant timeFormat(QLocale::FormatType); QVariant dateTimeFormat(QLocale::FormatType); @@ -150,7 +150,9 @@ private: QString zero; // cached value for zeroDigit() int getLocaleInfo(LCTYPE type, LPWSTR data, int size); - QString getLocaleInfo(LCTYPE type, int maxlen = 0); + // Need to distinguish empty QString packaged as (non-null) QVariant from null QVariant: + template <typename T = QString> + T getLocaleInfo(LCTYPE type, int maxlen = 0); int getLocaleInfo_int(LCTYPE type, int maxlen = 0); int getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size); @@ -211,19 +213,30 @@ inline int QSystemLocalePrivate::getLocaleInfo(LCTYPE type, LPWSTR data, int siz #endif } -QString QSystemLocalePrivate::getLocaleInfo(LCTYPE type, int maxlen) +template<typename T> +T QSystemLocalePrivate::getLocaleInfo(LCTYPE type, int maxlen) { + // https://docs.microsoft.com/en-us/windows/win32/intl/locale-spositivesign + // says empty for LOCALE_SPOSITIVESIGN means "+", although GetLocaleInfo() + // is documented to return 0 only on failure, so it's not clear how it + // returns empty to mean this; hence the two checks for it below. + const QString plus = QStringLiteral("+"); QVarLengthArray<wchar_t, 64> buf(maxlen ? maxlen : 64); - if (!getLocaleInfo(type, buf.data(), buf.size())) - return QString(); - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + if (!getLocaleInfo(type, buf.data(), buf.size())) { + const auto lastError = GetLastError(); + if (type == LOCALE_SPOSITIVESIGN && lastError == ERROR_SUCCESS) + return plus; + if (lastError != ERROR_INSUFFICIENT_BUFFER) + return {}; int cnt = getLocaleInfo(type, 0, 0); if (cnt == 0) - return QString(); + return {}; buf.resize(cnt); if (!getLocaleInfo(type, buf.data(), buf.size())) - return QString(); + return {}; } + if (type == LOCALE_SPOSITIVESIGN && !buf[0]) + return plus; return QString::fromWCharArray(buf.data()); } @@ -298,7 +311,7 @@ QString &QSystemLocalePrivate::substituteDigits(QString &string) return string; } -QString QSystemLocalePrivate::zeroDigit() +QVariant QSystemLocalePrivate::zeroDigit() { if (zero.isEmpty()) { /* Ten digits plus a terminator. @@ -317,24 +330,24 @@ QString QSystemLocalePrivate::zeroDigit() return zero; } -QString QSystemLocalePrivate::decimalPoint() +QVariant QSystemLocalePrivate::decimalPoint() { - return getLocaleInfo(LOCALE_SDECIMAL); + return getLocaleInfo<QVariant>(LOCALE_SDECIMAL); } -QString QSystemLocalePrivate::groupSeparator() +QVariant QSystemLocalePrivate::groupSeparator() { - return getLocaleInfo(LOCALE_STHOUSAND); + return getLocaleInfo<QVariant>(LOCALE_STHOUSAND); } -QString QSystemLocalePrivate::negativeSign() +QVariant QSystemLocalePrivate::negativeSign() { - return getLocaleInfo(LOCALE_SNEGATIVESIGN); + return getLocaleInfo<QVariant>(LOCALE_SNEGATIVESIGN); } -QString QSystemLocalePrivate::positiveSign() +QVariant QSystemLocalePrivate::positiveSign() { - return getLocaleInfo(LOCALE_SPOSITIVESIGN); + return getLocaleInfo<QVariant>(LOCALE_SPOSITIVESIGN); } QVariant QSystemLocalePrivate::dateFormat(QLocale::FormatType type) @@ -392,10 +405,10 @@ QVariant QSystemLocalePrivate::dayName(int day, QLocale::FormatType type) day -= 1; if (type == QLocale::LongFormat) - return getLocaleInfo(long_day_map[day]); + return getLocaleInfo<QVariant>(long_day_map[day]); if (type == QLocale::NarrowFormat) - return getLocaleInfo(narrow_day_map[day]); - return getLocaleInfo(short_day_map[day]); + return getLocaleInfo<QVariant>(narrow_day_map[day]); + return getLocaleInfo<QVariant>(short_day_map[day]); } QVariant QSystemLocalePrivate::monthName(int month, QLocale::FormatType type) @@ -418,7 +431,7 @@ QVariant QSystemLocalePrivate::monthName(int month, QLocale::FormatType type) LCTYPE lctype = (type == QLocale::ShortFormat || type == QLocale::NarrowFormat) ? short_month_map[month] : long_month_map[month]; - return getLocaleInfo(lctype); + return getLocaleInfo<QVariant>(lctype); } QVariant QSystemLocalePrivate::toString(QDate date, QLocale::FormatType type) @@ -485,7 +498,7 @@ QVariant QSystemLocalePrivate::measurementSystem() QVariant QSystemLocalePrivate::collation() { - return getLocaleInfo(LOCALE_SSORTLOCALE); + return getLocaleInfo<QVariant>(LOCALE_SSORTLOCALE); } QVariant QSystemLocalePrivate::amText() @@ -687,12 +700,12 @@ QVariant QSystemLocalePrivate::uiLanguages() QVariant QSystemLocalePrivate::nativeLanguageName() { - return getLocaleInfo(LOCALE_SNATIVELANGUAGENAME); + return getLocaleInfo<QVariant>(LOCALE_SNATIVELANGUAGENAME); } QVariant QSystemLocalePrivate::nativeCountryName() { - return getLocaleInfo(LOCALE_SNATIVECOUNTRYNAME); + return getLocaleInfo<QVariant>(LOCALE_SNATIVECOUNTRYNAME); } diff --git a/src/corelib/thread/qrunnable.cpp b/src/corelib/thread/qrunnable.cpp index b355ca605f..5b883a05da 100644 --- a/src/corelib/thread/qrunnable.cpp +++ b/src/corelib/thread/qrunnable.cpp @@ -113,4 +113,31 @@ QRunnable::~QRunnable() \sa autoDelete(), QThreadPool */ +class FunctionRunnable : public QRunnable +{ + std::function<void()> m_functor; +public: + FunctionRunnable(std::function<void()> functor) : m_functor(std::move(functor)) + { + } + void run() override + { + m_functor(); + } +}; + +/*! + \since 5.15 + + Creates a QRunnable that calls \a fun in run(). + + Auto-deletion is enabled by default. + + \sa run(), autoDelete() +*/ +QRunnable *QRunnable::create(std::function<void()> fun) +{ + return new FunctionRunnable(std::move(fun)); +} + QT_END_NAMESPACE diff --git a/src/corelib/thread/qrunnable.h b/src/corelib/thread/qrunnable.h index b8e842118c..c13aa3fa8c 100644 --- a/src/corelib/thread/qrunnable.h +++ b/src/corelib/thread/qrunnable.h @@ -41,6 +41,7 @@ #define QRUNNABLE_H #include <QtCore/qglobal.h> +#include <functional> QT_BEGIN_NAMESPACE @@ -59,6 +60,7 @@ public: QRunnable() : ref(0) { } virtual ~QRunnable(); + static QRunnable *create(std::function<void()> fun); bool autoDelete() const { return ref != -1; } void setAutoDelete(bool _autoDelete) { ref = _autoDelete ? 0 : -1; } diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index 5f23a78c8a..d1875a69a9 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -512,6 +512,22 @@ void QThreadPool::start(QRunnable *runnable, int priority) } /*! + \overload + \since 5.15 + + Reserves a thread and uses it to run \a fun, unless this thread will + make the current thread count exceed maxThreadCount(). In that case, + \a fun is added to a run queue instead. The \a priority argument can + be used to control the run queue's order of execution. +*/ +void QThreadPool::start(std::function<void()> fun, int priority) +{ + if (!fun) + return; + start(QRunnable::create(std::move(fun)), priority); +} + +/*! Attempts to reserve a thread to run \a runnable. If no threads are available at the time of calling, then this function @@ -542,6 +558,22 @@ bool QThreadPool::tryStart(QRunnable *runnable) return d->tryStart(runnable); } +/*! + \overload + \since 5.15 + Attempts to reserve a thread to run \a fun. + + If no threads are available at the time of calling, then this function + does nothing and returns \c false. Otherwise, \a fun is run immediately + using one available thread and this function returns \c true. +*/ +bool QThreadPool::tryStart(std::function<void()> fun) +{ + if (!fun) + return false; + return tryStart(QRunnable::create(std::move(fun))); +} + /*! \property QThreadPool::expiryTimeout Threads that are unused for \a expiryTimeout milliseconds are considered diff --git a/src/corelib/thread/qthreadpool.h b/src/corelib/thread/qthreadpool.h index cd27b7c08a..2eede44eca 100644 --- a/src/corelib/thread/qthreadpool.h +++ b/src/corelib/thread/qthreadpool.h @@ -45,6 +45,8 @@ #include <QtCore/qthread.h> #include <QtCore/qrunnable.h> +#include <functional> + QT_REQUIRE_CONFIG(thread); QT_BEGIN_NAMESPACE @@ -70,6 +72,9 @@ public: void start(QRunnable *runnable, int priority = 0); bool tryStart(QRunnable *runnable); + void start(std::function<void()> fun, int priority = 0); + bool tryStart(std::function<void()> fun); + int expiryTimeout() const; void setExpiryTimeout(int expiryTimeout); diff --git a/src/corelib/time/qcalendar.cpp b/src/corelib/time/qcalendar.cpp index 9d485f181e..32f0a511a3 100644 --- a/src/corelib/time/qcalendar.cpp +++ b/src/corelib/time/qcalendar.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -750,6 +750,8 @@ int QCalendar::daysInMonth(int month, int year) const /*! Returns the number of days in the given \a year. + + Handling of \c Unspecified as \a year is undefined. */ int QCalendar::daysInYear(int year) const { @@ -758,10 +760,15 @@ int QCalendar::daysInYear(int year) const /*! Returns the number of months in the given \a year. + + If \a year is \c Unspecified, returns the maximum number of months in a + year. + + \sa maximumMonthsInYear() */ int QCalendar::monthsInYear(int year) const { - return d ? d->monthsInYear(year) : 0; + return d ? year == Unspecified ? d->maximumMonthsInYear() : d->monthsInYear(year) : 0; } /*! diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index 80751e60a0..773280ad68 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -682,7 +682,7 @@ static bool inDateTimeRange(qint64 jd, bool start) return jd >= minDay && jd < maxDay; } -static QDateTime toEarliest(const QDate &day, const QDateTime &form) +static QDateTime toEarliest(QDate day, const QDateTime &form) { const Qt::TimeSpec spec = form.timeSpec(); const int offset = (spec == Qt::OffsetFromUTC) ? form.offsetFromUtc() : 0; @@ -806,7 +806,7 @@ QDateTime QDate::startOfDay(const QTimeZone &zone) const } #endif // timezone -static QDateTime toLatest(const QDate &day, const QDateTime &form) +static QDateTime toLatest(QDate day, const QDateTime &form) { const Qt::TimeSpec spec = form.timeSpec(); const int offset = (spec == Qt::OffsetFromUTC) ? form.offsetFromUtc() : 0; @@ -1098,9 +1098,8 @@ QString QDate::longDayName(int weekday, MonthNameType type) } #endif // textdate && deprecated -#if QT_CONFIG(datestring) +#if QT_CONFIG(datestring) // depends on, so implies, textdate -#if QT_CONFIG(textdate) static QString toStringTextDate(QDate date, QCalendar cal) { if (date.isValid()) { @@ -1115,13 +1114,7 @@ static QString toStringTextDate(QDate date, QCalendar cal) return QString(); } -static QString toStringTextDate(QDate date) -{ - return toStringTextDate(date, QCalendar()); -} -#endif // textdate - -static QString toStringIsoDate(const QDate &date) +static QString toStringIsoDate(QDate date) { const auto parts = QCalendar().partsFromDate(date); if (parts.isValid() && parts.year >= 0 && parts.year <= 9999) @@ -1131,11 +1124,13 @@ static QString toStringIsoDate(const QDate &date) /*! \fn QString QDate::toString(Qt::DateFormat format) const + \fn QString QDate::toString(Qt::DateFormat format, QCalendar cal) const \overload - Returns the date as a string. The \a format parameter determines - the format of the string. + Returns the date as a string. The \a format parameter determines the format + of the string. If \a cal is supplied, it determines the calendar used to + represent the date; it defaults to Gregorian. If the \a format is Qt::TextDate, the string is formatted in the default way. The day and month names will be localized names using the system @@ -1148,18 +1143,16 @@ static QString toStringIsoDate(const QDate &date) year, MM is the month of the year (between 01 and 12), and dd is the day of the month between 01 and 31. - If the \a format is Qt::SystemLocaleShortDate or - Qt::SystemLocaleLongDate, the string format depends on the locale - settings of the system. Identical to calling - QLocale::system().toString(date, QLocale::ShortFormat) or - QLocale::system().toString(date, QLocale::LongFormat). - - If the \a format is Qt::DefaultLocaleShortDate or - Qt::DefaultLocaleLongDate, the string format depends on the - default application locale. This is the locale set with - QLocale::setDefault(), or the system locale if no default locale - has been set. Identical to calling - \l {QLocale::toString()}{QLocale().toString(date, QLocale::ShortFormat) } or + The \a format options Qt::SystemLocaleDate, Qt::SystemLocaleShortDate and + Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with + \l {QLocale::toString()}{QLocale::system().toString(date, QLocale::ShortFormat)} or + \l {QLocale::toString()}{QLocale::system().toString(date, QLocale::LongFormat)}. + + The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and + Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with + \l {QLocale::toString()}{QLocale().toString(date, QLocale::ShortFormat)} or \l {QLocale::toString()}{QLocale().toString(date, QLocale::LongFormat)}. If the \a format is Qt::RFC2822Date, the string is formatted in @@ -1169,46 +1162,54 @@ static QString toStringIsoDate(const QDate &date) If the date is invalid, an empty string will be returned. \warning The Qt::ISODate format is only valid for years in the - range 0 to 9999. This restriction may apply to locale-aware - formats as well, depending on the locale settings. + range 0 to 9999. \sa fromString(), QLocale::toString() */ QString QDate::toString(Qt::DateFormat format) const { + return toString(format, QCalendar()); +} + +QString QDate::toString(Qt::DateFormat format, QCalendar cal) const +{ if (!isValid()) return QString(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: - return QLocale::system().toString(*this, QLocale::ShortFormat); + return QLocale::system().toString(*this, QLocale::ShortFormat, cal); case Qt::SystemLocaleLongDate: - return QLocale::system().toString(*this, QLocale::LongFormat); + return QLocale::system().toString(*this, QLocale::LongFormat, cal); case Qt::LocaleDate: case Qt::DefaultLocaleShortDate: - return QLocale().toString(*this, QLocale::ShortFormat); + return QLocale().toString(*this, QLocale::ShortFormat, cal); case Qt::DefaultLocaleLongDate: - return QLocale().toString(*this, QLocale::LongFormat); + return QLocale().toString(*this, QLocale::LongFormat, cal); +#endif // 5.15 case Qt::RFC2822Date: - return QLocale::c().toString(*this, u"dd MMM yyyy"); + return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal); default: -#if QT_CONFIG(textdate) case Qt::TextDate: - return toStringTextDate(*this); -#endif + return toStringTextDate(*this, cal); case Qt::ISODate: case Qt::ISODateWithMs: + // No calendar dependence return toStringIsoDate(*this); } } /*! \fn QString QDate::toString(const QString &format) const + \fn QString QDate::toString(const QString &format, QCalendar cal) const \fn QString QDate::toString(QStringView format) const + \fn QString QDate::toString(QStringView format, QCalendar cal) const - Returns the date as a string. The \a format parameter determines - the format of the result string. + Returns the date as a string. The \a format parameter determines the format + of the result string. If \cal is supplied, it determines the calendar used + to represent the date; it defaults to Gregorian. These expressions may be used: @@ -1263,43 +1264,7 @@ QString QDate::toString(Qt::DateFormat format) const */ QString QDate::toString(QStringView format) const { - return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6 -} - -#if QT_STRINGVIEW_LEVEL < 2 -QString QDate::toString(const QString &format) const -{ - return toString(qToStringViewIgnoringNull(format)); -} -#endif - -QString QDate::toString(Qt::DateFormat format, QCalendar cal) const -{ - if (!isValid()) - return QString(); - - switch (format) { - case Qt::SystemLocaleDate: - case Qt::SystemLocaleShortDate: - return QLocale::system().toString(*this, QLocale::ShortFormat, cal); - case Qt::SystemLocaleLongDate: - return QLocale::system().toString(*this, QLocale::LongFormat, cal); - case Qt::LocaleDate: - case Qt::DefaultLocaleShortDate: - return QLocale().toString(*this, QLocale::ShortFormat, cal); - case Qt::DefaultLocaleLongDate: - return QLocale().toString(*this, QLocale::LongFormat, cal); - case Qt::RFC2822Date: - return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal); - default: -#ifndef QT_NO_TEXTDATE - case Qt::TextDate: - return toStringTextDate(*this, cal); -#endif - case Qt::ISODate: - case Qt::ISODateWithMs: - return toStringIsoDate(*this); - } + return toString(format, QCalendar()); } QString QDate::toString(QStringView format, QCalendar cal) const @@ -1308,6 +1273,11 @@ QString QDate::toString(QStringView format, QCalendar cal) const } #if QT_STRINGVIEW_LEVEL < 2 +QString QDate::toString(const QString &format) const +{ + return toString(qToStringViewIgnoringNull(format), QCalendar()); +} + QString QDate::toString(const QString &format, QCalendar cal) const { return toString(qToStringViewIgnoringNull(format), cal); @@ -1625,7 +1595,7 @@ qint64 QDate::daysTo(const QDate &d) const \sa QTime::currentTime(), QDateTime::currentDateTime() */ -#if QT_CONFIG(datestring) +#if QT_CONFIG(datestring) // depends on, so implies, textdate namespace { struct ParsedInt { int value = 0; bool ok = false; }; @@ -1654,9 +1624,14 @@ ParsedInt readInt(QStringView text) \a format given, or an invalid date if the string cannot be parsed. - Note for Qt::TextDate: It is recommended that you use the - English short month names (e.g. "Jan"). Although localized month - names can also be used, they depend on the user's locale settings. + Note for Qt::TextDate: It is recommended that you use the English short + month names (e.g. "Jan"). Although localized month names can also be used in + Qt 5, they depend on the user's locale settings. + + \note Support for localized dates, including the format options + Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate, + Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate, + shall be removed in Qt 6. Use QLocale::toDate() instead. \sa toString(), QLocale::toDate() */ @@ -1667,6 +1642,7 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format) return QDate(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toDate(string, QLocale::ShortFormat); @@ -1677,10 +1653,10 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format) return QLocale().toDate(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toDate(string, QLocale::LongFormat); +#endif // 5.15 case Qt::RFC2822Date: return rfcDateImpl(string).date; default: -#if QT_CONFIG(textdate) case Qt::TextDate: { QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), QString::SkipEmptyParts); @@ -1699,7 +1675,6 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format) return QDate(year, month, day); } -#endif // textdate case Qt::ISODate: // Semi-strict parsing, must be long enough and have punctuators as separators if (string.size() >= 10 && string.at(4).isPunct() && string.at(7).isPunct() @@ -2014,7 +1989,7 @@ int QTime::msec() const return ds() % 1000; } -#if QT_CONFIG(datestring) +#if QT_CONFIG(datestring) // depends on, so implies, textdate /*! \overload @@ -2030,18 +2005,15 @@ int QTime::msec() const date, use the \a format Qt::ISODateWithMs, which corresponds to HH:mm:ss.zzz. - If the \a format is Qt::SystemLocaleShortDate or - Qt::SystemLocaleLongDate, the string format depends on the locale - settings of the system. Identical to calling - QLocale::system().toString(time, QLocale::ShortFormat) or - QLocale::system().toString(time, QLocale::LongFormat). - - If the \a format is Qt::DefaultLocaleShortDate or - Qt::DefaultLocaleLongDate, the string format depends on the - default application locale. This is the locale set with - QLocale::setDefault(), or the system locale if no default locale - has been set. Identical to calling + The \a format options Qt::SystemLocaleDate:, Qt::SystemLocaleShortDate and + Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with: + \l {QLocale::toString()}{QLocale::system().toString(time, QLocale::ShortFormat)} or + \l {QLocale::toString()}{QLocale::system().toString(time, QLocale::LongFormat)}. + The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and + Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with: \l {QLocale::toString()}{QLocale().toString(time, QLocale::ShortFormat)} or \l {QLocale::toString()}{QLocale().toString(time, QLocale::LongFormat)}. @@ -2060,6 +2032,7 @@ QString QTime::toString(Qt::DateFormat format) const return QString(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toString(*this, QLocale::ShortFormat); @@ -2070,6 +2043,7 @@ QString QTime::toString(Qt::DateFormat format) const return QLocale().toString(*this, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toString(*this, QLocale::LongFormat); +#endif // 5.15 case Qt::ISODateWithMs: return QString::asprintf("%02d:%02d:%02d.%03d", hour(), minute(), second(), msec()); case Qt::RFC2822Date: @@ -2347,7 +2321,7 @@ int QTime::msecsTo(const QTime &t) const \sa QDateTime::currentDateTime(), QDateTime::currentDateTimeUtc() */ -#if QT_CONFIG(datestring) +#if QT_CONFIG(datestring) // depends on, so implies, textdate static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool *isMidnight24) { @@ -2445,6 +2419,12 @@ static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool * fails for the default locale). This should be considered an implementation detail. + + \note Support for localized dates, including the format options + Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate, + Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate, + shall be removed in Qt 6. Use QLocale::toTime() instead. + \sa toString(), QLocale::toTime() */ QTime QTime::fromString(const QString &string, Qt::DateFormat format) @@ -2453,6 +2433,7 @@ QTime QTime::fromString(const QString &string, Qt::DateFormat format) return QTime(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toTime(string, QLocale::ShortFormat); @@ -2463,6 +2444,7 @@ QTime QTime::fromString(const QString &string, Qt::DateFormat format) return QLocale().toTime(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toTime(string, QLocale::LongFormat); +#endif // 5.15 case Qt::RFC2822Date: return rfcDateImpl(string).time; case Qt::ISODate: @@ -2877,7 +2859,7 @@ static void msecsToTime(qint64 msecs, QDate *date, QTime *time) } // Converts a date/time value into msecs -static qint64 timeToMSecs(const QDate &date, const QTime &time) +static qint64 timeToMSecs(QDate date, QTime time) { return ((date.toJulianDay() - JULIAN_DAY_FOR_EPOCH) * MSECS_PER_DAY) + time.msecsSinceStartOfDay(); @@ -3222,7 +3204,7 @@ static void setTimeSpec(QDateTimeData &d, Qt::TimeSpec spec, int offsetSeconds) } } -static void setDateTime(QDateTimeData &d, const QDate &date, const QTime &time) +static void setDateTime(QDateTimeData &d, QDate date, QTime time) { // If the date is valid and the time is not we set time to 00:00:00 QTime useTime = time; @@ -3631,15 +3613,18 @@ QDateTime::QDateTime() noexcept(Data::CanBeSmall) } +#if QT_DEPRECATED_SINCE(5, 17) // ### Qt 6: remove /*! - Constructs a datetime with the given \a date, a valid - time(00:00:00.000), and sets the timeSpec() to Qt::LocalTime. -*/ + Constructs a datetime with the given \a date, using Qt::LocalTime as the + timeSpec() and the time at the start of that date. + \sa QDate::startOfDay() +*/ QDateTime::QDateTime(const QDate &date) - : d(QDateTimePrivate::create(date, QTime(0, 0), Qt::LocalTime, 0)) + : QDateTime(date.startOfDay(Qt::LocalTime, 0)) { } +#endif /*! Constructs a datetime with the given \a date and \a time, using @@ -4292,13 +4277,16 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) } #endif -#if QT_CONFIG(datestring) +#if QT_CONFIG(datestring) // depends on, so implies, textdate /*! \fn QString QDateTime::toString(Qt::DateFormat format) const + \fn QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const \overload - Returns the datetime as a string in the \a format given. + Returns the datetime as a string in the \a format given. If \cal is + supplied, it determines the calendar used to represent the date; it defaults + to Gregorian. If the \a format is Qt::TextDate, the string is formatted in the default way. The day and month names will be localized names using the system @@ -4315,19 +4303,17 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) date, use the \a format Qt::ISODateWithMs, which corresponds to yyyy-MM-ddTHH:mm:ss.zzz[Z|[+|-]HH:mm]. - If the \a format is Qt::SystemLocaleShortDate or - Qt::SystemLocaleLongDate, the string format depends on the locale - settings of the system. Identical to calling - QLocale::system().toString(datetime, QLocale::ShortFormat) or - QLocale::system().toString(datetime, QLocale::LongFormat). + The \a format options Qt::SystemLocaleDate, Qt::SystemLocaleShortDate and + Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with + \l {QLocale::toString()}{QLocale::system().toString(datetime, QLocale::ShortFormat)} or + \l {QLocale::toString()}{QLocale::system().toString(datetime, QLocale::LongFormat)}. - If the \a format is Qt::DefaultLocaleShortDate or - Qt::DefaultLocaleLongDate, the string format depends on the - default application locale. This is the locale set with - QLocale::setDefault(), or the system locale if no default locale - has been set. Identical to calling QLocale().toString(datetime, - QLocale::ShortFormat) or QLocale().toString(datetime, - QLocale::LongFormat). + The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and + Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with + \l {QLocale::toString()}{QLocale().toString(datetime, QLocale::ShortFormat)} or + \l {QLocale::toString()}{QLocale().toString(datetime, QLocale::LongFormat)}. If the \a format is Qt::RFC2822Date, the string is formatted following \l{RFC 2822}. @@ -4335,8 +4321,7 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) If the datetime is invalid, an empty string will be returned. \warning The Qt::ISODate format is only valid for years in the - range 0 to 9999. This restriction may apply to locale-aware - formats as well, depending on the locale settings. + range 0 to 9999. \sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString() @@ -4344,31 +4329,37 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) QString QDateTime::toString(Qt::DateFormat format) const { + return toString(format, QCalendar()); +} + +QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const +{ QString buf; if (!isValid()) return buf; switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: - return QLocale::system().toString(*this, QLocale::ShortFormat); + return QLocale::system().toString(*this, QLocale::ShortFormat, cal); case Qt::SystemLocaleLongDate: - return QLocale::system().toString(*this, QLocale::LongFormat); + return QLocale::system().toString(*this, QLocale::LongFormat, cal); case Qt::LocaleDate: case Qt::DefaultLocaleShortDate: - return QLocale().toString(*this, QLocale::ShortFormat); + return QLocale().toString(*this, QLocale::ShortFormat, cal); case Qt::DefaultLocaleLongDate: - return QLocale().toString(*this, QLocale::LongFormat); + return QLocale().toString(*this, QLocale::LongFormat, cal); +#endif // 5.15 case Qt::RFC2822Date: { - buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss "); + buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss ", cal); buf += toOffsetString(Qt::TextDate, offsetFromUtc()); return buf; } default: -#if QT_CONFIG(textdate) case Qt::TextDate: { const QPair<QDate, QTime> p = getDateTime(d); - buf = p.first.toString(Qt::TextDate); + buf = toStringTextDate(p.first, cal); // Insert time between date's day and year: buf.insert(buf.lastIndexOf(QLatin1Char(' ')), QLatin1Char(' ') + p.second.toString(Qt::TextDate)); @@ -4376,11 +4367,11 @@ QString QDateTime::toString(Qt::DateFormat format) const switch (timeSpec()) { case Qt::LocalTime: break; -# if QT_CONFIG(timezone) +#if QT_CONFIG(timezone) case Qt::TimeZone: buf += QLatin1Char(' ') + d->m_timeZone.abbreviation(*this); break; -# endif +#endif default: buf += QLatin1String(" GMT"); if (getSpec(d) == Qt::OffsetFromUTC) @@ -4388,17 +4379,14 @@ QString QDateTime::toString(Qt::DateFormat format) const } return buf; } -#endif case Qt::ISODate: case Qt::ISODateWithMs: { + // No calendar dependence const QPair<QDate, QTime> p = getDateTime(d); - const QDate &dt = p.first; - const QTime &tm = p.second; - buf = dt.toString(Qt::ISODate); + buf = toStringIsoDate(p.first); if (buf.isEmpty()) return QString(); // failed to convert - buf += QLatin1Char('T'); - buf += tm.toString(format); + buf += QLatin1Char('T') + p.second.toString(format); switch (getSpec(d)) { case Qt::UTC: buf += QLatin1Char('Z'); @@ -4419,11 +4407,15 @@ QString QDateTime::toString(Qt::DateFormat format) const /*! \fn QString QDateTime::toString(const QString &format) const + \fn QString QDateTime::toString(const QString &format, QCalendar cal) const \fn QString QDateTime::toString(QStringView format) const + \fn QString QDateTime::toString(QStringView format, QCalendar cal) const Returns the datetime as a string. The \a format parameter determines the - format of the result string. See QTime::toString() and QDate::toString() for - the supported specifiers for time and date, respectively. + format of the result string. If \cal is supplied, it determines the calendar + used to represent the date; it defaults to Gregorian. See QTime::toString() + and QDate::toString() for the supported specifiers for time and date, + respectively. Any sequence of characters enclosed in single quotes will be included verbatim in the output string (stripped of the quotes), even if it contains @@ -4454,13 +4446,23 @@ QString QDateTime::toString(Qt::DateFormat format) const */ QString QDateTime::toString(QStringView format) const { - return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6 + return toString(format, QCalendar()); +} + +QString QDateTime::toString(QStringView format, QCalendar cal) const +{ + return QLocale::system().toString(*this, format, cal); // QLocale::c() ### Qt6 } #if QT_STRINGVIEW_LEVEL < 2 QString QDateTime::toString(const QString &format) const { - return toString(qToStringViewIgnoringNull(format)); + return toString(qToStringViewIgnoringNull(format), QCalendar()); +} + +QString QDateTime::toString(const QString &format, QCalendar cal) const +{ + return toString(qToStringViewIgnoringNull(format), cal); } #endif @@ -5202,15 +5204,20 @@ int QDateTime::utcOffset() const } #endif // QT_DEPRECATED_SINCE -#if QT_CONFIG(datestring) +#if QT_CONFIG(datestring) // depends on, so implies, textdate /*! Returns the QDateTime represented by the \a string, using the \a format given, or an invalid datetime if this is not possible. - Note for Qt::TextDate: It is recommended that you use the - English short month names (e.g. "Jan"). Although localized month - names can also be used, they depend on the user's locale settings. + Note for Qt::TextDate: It is recommended that you use the English short + month names (e.g. "Jan"). Although localized month names can also be used in + Qt 5, they depend on the user's locale settings. + + \note Support for localized dates, including the format options + Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate, + Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate, + shall be removed in Qt 6. Use QLocale::toDateTime() instead. \sa toString(), QLocale::toDateTime() */ @@ -5220,6 +5227,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) return QDateTime(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toDateTime(string, QLocale::ShortFormat); @@ -5230,6 +5238,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) return QLocale().toDateTime(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toDateTime(string, QLocale::LongFormat); +#endif // 5.15 case Qt::RFC2822Date: { const ParsedRfcDateTime rfc = rfcDateImpl(string); @@ -5306,7 +5315,6 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) date = date.addDays(1); return QDateTime(date, time, spec, offset); } -#if QT_CONFIG(textdate) case Qt::TextDate: { QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), QString::SkipEmptyParts); @@ -5412,7 +5420,6 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) return QDateTime(date, time, Qt::UTC); } } -#endif // textdate } return QDateTime(); diff --git a/src/corelib/time/qdatetime.h b/src/corelib/time/qdatetime.h index 3eae8ebf64..c1653b5585 100644 --- a/src/corelib/time/qdatetime.h +++ b/src/corelib/time/qdatetime.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -110,14 +110,15 @@ public: static QString longDayName(int weekday, MonthNameType type = DateFormat); #endif // textdate && deprecated #if QT_CONFIG(datestring) - QString toString(Qt::DateFormat f = Qt::TextDate) const; + QString toString(Qt::DateFormat format = Qt::TextDate) const; + QString toString(Qt::DateFormat format, QCalendar cal) const; + #if QT_STRINGVIEW_LEVEL < 2 QString toString(const QString &format) const; QString toString(const QString &format, QCalendar cal) const; #endif QString toString(QStringView format) const; - QString toString(Qt::DateFormat f, QCalendar cal) const; QString toString(QStringView format, QCalendar cal) const; #endif #if QT_DEPRECATED_SINCE(5,0) @@ -287,7 +288,9 @@ class Q_CORE_EXPORT QDateTime public: QDateTime() noexcept(Data::CanBeSmall); - explicit QDateTime(const QDate &); // ### Qt 6: plain QDate, QTime +#if QT_DEPRECATED_SINCE(5, 15) // ### Qt 6: remove + QT_DEPRECATED_X("Use QDate::startOfDay()") explicit QDateTime(const QDate &); +#endif QDateTime(const QDate &, const QTime &, Qt::TimeSpec spec = Qt::LocalTime); // ### Qt 6: Merge with above with default offsetSeconds = 0 QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds); @@ -330,11 +333,14 @@ public: void setSecsSinceEpoch(qint64 secs); #if QT_CONFIG(datestring) - QString toString(Qt::DateFormat f = Qt::TextDate) const; + QString toString(Qt::DateFormat format = Qt::TextDate) const; + QString toString(Qt::DateFormat format, QCalendar cal) const; #if QT_STRINGVIEW_LEVEL < 2 QString toString(const QString &format) const; + QString toString(const QString &format, QCalendar cal) const; #endif QString toString(QStringView format) const; + QString toString(QStringView format, QCalendar cal) const; #endif Q_REQUIRED_RESULT QDateTime addDays(qint64 days) const; Q_REQUIRED_RESULT QDateTime addMonths(int months) const; diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp index 70460ae632..790c20004a 100644 --- a/src/corelib/time/qdatetimeparser.cpp +++ b/src/corelib/time/qdatetimeparser.cpp @@ -219,7 +219,8 @@ int QDateTimeParser::absoluteMax(int s, const QDateTime &cur) const const SectionNode &sn = sectionNode(s); switch (sn.type) { #if QT_CONFIG(timezone) - case TimeZoneSection: return QTimeZone::MaxUtcOffsetSecs; + case TimeZoneSection: + return QTimeZone::MaxUtcOffsetSecs; #endif case Hour24Section: case Hour12Section: @@ -227,20 +228,25 @@ int QDateTimeParser::absoluteMax(int s, const QDateTime &cur) const // We want it to be 23 for the stepBy case. return 23; case MinuteSection: - case SecondSection: return 59; - case MSecSection: return 999; + case SecondSection: + return 59; + case MSecSection: + return 999; case YearSection2Digits: case YearSection: // sectionMaxSize will prevent people from typing in a larger number in // count == 2 sections; stepBy() will work on real years anyway. return 9999; - case MonthSection: return calendar.maximumMonthsInYear(); + case MonthSection: + return calendar.maximumMonthsInYear(); case DaySection: case DayOfWeekSectionShort: case DayOfWeekSectionLong: return cur.isValid() ? cur.date().daysInMonth(calendar) : calendar.maximumDaysInMonth(); - case AmPmSection: return 1; - default: break; + case AmPmSection: + return 1; + default: + break; } qWarning("QDateTimeParser::absoluteMax() Internal error (%ls)", qUtf16Printable(sn.name())); @@ -620,7 +626,8 @@ int QDateTimeParser::sectionMaxSize(Section s, int count) const switch (s) { case FirstSection: case NoSection: - case LastSection: return 0; + case LastSection: + return 0; case AmPmSection: { const int lowerMax = qMax(getAmPmText(AmText, LowerCase).size(), @@ -634,7 +641,9 @@ int QDateTimeParser::sectionMaxSize(Section s, int count) const case Hour12Section: case MinuteSection: case SecondSection: - case DaySection: return 2; + case DaySection: + return 2; + case DayOfWeekSectionShort: case DayOfWeekSectionLong: #if !QT_CONFIG(textdate) @@ -663,11 +672,15 @@ int QDateTimeParser::sectionMaxSize(Section s, int count) const return ret; } #endif - case MSecSection: return 3; - case YearSection: return 4; - case YearSection2Digits: return 2; + case MSecSection: + return 3; + case YearSection: + return 4; + case YearSection2Digits: + return 2; + case TimeZoneSection: // Arbitrarily many tokens (each up to 14 bytes) joined with / separators: - case TimeZoneSection: return std::numeric_limits<int>::max(); + return std::numeric_limits<int>::max(); case CalendarPopupSection: case Internal: @@ -903,7 +916,7 @@ QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionIndex, by \a weekDay. */ -static int weekDayWithinMonth(const QCalendar &calendar, const QDate &rough, int weekDay) +static int weekDayWithinMonth(QCalendar calendar, QDate rough, int weekDay) { // TODO: can we adapt this to cope gracefully with intercallary days (day of // week > 7) without making it slower for more widely-used calendars ? diff --git a/src/corelib/time/qtimezoneprivate_win.cpp b/src/corelib/time/qtimezoneprivate_win.cpp index 0fec5355b2..0aaf469ed9 100644 --- a/src/corelib/time/qtimezoneprivate_win.cpp +++ b/src/corelib/time/qtimezoneprivate_win.cpp @@ -363,7 +363,7 @@ QDate calculateTransitionLocalDate(const SYSTEMTIME &rule, int year) } // Converts a date/time value into msecs -inline qint64 timeToMSecs(const QDate &date, const QTime &time) +inline qint64 timeToMSecs(QDate date, QTime time) { return ((date.toJulianDay() - JULIAN_DAY_FOR_EPOCH) * MSECS_PER_DAY) + time.msecsSinceStartOfDay(); diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp index a1dd537d4d..12ad6f4573 100644 --- a/src/corelib/tools/qbitarray.cpp +++ b/src/corelib/tools/qbitarray.cpp @@ -305,7 +305,7 @@ void QBitArray::fill(bool value, int begin, int end) \since 5.11 Returns a pointer to a dense bit array for this QBitArray. Bits are counted - upwards from the least significant bit in each byte. The the number of bits + upwards from the least significant bit in each byte. The number of bits relevant in the last byte is given by \c{size() % 8}. \sa fromBits(), size() diff --git a/src/corelib/tools/qcontainerfwd.h b/src/corelib/tools/qcontainerfwd.h index f6efa99b6a..d6e30d77e3 100644 --- a/src/corelib/tools/qcontainerfwd.h +++ b/src/corelib/tools/qcontainerfwd.h @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE template <class Key, class T> class QCache; template <class Key, class T> class QHash; -#ifndef QT_NO_LINKED_LIST +#if !defined(QT_NO_LINKED_LIST) && QT_DEPRECATED_SINCE(5, 15) template <class T> class QLinkedList; #endif template <class Key, class T> class QMap; diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index c56324eef7..47fa0520d9 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -1245,6 +1245,7 @@ Q_OUTOFLINE_TEMPLATE int QMultiHash<Key, T>::count(const Key &akey) const return cnt; } +#if !defined(QT_NO_JAVA_STYLE_ITERATORS) template <class Key, class T> class QHashIterator { @@ -1419,6 +1420,7 @@ public: } #endif }; +#endif // !QT_NO_JAVA_STYLE_ITERATORS template <class Key, class T> uint qHash(const QHash<Key, T> &key, uint seed = 0) diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc index b4d332b7b1..3531fb202c 100644 --- a/src/corelib/tools/qiterator.qdoc +++ b/src/corelib/tools/qiterator.qdoc @@ -203,6 +203,7 @@ /*! \class QLinkedListIterator \inmodule QtCore + \obsolete \brief The QLinkedListIterator class provides a Java-style const iterator for QLinkedList. @@ -416,6 +417,7 @@ /*! \class QMutableLinkedListIterator \inmodule QtCore + \obsolete \brief The QMutableLinkedListIterator class provides a Java-style non-const iterator for QLinkedList. diff --git a/src/corelib/tools/qlinkedlist.cpp b/src/corelib/tools/qlinkedlist.cpp index 3b1bc8aab1..6a423545da 100644 --- a/src/corelib/tools/qlinkedlist.cpp +++ b/src/corelib/tools/qlinkedlist.cpp @@ -45,6 +45,11 @@ QT_BEGIN_NAMESPACE +#if QT_DEPRECATED_SINCE(5, 15) + +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + const QLinkedListData QLinkedListData::shared_null = { const_cast<QLinkedListData *>(&QLinkedListData::shared_null), const_cast<QLinkedListData *>(&QLinkedListData::shared_null), @@ -53,6 +58,7 @@ const QLinkedListData QLinkedListData::shared_null = { /*! \class QLinkedList \inmodule QtCore + \obsolete \brief The QLinkedList class is a template class that provides linked lists. \ingroup tools @@ -60,6 +66,8 @@ const QLinkedListData QLinkedListData::shared_null = { \reentrant + \note This class is obsolete, please use std::list instead. + QLinkedList\<T\> is one of Qt's generic \l{container classes}. It stores a list of values and provides iterator-based access as well as \l{constant time} insertions and removals. @@ -720,6 +728,7 @@ const QLinkedListData QLinkedListData::shared_null = { /*! \class QLinkedList::iterator \inmodule QtCore + \obsolete \brief The QLinkedList::iterator class provides an STL-style non-const iterator for QLinkedList. QLinkedList features both \l{STL-style iterators} and @@ -965,6 +974,7 @@ const QLinkedListData QLinkedListData::shared_null = { /*! \class QLinkedList::const_iterator \inmodule QtCore + \obsolete \brief The QLinkedList::const_iterator class provides an STL-style const iterator for QLinkedList. QLinkedList features both \l{STL-style iterators} and @@ -1221,4 +1231,8 @@ const QLinkedListData QLinkedListData::shared_null = { \sa fromStdList() */ +QT_WARNING_POP + +#endif // QT_DEPRECATED_SINCE(5, 15) + QT_END_NAMESPACE diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h index e3713d2c1c..fd3df74059 100644 --- a/src/corelib/tools/qlinkedlist.h +++ b/src/corelib/tools/qlinkedlist.h @@ -55,10 +55,22 @@ #include <iterator> #include <list> -QT_BEGIN_NAMESPACE +#if 0 +// This is needed because of QTBUG-80347 +#pragma qt_class(QLinkedList) +#pragma qt_class(QLinkedListData) +#pragma qt_class(QLinkedListNode) +#endif + +#if QT_DEPRECATED_SINCE(5, 15) + +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED -struct Q_CORE_EXPORT QLinkedListData +QT_BEGIN_NAMESPACE + +struct QT_DEPRECATED_VERSION_5_15 Q_CORE_EXPORT QLinkedListData { QLinkedListData *n, *p; QtPrivate::RefCount ref; @@ -69,7 +81,7 @@ struct Q_CORE_EXPORT QLinkedListData }; template <typename T> -struct QLinkedListNode +struct QT_DEPRECATED_VERSION_5_15 QLinkedListNode { inline QLinkedListNode(const T &arg): t(arg) { } QLinkedListNode *n, *p; @@ -77,7 +89,7 @@ struct QLinkedListNode }; template <class T> -class QLinkedList +class QT_DEPRECATED_VERSION_X_5_15("Use std::list instead") QLinkedList { typedef QLinkedListNode<T> Node; union { QLinkedListData *d; QLinkedListNode<T> *e; }; @@ -591,6 +603,10 @@ QT_END_NAMESPACE Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(QLinkedList) +QT_WARNING_POP + +#endif // QT_DEPRECATED_SINCE(5, 15) + #endif // QT_NO_LINKED_LIST #endif // QLINKEDLIST_H diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index e2b7705b55..9b9c67e42b 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -1999,7 +1999,7 @@ void QMapDataBase::freeData(QMapDataBase *d) \sa replace() */ -/*! \fn template <class Key, class T> typename QMap<Key, T>::iterator QMultiMap<Key, T>::insert(typename QMap<Key, T>::const_iterator pos, const Key &key, const T &value) +/*! \fn template <class Key, class T> typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(typename QMultiMap<Key, T>::const_iterator pos, const Key &key, const T &value) \since 5.1 Inserts a new item with the key \a key and value \a value and with hint \a pos diff --git a/src/corelib/tools/qscopeguard.h b/src/corelib/tools/qscopeguard.h index 40d2747b1d..6a5bc6cc61 100644 --- a/src/corelib/tools/qscopeguard.h +++ b/src/corelib/tools/qscopeguard.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@kdab.com> +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -42,13 +43,11 @@ #include <QtCore/qglobal.h> +#include <type_traits> +#include <utility> QT_BEGIN_NAMESPACE - -template <typename F> class QScopeGuard; -template <typename F> QScopeGuard<F> qScopeGuard(F f); - template <typename F> class #if __has_cpp_attribute(nodiscard) @@ -59,13 +58,23 @@ Q_REQUIRED_RESULT QScopeGuard { public: + explicit QScopeGuard(F &&f) noexcept + : m_func(std::move(f)) + { + } + + explicit QScopeGuard(const F &f) noexcept + : m_func(f) + { + } + QScopeGuard(QScopeGuard &&other) noexcept : m_func(std::move(other.m_func)) , m_invoke(qExchange(other.m_invoke, false)) { } - ~QScopeGuard() + ~QScopeGuard() noexcept { if (m_invoke) m_func(); @@ -77,26 +86,23 @@ public: } private: - explicit QScopeGuard(F &&f) noexcept - : m_func(std::move(f)) - { - } - Q_DISABLE_COPY(QScopeGuard) F m_func; bool m_invoke = true; - friend QScopeGuard qScopeGuard<F>(F); }; +#ifdef __cpp_deduction_guides +template <typename F> QScopeGuard(F(&)()) -> QScopeGuard<F(*)()>; +#endif template <typename F> #if __has_cpp_attribute(nodiscard) Q_REQUIRED_RESULT #endif -QScopeGuard<F> qScopeGuard(F f) +QScopeGuard<typename std::decay<F>::type> qScopeGuard(F &&f) { - return QScopeGuard<F>(std::move(f)); + return QScopeGuard<typename std::decay<F>::type>(std::forward<F>(f)); } QT_END_NAMESPACE diff --git a/src/corelib/tools/qscopeguard.qdoc b/src/corelib/tools/qscopeguard.qdoc index 6b3c942e84..572934d890 100644 --- a/src/corelib/tools/qscopeguard.qdoc +++ b/src/corelib/tools/qscopeguard.qdoc @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@kdab.com> +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -35,6 +36,30 @@ QT_BEGIN_NAMESPACE \inmodule QtCore \brief Provides a scope guard for calling a function at the end of a scope. + + QScopeGuard<F> is a class of which the sole purpose is to run the function + \a f in its destructor. This is useful for guaranteeing + your cleanup code is executed, whether the function is exited normally, + exited early by a return statement, or exited by an exception. + + \note Exceptions are not supported. The callable shouldn't throw when + executed, copied or moved. + + \sa QScopedValueRollback +*/ + +/*! + \fn template <typename F> QScopeGuard<F>::QScopeGuard(F &&f) + \fn template <typename F> QScopeGuard<F>::QScopeGuard(const F &f) + + Create a scope guard that will execute \a f at the end of the scope. + + If \e F is a lambda, its type cannot be written. In that case you need to + either rely on class template argument deduction (C++17 feature) and leave + the template parameter out completely or use the helper function + qScopeGuard() instead of this constructor. + + \since 5.15 */ /*! \fn template <typename F> void QScopeGuard<F>::dismiss() @@ -51,23 +76,17 @@ QT_BEGIN_NAMESPACE of the scope. \ingroup misc - QScopeGuard<F> is a class of which the sole purpose is to run the function - \a f in its destructor. This is useful for guaranteeing - your cleanup code is executed, whether the function is exited normally, - exited early by a return statement, or exited by an exception. + Create a scope guard that will execute \a f at the end of the scope. - If \e F is a lambda then you cannot instantiate the template directly, - therefore the qScopeGuard() helper is provided and QScopeGuard<F> is made a - private implementation detail. + This helper function is provided so that you can easily construct a + QScopeGuard without having to name the template parameter for the type of + the callable. If \e F is a lambda then you cannot write its type and relying + on this helper or class template argument deduction is necessary. Example usage is as follows: \snippet code/src_corelib_tools_qscopeguard.cpp 0 - \note Exceptions are not supported. The callable shouldn't throw when - executed, copied or moved. - - \sa QScopedValueRollback */ QT_END_NAMESPACE |