diff options
189 files changed, 2667 insertions, 3203 deletions
diff --git a/config_help.txt b/config_help.txt index 5d116ce780..3d3ddb803c 100644 --- a/config_help.txt +++ b/config_help.txt @@ -164,8 +164,6 @@ Build options: -reduce-exports ...... Reduce amount of exported symbols [auto] -reduce-relocations .. Reduce amount of relocations [auto] (Unix only) - -relocatable ......... Enable the Qt installation to be relocated [auto] - -plugin-manifests .... Embed manifests into plugins [no] (Windows only) -static-runtime ...... With -static, use static runtime [no] (Windows only) diff --git a/configure.json b/configure.json index d11fa18bf1..cf123602c2 100644 --- a/configure.json +++ b/configure.json @@ -1407,6 +1407,7 @@ }, "relocatable": { "label": "Relocatable", + "purpose": "Enable the Qt installation to be relocated.", "autoDetect": "features.shared", "condition": "features.dlopen || config.win32 || !features.shared", "output": [ "privateFeature" ] diff --git a/dist/changes-5.14.0 b/dist/changes-5.14.0 index 77cbb70928..9069663715 100644 --- a/dist/changes-5.14.0 +++ b/dist/changes-5.14.0 @@ -476,6 +476,9 @@ information about a particular change. - MinGW: * [QTBUG-4155] Added a suffix to debug mode pkgconfig files. + * MinGW does not built with -debug-and-release mode anymore. + Instead, the binaries are built with -release -force-debug-info + -separate-debug-info. - macOS: * The drawableSize of Metal layers is no longer updated automatically on diff --git a/examples/embedded/lightmaps/mapzoom.cpp b/examples/embedded/lightmaps/mapzoom.cpp index d82b9ad473..781d4f27e3 100644 --- a/examples/embedded/lightmaps/mapzoom.cpp +++ b/examples/embedded/lightmaps/mapzoom.cpp @@ -81,52 +81,9 @@ MapZoom::MapZoom() menu->addAction(nightModeAction); menu->addAction(osmAction); - QNetworkConfigurationManager manager; - if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) { - // Get saved network configuration - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - const QString id = - settings.value(QLatin1String("DefaultNetworkConfiguration")).toString(); - settings.endGroup(); - - // If the saved network configuration is not currently discovered use the system - // default - QNetworkConfiguration config = manager.configurationFromIdentifier(id); - if ((config.state() & QNetworkConfiguration::Discovered) != - QNetworkConfiguration::Discovered) { - config = manager.defaultConfiguration(); - } - - networkSession = new QNetworkSession(config, this); - connect(networkSession, SIGNAL(opened()), this, SLOT(sessionOpened())); - - networkSession->open(); - } else { - networkSession = 0; - } - setWindowTitle(tr("Light Maps")); } -void MapZoom::sessionOpened() -{ - // Save the used configuration - QNetworkConfiguration config = networkSession->configuration(); - QString id; - if (config.type() == QNetworkConfiguration::UserChoice) { - id = networkSession->sessionProperty( - QLatin1String("UserChoiceConfiguration")).toString(); - } else { - id = config.identifier(); - } - - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id); - settings.endGroup(); -} - void MapZoom::chooseOslo() { map->setCenter(59.9138204, 10.7387413); diff --git a/examples/embedded/lightmaps/mapzoom.h b/examples/embedded/lightmaps/mapzoom.h index 30f2e63138..3844eca718 100644 --- a/examples/embedded/lightmaps/mapzoom.h +++ b/examples/embedded/lightmaps/mapzoom.h @@ -53,7 +53,6 @@ #include <QMainWindow> -class QNetworkSession; class LightMaps; class MapZoom : public QMainWindow @@ -64,7 +63,6 @@ public: MapZoom(); private slots: - void sessionOpened(); void chooseOslo(); void chooseBerlin(); void chooseJakarta(); @@ -72,7 +70,6 @@ private slots: private: LightMaps *map; - QNetworkSession *networkSession; }; #endif
\ No newline at end of file diff --git a/examples/network/CMakeLists.txt b/examples/network/CMakeLists.txt index af1f923dc6..919310df9a 100644 --- a/examples/network/CMakeLists.txt +++ b/examples/network/CMakeLists.txt @@ -20,7 +20,6 @@ if(TARGET Qt::Widgets) add_subdirectory(multicastsender) if(QT_FEATURE_bearermanagement) - add_subdirectory(bearermonitor) add_subdirectory(fortuneclient) add_subdirectory(fortuneserver) diff --git a/examples/network/bearermonitor/CMakeLists.txt b/examples/network/bearermonitor/CMakeLists.txt deleted file mode 100644 index 4e8bfca813..0000000000 --- a/examples/network/bearermonitor/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -# Generated from bearermonitor.pro. - -cmake_minimum_required(VERSION 3.14) -project(bearermonitor LANGUAGES CXX) - -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_AUTOUIC ON) - -set(INSTALL_EXAMPLEDIR "examples/network/bearermonitor") - -find_package(Qt6 COMPONENTS Core) -find_package(Qt6 COMPONENTS Gui) -find_package(Qt6 COMPONENTS Network) -find_package(Qt6 COMPONENTS Widgets) - -add_executable(bearermonitor - bearermonitor.cpp bearermonitor.h - bearermonitor_240_320.ui - bearermonitor_640_480.ui - main.cpp - sessionwidget.cpp sessionwidget.h sessionwidget.ui -) -target_link_libraries(bearermonitor PUBLIC - Qt::Core - Qt::Gui - Qt::Network - Qt::Widgets -) - -if(WIN32) - target_link_libraries(bearermonitor PUBLIC - ws2_32 - ) -endif() - -install(TARGETS bearermonitor - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" -) diff --git a/examples/network/bearermonitor/bearermonitor.cpp b/examples/network/bearermonitor/bearermonitor.cpp deleted file mode 100644 index 322224a902..0000000000 --- a/examples/network/bearermonitor/bearermonitor.cpp +++ /dev/null @@ -1,421 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "bearermonitor.h" -#include "sessionwidget.h" - -#include <QtCore/QDebug> - -#ifdef Q_OS_WIN -#include <winsock2.h> -#undef interface - -#ifndef NS_NLA -#define NS_NLA 15 -#endif -#endif - -BearerMonitor::BearerMonitor(QWidget *parent) -: QWidget(parent) -{ - setupUi(this); - delete tabWidget->currentWidget(); - sessionGroup->hide(); - updateConfigurations(); - onlineStateChanged(!manager.allConfigurations(QNetworkConfiguration::Active).isEmpty()); - QNetworkConfiguration defaultConfiguration = manager.defaultConfiguration(); - for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) { - QTreeWidgetItem *item = treeWidget->topLevelItem(i); - - if (item->data(0, Qt::UserRole).toString() == defaultConfiguration.identifier()) { - treeWidget->setCurrentItem(item); - showConfigurationFor(item); - break; - } - } - connect(&manager, &QNetworkConfigurationManager::onlineStateChanged, - this, &BearerMonitor::onlineStateChanged); - connect(&manager, &QNetworkConfigurationManager::configurationAdded, - this, [this](const QNetworkConfiguration &config) { configurationAdded(config); }); - connect(&manager, &QNetworkConfigurationManager::configurationRemoved, - this, &BearerMonitor::configurationRemoved); - connect(&manager, &QNetworkConfigurationManager::configurationChanged, - this, &BearerMonitor::configurationChanged); - connect(&manager, &QNetworkConfigurationManager::updateCompleted, - this, &BearerMonitor::updateConfigurations); - -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - connect(registerButton, &QPushButton::clicked, - this, &BearerMonitor::registerNetwork); - connect(unregisterButton, &QPushButton::clicked, - this, &BearerMonitor::unregisterNetwork); -#else // Q_OS_WIN && !Q_OS_WINRT - nlaGroup->hide(); -#endif - - connect(treeWidget, &QTreeWidget::itemActivated, - this, &BearerMonitor::createSessionFor); - connect(treeWidget, &QTreeWidget::currentItemChanged, - this, &BearerMonitor::showConfigurationFor); - - connect(newSessionButton, &QPushButton::clicked, - this, &BearerMonitor::createNewSession); - connect(deleteSessionButton, &QPushButton::clicked, - this, &BearerMonitor::deleteSession); - connect(scanButton, &QPushButton::clicked, - this, &BearerMonitor::performScan); - - // Just in case update all configurations so that all - // configurations are up to date. - manager.updateConfigurations(); -} - -BearerMonitor::~BearerMonitor() -{ -} - -static void updateItem(QTreeWidgetItem *item, const QNetworkConfiguration &config) -{ - item->setText(0, config.name()); - item->setData(0, Qt::UserRole, config.identifier()); - - QFont font = item->font(1); - font.setBold(config.state().testFlag(QNetworkConfiguration::Active)); - item->setFont(0, font); -} - -void BearerMonitor::configurationAdded(const QNetworkConfiguration &config, QTreeWidgetItem *parent) -{ - if (!config.isValid()) - return; - - QTreeWidgetItem *item = new QTreeWidgetItem; - updateItem(item, config); - - if (parent) - parent->addChild(item); - else - treeWidget->addTopLevelItem(item); - - if (config.type() == QNetworkConfiguration::ServiceNetwork) { - const QList<QNetworkConfiguration> children = config.children(); - for (const QNetworkConfiguration &child : children) - configurationAdded(child, item); - } -} - -void BearerMonitor::configurationRemoved(const QNetworkConfiguration &config) -{ - for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) { - QTreeWidgetItem *item = treeWidget->topLevelItem(i); - - if (item->data(0, Qt::UserRole).toString() == config.identifier()) { - delete item; - break; - } - } -} - -void BearerMonitor::configurationChanged(const QNetworkConfiguration &config) -{ - for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) { - QTreeWidgetItem *item = treeWidget->topLevelItem(i); - - if (item->data(0, Qt::UserRole).toString() == config.identifier()) { - updateItem(item, config); - - if (config.type() == QNetworkConfiguration::ServiceNetwork) - updateSnapConfiguration(item, config); - - if (item == treeWidget->currentItem()) - showConfigurationFor(item); - - break; - } - } -} - -void BearerMonitor::updateSnapConfiguration(QTreeWidgetItem *parent, const QNetworkConfiguration &snap) -{ - QMap<QString, QTreeWidgetItem *> itemMap; - const QList<QTreeWidgetItem *> children = parent->takeChildren(); - for (QTreeWidgetItem *item : children) - itemMap.insert(item->data(0, Qt::UserRole).toString(), item); - - QList<QNetworkConfiguration> allConfigurations = snap.children(); - - while (!allConfigurations.isEmpty()) { - QNetworkConfiguration config = allConfigurations.takeFirst(); - - QTreeWidgetItem *item = itemMap.take(config.identifier()); - if (item) { - updateItem(item, config); - - parent->addChild(item); - - if (config.type() == QNetworkConfiguration::ServiceNetwork) - updateSnapConfiguration(item, config); - } else { - configurationAdded(config, parent); - } - } - - qDeleteAll(itemMap); -} - -void BearerMonitor::updateConfigurations() -{ - progressBar->hide(); - scanButton->show(); - - // Just in case update online state, on Symbian platform - // WLAN scan needs to be triggered initially to have their true state. - onlineStateChanged(manager.isOnline()); - - QList<QTreeWidgetItem *> items = treeWidget->findItems(QLatin1String("*"), Qt::MatchWildcard); - QMap<QString, QTreeWidgetItem *> itemMap; - while (!items.isEmpty()) { - QTreeWidgetItem *item = items.takeFirst(); - itemMap.insert(item->data(0, Qt::UserRole).toString(), item); - } - - QNetworkConfiguration defaultConfiguration = manager.defaultConfiguration(); - QTreeWidgetItem *defaultItem = itemMap.take(defaultConfiguration.identifier()); - - if (defaultItem) { - updateItem(defaultItem, defaultConfiguration); - - if (defaultConfiguration.type() == QNetworkConfiguration::ServiceNetwork) - updateSnapConfiguration(defaultItem, defaultConfiguration); - } else { - configurationAdded(defaultConfiguration); - } - - QList<QNetworkConfiguration> allConfigurations = manager.allConfigurations(); - - while (!allConfigurations.isEmpty()) { - QNetworkConfiguration config = allConfigurations.takeFirst(); - - if (config.identifier() == defaultConfiguration.identifier()) - continue; - - QTreeWidgetItem *item = itemMap.take(config.identifier()); - if (item) { - updateItem(item, config); - - if (config.type() == QNetworkConfiguration::ServiceNetwork) - updateSnapConfiguration(item, config); - } else { - configurationAdded(config); - } - } - - qDeleteAll(itemMap); -} - -void BearerMonitor::onlineStateChanged(bool isOnline) -{ - if (isOnline) - onlineState->setText(tr("Online")); - else - onlineState->setText(tr("Offline")); -} - -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) -void BearerMonitor::registerNetwork() -{ - QTreeWidgetItem *item = treeWidget->currentItem(); - if (!item) return; - - QNetworkConfiguration configuration = - manager.configurationFromIdentifier(item->data(0, Qt::UserRole).toString()); - - const QString name = configuration.name(); - - qDebug() << "Registering" << name << "with system"; - - WSAQUERYSET networkInfo; - memset(&networkInfo, 0, sizeof(networkInfo)); - networkInfo.dwSize = sizeof(networkInfo); - networkInfo.lpszServiceInstanceName = (LPWSTR)name.utf16(); - networkInfo.dwNameSpace = NS_NLA; - - if (WSASetService(&networkInfo, RNRSERVICE_REGISTER, 0) == SOCKET_ERROR) - qDebug() << "WSASetService(RNRSERVICE_REGISTER) returned" << WSAGetLastError(); -} - -void BearerMonitor::unregisterNetwork() -{ - QTreeWidgetItem *item = treeWidget->currentItem(); - if (!item) return; - - QNetworkConfiguration configuration = - manager.configurationFromIdentifier(item->data(0, Qt::UserRole).toString()); - - const QString name = configuration.name(); - - qDebug() << "Unregistering" << name << "with system"; - - WSAQUERYSET networkInfo; - memset(&networkInfo, 0, sizeof(networkInfo)); - networkInfo.dwSize = sizeof(networkInfo); - networkInfo.lpszServiceInstanceName = (LPWSTR)name.utf16(); - networkInfo.dwNameSpace = NS_NLA; - - if (WSASetService(&networkInfo, RNRSERVICE_DELETE, 0) == SOCKET_ERROR) - qDebug() << "WSASetService(RNRSERVICE_DELETE) returned" << WSAGetLastError(); -} -#endif // Q_OS_WIN && !Q_OS_WINRT - -void BearerMonitor::showConfigurationFor(QTreeWidgetItem *item) -{ - QString identifier; - - if (item) - identifier = item->data(0, Qt::UserRole).toString(); - - QNetworkConfiguration conf = manager.configurationFromIdentifier(identifier); - - switch (conf.state()) { - case QNetworkConfiguration::Active: - configurationState->setText(tr("Active")); - break; - case QNetworkConfiguration::Discovered: - configurationState->setText(tr("Discovered")); - break; - case QNetworkConfiguration::Defined: - configurationState->setText(tr("Defined")); - break; - case QNetworkConfiguration::Undefined: - configurationState->setText(tr("Undefined")); - break; - } - - switch (conf.type()) { - case QNetworkConfiguration::InternetAccessPoint: - configurationType->setText(tr("Internet Access Point")); - break; - case QNetworkConfiguration::ServiceNetwork: - configurationType->setText(tr("Service Network")); - break; - case QNetworkConfiguration::UserChoice: - configurationType->setText(tr("User Choice")); - break; - case QNetworkConfiguration::Invalid: - configurationType->setText(tr("Invalid")); - break; - } - - switch (conf.purpose()) { - case QNetworkConfiguration::UnknownPurpose: - configurationPurpose->setText(tr("Unknown")); - break; - case QNetworkConfiguration::PublicPurpose: - configurationPurpose->setText(tr("Public")); - break; - case QNetworkConfiguration::PrivatePurpose: - configurationPurpose->setText(tr("Private")); - break; - case QNetworkConfiguration::ServiceSpecificPurpose: - configurationPurpose->setText(tr("Service Specific")); - break; - } - - configurationIdentifier->setText(conf.identifier()); - - configurationRoaming->setText(conf.isRoamingAvailable() ? tr("Available") : tr("Not available")); - - configurationChildren->setText(QString::number(conf.children().count())); - - configurationName->setText(conf.name()); -} - -void BearerMonitor::createSessionFor(QTreeWidgetItem *item) -{ - const QString identifier = item->data(0, Qt::UserRole).toString(); - - QNetworkConfiguration conf = manager.configurationFromIdentifier(identifier); - - SessionWidget *session = new SessionWidget(conf); - - tabWidget->addTab(session, conf.name()); - - sessionGroup->show(); - - sessionWidgets.append(session); -} - -void BearerMonitor::createNewSession() -{ - QTreeWidgetItem *item = treeWidget->currentItem(); - if (!item) return; - - createSessionFor(item); -} - -void BearerMonitor::deleteSession() -{ - SessionWidget *session = qobject_cast<SessionWidget *>(tabWidget->currentWidget()); - if (session) { - sessionWidgets.removeAll(session); - - delete session; - - if (tabWidget->count() == 0) - sessionGroup->hide(); - } -} - -void BearerMonitor::performScan() -{ - scanButton->hide(); - progressBar->show(); - manager.updateConfigurations(); -} diff --git a/examples/network/bearermonitor/bearermonitor.h b/examples/network/bearermonitor/bearermonitor.h deleted file mode 100644 index 79b8d876ec..0000000000 --- a/examples/network/bearermonitor/bearermonitor.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef BEARERMONITOR_H -#define BEARERMONITOR_H - -#include <QNetworkConfigurationManager> -#include "ui_bearermonitor_640_480.h" - -QT_USE_NAMESPACE - -class SessionWidget; - -class BearerMonitor : public QWidget, public Ui_BearerMonitor -{ - Q_OBJECT - -public: - BearerMonitor(QWidget *parent = nullptr); - ~BearerMonitor(); - -private slots: - void configurationAdded(const QNetworkConfiguration &config, QTreeWidgetItem *parent = nullptr); - void configurationRemoved(const QNetworkConfiguration &config); - void configurationChanged(const QNetworkConfiguration &config); - void updateSnapConfiguration(QTreeWidgetItem *parent, const QNetworkConfiguration &snap); - void updateConfigurations(); - - void onlineStateChanged(bool isOnline); - -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - void registerNetwork(); - void unregisterNetwork(); -#endif // Q_OS_WIN && !Q_OS_WINRT - - void showConfigurationFor(QTreeWidgetItem *item); - - void createSessionFor(QTreeWidgetItem *item); - void createNewSession(); - void deleteSession(); - void performScan(); - -private: - QNetworkConfigurationManager manager; - QVector<SessionWidget *> sessionWidgets; -}; - -#endif //BEARERMONITOR_H diff --git a/examples/network/bearermonitor/bearermonitor.pro b/examples/network/bearermonitor/bearermonitor.pro deleted file mode 100644 index 16ac41298a..0000000000 --- a/examples/network/bearermonitor/bearermonitor.pro +++ /dev/null @@ -1,22 +0,0 @@ -TARGET = bearermonitor -QT = core gui network widgets -requires(qtConfig(treeview)) - -HEADERS = sessionwidget.h \ - bearermonitor.h - -SOURCES = main.cpp \ - bearermonitor.cpp \ - sessionwidget.cpp - -FORMS = bearermonitor_240_320.ui \ - bearermonitor_640_480.ui \ - sessionwidget.ui - -win32: QMAKE_USE += ws2_32 - -CONFIG += console - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/network/bearermonitor -INSTALLS += target diff --git a/examples/network/bearermonitor/bearermonitor_240_320.ui b/examples/network/bearermonitor/bearermonitor_240_320.ui deleted file mode 100644 index 93cfc5e0e3..0000000000 --- a/examples/network/bearermonitor/bearermonitor_240_320.ui +++ /dev/null @@ -1,420 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>BearerMonitor</class> - <widget class="QWidget" name="BearerMonitor"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>240</width> - <height>320</height> - </rect> - </property> - <property name="windowTitle"> - <string>BearerMonitor</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_5"> - <item> - <widget class="QScrollArea" name="scrollArea"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents"> - <property name="geometry"> - <rect> - <x>0</x> - <y>-274</y> - <width>206</width> - <height>576</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QGroupBox" name="systemState"> - <property name="title"> - <string>System State</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <layout class="QHBoxLayout" name="onlineStateLayout"> - <item> - <widget class="QLabel" name="onlineStateLabel"> - <property name="text"> - <string>Online State:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="onlineState"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Configurations</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_9"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="configurationNameLayout"> - <item> - <widget class="QLabel" name="configurationNameLabel"> - <property name="text"> - <string>Name:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationName"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationStateLayout"> - <item> - <widget class="QLabel" name="configurationStateLabel"> - <property name="text"> - <string>State:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationState"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationTypeLayout"> - <item> - <widget class="QLabel" name="configurationTypeLabel"> - <property name="text"> - <string>Type:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationType"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Invalid</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationPurposeLayout"> - <item> - <widget class="QLabel" name="configurationPurposeLabel"> - <property name="text"> - <string>Purpose:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationPurpose"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Unknown</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationIdentifierLayout"> - <item> - <widget class="QLabel" name="configurationIdentifierLabel"> - <property name="text"> - <string>Identifier:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationIdentifier"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationRoamingLayout"> - <item> - <widget class="QLabel" name="configurationRoamingLabel"> - <property name="text"> - <string>Roaming:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationRoaming"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationChildrenLayout"> - <item> - <widget class="QLabel" name="configurationChildrenLabel"> - <property name="text"> - <string>Children:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationChildren"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QGroupBox" name="nlaGroup"> - <property name="title"> - <string>Network Location Awareness</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QPushButton" name="registerButton"> - <property name="text"> - <string>Register</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="unregisterButton"> - <property name="text"> - <string>Unregister</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QPushButton" name="newSessionButton"> - <property name="text"> - <string>New Session</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="deleteSessionButton"> - <property name="text"> - <string>Delete Session</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="scanButton"> - <property name="text"> - <string>Scan</string> - </property> - </widget> - </item> - <item> - <widget class="QProgressBar" name="progressBar"> - <property name="maximum"> - <number>0</number> - </property> - <property name="value"> - <number>-1</number> - </property> - <property name="textVisible"> - <bool>false</bool> - </property> - <property name="invertedAppearance"> - <bool>false</bool> - </property> - <property name="format"> - <string>%p%</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QTreeWidget" name="treeWidget"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <attribute name="headerVisible"> - <bool>false</bool> - </attribute> - <column> - <property name="text"> - <string>1</string> - </property> - </column> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="sessionGroup"> - <property name="title"> - <string>Sessions</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QTabWidget" name="tabWidget"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="tab"> - <attribute name="title"> - <string>Session 1</string> - </attribute> - </widget> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/examples/network/bearermonitor/bearermonitor_640_480.ui b/examples/network/bearermonitor/bearermonitor_640_480.ui deleted file mode 100644 index 52866bc9cd..0000000000 --- a/examples/network/bearermonitor/bearermonitor_640_480.ui +++ /dev/null @@ -1,386 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>BearerMonitor</class> - <widget class="QWidget" name="BearerMonitor"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>640</width> - <height>515</height> - </rect> - </property> - <property name="windowTitle"> - <string>BearerMonitor</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QGroupBox" name="systemState"> - <property name="title"> - <string>System State</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <layout class="QHBoxLayout" name="onlineStateLayout"> - <item> - <widget class="QLabel" name="onlineStateLabel"> - <property name="text"> - <string>Online State:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="onlineState"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item row="1" column="0"> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Configurations</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_9"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QTreeWidget" name="treeWidget"> - <attribute name="headerVisible"> - <bool>false</bool> - </attribute> - <column> - <property name="text"> - <string>1</string> - </property> - </column> - </widget> - </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="configurationNameLayout"> - <item> - <widget class="QLabel" name="configurationNameLabel"> - <property name="text"> - <string>Name:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationName"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationStateLayout"> - <item> - <widget class="QLabel" name="configurationStateLabel"> - <property name="text"> - <string>State:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationState"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationTypeLayout"> - <item> - <widget class="QLabel" name="configurationTypeLabel"> - <property name="text"> - <string>Type:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationType"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Invalid</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationPurposeLayout"> - <item> - <widget class="QLabel" name="configurationPurposeLabel"> - <property name="text"> - <string>Purpose:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationPurpose"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Unknown</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationIdentifierLayout"> - <item> - <widget class="QLabel" name="configurationIdentifierLabel"> - <property name="text"> - <string>Identifier:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationIdentifier"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationRoamingLayout"> - <item> - <widget class="QLabel" name="configurationRoamingLabel"> - <property name="text"> - <string>Roaming:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationRoaming"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationChildrenLayout"> - <item> - <widget class="QLabel" name="configurationChildrenLabel"> - <property name="text"> - <string>Children:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configurationChildren"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QGroupBox" name="nlaGroup"> - <property name="title"> - <string>Network Location Awareness</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QPushButton" name="registerButton"> - <property name="text"> - <string>Register</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="unregisterButton"> - <property name="text"> - <string>Unregister</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QPushButton" name="newSessionButton"> - <property name="text"> - <string>New Session</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="deleteSessionButton"> - <property name="text"> - <string>Delete Session</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="scanButton"> - <property name="text"> - <string>Scan</string> - </property> - </widget> - </item> - <item> - <widget class="QProgressBar" name="progressBar"> - <property name="maximum"> - <number>0</number> - </property> - <property name="value"> - <number>-1</number> - </property> - <property name="textVisible"> - <bool>false</bool> - </property> - <property name="invertedAppearance"> - <bool>false</bool> - </property> - <property name="format"> - <string>%p%</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item row="2" column="0"> - <widget class="QGroupBox" name="sessionGroup"> - <property name="title"> - <string>Sessions</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QTabWidget" name="tabWidget"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="tab"> - <attribute name="title"> - <string>Session 1</string> - </attribute> - </widget> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/examples/network/bearermonitor/main.cpp b/examples/network/bearermonitor/main.cpp deleted file mode 100644 index 3c2525012d..0000000000 --- a/examples/network/bearermonitor/main.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QApplication> -#include <QMainWindow> - -#include "bearermonitor.h" - -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - - QMainWindow mainWindow; - - BearerMonitor monitor; - - mainWindow.setCentralWidget(&monitor); - mainWindow.show(); - - return app.exec(); -} - diff --git a/examples/network/bearermonitor/sessionwidget.cpp b/examples/network/bearermonitor/sessionwidget.cpp deleted file mode 100644 index 0fd5d4f67f..0000000000 --- a/examples/network/bearermonitor/sessionwidget.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "sessionwidget.h" -#include <QNetworkConfigurationManager> - -SessionWidget::SessionWidget(const QNetworkConfiguration &config, QWidget *parent) -: QWidget(parent) -{ - setupUi(this); - -#ifdef QT_NO_NETWORKINTERFACE - interfaceName->setVisible(false); - interfaceNameLabel->setVisible(false); - interfaceGuid->setVisible(false); - interfaceGuidLabel->setVisible(false); -#endif - - session = new QNetworkSession(config, this); - - connect(session, &QNetworkSession::stateChanged, - this, &SessionWidget::updateSession); - connect(session, QOverload<QNetworkSession::SessionError>::of(&QNetworkSession::error), - this, &SessionWidget::updateSessionError); - - updateSession(); - - sessionId->setText(QString("0x%1").arg(qulonglong(session), 8, 16, QChar('0'))); - - configuration->setText(session->configuration().name()); - - connect(openSessionButton, &QPushButton::clicked, - this, &SessionWidget::openSession); - connect(openSyncSessionButton, &QPushButton::clicked, - this, &SessionWidget::openSyncSession); - connect(closeSessionButton, &QPushButton::clicked, - this, &SessionWidget::closeSession); - connect(stopSessionButton, &QPushButton::clicked, - this, &SessionWidget::stopSession); -} - -SessionWidget::~SessionWidget() -{ - delete session; -} - -void SessionWidget::timerEvent(QTimerEvent *e) -{ - if (e->timerId() == statsTimer) { - rxData->setText(QString::number(session->bytesReceived())); - txData->setText(QString::number(session->bytesWritten())); - activeTime->setText(QString::number(session->activeTime())); - } -} - -void SessionWidget::updateSession() -{ - updateSessionState(session->state()); - - if (session->state() == QNetworkSession::Connected) - statsTimer = startTimer(1000); - else if (statsTimer != -1) - killTimer(statsTimer); - - if (session->configuration().type() == QNetworkConfiguration::InternetAccessPoint) - bearer->setText(session->configuration().bearerTypeName()); - else { - QNetworkConfigurationManager mgr; - QNetworkConfiguration c = mgr.configurationFromIdentifier(session->sessionProperty("ActiveConfiguration").toString()); - bearer->setText(c.bearerTypeName()); - } - -#ifndef QT_NO_NETWORKINTERFACE - interfaceName->setText(session->interface().humanReadableName()); - interfaceGuid->setText(session->interface().name()); -#endif -} - -void SessionWidget::openSession() -{ - clearError(); - session->open(); - updateSession(); -} - -void SessionWidget::openSyncSession() -{ - clearError(); - session->open(); - session->waitForOpened(); - updateSession(); -} - -void SessionWidget::closeSession() -{ - clearError(); - session->close(); - updateSession(); -} - -void SessionWidget::stopSession() -{ - clearError(); - session->stop(); - updateSession(); -} - -void SessionWidget::updateSessionState(QNetworkSession::State state) -{ - QString s = tr("%1 (%2)"); - - switch (state) { - case QNetworkSession::Invalid: - s = s.arg(tr("Invalid")); - break; - case QNetworkSession::NotAvailable: - s = s.arg(tr("Not Available")); - break; - case QNetworkSession::Connecting: - s = s.arg(tr("Connecting")); - break; - case QNetworkSession::Connected: - s = s.arg(tr("Connected")); - break; - case QNetworkSession::Closing: - s = s.arg(tr("Closing")); - break; - case QNetworkSession::Disconnected: - s = s.arg(tr("Disconnected")); - break; - case QNetworkSession::Roaming: - s = s.arg(tr("Roaming")); - break; - default: - s = s.arg(tr("Unknown")); - } - - if (session->isOpen()) - s = s.arg(tr("Open")); - else - s = s.arg(tr("Closed")); - - sessionState->setText(s); -} - -void SessionWidget::updateSessionError(QNetworkSession::SessionError error) -{ - lastError->setText(QString::number(error)); - errorString->setText(session->errorString()); -} - -void SessionWidget::clearError() -{ - lastError->clear(); - errorString->clear(); -} diff --git a/examples/network/bearermonitor/sessionwidget.h b/examples/network/bearermonitor/sessionwidget.h deleted file mode 100644 index 6b2da2c1c1..0000000000 --- a/examples/network/bearermonitor/sessionwidget.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef SESSIONWIDGET_H -#define SESSIONWIDGET_H - -#include <QNetworkSession> - -#include "ui_sessionwidget.h" - -QT_USE_NAMESPACE - -class SessionWidget : public QWidget, public Ui_SessionWidget -{ - Q_OBJECT - -public: - explicit SessionWidget(const QNetworkConfiguration &config, QWidget *parent = nullptr); - ~SessionWidget(); - - void timerEvent(QTimerEvent *e) override; - -private: - void updateSessionState(QNetworkSession::State state); - void clearError(); - -private Q_SLOTS: - void openSession(); - void openSyncSession(); - void closeSession(); - void stopSession(); - void updateSession(); - void updateSessionError(QNetworkSession::SessionError error); - -private: - QNetworkSession *session = nullptr; - int statsTimer = -1; -}; - -#endif - diff --git a/examples/network/bearermonitor/sessionwidget.ui b/examples/network/bearermonitor/sessionwidget.ui deleted file mode 100644 index 4199109ce3..0000000000 --- a/examples/network/bearermonitor/sessionwidget.ui +++ /dev/null @@ -1,307 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>SessionWidget</class> - <widget class="QWidget" name="SessionWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>340</width> - <height>276</height> - </rect> - </property> - <property name="windowTitle"> - <string>Session Details</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="sessionIdLayout"> - <item> - <widget class="QLabel" name="sessionIdLabel"> - <property name="text"> - <string>Session ID:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="sessionId"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="sessionStateLayout"> - <item> - <widget class="QLabel" name="sessionStateLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Session State:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="sessionState"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Invalid</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="configurationLayout"> - <item> - <widget class="QLabel" name="configurationLabel"> - <property name="text"> - <string>Configuration:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="configuration"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="bearerLayout"> - <item> - <widget class="QLabel" name="bearerLabel"> - <property name="text"> - <string>Bearer:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="bearer"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="interfaceNameLayout"> - <item> - <widget class="QLabel" name="interfaceNameLabel"> - <property name="text"> - <string>Interface Name:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="interfaceName"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="interfaceGuidLayout"> - <item> - <widget class="QLabel" name="interfaceGuidLabel"> - <property name="text"> - <string>Interface GUID:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="interfaceGuid"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="lastErrorLayout"> - <item> - <widget class="QLabel" name="lastErrorLabel"> - <property name="text"> - <string>Last Error:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="lastError"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="errorStringLayout"> - <item> - <widget class="QLabel" name="errorStringLabel"> - <property name="text"> - <string>Error String:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="errorString"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QLabel" name="rxData"> - <property name="text"> - <string>0</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="txData"> - <property name="text"> - <string>0</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Active Time:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="activeTime"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>0 seconds</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QPushButton" name="openSessionButton"> - <property name="text"> - <string>Open</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="openSyncSessionButton"> - <property name="text"> - <string>Blocking Open</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QPushButton" name="closeSessionButton"> - <property name="text"> - <string>Close</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="stopSessionButton"> - <property name="text"> - <string>Stop</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/examples/network/fortuneclient/client.cpp b/examples/network/fortuneclient/client.cpp index 4d3a318a7b..0ccbf51df8 100644 --- a/examples/network/fortuneclient/client.cpp +++ b/examples/network/fortuneclient/client.cpp @@ -150,29 +150,6 @@ Client::Client(QWidget *parent) setWindowTitle(QGuiApplication::applicationDisplayName()); portLineEdit->setFocus(); - - QNetworkConfigurationManager manager; - if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) { - // Get saved network configuration - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString(); - settings.endGroup(); - - // If the saved network configuration is not currently discovered use the system default - QNetworkConfiguration config = manager.configurationFromIdentifier(id); - if ((config.state() & QNetworkConfiguration::Discovered) != - QNetworkConfiguration::Discovered) { - config = manager.defaultConfiguration(); - } - - networkSession = new QNetworkSession(config, this); - connect(networkSession, &QNetworkSession::opened, this, &Client::sessionOpened); - - getFortuneButton->setEnabled(false); - statusLabel->setText(tr("Opening network session.")); - networkSession->open(); - } //! [5] } //! [5] @@ -241,30 +218,7 @@ void Client::displayError(QAbstractSocket::SocketError socketError) void Client::enableGetFortuneButton() { - getFortuneButton->setEnabled((!networkSession || networkSession->isOpen()) && - !hostCombo->currentText().isEmpty() && + getFortuneButton->setEnabled(!hostCombo->currentText().isEmpty() && !portLineEdit->text().isEmpty()); } - -void Client::sessionOpened() -{ - // Save the used configuration - QNetworkConfiguration config = networkSession->configuration(); - QString id; - if (config.type() == QNetworkConfiguration::UserChoice) - id = networkSession->sessionProperty(QLatin1String("UserChoiceConfiguration")).toString(); - else - id = config.identifier(); - - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id); - settings.endGroup(); - - statusLabel->setText(tr("This examples requires that you run the " - "Fortune Server example as well.")); - - enableGetFortuneButton(); -} - diff --git a/examples/network/fortuneclient/client.h b/examples/network/fortuneclient/client.h index ac335acb83..80177bacbf 100644 --- a/examples/network/fortuneclient/client.h +++ b/examples/network/fortuneclient/client.h @@ -61,7 +61,6 @@ class QLabel; class QLineEdit; class QPushButton; class QTcpSocket; -class QNetworkSession; QT_END_NAMESPACE //! [0] @@ -77,7 +76,6 @@ private slots: void readFortune(); void displayError(QAbstractSocket::SocketError socketError); void enableGetFortuneButton(); - void sessionOpened(); private: QComboBox *hostCombo = nullptr; @@ -88,8 +86,6 @@ private: QTcpSocket *tcpSocket = nullptr; QDataStream in; QString currentFortune; - - QNetworkSession *networkSession = nullptr; }; //! [0] diff --git a/examples/network/fortuneserver/server.cpp b/examples/network/fortuneserver/server.cpp index 7db81fe07a..c91b6a5c0c 100644 --- a/examples/network/fortuneserver/server.cpp +++ b/examples/network/fortuneserver/server.cpp @@ -61,29 +61,7 @@ Server::Server(QWidget *parent) setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); statusLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - QNetworkConfigurationManager manager; - if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) { - // Get saved network configuration - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString(); - settings.endGroup(); - - // If the saved network configuration is not currently discovered use the system default - QNetworkConfiguration config = manager.configurationFromIdentifier(id); - if ((config.state() & QNetworkConfiguration::Discovered) != - QNetworkConfiguration::Discovered) { - config = manager.defaultConfiguration(); - } - - networkSession = new QNetworkSession(config, this); - connect(networkSession, &QNetworkSession::opened, this, &Server::sessionOpened); - - statusLabel->setText(tr("Opening network session.")); - networkSession->open(); - } else { - sessionOpened(); - } + initServer(); //! [2] fortunes << tr("You've been leading a dog's life. Stay off the furniture.") @@ -128,23 +106,8 @@ Server::Server(QWidget *parent) setWindowTitle(QGuiApplication::applicationDisplayName()); } -void Server::sessionOpened() +void Server::initServer() { - // Save the used configuration - if (networkSession) { - QNetworkConfiguration config = networkSession->configuration(); - QString id; - if (config.type() == QNetworkConfiguration::UserChoice) - id = networkSession->sessionProperty(QLatin1String("UserChoiceConfiguration")).toString(); - else - id = config.identifier(); - - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id); - settings.endGroup(); - } - //! [0] //! [1] tcpServer = new QTcpServer(this); if (!tcpServer->listen()) { diff --git a/examples/network/fortuneserver/server.h b/examples/network/fortuneserver/server.h index c5bfa7d928..96d7145148 100644 --- a/examples/network/fortuneserver/server.h +++ b/examples/network/fortuneserver/server.h @@ -58,7 +58,6 @@ QT_BEGIN_NAMESPACE class QLabel; class QTcpServer; -class QNetworkSession; QT_END_NAMESPACE //! [0] @@ -70,14 +69,14 @@ public: explicit Server(QWidget *parent = nullptr); private slots: - void sessionOpened(); void sendFortune(); private: + void initServer(); + QLabel *statusLabel = nullptr; QTcpServer *tcpServer = nullptr; QVector<QString> fortunes; - QNetworkSession *networkSession = nullptr; }; //! [0] diff --git a/examples/network/network-chat/main.cpp b/examples/network/network-chat/main.cpp index f88e29977b..029c18f0ff 100644 --- a/examples/network/network-chat/main.cpp +++ b/examples/network/network-chat/main.cpp @@ -53,50 +53,11 @@ #include "chatdialog.h" #include <QtCore/QSettings> -#include <QtNetwork/QNetworkConfigurationManager> -#include <QtNetwork/QNetworkSession> int main(int argc, char *argv[]) { QApplication app(argc, argv); - QNetworkConfigurationManager manager; - if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) { - // Get saved network configuration - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString(); - settings.endGroup(); - - // If the saved network configuration is not currently discovered use the system default - QNetworkConfiguration config = manager.configurationFromIdentifier(id); - if ((config.state() & QNetworkConfiguration::Discovered) != - QNetworkConfiguration::Discovered) { - config = manager.defaultConfiguration(); - } - - QNetworkSession *networkSession = new QNetworkSession(config, &app); - networkSession->open(); - networkSession->waitForOpened(); - - if (networkSession->isOpen()) { - // Save the used configuration - QNetworkConfiguration config = networkSession->configuration(); - QString id; - if (config.type() == QNetworkConfiguration::UserChoice) { - id = networkSession->sessionProperty( - QLatin1String("UserChoiceConfiguration")).toString(); - } else { - id = config.identifier(); - } - - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("QtNetwork")); - settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id); - settings.endGroup(); - } - } - ChatDialog dialog; dialog.show(); return app.exec(); diff --git a/examples/network/network.pro b/examples/network/network.pro index af3c0df43e..3f851d7c71 100644 --- a/examples/network/network.pro +++ b/examples/network/network.pro @@ -19,15 +19,11 @@ qtHaveModule(widgets) { multicastreceiver \ multicastsender - qtConfig(bearermanagement) { - qtConfig(processenvironment): SUBDIRS += network-chat + qtConfig(processenvironment): SUBDIRS += network-chat - SUBDIRS += \ - bearermonitor \ - fortuneclient \ - fortuneserver - - } + SUBDIRS += \ + fortuneclient \ + fortuneserver qtConfig(ssl): SUBDIRS += securesocketclient qtConfig(dtls): SUBDIRS += secureudpserver secureudpclient diff --git a/examples/widgets/doc/src/syntaxhighlighter.qdoc b/examples/widgets/doc/src/syntaxhighlighter.qdoc index 8583d86114..618b387ed5 100644 --- a/examples/widgets/doc/src/syntaxhighlighter.qdoc +++ b/examples/widgets/doc/src/syntaxhighlighter.qdoc @@ -246,11 +246,7 @@ \section1 Other Code Editor Features - It is possible to implement parenthesis matching with - QSyntaxHighlighter. The "Matching Parentheses with - QSyntaxHighlighter" article in Qt Quarterly 31 - (\l{http://doc.qt.io/archives/qq/}) implements this. We also have - the \l{Code Editor Example}, which shows how to implement line + The \l{Code Editor Example} shows how to implement line numbers and how to highlight the current line. */ diff --git a/examples/widgets/widgets/tablet/tabletcanvas.cpp b/examples/widgets/widgets/tablet/tabletcanvas.cpp index 59ca608cef..90a5017500 100644 --- a/examples/widgets/widgets/tablet/tabletcanvas.cpp +++ b/examples/widgets/widgets/tablet/tabletcanvas.cpp @@ -106,7 +106,7 @@ void TabletCanvas::tabletEvent(QTabletEvent *event) break; case QEvent::TabletMove: #ifndef Q_OS_IOS - if (event->device() == QTabletEvent::RotationStylus) + if (event->deviceType() == QTabletEvent::RotationStylus) updateCursor(event); #endif if (m_deviceDown) { @@ -161,7 +161,7 @@ void TabletCanvas::paintPixmap(QPainter &painter, QTabletEvent *event) static qreal maxPenRadius = pressureToWidth(1.0); painter.setRenderHint(QPainter::Antialiasing); - switch (event->device()) { + switch (event->deviceType()) { //! [6] case QTabletEvent::Airbrush: { @@ -251,7 +251,7 @@ void TabletCanvas::updateBrush(const QTabletEvent *event) m_color.setAlphaF(event->pressure()); break; case TangentialPressureValuator: - if (event->device() == QTabletEvent::Airbrush) + if (event->deviceType() == QTabletEvent::Airbrush) m_color.setAlphaF(qMax(0.01, (event->tangentialPressure() + 1.0) / 2.0)); else m_color.setAlpha(255); @@ -312,7 +312,7 @@ void TabletCanvas::updateCursor(const QTabletEvent *event) if (event->pointerType() == QTabletEvent::Eraser) { cursor = QCursor(QPixmap(":/images/cursor-eraser.png"), 3, 28); } else { - switch (event->device()) { + switch (event->deviceType()) { case QTabletEvent::Stylus: cursor = QCursor(QPixmap(":/images/cursor-pencil.png"), 0, 0); break; diff --git a/mkspecs/features/lrelease.prf b/mkspecs/features/lrelease.prf index 1e828b64df..f611c74184 100644 --- a/mkspecs/features/lrelease.prf +++ b/mkspecs/features/lrelease.prf @@ -35,6 +35,7 @@ embed_translations { !isEmpty(QM_FILES_INSTALL_PATH) { qm_files.files = $$QM_FILES qm_files.path = $$QM_FILES_INSTALL_PATH + qm_files.CONFIG = no_check_exist INSTALLS += qm_files } lrelease.CONFIG += target_predeps no_clean diff --git a/mkspecs/features/wasm/default_pre.prf b/mkspecs/features/wasm/default_pre.prf index 2760889929..d092149b32 100644 --- a/mkspecs/features/wasm/default_pre.prf +++ b/mkspecs/features/wasm/default_pre.prf @@ -1,2 +1,2 @@ -load(default_pre) load(emcc_ver) +load(default_pre) diff --git a/mkspecs/features/wasm/emcc_ver.prf b/mkspecs/features/wasm/emcc_ver.prf index 505a321d64..411f53e95d 100644 --- a/mkspecs/features/wasm/emcc_ver.prf +++ b/mkspecs/features/wasm/emcc_ver.prf @@ -3,7 +3,9 @@ defineReplace(qtEmccRecommendedVersion) { } defineReplace(qtSystemEmccVersion) { - E_VERSION = $$system("emcc -v 2>&1 | perl -alne $$shell_quote($_ = $F[9]; s/://; print;) ") + EMCC = $$system("emcc -v 2>&1", lines) + EMCC_LINE = $$find(EMCC, "^.*\b(emcc)\b.*$") + E_VERSION = $$section(EMCC_LINE, " ", 9,9) return ($${E_VERSION}) } diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 4c71ceb929..1e1e23495c 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -960,6 +960,10 @@ default is used. \row \li thread \li Thread support is enabled. This is enabled when CONFIG includes \c qt, which is the default. + \row \li utf8_source \li Specifies that the project's source files use the + UTF-8 encoding. By default, the compiler default is used. + \row \li hide_symbols \li Set the default visibility of symbols in the binary + to hidden. By default, the compiler default is used. \row \li c99 \li C99 support is enabled. This option has no effect if the compiler does not support C99, or can't select the C standard. By default, the compiler default is used. diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 4a6a42c7d2..9789c9c8e5 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -558,6 +558,8 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") << ' ' << incr_deps << " $(SUBLIBS) " << target_deps << ' ' << depVar("POST_TARGETDEPS"); } else { + ProStringList &cmd = project->values("QMAKE_LINK_SHLIB_CMD"); + cmd[0] = cmd.at(0).toQString().replace(QLatin1String("$(OBJECTS)"), objectParts.second); t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) $(SUBLIBS) $(OBJCOMP) " << target_deps << ' ' << depVar("POST_TARGETDEPS"); diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 86d10c213c..3ec2704625 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -736,6 +736,18 @@ QString Win32MakefileGenerator::defaultInstall(const QString &t) if(targetdir.right(1) != Option::dir_sep) targetdir += Option::dir_sep; + const ProStringList &targets = project->values(ProKey(t + ".targets")); + for (int i = 0; i < targets.size(); ++i) { + QString src = targets.at(i).toQString(), + dst = escapeFilePath(filePrefixRoot(root, targetdir + src.section('/', -1))); + if (!ret.isEmpty()) + ret += "\n\t"; + ret += "$(QINSTALL) " + escapeFilePath(Option::fixPathToTargetOS(src, false)) + ' ' + dst; + if (!uninst.isEmpty()) + uninst.append("\n\t"); + uninst.append("-$(DEL_FILE) " + dst); + } + if(t == "target" && project->first("TEMPLATE") == "lib") { if(project->isActiveConfig("create_prl") && !project->isActiveConfig("no_install_prl") && !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) { @@ -744,6 +756,8 @@ QString Win32MakefileGenerator::defaultInstall(const QString &t) if(slsh != -1) dst_prl = dst_prl.right(dst_prl.length() - slsh - 1); dst_prl = filePrefixRoot(root, targetdir + dst_prl); + if (!ret.isEmpty()) + ret += "\n\t"; ret += installMetaFile(ProKey("QMAKE_PRL_INSTALL_REPLACE"), project->first("QMAKE_INTERNAL_PRL_FILE").toQString(), dst_prl); if(!uninst.isEmpty()) uninst.append("\n\t"); diff --git a/src/3rdparty/md4c/md4c.c b/src/3rdparty/md4c/md4c.c index 3745cf3e46..b0ef739b3c 100644 --- a/src/3rdparty/md4c/md4c.c +++ b/src/3rdparty/md4c/md4c.c @@ -2,7 +2,7 @@ * MD4C: Markdown parser for C * (http://github.com/mity/md4c) * - * Copyright (c) 2016-2019 Martin Mitas + * Copyright (c) 2016-2020 Martin Mitas * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -35,14 +35,23 @@ *** Miscellaneous Stuff *** *****************************/ -#ifdef _MSC_VER - /* MSVC does not understand "inline" when building as pure C (not C++). - * However it understands "__inline" */ - #ifndef __cplusplus +#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199409L + /* C89/90 or old compilers in general may not understand "inline". */ + #if defined __GNUC__ + #define inline __inline__ + #elif defined _MSC_VER #define inline __inline + #else + #define inline #endif #endif +/* Make the UTF-8 support the default. */ +#if !defined MD4C_USE_ASCII && !defined MD4C_USE_UTF8 && !defined MD4C_USE_UTF16 + #define MD4C_USE_UTF8 +#endif + +/* Magic for making wide literals with MD4C_USE_UTF16. */ #ifdef _T #undef _T #endif @@ -127,7 +136,7 @@ struct MD_CTX_tag { #endif /* For resolving of inline spans. */ - MD_MARKCHAIN mark_chains[12]; + MD_MARKCHAIN mark_chains[13]; #define PTR_CHAIN ctx->mark_chains[0] #define TABLECELLBOUNDARIES ctx->mark_chains[1] #define ASTERISK_OPENERS_extraword_mod3_0 ctx->mark_chains[2] @@ -137,11 +146,12 @@ struct MD_CTX_tag { #define ASTERISK_OPENERS_intraword_mod3_1 ctx->mark_chains[6] #define ASTERISK_OPENERS_intraword_mod3_2 ctx->mark_chains[7] #define UNDERSCORE_OPENERS ctx->mark_chains[8] -#define TILDE_OPENERS ctx->mark_chains[9] -#define BRACKET_OPENERS ctx->mark_chains[10] -#define DOLLAR_OPENERS ctx->mark_chains[11] +#define TILDE_OPENERS_1 ctx->mark_chains[9] +#define TILDE_OPENERS_2 ctx->mark_chains[10] +#define BRACKET_OPENERS ctx->mark_chains[11] +#define DOLLAR_OPENERS ctx->mark_chains[12] #define OPENERS_CHAIN_FIRST 2 -#define OPENERS_CHAIN_LAST 11 +#define OPENERS_CHAIN_LAST 12 int n_table_cell_boundaries; @@ -263,6 +273,9 @@ struct MD_VERBATIMLINE_tag { #define CH(off) (ctx->text[(off)]) #define STR(off) (ctx->text + (off)) +/* Check whether the pointer points into ctx->text. */ +#define IS_INPUT_STR(ptr) (ctx->text <= (ptr) && (ptr) < (ctx->text + ctx->size)) + /* Character classification. * Note we assume ASCII compatibility of code points < 128 here. */ #define ISIN_(ch, ch_min, ch_max) ((ch_min) <= (unsigned)(ch) && (unsigned)(ch) <= (ch_max)) @@ -297,16 +310,14 @@ struct MD_VERBATIMLINE_tag { #define ISDIGIT(off) ISDIGIT_(CH(off)) #define ISXDIGIT(off) ISXDIGIT_(CH(off)) #define ISALNUM(off) ISALNUM_(CH(off)) -static inline const CHAR* -md_strchr(const CHAR* str, CHAR ch) -{ - OFF i; - for(i = 0; str[i] != _T('\0'); i++) { - if(ch == str[i]) - return (str + i); - } - return NULL; -} + + +#if defined MD4C_USE_UTF16 + #define md_strchr wcschr +#else + #define md_strchr strchr +#endif + /* Case insensitive check of string equality. */ static inline int @@ -364,89 +375,89 @@ md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ } -#define MD_CHECK(func) \ - do { \ - ret = (func); \ - if(ret < 0) \ - goto abort; \ +#define MD_CHECK(func) \ + do { \ + ret = (func); \ + if(ret < 0) \ + goto abort; \ } while(0) -#define MD_TEMP_BUFFER(sz) \ - do { \ - if(sz > ctx->alloc_buffer) { \ - CHAR* new_buffer; \ - SZ new_size = ((sz) + (sz) / 2 + 128) & ~127; \ - \ - new_buffer = realloc(ctx->buffer, new_size); \ - if(new_buffer == NULL) { \ - MD_LOG("realloc() failed."); \ - ret = -1; \ - goto abort; \ - } \ - \ - ctx->buffer = new_buffer; \ - ctx->alloc_buffer = new_size; \ - } \ +#define MD_TEMP_BUFFER(sz) \ + do { \ + if(sz > ctx->alloc_buffer) { \ + CHAR* new_buffer; \ + SZ new_size = ((sz) + (sz) / 2 + 128) & ~127; \ + \ + new_buffer = realloc(ctx->buffer, new_size); \ + if(new_buffer == NULL) { \ + MD_LOG("realloc() failed."); \ + ret = -1; \ + goto abort; \ + } \ + \ + ctx->buffer = new_buffer; \ + ctx->alloc_buffer = new_size; \ + } \ } while(0) -#define MD_ENTER_BLOCK(type, arg) \ - do { \ - ret = ctx->parser.enter_block((type), (arg), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from enter_block() callback."); \ - goto abort; \ - } \ +#define MD_ENTER_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.enter_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_block() callback."); \ + goto abort; \ + } \ } while(0) -#define MD_LEAVE_BLOCK(type, arg) \ - do { \ - ret = ctx->parser.leave_block((type), (arg), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from leave_block() callback."); \ - goto abort; \ - } \ +#define MD_LEAVE_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.leave_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_block() callback."); \ + goto abort; \ + } \ } while(0) -#define MD_ENTER_SPAN(type, arg) \ - do { \ - ret = ctx->parser.enter_span((type), (arg), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from enter_span() callback."); \ - goto abort; \ - } \ +#define MD_ENTER_SPAN(type, arg) \ + do { \ + ret = ctx->parser.enter_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_span() callback."); \ + goto abort; \ + } \ } while(0) -#define MD_LEAVE_SPAN(type, arg) \ - do { \ - ret = ctx->parser.leave_span((type), (arg), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from leave_span() callback."); \ - goto abort; \ - } \ +#define MD_LEAVE_SPAN(type, arg) \ + do { \ + ret = ctx->parser.leave_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_span() callback."); \ + goto abort; \ + } \ } while(0) -#define MD_TEXT(type, str, size) \ - do { \ - if(size > 0) { \ - ret = ctx->parser.text((type), (str), (size), ctx->userdata); \ - if(ret != 0) { \ - MD_LOG("Aborted from text() callback."); \ - goto abort; \ - } \ - } \ +#define MD_TEXT(type, str, size) \ + do { \ + if(size > 0) { \ + ret = ctx->parser.text((type), (str), (size), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ } while(0) -#define MD_TEXT_INSECURE(type, str, size) \ - do { \ - if(size > 0) { \ - ret = md_text_with_null_replacement(ctx, type, str, size); \ - if(ret != 0) { \ - MD_LOG("Aborted from text() callback."); \ - goto abort; \ - } \ - } \ +#define MD_TEXT_INSECURE(type, str, size) \ + do { \ + if(size > 0) { \ + ret = md_text_with_null_replacement(ctx, type, str, size); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ } while(0) @@ -1329,8 +1340,9 @@ md_build_attr_append_substr(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build, MD_TEXTTYPE* new_substr_types; OFF* new_substr_offsets; - build->substr_alloc = (build->substr_alloc == 0 ? 8 : build->substr_alloc * 2); - + build->substr_alloc = (build->substr_alloc > 0 + ? build->substr_alloc + build->substr_alloc / 2 + : 8); new_substr_types = (MD_TEXTTYPE*) realloc(build->substr_types, build->substr_alloc * sizeof(MD_TEXTTYPE)); if(new_substr_types == NULL) { @@ -1456,8 +1468,8 @@ abort: *** Dictionary of Reference Definitions *** *********************************************/ -#define MD_FNV1A_BASE 2166136261 -#define MD_FNV1A_PRIME 16777619 +#define MD_FNV1A_BASE 2166136261U +#define MD_FNV1A_PRIME 16777619U static inline unsigned md_fnv1a(unsigned base, const void* data, size_t n) @@ -1479,9 +1491,7 @@ struct MD_REF_DEF_tag { CHAR* label; CHAR* title; unsigned hash; - SZ label_size : 24; - unsigned label_needs_free : 1; - unsigned title_needs_free : 1; + SZ label_size; SZ title_size; OFF dest_beg; OFF dest_end; @@ -1530,7 +1540,7 @@ md_link_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size, SZ char_size; if(off >= size) { - /* Treat end of link label as a whitespace. */ + /* Treat end of a link label as a whitespace. */ goto whitespace; } @@ -1554,7 +1564,7 @@ md_link_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size, whitespace: fold_info->codepoints[0] = _T(' '); fold_info->n_codepoints = 1; - return off; + return md_skip_unicode_whitespace(label, off, size); } static int @@ -1572,7 +1582,7 @@ md_link_label_cmp(const CHAR* a_label, SZ a_size, const CHAR* b_label, SZ b_size a_off = md_skip_unicode_whitespace(a_label, 0, a_size); b_off = md_skip_unicode_whitespace(b_label, 0, b_size); - while(!a_reached_end && !b_reached_end) { + while(!a_reached_end || !b_reached_end) { /* If needed, load fold info for next char. */ if(a_fi_off >= a_fi.n_codepoints) { a_fi_off = 0; @@ -1618,7 +1628,7 @@ md_ref_def_cmp(const void* a, const void* b) } static int -md_ref_def_cmp_stable(const void* a, const void* b) +md_ref_def_cmp_for_sort(const void* a, const void* b) { int cmp; @@ -1671,6 +1681,7 @@ md_build_ref_def_hashtable(MD_CTX* ctx) bucket = ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size]; if(bucket == NULL) { + /* The bucket is empty. Make it just point to the def. */ ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = def; continue; } @@ -1682,12 +1693,12 @@ md_build_ref_def_hashtable(MD_CTX* ctx) MD_REF_DEF* old_def = (MD_REF_DEF*) bucket; if(md_link_label_cmp(def->label, def->label_size, old_def->label, old_def->label_size) == 0) { - /* Ignore this ref. def. */ + /* Duplicate label: Ignore this ref. def. */ continue; } - /* Make the bucket capable of holding more ref. defs. */ - list = (MD_REF_DEF_LIST*) malloc(sizeof(MD_REF_DEF_LIST) + 4 * sizeof(MD_REF_DEF*)); + /* Make the bucket complex, i.e. able to hold more ref. defs. */ + list = (MD_REF_DEF_LIST*) malloc(sizeof(MD_REF_DEF_LIST) + 2 * sizeof(MD_REF_DEF*)); if(list == NULL) { MD_LOG("malloc() failed."); goto abort; @@ -1695,22 +1706,28 @@ md_build_ref_def_hashtable(MD_CTX* ctx) list->ref_defs[0] = old_def; list->ref_defs[1] = def; list->n_ref_defs = 2; - list->alloc_ref_defs = 4; + list->alloc_ref_defs = 2; ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list; continue; } - /* Append the def to the bucket list. */ + /* Append the def to the complex bucket list. + * + * Note in this case we ignore potential duplicates to avoid expensive + * iterating over the complex bucket. Below, we revisit all the complex + * buckets and handle it more cheaply after the complex bucket contents + * is sorted. */ list = (MD_REF_DEF_LIST*) bucket; if(list->n_ref_defs >= list->alloc_ref_defs) { + int alloc_ref_defs = list->alloc_ref_defs + list->alloc_ref_defs / 2; MD_REF_DEF_LIST* list_tmp = (MD_REF_DEF_LIST*) realloc(list, - sizeof(MD_REF_DEF_LIST) + 2 * list->alloc_ref_defs * sizeof(MD_REF_DEF*)); + sizeof(MD_REF_DEF_LIST) + alloc_ref_defs * sizeof(MD_REF_DEF*)); if(list_tmp == NULL) { MD_LOG("realloc() failed."); goto abort; } list = list_tmp; - list->alloc_ref_defs *= 2; + list->alloc_ref_defs = alloc_ref_defs; ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list; } @@ -1729,9 +1746,12 @@ md_build_ref_def_hashtable(MD_CTX* ctx) continue; list = (MD_REF_DEF_LIST*) bucket; - qsort(list->ref_defs, list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp_stable); + qsort(list->ref_defs, list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp_for_sort); - /* Disable duplicates. */ + /* Disable all duplicates in the complex bucket by forcing all such + * records to point to the 1st such ref. def. I.e. no matter which + * record is found during the lookup, it will always point to the right + * ref. def. in ctx->ref_defs[]. */ for(j = 1; j < list->n_ref_defs; j++) { if(md_ref_def_cmp(&list->ref_defs[j-1], &list->ref_defs[j]) == 0) list->ref_defs[j] = list->ref_defs[j-1]; @@ -2055,9 +2075,8 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) OFF label_contents_end; int label_contents_line_index = -1; int label_is_multiline; - CHAR* label; + CHAR* label = NULL; SZ label_size; - int label_needs_free = FALSE; OFF dest_contents_beg; OFF dest_contents_end; OFF title_contents_beg; @@ -2123,23 +2142,22 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) if(!label_is_multiline) { label = (CHAR*) STR(label_contents_beg); label_size = label_contents_end - label_contents_beg; - label_needs_free = FALSE; } else { MD_CHECK(md_merge_lines_alloc(ctx, label_contents_beg, label_contents_end, lines + label_contents_line_index, n_lines - label_contents_line_index, _T(' '), &label, &label_size)); - label_needs_free = TRUE; } /* Store the reference definition. */ if(ctx->n_ref_defs >= ctx->alloc_ref_defs) { MD_REF_DEF* new_defs; - ctx->alloc_ref_defs = (ctx->alloc_ref_defs > 0 ? ctx->alloc_ref_defs * 2 : 16); + ctx->alloc_ref_defs = (ctx->alloc_ref_defs > 0 + ? ctx->alloc_ref_defs + ctx->alloc_ref_defs / 2 + : 16); new_defs = (MD_REF_DEF*) realloc(ctx->ref_defs, ctx->alloc_ref_defs * sizeof(MD_REF_DEF)); if(new_defs == NULL) { MD_LOG("realloc() failed."); - ret = -1; goto abort; } @@ -2151,7 +2169,6 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) def->label = label; def->label_size = label_size; - def->label_needs_free = label_needs_free; def->dest_beg = dest_contents_beg; def->dest_end = dest_contents_end; @@ -2166,7 +2183,6 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, lines + title_contents_line_index, n_lines - title_contents_line_index, _T('\n'), &def->title, &def->title_size)); - def->title_needs_free = TRUE; } /* Success. */ @@ -2175,9 +2191,9 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines) abort: /* Failure. */ - if(label_needs_free) + if(!IS_INPUT_STR(label)) free(label); - return -1; + return ret; } static int @@ -2225,7 +2241,7 @@ md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines, attr->title_needs_free = FALSE; } - if(beg_line != end_line) + if(!IS_INPUT_STR(label)) free(label); ret = (def != NULL); @@ -2339,9 +2355,9 @@ md_free_ref_defs(MD_CTX* ctx) for(i = 0; i < ctx->n_ref_defs; i++) { MD_REF_DEF* def = &ctx->ref_defs[i]; - if(def->label_needs_free) + if(!IS_INPUT_STR(def->label)) free(def->label); - if(def->title_needs_free) + if(!IS_INPUT_STR(def->title)) free(def->title); } @@ -2470,7 +2486,7 @@ md_mark_chain(MD_CTX* ctx, int mark_index) switch(mark->ch) { case _T('*'): return md_asterisk_chain(ctx, mark->flags); case _T('_'): return &UNDERSCORE_OPENERS; - case _T('~'): return &TILDE_OPENERS; + case _T('~'): return (mark->end - mark->beg == 1) ? &TILDE_OPENERS_1 : &TILDE_OPENERS_2; case _T('['): return &BRACKET_OPENERS; case _T('|'): return &TABLECELLBOUNDARIES; default: return NULL; @@ -2483,7 +2499,9 @@ md_push_mark(MD_CTX* ctx) if(ctx->n_marks >= ctx->alloc_marks) { MD_MARK* new_marks; - ctx->alloc_marks = (ctx->alloc_marks > 0 ? ctx->alloc_marks * 2 : 64); + ctx->alloc_marks = (ctx->alloc_marks > 0 + ? ctx->alloc_marks + ctx->alloc_marks / 2 + : 64); new_marks = realloc(ctx->marks, ctx->alloc_marks * sizeof(MD_MARK)); if(new_marks == NULL) { MD_LOG("realloc() failed."); @@ -2526,6 +2544,7 @@ md_mark_chain_append(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index) chain->head = mark_index; ctx->marks[mark_index].prev = chain->tail; + ctx->marks[mark_index].next = -1; chain->tail = mark_index; } @@ -2617,7 +2636,7 @@ md_rollback(MD_CTX* ctx, int opener_index, int closer_index, int how) chain->head = -1; } - /* Go backwards so that un-resolved openers are re-added into their + /* Go backwards so that unresolved openers are re-added into their * respective chains, in the right order. */ mark_index = closer_index - 1; while(mark_index > opener_index) { @@ -2696,7 +2715,7 @@ md_build_mark_char_map(MD_CTX* ctx) if(ctx->parser.flags & MD_FLAG_PERMISSIVEWWWAUTOLINKS) ctx->mark_char_map['.'] = 1; - if(ctx->parser.flags & MD_FLAG_TABLES) + if((ctx->parser.flags & MD_FLAG_TABLES) || (ctx->parser.flags & MD_FLAG_WIKILINKS)) ctx->mark_char_map['|'] = 1; if(ctx->parser.flags & MD_FLAG_COLLAPSEWHITESPACE) { @@ -2896,7 +2915,7 @@ md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) return FALSE; off++; - /* Labels delimited with '.'; each label is sequence of 1 - 62 alnum + /* Labels delimited with '.'; each label is sequence of 1 - 63 alnum * characters or '-', but '-' is not allowed as first or last char. */ label_len = 0; while(off < max_end) { @@ -2909,7 +2928,7 @@ md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) else break; - if(label_len > 62) + if(label_len > 63) return FALSE; off++; @@ -3236,8 +3255,8 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) continue; } - /* A potential table cell boundary. */ - if(table_mode && ch == _T('|')) { + /* A potential table cell boundary or wiki link label delimiter. */ + if((table_mode || ctx->parser.flags & MD_FLAG_WIKILINKS) && ch == _T('|')) { PUSH_MARK(ch, off, off+1, 0); off++; continue; @@ -3250,7 +3269,17 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode) while(tmp < line_end && CH(tmp) == _T('~')) tmp++; - PUSH_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER); + if(tmp - off < 3) { + unsigned flags = 0; + + if(tmp < line_end && !ISUNICODEWHITESPACE(tmp)) + flags |= MD_MARK_POTENTIAL_OPENER; + if(off > line->beg && !ISUNICODEWHITESPACEBEFORE(off)) + flags |= MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + PUSH_MARK(ch, off, tmp, flags); + } + off = tmp; continue; } @@ -3398,6 +3427,91 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines) continue; } + /* Recognize and resolve wiki links. + * Wiki-links maybe '[[destination]]' or '[[destination|label]]'. + */ + if ((ctx->parser.flags & MD_FLAG_WIKILINKS) && + (opener->end - opener->beg == 1) && /* not image */ + next_opener != NULL && /* double '[' opener */ + next_opener->ch == '[' && + (next_opener->beg == opener->beg - 1) && + (next_opener->end - next_opener->beg == 1) && + next_closer != NULL && /* double ']' closer */ + next_closer->ch == ']' && + (next_closer->beg == closer->beg + 1) && + (next_closer->end - next_closer->beg == 1)) + { + MD_MARK* delim = NULL; + int delim_index; + OFF dest_beg, dest_end; + + is_link = TRUE; + + /* We don't allow destination to be longer then 100 characters. + * Lets scan to see whether there is '|'. (If not then the whole + * wiki-link has to be below the 100 characters.) */ + delim_index = opener_index + 1; + while(delim_index < closer_index) { + MD_MARK* m = &ctx->marks[delim_index]; + if(m->ch == '|') { + delim = m; + break; + } + if(m->ch != 'D' && m->beg - opener->end > 100) + break; + delim_index++; + } + dest_beg = opener->end; + dest_end = (delim != NULL) ? delim->beg : closer->beg; + if(dest_end - dest_beg == 0 || dest_end - dest_beg > 100) + is_link = FALSE; + + /* There may not be any new line in the destination. */ + if(is_link) { + OFF off; + for(off = dest_beg; off < dest_end; off++) { + if(ISNEWLINE(off)) { + is_link = FALSE; + break; + } + } + } + + if(is_link) { + if(delim != NULL) { + if(delim->end < closer->beg) { + opener->end = delim->beg; + } else { + /* The pipe is just before the closer: [[foo|]] */ + closer->beg = delim->beg; + delim = NULL; + } + } + + opener->beg = next_opener->beg; + opener->next = closer_index; + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + + closer->end = next_closer->end; + closer->prev = opener_index; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; + + last_link_beg = opener->beg; + last_link_end = closer->end; + + if(delim != NULL) { + delim->flags |= MD_MARK_RESOLVED; + md_rollback(ctx, opener_index, delim_index, MD_ROLLBACK_ALL); + md_analyze_link_contents(ctx, lines, n_lines, opener_index+1, closer_index); + } else { + md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL); + } + + opener_index = next_opener->prev; + continue; + } + } + if(next_opener != NULL && next_opener->beg == closer->end) { if(next_closer->beg > closer->end + 1) { /* Might be full reference link. */ @@ -3436,7 +3550,7 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines) if((mark->flags & (MD_MARK_OPENER | MD_MARK_RESOLVED)) == (MD_MARK_OPENER | MD_MARK_RESOLVED)) { if(ctx->marks[mark->next].beg >= inline_link_end) { /* Cancel the link status. */ - if(attr.title_needs_free) + if(!IS_INPUT_STR(attr.title)) free(attr.title); is_link = FALSE; break; @@ -3476,6 +3590,7 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines) MD_ASSERT(ctx->marks[opener_index+2].ch == 'D'); md_mark_store_ptr(ctx, opener_index+2, attr.title); + /* The title might or might not have been allocated for us. */ if(attr.title_needs_free) md_mark_chain_append(ctx, &PTR_CHAIN, opener_index+2); ctx->marks[opener_index+2].prev = attr.title_size; @@ -3574,8 +3689,7 @@ md_analyze_emph(MD_CTX* ctx, int mark_index) int i, n_opener_chains; unsigned flags = mark->flags; - /* Apply "rule of three". (This is why we break asterisk opener - * marks into multiple chains.) */ + /* Apply the "rule of three". */ n_opener_chains = 0; opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_0; if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) @@ -3611,16 +3725,17 @@ md_analyze_emph(MD_CTX* ctx, int mark_index) if(opener != NULL) { SZ opener_size = opener->end - opener->beg; SZ closer_size = mark->end - mark->beg; + MD_MARKCHAIN* opener_chain = md_mark_chain(ctx, opener_index); if(opener_size > closer_size) { opener_index = md_split_emph_mark(ctx, opener_index, closer_size); - md_mark_chain_append(ctx, md_mark_chain(ctx, opener_index), opener_index); + md_mark_chain_append(ctx, opener_chain, opener_index); } else if(opener_size < closer_size) { md_split_emph_mark(ctx, mark_index, closer_size - opener_size); } md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); - md_resolve_range(ctx, chain, opener_index, mark_index); + md_resolve_range(ctx, opener_chain, opener_index, mark_index); return; } } @@ -3633,20 +3748,23 @@ md_analyze_emph(MD_CTX* ctx, int mark_index) static void md_analyze_tilde(MD_CTX* ctx, int mark_index) { - /* We attempt to be Github Flavored Markdown compatible here. GFM says - * that length of the tilde sequence is not important at all. Note that - * implies the TILDE_OPENERS chain can have at most one item. */ + MD_MARK* mark = &ctx->marks[mark_index]; + MD_MARKCHAIN* chain = md_mark_chain(ctx, mark_index); + + /* We attempt to be Github Flavored Markdown compatible here. GFM accepts + * only tildes sequences of length 1 and 2, and the length of the opener + * and closer has to match. */ - if(TILDE_OPENERS.head >= 0) { - /* The chain already contains an opener, so we may resolve the span. */ - int opener_index = TILDE_OPENERS.head; + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && chain->head >= 0) { + int opener_index = chain->head; md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); - md_resolve_range(ctx, &TILDE_OPENERS, opener_index, mark_index); - } else { - /* We can only be opener. */ - md_mark_chain_append(ctx, &TILDE_OPENERS, mark_index); + md_resolve_range(ctx, chain, opener_index, mark_index); + return; } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_chain_append(ctx, chain, mark_index); } static void @@ -3860,8 +3978,16 @@ md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mod /* (1) Entities; code spans; autolinks; raw HTML. */ md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("&")); + /* (2) Links. */ + md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!")); + MD_CHECK(md_resolve_links(ctx, lines, n_lines)); + BRACKET_OPENERS.head = -1; + BRACKET_OPENERS.tail = -1; + ctx->unresolved_link_head = -1; + ctx->unresolved_link_tail = -1; + if(table_mode) { - /* (2) Analyze table cell boundaries. + /* (3) Analyze table cell boundaries. * Note we reset TABLECELLBOUNDARIES chain prior to the call md_analyze_marks(), * not after, because caller may need it. */ MD_ASSERT(n_lines == 1); @@ -3872,14 +3998,6 @@ md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mod return ret; } - /* (3) Links. */ - md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!")); - MD_CHECK(md_resolve_links(ctx, lines, n_lines)); - BRACKET_OPENERS.head = -1; - BRACKET_OPENERS.tail = -1; - ctx->unresolved_link_head = -1; - ctx->unresolved_link_tail = -1; - /* (4) Emphasis and strong emphasis; permissive autolinks. */ md_analyze_link_contents(ctx, lines, n_lines, 0, ctx->n_marks); @@ -3891,25 +4009,14 @@ static void md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int mark_beg, int mark_end) { + int i; + md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("*_~$@:.")); - ASTERISK_OPENERS_extraword_mod3_0.head = -1; - ASTERISK_OPENERS_extraword_mod3_0.tail = -1; - ASTERISK_OPENERS_extraword_mod3_1.head = -1; - ASTERISK_OPENERS_extraword_mod3_1.tail = -1; - ASTERISK_OPENERS_extraword_mod3_2.head = -1; - ASTERISK_OPENERS_extraword_mod3_2.tail = -1; - ASTERISK_OPENERS_intraword_mod3_0.head = -1; - ASTERISK_OPENERS_intraword_mod3_0.tail = -1; - ASTERISK_OPENERS_intraword_mod3_1.head = -1; - ASTERISK_OPENERS_intraword_mod3_1.tail = -1; - ASTERISK_OPENERS_intraword_mod3_2.head = -1; - ASTERISK_OPENERS_intraword_mod3_2.tail = -1; - UNDERSCORE_OPENERS.head = -1; - UNDERSCORE_OPENERS.tail = -1; - TILDE_OPENERS.head = -1; - TILDE_OPENERS.tail = -1; - DOLLAR_OPENERS.head = -1; - DOLLAR_OPENERS.tail = -1; + + for(i = OPENERS_CHAIN_FIRST; i <= OPENERS_CHAIN_LAST; i++) { + ctx->mark_chains[i].head = -1; + ctx->mark_chains[i].tail = -1; + } } static int @@ -3941,6 +4048,27 @@ abort: return ret; } +static int +md_enter_leave_span_wikilink(MD_CTX* ctx, int enter, const CHAR* target, SZ target_size) +{ + MD_ATTRIBUTE_BUILD target_build = { 0 }; + MD_SPAN_WIKILINK_DETAIL det; + int ret = 0; + + memset(&det, 0, sizeof(MD_SPAN_WIKILINK_DETAIL)); + MD_CHECK(md_build_attribute(ctx, target, target_size, 0, &det.target, &target_build)); + + if (enter) + MD_ENTER_SPAN(MD_SPAN_WIKILINK, &det); + else + MD_LEAVE_SPAN(MD_SPAN_WIKILINK, &det); + +abort: + md_free_attribute(ctx, &target_build); + return ret; +} + + /* Render the output, accordingly to the analyzed ctx->marks. */ static int md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines) @@ -3996,7 +4124,23 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines) } break; - case '_': + case '_': /* Underline (or emphasis if we fall through). */ + if(ctx->parser.flags & MD_FLAG_UNDERLINE) { + if(mark->flags & MD_MARK_OPENER) { + while(off < mark->end) { + MD_ENTER_SPAN(MD_SPAN_U, NULL); + off++; + } + } else { + while(off < mark->end) { + MD_LEAVE_SPAN(MD_SPAN_U, NULL); + off++; + } + } + break; + } + /* Fall though. */ + case '*': /* Emphasis, strong emphasis. */ if(mark->flags & MD_MARK_OPENER) { if((mark->end - off) % 2) { @@ -4036,15 +4180,37 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines) } break; - case '[': /* Link, image. */ + case '[': /* Link, wiki link, image. */ case '!': case ']': { const MD_MARK* opener = (mark->ch != ']' ? mark : &ctx->marks[mark->prev]); - const MD_MARK* dest_mark = opener+1; - const MD_MARK* title_mark = opener+2; + const MD_MARK* closer = &ctx->marks[opener->next]; + const MD_MARK* dest_mark; + const MD_MARK* title_mark; + + if ((opener->ch == '[' && closer->ch == ']') && + opener->end - opener->beg >= 2 && + closer->end - closer->beg >= 2) + { + int has_label = (opener->end - opener->beg > 2); + SZ target_sz; + + if(has_label) + target_sz = opener->end - (opener->beg+2); + else + target_sz = closer->beg - opener->end; + MD_CHECK(md_enter_leave_span_wikilink(ctx, (mark->ch != ']'), + has_label ? STR(opener->beg+2) : STR(opener->end), + target_sz)); + + break; + } + + dest_mark = opener+1; MD_ASSERT(dest_mark->ch == 'D'); + title_mark = opener+2; MD_ASSERT(title_mark->ch == 'D'); MD_CHECK(md_enter_leave_span_a(ctx, (mark->ch != ']'), @@ -4251,7 +4417,7 @@ md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end, { MD_LINE line; OFF* pipe_offs = NULL; - int i, j, n; + int i, j, k, n; int ret = 0; line.beg = beg; @@ -4263,32 +4429,32 @@ md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end, /* We have to remember the cell boundaries in local buffer because * ctx->marks[] shall be reused during cell contents processing. */ - n = ctx->n_table_cell_boundaries; + n = ctx->n_table_cell_boundaries + 2; pipe_offs = (OFF*) malloc(n * sizeof(OFF)); if(pipe_offs == NULL) { MD_LOG("malloc() failed."); ret = -1; goto abort; } - for(i = TABLECELLBOUNDARIES.head, j = 0; i >= 0; i = ctx->marks[i].next) { + j = 0; + pipe_offs[j++] = beg; + for(i = TABLECELLBOUNDARIES.head; i >= 0; i = ctx->marks[i].next) { MD_MARK* mark = &ctx->marks[i]; - pipe_offs[j++] = mark->beg; + pipe_offs[j++] = mark->end; } + pipe_offs[j++] = end+1; /* Process cells. */ MD_ENTER_BLOCK(MD_BLOCK_TR, NULL); - j = 0; - if(beg < pipe_offs[0] && j < col_count) - MD_CHECK(md_process_table_cell(ctx, cell_type, align[j++], beg, pipe_offs[0])); - for(i = 0; i < n-1 && j < col_count; i++) - MD_CHECK(md_process_table_cell(ctx, cell_type, align[j++], pipe_offs[i]+1, pipe_offs[i+1])); - if(pipe_offs[n-1] < end-1 && j < col_count) - MD_CHECK(md_process_table_cell(ctx, cell_type, align[j++], pipe_offs[n-1]+1, end)); + k = 0; + for(i = 0; i < j-1 && k < col_count; i++) { + if(pipe_offs[i] < pipe_offs[i+1]-1) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], pipe_offs[i], pipe_offs[i+1]-1)); + } /* Make sure we call enough table cells even if the current table contains * too few of them. */ - while(j < col_count) - MD_CHECK(md_process_table_cell(ctx, cell_type, align[j++], 0, 0)); - + while(k < col_count) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], 0, 0)); MD_LEAVE_BLOCK(MD_BLOCK_TR, NULL); abort: @@ -4340,38 +4506,6 @@ abort: return ret; } -static int -md_is_table_row(MD_CTX* ctx, OFF beg, OFF* p_end) -{ - MD_LINE line; - int i; - int ret = FALSE; - - line.beg = beg; - line.end = beg; - - /* Find end of line. */ - while(line.end < ctx->size && !ISNEWLINE(line.end)) - line.end++; - - MD_CHECK(md_analyze_inlines(ctx, &line, 1, TRUE)); - - if(TABLECELLBOUNDARIES.head >= 0) { - if(p_end != NULL) - *p_end = line.end; - ret = TRUE; - } - -abort: - /* Free any temporary memory blocks stored within some dummy marks. */ - for(i = PTR_CHAIN.head; i >= 0; i = ctx->marks[i].next) - free(md_mark_get_ptr(ctx, i)); - PTR_CHAIN.head = -1; - PTR_CHAIN.tail = -1; - - return ret; -} - /************************** *** Processing Block *** @@ -4704,7 +4838,9 @@ md_push_block_bytes(MD_CTX* ctx, int n_bytes) if(ctx->n_block_bytes + n_bytes > ctx->alloc_block_bytes) { void* new_block_bytes; - ctx->alloc_block_bytes = (ctx->alloc_block_bytes > 0 ? ctx->alloc_block_bytes * 2 : 512); + ctx->alloc_block_bytes = (ctx->alloc_block_bytes > 0 + ? ctx->alloc_block_bytes + ctx->alloc_block_bytes / 2 + : 512); new_block_bytes = realloc(ctx->block_bytes, ctx->alloc_block_bytes); if(new_block_bytes == NULL) { MD_LOG("realloc() failed."); @@ -5136,7 +5272,7 @@ md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) #ifdef X #undef X #endif -#define X(name) { _T(name), sizeof(name)-1 } +#define X(name) { _T(name), (sizeof(name)-1) / sizeof(CHAR) } #define Xend { NULL, 0 } static const TAG t1[] = { X("script"), X("pre"), X("style"), Xend }; @@ -5192,7 +5328,7 @@ md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) /* Check for type 5: <![CDATA[ */ if(off + 8 < ctx->size) { - if(md_ascii_eq(STR(off), _T("![CDATA["), 8 * sizeof(CHAR))) + if(md_ascii_eq(STR(off), _T("![CDATA["), 8)) return 5; } } @@ -5341,7 +5477,9 @@ md_push_container(MD_CTX* ctx, const MD_CONTAINER* container) if(ctx->n_containers >= ctx->alloc_containers) { MD_CONTAINER* new_containers; - ctx->alloc_containers = (ctx->alloc_containers > 0 ? ctx->alloc_containers * 2 : 16); + ctx->alloc_containers = (ctx->alloc_containers > 0 + ? ctx->alloc_containers + ctx->alloc_containers / 2 + : 16); new_containers = realloc(ctx->containers, ctx->alloc_containers * sizeof(MD_CONTAINER)); if(new_containers == NULL) { MD_LOG("realloc() failed."); @@ -5561,6 +5699,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, line->indent--; line->beg = off; + } else if(c->ch != _T('>') && line->indent >= c->contents_indent) { /* List. */ line->indent -= c->contents_indent; @@ -5803,9 +5942,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, } /* Check whether we are table continuation. */ - if(pivot_line->type == MD_LINE_TABLE && md_is_table_row(ctx, off, &off) && - n_parents == ctx->n_containers) - { + if(pivot_line->type == MD_LINE_TABLE && n_parents == ctx->n_containers) { line->type = MD_LINE_TABLE; break; } @@ -5859,8 +5996,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned col_count; if(ctx->current_block != NULL && ctx->current_block->n_lines == 1 && - md_is_table_underline(ctx, off, &off, &col_count) && - md_is_table_row(ctx, pivot_line->beg, NULL)) + md_is_table_underline(ctx, off, &off, &col_count)) { line->data = col_count; line->type = MD_LINE_TABLEUNDERLINE; diff --git a/src/3rdparty/md4c/md4c.h b/src/3rdparty/md4c/md4c.h index 6d9fce5180..c2c4311f50 100644 --- a/src/3rdparty/md4c/md4c.h +++ b/src/3rdparty/md4c/md4c.h @@ -2,7 +2,7 @@ * MD4C: Markdown parser for C * (http://github.com/mity/md4c) * - * Copyright (c) 2016-2019 Martin Mitas + * Copyright (c) 2016-2020 Martin Mitas * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -135,7 +135,16 @@ typedef enum MD_SPANTYPE { * Note: Recognized only when MD_FLAG_LATEXMATHSPANS is enabled. */ MD_SPAN_LATEXMATH, - MD_SPAN_LATEXMATH_DISPLAY + MD_SPAN_LATEXMATH_DISPLAY, + + /* Wiki links + * Note: Recognized only when MD_FLAG_WIKILINKS is enabled. + */ + MD_SPAN_WIKILINK, + + /* <u>...</u> + * Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */ + MD_SPAN_U } MD_SPANTYPE; /* Text is the actual textual contents of span. */ @@ -268,6 +277,10 @@ typedef struct MD_SPAN_IMG_DETAIL { MD_ATTRIBUTE title; } MD_SPAN_IMG_DETAIL; +/* Detailed info for MD_SPAN_WIKILINK. */ +typedef struct MD_SPAN_WIKILINK { + MD_ATTRIBUTE target; +} MD_SPAN_WIKILINK_DETAIL; /* Flags specifying extensions/deviations from CommonMark specification. * @@ -286,6 +299,8 @@ typedef struct MD_SPAN_IMG_DETAIL { #define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x0400 /* Enable WWW autolinks (even without any scheme prefix, if they begin with 'www.') */ #define MD_FLAG_TASKLISTS 0x0800 /* Enable task list extension. */ #define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */ +#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */ +#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */ #define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS) #define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS) diff --git a/src/3rdparty/md4c/qt_attribution.json b/src/3rdparty/md4c/qt_attribution.json index 5fd77269e9..c574b97711 100644 --- a/src/3rdparty/md4c/qt_attribution.json +++ b/src/3rdparty/md4c/qt_attribution.json @@ -9,7 +9,7 @@ "License": "MIT License", "LicenseId": "MIT", "LicenseFile": "LICENSE.md", - "Version": "0.3.4", - "DownloadLocation": "https://github.com/mity/md4c/releases/tag/release-0.3.4", - "Copyright": "Copyright © 2016-2019 Martin Mitáš" + "Version": "0.4.3", + "DownloadLocation": "https://github.com/mity/md4c/releases/tag/release-0.4.3", + "Copyright": "Copyright © 2016-2020 Martin Mitáš" } diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index c1c4d5559d..87d326e225 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -47,11 +47,13 @@ import java.util.concurrent.Semaphore; import android.app.Activity; import android.app.Service; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ActivityInfo; +import android.content.UriPermission; import android.net.Uri; import android.os.Build; import android.os.Handler; @@ -73,6 +75,7 @@ import java.lang.reflect.Method; import java.security.KeyStore; import java.security.cert.X509Certificate; import java.util.Iterator; +import java.util.List; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; @@ -152,35 +155,79 @@ public class QtNative } } - public static boolean openURL(String url, String mime) + private static Uri getUriWithValidPermission(Context context, String uri, String openMode) { - boolean ok = true; + try { + List<UriPermission> permissions = context.getContentResolver().getPersistedUriPermissions(); + String uriStr = Uri.parse(uri).getPath(); + + for (int i = 0; i < permissions.size(); ++i) { + Uri iterUri = permissions.get(i).getUri(); + boolean isRightPermission = permissions.get(i).isReadPermission(); + + if (!openMode.equals("r")) + isRightPermission = permissions.get(i).isWritePermission(); + + if (iterUri.getPath().equals(uriStr) && isRightPermission) + return iterUri; + } + + return null; + } catch (SecurityException e) { + e.printStackTrace(); + return null; + } + } + + public static boolean openURL(Context context, String url, String mime) + { + Uri uri = getUriWithValidPermission(context, url, "r"); + + if (uri == null) { + Log.e(QtTAG, "openURL(): No permissions to open Uri"); + return false; + } try { - Uri uri = Uri.parse(url); Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); if (!mime.isEmpty()) intent.setDataAndType(uri, mime); + activity().startActivity(intent); - } catch (Exception e) { + + return true; + } catch (IllegalArgumentException e) { + Log.e(QtTAG, "openURL(): Invalid Uri"); + return false; + } catch (UnsupportedOperationException e) { + Log.e(QtTAG, "openURL(): Unsupported operation for given Uri"); + return false; + } catch (ActivityNotFoundException e) { e.printStackTrace(); - ok = false; + return false; } - - return ok; } public static int openFdForContentUrl(Context context, String contentUrl, String openMode) { + Uri uri = getUriWithValidPermission(context, contentUrl, openMode); + int error = -1; + + if (uri == null) { + Log.e(QtTAG, "openFdForContentUrl(): No permissions to open Uri"); + return error; + } + try { ContentResolver resolver = context.getContentResolver(); - ParcelFileDescriptor fdDesc = resolver.openFileDescriptor(Uri.parse(contentUrl), openMode); + ParcelFileDescriptor fdDesc = resolver.openFileDescriptor(uri, openMode); return fdDesc.detachFd(); } catch (FileNotFoundException e) { - return -1; - } catch (SecurityException e) { - Log.e(QtTAG, "Exception when opening file", e); - return -1; + return error; + } catch (IllegalArgumentException e) { + Log.e(QtTAG, "openFdForContentUrl(): Invalid Uri"); + return error; } } diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp index af36bd7e2f..8561f908b9 100644 --- a/src/corelib/codecs/qutfcodec.cpp +++ b/src/corelib/codecs/qutfcodec.cpp @@ -930,6 +930,7 @@ QString QUtf32::convertToUnicode(const char *chars, int len, QTextCodec::Convert tuple[num++] = *chars++; if (num == 4) { if (!headerdone) { + headerdone = true; if (endian == DetectEndianness) { if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BigEndianness) { endian = LittleEndianness; diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 57ccd308d7..8851e08d4f 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -505,7 +505,7 @@ namespace Qt { AA_DontUseNativeMenuBar = 6, AA_MacDontSwapCtrlAndMeta = 7, AA_Use96Dpi = 8, - AA_MSWindowsDisableVirtualKeyboard = 9, + AA_DisableNativeVirtualKeyboard = 9, #if QT_DEPRECATED_SINCE(5, 14) AA_X11InitThreads Q_DECL_ENUMERATOR_DEPRECATED = 10, #endif diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 708ecb11ab..3e22c9e661 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -293,10 +293,10 @@ This attribute must be set before QGuiApplication is constructed. This value was added in 5.13 - \value AA_MSWindowsDisableVirtualKeyboard When this attribute is set, - Windows' native on-screen virtual keyboard will not be shown - automatically when a text input widget gains focus on a system - without a physical keyboard. + \value AA_DisableNativeVirtualKeyboard When this attribute is set, the native + on-screen virtual keyboard will not be shown automatically when a + text input widget gains focus on a system without a physical keyboard. + Currently supported on the Windows platform only. This value was added in 5.15 The following values are deprecated or obsolete: @@ -3339,6 +3339,8 @@ This is a dummy type, designed to help users transition from certain deprecated APIs to their replacement APIs. + \omitvalue ReturnByValue + \sa QCursor::bitmap() \sa QCursor::mask() \sa QLabel::picture() diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 5d5b0b2a29..acc60915e7 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -2230,8 +2230,16 @@ void QProcessPrivate::start(QIODevice::OpenMode mode) startProcess(); } +/*! + \since 5.15 + + Splits the string \a command into a list of tokens, and returns + the list. -static QStringList parseCombinedArgString(const QString &program) + Tokens with spaces can be surrounded by double quotes; three + consecutive double quotes represent the quote character itself. +*/ +QStringList QProcess::splitCommand(const QString &command) { QStringList args; QString tmp; @@ -2241,13 +2249,13 @@ static QStringList parseCombinedArgString(const QString &program) // handle quoting. tokens can be surrounded by double quotes // "hello world". three consecutive double quotes represent // the quote character itself. - for (int i = 0; i < program.size(); ++i) { - if (program.at(i) == QLatin1Char('"')) { + for (int i = 0; i < command.size(); ++i) { + if (command.at(i) == QLatin1Char('"')) { ++quoteCount; if (quoteCount == 3) { // third consecutive quote quoteCount = 0; - tmp += program.at(i); + tmp += command.at(i); } continue; } @@ -2256,13 +2264,13 @@ static QStringList parseCombinedArgString(const QString &program) inQuote = !inQuote; quoteCount = 0; } - if (!inQuote && program.at(i).isSpace()) { + if (!inQuote && command.at(i).isSpace()) { if (!tmp.isEmpty()) { args += tmp; tmp.clear(); } } else { - tmp += program.at(i); + tmp += command.at(i); } } if (!tmp.isEmpty()) @@ -2272,6 +2280,7 @@ static QStringList parseCombinedArgString(const QString &program) } /*! + \obsolete \overload Starts the command \a command in a new process. @@ -2308,11 +2317,13 @@ static QStringList parseCombinedArgString(const QString &program) list-based API. In these rare cases you need to use setProgram() and setNativeArguments() instead of this function. + \sa splitCommand() + */ #if !defined(QT_NO_PROCESS_COMBINED_ARGUMENT_START) void QProcess::start(const QString &command, OpenMode mode) { - QStringList args = parseCombinedArgString(command); + QStringList args = splitCommand(command); if (args.isEmpty()) { Q_D(QProcess); d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined")); @@ -2477,6 +2488,7 @@ int QProcess::execute(const QString &program, const QStringList &arguments) } /*! + \obsolete \overload Starts the program \a command in a new process, waits for it to finish, @@ -2487,7 +2499,7 @@ int QProcess::execute(const QString &program, const QStringList &arguments) After the \a command string has been split and unquoted, this function behaves like the overload which takes the arguments as a string list. - \sa start() + \sa start(), splitCommand() */ int QProcess::execute(const QString &command) { @@ -2543,6 +2555,7 @@ bool QProcess::startDetached(const QString &program, } /*! + \obsolete \overload startDetached() Starts the command \a command in a new process, and detaches from it. @@ -2553,11 +2566,11 @@ bool QProcess::startDetached(const QString &program, After the \a command string has been split and unquoted, this function behaves like the overload which takes the arguments as a string list. - \sa start(const QString &command, QIODevice::OpenMode mode) + \sa start(const QString &command, QIODevice::OpenMode mode), splitCommand() */ bool QProcess::startDetached(const QString &command) { - QStringList args = parseCombinedArgString(command); + QStringList args = splitCommand(command); if (args.isEmpty()) return false; diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 0a2187750f..0ef02b196d 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -160,8 +160,14 @@ public: void start(const QString &program, const QStringList &arguments, OpenMode mode = ReadWrite); #if !defined(QT_NO_PROCESS_COMBINED_ARGUMENT_START) +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_X( + "Use QProcess::start(const QString &program, const QStringList &arguments," + "OpenMode mode = ReadWrite) instead" + ) void start(const QString &command, OpenMode mode = ReadWrite); #endif +#endif void start(OpenMode mode = ReadWrite); bool startDetached(qint64 *pid = nullptr); bool open(OpenMode mode = ReadWrite) override; @@ -250,8 +256,12 @@ public: bool atEnd() const override; // ### Qt6: remove trivial override static int execute(const QString &program, const QStringList &arguments); +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_X( + "Use QProcess::execute(const QString &program, const QStringList &arguments) instead" + ) static int execute(const QString &command); - +#endif static bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory #if defined(Q_QDOC) @@ -261,12 +271,19 @@ public: #if !defined(Q_QDOC) static bool startDetached(const QString &program, const QStringList &arguments); // ### Qt6: merge overloads #endif +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_X( + "Use QProcess::startDetached(const QString &program, const QStringList &arguments) instead" + ) static bool startDetached(const QString &command); +#endif static QStringList systemEnvironment(); static QString nullDevice(); + static QStringList splitCommand(const QString &command); + public Q_SLOTS: void terminate(); void kill(); diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index a5128a868b..9d773e6f52 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -343,7 +343,10 @@ QT_BEGIN_NAMESPACE OS configuration, locale, or they may change in future Qt versions. \note On Android, applications with open files on the external storage (<USER> locations), - will be killed if the external storage is unmounted. + will be killed if the external storage is unmounted. + + \note On Android 6.0 (API 23) or higher, the "WRITE_EXTERNAL_STORAGE" permission must be + requested at runtime when using QStandardPaths::writableLocation or QStandardPaths::standardLocations. \note On Android, reading/writing to GenericDataLocation needs the READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE permission granted. diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index b6ddcce27c..3e7d8e113c 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -4149,7 +4149,7 @@ static bool isIp6(const QString &text) /*! Returns a valid URL from a user supplied \a userInput string if one can be - deducted. In the case that is not possible, an invalid QUrl() is returned. + deduced. In the case that is not possible, an invalid QUrl() is returned. This overload takes a \a workingDirectory path, in order to be able to handle relative paths. This is especially useful when handling command diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 033e4e2f97..e0506b12db 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -3056,12 +3056,8 @@ bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex & Returns \c true if the item in the column indicated by the given \a source_column and \a source_parent should be included in the model; otherwise returns \c false. - The default implementation returns \c true if the value held by the relevant item - matches the filter string, wildcard string or regular expression. - - \note By default, the Qt::DisplayRole is used to determine if the column - should be accepted or not. This can be changed by setting the \l - filterRole property. + \note The default implementation always returns \c true. You must reimplement this + method to get the described behavior. \sa filterAcceptsRow(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard() */ diff --git a/src/corelib/kernel/qmath.qdoc b/src/corelib/kernel/qmath.qdoc index a2e24e925b..346171f044 100644 --- a/src/corelib/kernel/qmath.qdoc +++ b/src/corelib/kernel/qmath.qdoc @@ -51,8 +51,6 @@ \value M_2_SQRTPI Two divided by the square root of pi, 2 / \unicode{0x221A}\unicode{0x3C0} \value M_SQRT2 The square root of two, \unicode{0x221A}2 \value M_SQRT1_2 The square roof of half, 1 / \unicode{0x221A}2 - - \pagekeywords math trigonometry qmath floor ceiling absolute sine cosine tangent inverse tan exponent power natural logarithm pi */ /*! diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 0730dbffd1..4c1f9f20f7 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -714,7 +714,7 @@ QMetaType &QMetaType::operator=(const QMetaType &other) as the QMetaType \a b, otherwise returns \c false. */ -/*! \fn bool operator!=(const QMetaType &a, const QMetaType &c) +/*! \fn bool operator!=(const QMetaType &a, const QMetaType &b) \since 5.15 \relates QMetaType \overload diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 697c9b6148..2fdf94c38b 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -47,6 +47,7 @@ #include "qabstracteventdispatcher_p.h" #include "qcoreapplication.h" #include "qcoreapplication_p.h" +#include "qloggingcategory.h" #include "qvariant.h" #include "qmetaobject.h" #include <qregexp.h> @@ -78,6 +79,8 @@ QT_BEGIN_NAMESPACE static int DIRECT_CONNECTION_ONLY = 0; +Q_LOGGING_CATEGORY(lcConnections, "qt.core.qmetaobject.connectslotsbyname") + Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set = Q_BASIC_ATOMIC_INITIALIZER(nullptr); void qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set) @@ -183,15 +186,7 @@ QMetaObject *QObjectData::dynamicMetaObject() const QObjectPrivate::QObjectPrivate(int version) : threadData(nullptr), currentChildBeingDeleted(nullptr) { -#ifdef QT_BUILD_INTERNAL - // Don't check the version parameter in internal builds. - // This allows incompatible versions to be loaded, possibly for testing. - Q_UNUSED(version); -#else - if (Q_UNLIKELY(version != QObjectPrivateVersion)) - qFatal("Cannot mix incompatible Qt library (version 0x%x) with this library (version 0x%x)", - version, QObjectPrivateVersion); -#endif + checkForIncompatibleLibraryVersion(version); // QObjectData initialization q_ptr = nullptr; @@ -3555,6 +3550,37 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, return success; } +// Helpers for formatting the connect statements of connectSlotsByName()'s debug mode +static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method) +{ + const auto signature = method.methodSignature(); + Q_ASSERT(signature.endsWith(')')); + const int openParen = signature.indexOf('('); + const bool hasParameters = openParen >= 0 && openParen < signature.size() - 2; + QByteArray result; + if (hasParameters) { + result += "qOverload<" + + signature.mid(openParen + 1, signature.size() - openParen - 2) + ">("; + } + result += '&'; + result += className + QByteArrayLiteral("::") + method.name(); + if (hasParameters) + result += ')'; + return result; +} + +static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName, + const QMetaMethod &signal, const QObject *receiver, int receiverIndex) +{ + const auto receiverMo = receiver->metaObject(); + const auto slot = receiverMo->method(receiverIndex); + QByteArray message = QByteArrayLiteral("QObject::connect(") + + senderName + ", " + formatConnectionSignature(senderMo->className(), signal) + + ", " + receiver->objectName().toLatin1() + ", " + + formatConnectionSignature(receiverMo->className(), slot) + ");"; + return message; +} + /*! \fn void QMetaObject::connectSlotsByName(QObject *object) @@ -3636,6 +3662,8 @@ void QMetaObject::connectSlotsByName(QObject *o) // we connect it... if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) { foundIt = true; + qCDebug(lcConnections, "%s", + msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData()); // ...and stop looking for further objects with the same name. // Note: the Designer will make sure each object name is unique in the above // 'list' but other code may create two child objects with the same name. In diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index d6e73fbefc..97b492360c 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -310,6 +310,8 @@ public: virtual ~QObjectPrivate(); void deleteChildren(); + inline void checkForIncompatibleLibraryVersion(int version) const; + void setParent_helper(QObject *); void moveToThread_helper(); void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); @@ -384,6 +386,28 @@ public: Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE); +/* + Catch mixing of incompatible library versions. + + Should be called from the constructor of every non-final subclass + of QObjectPrivate, to ensure we catch incompatibilities between + the intermediate base and subclasses thereof. +*/ +inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) const +{ +#if defined(QT_BUILD_INTERNAL) + // Don't check the version parameter in internal builds. + // This allows incompatible versions to be loaded, possibly for testing. + Q_UNUSED(version); +#else + if (Q_UNLIKELY(version != QObjectPrivateVersion)) { + qFatal("Cannot mix incompatible Qt library (%d.%d.%d) with this library (%d.%d.%d)", + (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff, + (QObjectPrivateVersion >> 16) & 0xff, (QObjectPrivateVersion >> 8) & 0xff, QObjectPrivateVersion & 0xff); + } +#endif +} + inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const { return declarativeData && QAbstractDeclarativeData::isSignalConnected diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index b84b5a503f..fd7c081e88 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -356,7 +356,7 @@ struct Q_CORE_EXPORT QMetaObject static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1 && !std::is_convertible<Func, const char*>::value, bool>::type - invokeMethod(QObject *context, Func function, typename std::result_of<Func()>::type *ret) + invokeMethod(QObject *context, Func function, decltype(function()) *ret) { return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)), diff --git a/src/corelib/serialization/qcborcommon.cpp b/src/corelib/serialization/qcborcommon.cpp index 37fb198744..5fc47fa399 100644 --- a/src/corelib/serialization/qcborcommon.cpp +++ b/src/corelib/serialization/qcborcommon.cpp @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE \brief The <QtCborCommon> header contains definitions common to both the streaming classes (QCborStreamReader and QCborStreamWriter) and to QCborValue. + + \sa QCborError */ /*! @@ -203,7 +205,7 @@ QDataStream &operator>>(QDataStream &ds, QCborSimpleType &st) /*! \class QCborError \inmodule QtCore - \relates <QtCborCommon> + \inheaderfile <QtCborCommon> \reentrant \since 5.12 diff --git a/src/corelib/text/qharfbuzz.cpp b/src/corelib/text/qharfbuzz.cpp index a3e266ccd2..f54ce26206 100644 --- a/src/corelib/text/qharfbuzz.cpp +++ b/src/corelib/text/qharfbuzz.cpp @@ -72,7 +72,7 @@ HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch) void (*HB_Library_Resolve(const char *library, int version, const char *symbol))() { -#if !QT_CONFIG(library) +#if !QT_CONFIG(library) || defined(Q_OS_WASM) Q_UNUSED(library); Q_UNUSED(version); Q_UNUSED(symbol); diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 877f5df462..8cdf41ffbf 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -7397,6 +7397,8 @@ float QString::toFloat(bool *ok) const The formatting always uses QLocale::C, i.e., English/UnitedStates. To get a localized string representation of a number, use QLocale::toString() with the appropriate locale. + + \sa number() */ /*! \fn QString &QString::setNum(uint n, int base) @@ -7454,6 +7456,8 @@ QString &QString::setNum(qulonglong n, int base) The formatting always uses QLocale::C, i.e., English/UnitedStates. To get a localized string representation of a number, use QLocale::toString() with the appropriate locale. + + \sa number() */ QString &QString::setNum(double n, char f, int prec) @@ -7472,6 +7476,8 @@ QString &QString::setNum(double n, char f, int prec) The formatting always uses QLocale::C, i.e., English/UnitedStates. To get a localized string representation of a number, use QLocale::toString() with the appropriate locale. + + \sa number() */ diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 65d702ff1c..f08c7b0d00 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -1116,7 +1116,7 @@ int QStringView::toWCharArray(wchar_t *array) const if (sizeof(wchar_t) == sizeof(QChar)) { if (auto src = data()) memcpy(array, src, sizeof(QChar) * size()); - return size(); + return int(size()); // ### q6sizetype } else { return QString::toUcs4_helper(reinterpret_cast<const ushort *>(data()), int(size()), reinterpret_cast<uint *>(array)); diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp index c4ddb06ea4..08dade7e68 100644 --- a/src/corelib/text/qstringview.cpp +++ b/src/corelib/text/qstringview.cpp @@ -528,9 +528,9 @@ QT_BEGIN_NAMESPACE */ /*! - \fn QString QStringView::arg(Args &&...args) const - \fn QString QLatin1String::arg(Args &&...args) const - \fn QString QString::arg(Args &&...args) const + \fn template <typename...Args> QString QStringView::arg(Args &&...args) const + \fn template <typename...Args> QString QLatin1String::arg(Args &&...args) const + \fn template <typename...Args> QString QString::arg(Args &&...args) const \since 5.14 Replaces occurrences of \c{%N} in this string with the corresponding diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 0508932d68..9bfd50f2d9 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -212,7 +212,6 @@ QMutex::~QMutex() } /*! \fn void QMutex::lock() - \fn QRecursiveMutex::lock() Locks the mutex. If another thread has locked the mutex then this call will block until that thread has unlocked it. @@ -237,7 +236,6 @@ void QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT } /*! \fn bool QMutex::tryLock(int timeout) - \fn bool QRecursiveMutex::tryLock(int timeout) Attempts to lock the mutex. This function returns \c true if the lock was obtained; otherwise it returns \c false. If another thread has @@ -272,7 +270,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT } /*! \fn bool QMutex::try_lock() - \fn bool QRecursiveMutex::try_lock() \since 5.8 Attempts to lock the mutex. This function returns \c true if the lock @@ -286,7 +283,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT */ /*! \fn template <class Rep, class Period> bool QMutex::try_lock_for(std::chrono::duration<Rep, Period> duration) - \fn template <class Rep, class Period> bool QRecursiveMutex::try_lock_for(std::chrono::duration<Rep, Period> duration) \since 5.8 Attempts to lock the mutex. This function returns \c true if the lock @@ -311,7 +307,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT */ /*! \fn template<class Clock, class Duration> bool QMutex::try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) - \fn template<class Clock, class Duration> bool QRecursiveMutex::try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) \since 5.8 Attempts to lock the mutex. This function returns \c true if the lock @@ -336,7 +331,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT */ /*! \fn void QMutex::unlock() - \fn void QRecursiveMutex::unlock() Unlocks the mutex. Attempting to unlock a mutex in a different thread to the one that locked it results in an error. Unlocking a diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index 773280ad68..86c08058fc 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1100,9 +1100,10 @@ QString QDate::longDayName(int weekday, MonthNameType type) #if QT_CONFIG(datestring) // depends on, so implies, textdate -static QString toStringTextDate(QDate date, QCalendar cal) +static QString toStringTextDate(QDate date) { if (date.isValid()) { + QCalendar cal; // Always Gregorian const auto parts = cal.partsFromDate(date); if (parts.isValid()) { const QLatin1Char sp(' '); @@ -1123,14 +1124,10 @@ static QString toStringIsoDate(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. If \a cal is supplied, it determines the calendar used to - represent the date; it defaults to Gregorian. + of the string. 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 @@ -1168,16 +1165,44 @@ static QString toStringIsoDate(QDate date) */ QString QDate::toString(Qt::DateFormat format) const { - return toString(format, QCalendar()); + if (!isValid()) + return QString(); + + switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED + case Qt::SystemLocaleDate: + case Qt::SystemLocaleShortDate: + return QLocale::system().toString(*this, QLocale::ShortFormat); + case Qt::SystemLocaleLongDate: + return QLocale::system().toString(*this, QLocale::LongFormat); + case Qt::LocaleDate: + case Qt::DefaultLocaleShortDate: + return QLocale().toString(*this, QLocale::ShortFormat); + case Qt::DefaultLocaleLongDate: + return QLocale().toString(*this, QLocale::LongFormat); +QT_WARNING_POP +#endif // 5.15 + case Qt::RFC2822Date: + return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy")); + default: + case Qt::TextDate: + return toStringTextDate(*this); + case Qt::ISODate: + case Qt::ISODateWithMs: + // No calendar dependence + return toStringIsoDate(*this); + } } +#if QT_DEPRECATED_SINCE(5, 15) QString QDate::toString(Qt::DateFormat format, QCalendar cal) const { if (!isValid()) return QString(); switch (format) { -#if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toString(*this, QLocale::ShortFormat, cal); @@ -1188,18 +1213,19 @@ QString QDate::toString(Qt::DateFormat format, QCalendar cal) const return QLocale().toString(*this, QLocale::ShortFormat, cal); case Qt::DefaultLocaleLongDate: return QLocale().toString(*this, QLocale::LongFormat, cal); -#endif // 5.15 +QT_WARNING_POP case Qt::RFC2822Date: return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal); default: case Qt::TextDate: - return toStringTextDate(*this, cal); + return toStringTextDate(*this); case Qt::ISODate: case Qt::ISODateWithMs: // No calendar dependence return toStringIsoDate(*this); } } +#endif // 5.15 /*! \fn QString QDate::toString(const QString &format) const @@ -1208,7 +1234,7 @@ QString QDate::toString(Qt::DateFormat format, QCalendar cal) 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. If \cal is supplied, it determines the calendar used + of the result string. If \a cal is supplied, it determines the calendar used to represent the date; it defaults to Gregorian. These expressions may be used: @@ -1643,6 +1669,7 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format) switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toDate(string, QLocale::ShortFormat); @@ -1653,6 +1680,7 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format) return QLocale().toDate(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toDate(string, QLocale::LongFormat); +QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: return rfcDateImpl(string).date; @@ -2033,6 +2061,7 @@ QString QTime::toString(Qt::DateFormat format) const switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toString(*this, QLocale::ShortFormat); @@ -2043,6 +2072,7 @@ QString QTime::toString(Qt::DateFormat format) const return QLocale().toString(*this, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toString(*this, QLocale::LongFormat); +QT_WARNING_POP #endif // 5.15 case Qt::ISODateWithMs: return QString::asprintf("%02d:%02d:%02d.%03d", hour(), minute(), second(), msec()); @@ -2434,6 +2464,7 @@ QTime QTime::fromString(const QString &string, Qt::DateFormat format) switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toTime(string, QLocale::ShortFormat); @@ -2444,6 +2475,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); +QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: return rfcDateImpl(string).time; @@ -4279,14 +4311,9 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) #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. If \cal is - supplied, it determines the calendar used to represent the date; it defaults - to Gregorian. + Returns the datetime as a string in the \a format given. 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 @@ -4329,37 +4356,34 @@ 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) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: - return QLocale::system().toString(*this, QLocale::ShortFormat, cal); + return QLocale::system().toString(*this, QLocale::ShortFormat); case Qt::SystemLocaleLongDate: - return QLocale::system().toString(*this, QLocale::LongFormat, cal); + return QLocale::system().toString(*this, QLocale::LongFormat); case Qt::LocaleDate: case Qt::DefaultLocaleShortDate: - return QLocale().toString(*this, QLocale::ShortFormat, cal); + return QLocale().toString(*this, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: - return QLocale().toString(*this, QLocale::LongFormat, cal); + return QLocale().toString(*this, QLocale::LongFormat); +QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: { - buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss ", cal); + buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss "); buf += toOffsetString(Qt::TextDate, offsetFromUtc()); return buf; } default: case Qt::TextDate: { const QPair<QDate, QTime> p = getDateTime(d); - buf = toStringTextDate(p.first, cal); + buf = toStringTextDate(p.first); // Insert time between date's day and year: buf.insert(buf.lastIndexOf(QLatin1Char(' ')), QLatin1Char(' ') + p.second.toString(Qt::TextDate)); @@ -4381,7 +4405,6 @@ QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const } case Qt::ISODate: case Qt::ISODateWithMs: { - // No calendar dependence const QPair<QDate, QTime> p = getDateTime(d); buf = toStringIsoDate(p.first); if (buf.isEmpty()) @@ -4412,7 +4435,7 @@ QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) 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. If \cal is supplied, it determines the calendar + format of the result string. If \a 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. @@ -5228,6 +5251,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) switch (format) { #if QT_DEPRECATED_SINCE(5, 15) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toDateTime(string, QLocale::ShortFormat); @@ -5238,6 +5262,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); +QT_WARNING_POP #endif // 5.15 case Qt::RFC2822Date: { const ParsedRfcDateTime rfc = rfcDateImpl(string); diff --git a/src/corelib/time/qdatetime.h b/src/corelib/time/qdatetime.h index c1653b5585..645923ada8 100644 --- a/src/corelib/time/qdatetime.h +++ b/src/corelib/time/qdatetime.h @@ -111,7 +111,11 @@ public: #endif // textdate && deprecated #if QT_CONFIG(datestring) QString toString(Qt::DateFormat format = Qt::TextDate) const; +#if QT_DEPRECATED_SINCE(5, 15) + // Only the deprecated locale-dependent formats use the calendar. + QT_DEPRECATED_X("Use QLocale or omit the calendar") QString toString(Qt::DateFormat format, QCalendar cal) const; +#endif #if QT_STRINGVIEW_LEVEL < 2 QString toString(const QString &format) const; @@ -334,7 +338,6 @@ public: #if QT_CONFIG(datestring) 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; diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index 9b9c67e42b..6d2b8f7a3e 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 QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(typename QMultiMap<Key, T>::const_iterator pos, const Key &key, const T &value) +/*! \fn [qmultimap-insert-pos] 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 @@ -2128,7 +2128,8 @@ void QMapDataBase::freeData(QMapDataBase *d) once in the returned list. */ -/*! \fn template <class Key, class T> QMultiMap<Key, T> &QMultiMap<Key, T>::unite(const QMultiMap<Key, T> &other) +/*! + \fn [qmultimap-unite] template <class Key, class T> QMultiMap<Key, T> &QMultiMap<Key, T>::unite(const QMultiMap<Key, T> &other) Inserts all the items in the \a other map into this map. If a key is common to both maps, the resulting map will contain the diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index a70b355c67..a971919e54 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -1086,14 +1086,14 @@ public: QList<Key> uniqueKeys() const; QList<T> values(const Key &key) const; - using typename QMap<Key, T>::iterator; - using typename QMap<Key, T>::const_iterator; - inline typename QMap<Key, T>::iterator replace(const Key &key, const T &value) { return QMap<Key, T>::insert(key, value); } - iterator insert(const Key &key, const T &value); - iterator insert(const_iterator pos, const Key &key, const T &value); + typename QMap<Key, T>::iterator insert(const Key &key, const T &value); + //! [qmultimap-insert-pos] + typename QMap<Key, T>::iterator insert(typename QMap<Key, T>::const_iterator pos, + const Key &key, const T &value); + //! [qmultimap-unite] QMultiMap &unite(const QMultiMap &other); inline QMultiMap &operator+=(const QMultiMap &other) { return unite(other); } @@ -1151,7 +1151,7 @@ Q_OUTOFLINE_TEMPLATE QList<Key> QMultiMap<Key, T>::uniqueKeys() const { QList<Key> res; res.reserve(size()); // May be too much, but assume short lifetime - const_iterator i = this->begin(); + typename QMap<Key, T>::const_iterator i = this->begin(); if (i != this->end()) { for (;;) { const Key &aKey = i.key(); @@ -1172,7 +1172,7 @@ Q_OUTOFLINE_TEMPLATE QList<T> QMultiMap<Key, T>::values(const Key &akey) const QList<T> res; Node *n = this->d->findNode(akey); if (n) { - const_iterator it(n); + typename QMap<Key, T>::const_iterator it(n); do { res.append(*it); ++it; @@ -1182,8 +1182,8 @@ Q_OUTOFLINE_TEMPLATE QList<T> QMultiMap<Key, T>::values(const Key &akey) const } template <class Key, class T> -Q_INLINE_TEMPLATE typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(const Key &akey, - const T &avalue) +Q_INLINE_TEMPLATE typename QMap<Key, T>::iterator QMultiMap<Key, T>::insert(const Key &akey, + const T &avalue) { detach(); Node* y = this->d->end(); @@ -1195,11 +1195,13 @@ Q_INLINE_TEMPLATE typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert x = left ? x->leftNode() : x->rightNode(); } Node *z = this->d->createNode(akey, avalue, y, left); - return iterator(z); + return typename QMap<Key, T>::iterator(z); } +#ifndef Q_CLANG_QDOC template <class Key, class T> -typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(const_iterator pos, const Key &akey, const T &avalue) +typename QMap<Key, T>::iterator QMultiMap<Key, T>::insert(typename QMap<Key, T>::const_iterator pos, + const Key &akey, const T &avalue) { if (this->d->ref.isShared()) return insert(akey, avalue); @@ -1216,7 +1218,7 @@ typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(const_iterator po if (!qMapLessThanKey(n->key, akey)) return insert(akey, avalue); // ignore hint Node *z = this->d->createNode(akey, avalue, n, false); // insert right most - return iterator(z); + return typename QMap<Key, T>::iterator(z); } return insert(akey, avalue); } else { @@ -1229,7 +1231,7 @@ typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(const_iterator po if (pos == this->constBegin()) { // There is no previous value (insert left most) Node *z = this->d->createNode(akey, avalue, this->begin().i, true); - return iterator(z); + return typename QMap<Key, T>::iterator(z); } else { Node *prev = const_cast<Node*>(pos.i->previousNode()); if (!qMapLessThanKey(prev->key, akey)) @@ -1238,11 +1240,11 @@ typename QMultiMap<Key, T>::iterator QMultiMap<Key, T>::insert(const_iterator po // Hint is ok - do insert if (prev->right == nullptr) { Node *z = this->d->createNode(akey, avalue, prev, false); - return iterator(z); + return typename QMap<Key, T>::iterator(z); } if (next->left == nullptr) { Node *z = this->d->createNode(akey, avalue, next, true); - return iterator(z); + return typename QMap<Key, T>::iterator(z); } Q_ASSERT(false); // We should have prev->right == nullptr or next->left == nullptr. return insert(akey, avalue); @@ -1254,14 +1256,15 @@ template <class Key, class T> Q_INLINE_TEMPLATE QMultiMap<Key, T> &QMultiMap<Key, T>::unite(const QMultiMap<Key, T> &other) { QMultiMap<Key, T> copy(other); - const_iterator it = copy.constEnd(); - const const_iterator b = copy.constBegin(); + typename QMap<Key, T>::const_iterator it = copy.constEnd(); + const typename QMap<Key, T>::const_iterator b = copy.constBegin(); while (it != b) { --it; insert(it.key(), it.value()); } return *this; } +#endif // Q_CLANG_QDOC template <class Key, class T> Q_INLINE_TEMPLATE bool QMultiMap<Key, T>::contains(const Key &key, const T &value) const @@ -1293,8 +1296,8 @@ Q_INLINE_TEMPLATE int QMultiMap<Key, T>::count(const Key &akey) const QMultiMap::Node *lastNode; this->d->nodeRange(akey, &firstNode, &lastNode); - const_iterator ci_first(firstNode); - const const_iterator ci_last(lastNode); + typename QMap<Key, T>::const_iterator ci_first(firstNode); + const typename QMap<Key, T>::const_iterator ci_last(lastNode); int cnt = 0; while (ci_first != ci_last) { ++cnt; diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc index a0e9abe0ae..d530e4358e 100644 --- a/src/corelib/tools/qvarlengtharray.qdoc +++ b/src/corelib/tools/qvarlengtharray.qdoc @@ -903,7 +903,7 @@ */ /*! - template <typename T, int Prealloc> uint qHash(const QVarLengthArray<T, Prealloc> &key, uint seed = 0) + \fn template <typename T, int Prealloc> uint qHash(const QVarLengthArray<T, Prealloc> &key, uint seed = 0) \relates QVarLengthArray \since 5.14 diff --git a/src/gui/.prev_CMakeLists.txt b/src/gui/.prev_CMakeLists.txt index 953dc8b2da..36e53a0edc 100644 --- a/src/gui/.prev_CMakeLists.txt +++ b/src/gui/.prev_CMakeLists.txt @@ -494,7 +494,7 @@ qt_extend_target(Gui CONDITION QT_FEATURE_textmarkdownreader ) qt_extend_target(Gui CONDITION QT_FEATURE_system_textmarkdownreader AND QT_FEATURE_textmarkdownreader - PUBLIC_LIBRARIES + LIBRARIES libmd4c ) diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 14859069a5..eb3b07fdae 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -599,7 +599,7 @@ qt_extend_target(Gui CONDITION QT_FEATURE_textmarkdownreader ) qt_extend_target(Gui CONDITION QT_FEATURE_system_textmarkdownreader AND QT_FEATURE_textmarkdownreader - PUBLIC_LIBRARIES + LIBRARIES libmd4c ) diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index a9c0fbbe3e..5a1524b419 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -231,7 +231,8 @@ public: bool hasAlphaChannel() const; void setAlphaChannel(const QImage &alphaChannel); #if QT_DEPRECATED_SINCE(5, 15) - QT_DEPRECATED QImage alphaChannel() const; + QT_DEPRECATED_X("Use convertToFormat(QImage::Format_Alpha8)") + QImage alphaChannel() const; #endif QImage createAlphaMask(Qt::ImageConversionFlags flags = Qt::AutoColor) const; #ifndef QT_NO_IMAGE_HEURISTIC_MASK diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index c2dac71e0d..5ad37ae640 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -2368,6 +2368,7 @@ QTabletEvent::QTabletEvent(Type type, const QPointF &pos, const QPointF &globalP { } +#if QT_DEPRECATED_SINCE(5, 15) /*! Construct a tablet event of the given \a type. @@ -2411,6 +2412,7 @@ QTabletEvent::QTabletEvent(Type type, const QPointF &pos, const QPointF &globalP tangentialPressure, rotation, z, keyState, uniqueID, Qt::NoButton, Qt::NoButton) { } +#endif /*! \internal @@ -2451,6 +2453,12 @@ Qt::MouseButtons QTabletEvent::buttons() const /*! \fn TabletDevices QTabletEvent::device() const + \deprecated Use deviceType(). +*/ + +/*! + \fn TabletDevices QTabletEvent::deviceType() const + Returns the type of device that generated the event. \sa TabletDevice @@ -2615,12 +2623,16 @@ Qt::MouseButtons QTabletEvent::buttons() const \fn qreal &QTabletEvent::hiResGlobalX() const The high precision x position of the tablet device. + + \obsolete use globalPosF() */ /*! \fn qreal &QTabletEvent::hiResGlobalY() const The high precision y position of the tablet device. + + \obsolete use globalPosF() */ /*! diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 6f3215652b..87ec8e7bee 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -280,10 +280,15 @@ public: Q_ENUM(TabletDevice) enum PointerType { UnknownPointer, Pen, Cursor, Eraser }; Q_ENUM(PointerType) + +#if QT_DEPRECATED_SINCE(5, 15) + // Actually deprecated since 5.4, in docs + QT_DEPRECATED_VERSION_X_5_15("Use the other QTabletEvent constructor") QTabletEvent(Type t, const QPointF &pos, const QPointF &globalPos, int device, int pointerType, qreal pressure, int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, Qt::KeyboardModifiers keyState, qint64 uniqueID); // ### remove in Qt 6 +#endif QTabletEvent(Type t, const QPointF &pos, const QPointF &globalPos, int device, int pointerType, qreal pressure, int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, @@ -304,9 +309,15 @@ public: inline int y() const { return qRound(mPos.y()); } inline int globalX() const { return qRound(mGPos.x()); } inline int globalY() const { return qRound(mGPos.y()); } +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_VERSION_X_5_15("use globalPosF().x()") inline qreal hiResGlobalX() const { return mGPos.x(); } + QT_DEPRECATED_VERSION_X_5_15("use globalPosF().y()") inline qreal hiResGlobalY() const { return mGPos.y(); } + QT_DEPRECATED_VERSION_X_5_15("Use deviceType()") inline TabletDevice device() const { return TabletDevice(mDev); } +#endif + inline TabletDevice deviceType() const { return TabletDevice(mDev); } inline PointerType pointerType() const { return PointerType(mPointerType); } inline qint64 uniqueId() const { return mUnique; } inline qreal pressure() const { return mPress; } diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 1f8d8d21e9..5a9274e4f3 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -610,7 +610,7 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME \li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and \c none disables them. - \li \c {dpiawareness=[0|1|2} Sets the DPI awareness of the process + \li \c {dpiawareness=[0|1|2]} Sets the DPI awareness of the process (see \l{High DPI Displays}, since Qt 5.4). \li \c {fontengine=freetype}, uses the FreeType font engine. \li \c {fontengine=directwrite}, uses the experimental DirectWrite @@ -1738,6 +1738,8 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() window_list.clear(); screen_list.clear(); + + self = nullptr; } #if 0 @@ -1891,6 +1893,10 @@ bool QGuiApplication::event(QEvent *e) { if(e->type() == QEvent::LanguageChange) { setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight); + for (auto *topLevelWindow : QGuiApplication::topLevelWindows()) { + if (topLevelWindow->flags() != Qt::Desktop) + postEvent(topLevelWindow, new QEvent(QEvent::LanguageChange)); + } } else if (e->type() == QEvent::Quit) { // Close open windows. This is done in order to deliver de-expose // events while the event loop is still running. @@ -3412,8 +3418,11 @@ void QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(QWindow *window) */ QFont QGuiApplication::font() { - Q_ASSERT_X(QGuiApplicationPrivate::self, "QGuiApplication::font()", "no QGuiApplication instance"); const auto locker = qt_scoped_lock(applicationFontMutex); + if (!QGuiApplicationPrivate::self && !QGuiApplicationPrivate::app_font) { + qWarning("QGuiApplication::font(): no QGuiApplication instance and no application font set."); + return QFont(); // in effect: QFont((QFontPrivate*)nullptr), so no recursion + } initFontUnlocked(); return *QGuiApplicationPrivate::app_font; } diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index e544fce70e..eac2a50c8c 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -3224,6 +3224,7 @@ const uint qt_inv_premul_factor[256] = { /*! \namespace QColorConstants \inmodule QtGui + \since 5.14 \brief The QColorConstants namespace contains QColor predefined constants. diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp index 18f212f8e9..2b5cd58fb1 100644 --- a/src/gui/painting/qicc.cpp +++ b/src/gui/painting/qicc.cpp @@ -87,6 +87,11 @@ constexpr quint32 IccTag(uchar a, uchar b, uchar c, uchar d) return (a << 24) | (b << 16) | (c << 8) | d; } +enum class ColorSpaceType : quint32 { + Rgb = IccTag('R', 'G', 'B', ' '), + Gray = IccTag('G', 'R', 'A', 'Y'), +}; + enum class ProfileClass : quint32 { Input = IccTag('s', 'c', 'r', 'n'), Display = IccTag('m', 'n', 't', 'r'), @@ -105,6 +110,7 @@ enum class Tag : quint32 { rTRC = IccTag('r', 'T', 'R', 'C'), gTRC = IccTag('g', 'T', 'R', 'C'), bTRC = IccTag('b', 'T', 'R', 'C'), + kTRC = IccTag('k', 'T', 'R', 'C'), A2B0 = IccTag('A', '2', 'B', '0'), A2B1 = IccTag('A', '2', 'B', '1'), B2A0 = IccTag('B', '2', 'A', '0'), @@ -219,8 +225,10 @@ static bool isValidIccProfile(const ICCProfileHeader &header) } // Don't overflow 32bit integers: - if (header.tagCount >= INT32_MAX / sizeof(TagTableEntry)) + if (header.tagCount >= INT32_MAX / sizeof(TagTableEntry)) { + qCWarning(lcIcc, "Failed tag count sanity"); return false; + } if (header.profileSize - sizeof(ICCProfileHeader) < header.tagCount * sizeof(TagTableEntry)) { qCWarning(lcIcc, "Failed basic size sanity"); return false; @@ -231,7 +239,8 @@ static bool isValidIccProfile(const ICCProfileHeader &header) qCWarning(lcIcc, "Unsupported ICC profile class %x", quint32(header.profileClass)); return false; } - if (header.inputColorSpace != 0x52474220 /* 'RGB '*/) { + if (header.inputColorSpace != uint(ColorSpaceType::Rgb) + && header.inputColorSpace != uint(ColorSpaceType::Gray)) { qCWarning(lcIcc, "Unsupported ICC input color space %x", quint32(header.inputColorSpace)); return false; } @@ -610,10 +619,8 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace) return false; } const ICCProfileHeader *header = (const ICCProfileHeader *)data.constData(); - if (!isValidIccProfile(*header)) { - qCWarning(lcIcc) << "fromIccProfile: failed general sanity check"; - return false; - } + if (!isValidIccProfile(*header)) + return false; // if failed we already printing a warning if (qsizetype(header->profileSize) > data.size()) { qCWarning(lcIcc) << "fromIccProfile: failed size sanity 2"; return false; @@ -658,39 +665,74 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace) } // Check the profile is three-component matrix based (what we currently support): - if (!tagIndex.contains(Tag::rXYZ) || !tagIndex.contains(Tag::gXYZ) || !tagIndex.contains(Tag::bXYZ) || - !tagIndex.contains(Tag::rTRC) || !tagIndex.contains(Tag::gTRC) || !tagIndex.contains(Tag::bTRC) || - !tagIndex.contains(Tag::wtpt)) { - qCWarning(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based"; - return false; + if (header->inputColorSpace == uint(ColorSpaceType::Rgb)) { + if (!tagIndex.contains(Tag::rXYZ) || !tagIndex.contains(Tag::gXYZ) || !tagIndex.contains(Tag::bXYZ) || + !tagIndex.contains(Tag::rTRC) || !tagIndex.contains(Tag::gTRC) || !tagIndex.contains(Tag::bTRC) || + !tagIndex.contains(Tag::wtpt)) { + qCWarning(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based"; + return false; + } + } else { + Q_ASSERT(header->inputColorSpace == uint(ColorSpaceType::Gray)); + if (!tagIndex.contains(Tag::kTRC) || !tagIndex.contains(Tag::wtpt)) { + qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - not valid gray scale based"; + return false; + } } QColorSpacePrivate *colorspaceDPtr = QColorSpacePrivate::getWritable(*colorSpace); - // Parse XYZ tags - if (!parseXyzData(data, tagIndex[Tag::rXYZ], colorspaceDPtr->toXyz.r)) - return false; - if (!parseXyzData(data, tagIndex[Tag::gXYZ], colorspaceDPtr->toXyz.g)) - return false; - if (!parseXyzData(data, tagIndex[Tag::bXYZ], colorspaceDPtr->toXyz.b)) - return false; - if (!parseXyzData(data, tagIndex[Tag::wtpt], colorspaceDPtr->whitePoint)) - return false; + if (header->inputColorSpace == uint(ColorSpaceType::Rgb)) { + // Parse XYZ tags + if (!parseXyzData(data, tagIndex[Tag::rXYZ], colorspaceDPtr->toXyz.r)) + return false; + if (!parseXyzData(data, tagIndex[Tag::gXYZ], colorspaceDPtr->toXyz.g)) + return false; + if (!parseXyzData(data, tagIndex[Tag::bXYZ], colorspaceDPtr->toXyz.b)) + return false; + if (!parseXyzData(data, tagIndex[Tag::wtpt], colorspaceDPtr->whitePoint)) + return false; - colorspaceDPtr->primaries = QColorSpace::Primaries::Custom; - if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) { - qCDebug(lcIcc) << "fromIccProfile: sRGB primaries detected"; - colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb; - } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromAdobeRgb()) { - qCDebug(lcIcc) << "fromIccProfile: Adobe RGB primaries detected"; - colorspaceDPtr->primaries = QColorSpace::Primaries::AdobeRgb; - } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) { - qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected"; - colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65; - } - if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) { - qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected"; - colorspaceDPtr->primaries = QColorSpace::Primaries::ProPhotoRgb; + colorspaceDPtr->primaries = QColorSpace::Primaries::Custom; + if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) { + qCDebug(lcIcc) << "fromIccProfile: sRGB primaries detected"; + colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb; + } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromAdobeRgb()) { + qCDebug(lcIcc) << "fromIccProfile: Adobe RGB primaries detected"; + colorspaceDPtr->primaries = QColorSpace::Primaries::AdobeRgb; + } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) { + qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected"; + colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65; + } + if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) { + qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected"; + colorspaceDPtr->primaries = QColorSpace::Primaries::ProPhotoRgb; + } + } else { + // We will use sRGB primaries and fit to match the given white-point if + // it doesn't match sRGB's. + QColorVector whitePoint; + if (!parseXyzData(data, tagIndex[Tag::wtpt], whitePoint)) + return false; + if (!qFuzzyCompare(whitePoint.y, 1.0f) || (1.0f + whitePoint.z - whitePoint.x) == 0.0f) { + qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - gray white-point not normalized"; + return false; + } + if (whitePoint == QColorVector::D65()) { + colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb; + } else { + colorspaceDPtr->primaries = QColorSpace::Primaries::Custom; + // Calculate chromaticity from xyz (assuming y == 1.0f). + float y = 1.0f / (1.0f + whitePoint.z - whitePoint.x); + float x = whitePoint.x * y; + QColorSpacePrimaries primaries(QColorSpace::Primaries::SRgb); + primaries.whitePoint = QPointF(x,y); + if (!primaries.areValid()) { + qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - invalid white-point"; + return false; + } + colorspaceDPtr->toXyz = primaries.toXyzMatrix(); + } } // Reset the matrix to our canonical values: if (colorspaceDPtr->primaries != QColorSpace::Primaries::Custom) @@ -700,7 +742,11 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace) TagEntry rTrc; TagEntry gTrc; TagEntry bTrc; - if (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) { + if (header->inputColorSpace == uint(ColorSpaceType::Gray)) { + rTrc = tagIndex[Tag::kTRC]; + gTrc = tagIndex[Tag::kTRC]; + bTrc = tagIndex[Tag::kTRC]; + } else if (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) { // Apple extension for parametric version of TRCs in ICCv2: rTrc = tagIndex[Tag::aarg]; gTrc = tagIndex[Tag::aagg]; diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index f0bf19bd91..7a0d53e1e4 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -577,6 +577,11 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") specifying a non-zero level in QRhiReadbackDescription leads to returning an all-zero image. In practice this feature will be unsupported with OpenGL ES 2.0, while it will likely be supported everywhere else. + + \value TexelFetch Indicates that texelFetch() is available in shaders. In + practice this will be reported as unsupported with OpenGL ES 2.0 and OpenGL + 2.x contexts, because GLSL 100 es and versions before 130 do not support + this function. */ /*! @@ -622,18 +627,27 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") is what some OpenGL ES implementations provide. \value FramesInFlight The number of frames the backend may keep "in - flight". The value has no relevance, and is unspecified, with backends like - OpenGL and Direct3D 11. With backends like Vulkan or Metal, it is the - responsibility of QRhi to block whenever starting a new frame and finding - the CPU is already \c{N - 1} frames ahead of the GPU (because the command - buffer submitted in frame no. \c{current} - \c{N} has not yet completed). - The value N is what is returned from here, and is typically 2. This can be - relevant to applications that integrate rendering done directly with the - graphics API, as such rendering code may want to perform double (if the - value is 2) buffering for resources, such as, buffers, similarly to the - QRhi backends themselves. The current frame slot index (a value running 0, - 1, .., N-1, then wrapping around) is retrievable from - QRhi::currentFrameSlot(). + flight": with backends like Vulkan or Metal, it is the responsibility of + QRhi to block whenever starting a new frame and finding the CPU is already + \c{N - 1} frames ahead of the GPU (because the command buffer submitted in + frame no. \c{current} - \c{N} has not yet completed). The value N is what + is returned from here, and is typically 2. This can be relevant to + applications that integrate rendering done directly with the graphics API, + as such rendering code may want to perform double (if the value is 2) + buffering for resources, such as, buffers, similarly to the QRhi backends + themselves. The current frame slot index (a value running 0, 1, .., N-1, + then wrapping around) is retrievable from QRhi::currentFrameSlot(). The + value is 1 for backends where the graphics API offers no such low level + control over the command submission process. Note that pipelining may still + happen even when this value is 1 (some backends, such as D3D11, are + designed to attempt to enable this, for instance, by using an update + strategy for uniform buffers that does not stall the pipeline), but that is + then not controlled by QRhi and so not reflected here in the API. + + \value MaxAsyncReadbackFrames The number of \l{QRhi::endFrame()}{submitted} + frames (including the one that contains the readback) after which an + asynchronous texture or buffer readback is guaranteed to complete upon + \l{QRhi::beginFrame()}{starting a new frame}. */ /*! @@ -1946,6 +1960,40 @@ quint64 QRhiResource::globalResourceId() const */ /*! + \class QRhiBuffer::NativeBuffer + \brief Contains information about the underlying native resources of a buffer. + */ + +/*! + \variable QRhiBuffer::NativeBuffer::objects + \brief an array with pointers to the native object handles. + + With OpenGL, the native handle is a GLuint value, so the elements in the \c + objects array are pointers to a GLuint. With Vulkan, the native handle is a + VkBuffer, so the elements of the array are pointers to a VkBuffer. With + Direct3D 11 and Metal the elements are pointers to a ID3D11Buffer or + MTLBuffer pointer, respectively. + + \note Pay attention to the fact that the elements are always pointers to + the native buffer handle type, even if the native type itself is a pointer. + */ + +/*! + \variable QRhiBuffer::NativeBuffer::slotCount + \brief Specifies the number of valid elements in the objects array. + + The value can be 0, 1, 2, or 3 in practice. 0 indicates that the QRhiBuffer + is not backed by any native buffer objects. This can happen with + QRhiBuffers with the usage UniformBuffer when the underlying API does not + support (or the backend chooses not to use) native uniform buffers. 1 is + commonly used for Immutable and Static types (but some backends may + differ). 2 or 3 is typical when the type is Dynamic (but some backends may + differ). + + \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight + */ + +/*! \internal */ QRhiBuffer::QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, int size_) @@ -1974,6 +2022,46 @@ QRhiResource::Type QRhiBuffer::resourceType() const */ /*! + \return the underlying native resources for this buffer. The returned value + will be empty if exposing the underlying native resources is not supported by + the backend. + + A QRhiBuffer may be backed by multiple native buffer objects, depending on + the type() and the QRhi backend in use. When this is the case, all of them + are returned in the objects array in the returned struct, with slotCount + specifying the number of native buffer objects. While + \l{QRhi::beginFrame()}{recording a frame}, QRhi::currentFrameSlot() can be + used to determine which of the native buffers QRhi is using for operations + that read or write from this QRhiBuffer within the frame being recorded. + + In some cases a QRhiBuffer will not be backed by a native buffer object at + all. In this case slotCount will be set to 0 and no valid native objects + are returned. This is not an error, and is perfectly valid when a given + backend does not use native buffers for QRhiBuffers with certain types or + usages. + + \note Be aware that QRhi backends may employ various buffer update + strategies. Unlike textures, where uploading image data always means + recording a buffer-to-image (or similar) copy command on the command + buffer, buffers, in particular Dynamic and UniformBuffer ones, can operate + in many different ways. For example, a QRhiBuffer with usage type + UniformBuffer may not even be backed by a native buffer object at all if + uniform buffers are not used or supported by a given backend and graphics + API. There are also differences to how data is written to the buffer and + the type of backing memory used, and, if host visible memory is involved, + when memory writes become available and visible. Therefore, in general it + is recommended to limit native buffer object access to vertex and index + buffers with types Static or Immutable, because these operate in a + relatively uniform manner with all backends. + + \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight + */ +QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer() +{ + return {}; +} + +/*! \class QRhiRenderBuffer \internal \inmodule QtGui @@ -4334,7 +4422,15 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *da is supported only when the QRhi::ReadBackNonUniformBuffer feature is reported as supported. - \a readBackTexture(), QRhi::isFeatureSupported() + \note The asynchronous readback is guaranteed to have completed when one of + the following conditions is met: \l{QRhi::finish()}{finish()} has been + called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, + including the frame that issued the readback operation, and the + \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c + N is the \l{QRhi::resourceLimit()}{resource limit value} returned for + QRhi::MaxAsyncReadbackFrames. + + \sa readBackTexture(), QRhi::isFeatureSupported(), QRhi::resourceLimit() */ void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result) { @@ -4425,6 +4521,16 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, co happens with a byte ordered format. A \l{QRhiTexture::RGBA8}{RGBA8} texture maps therefore to byte ordered QImage formats, such as, QImage::Format_RGBA8888. + + \note The asynchronous readback is guaranteed to have completed when one of + the following conditions is met: \l{QRhi::finish()}{finish()} has been + called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, + including the frame that issued the readback operation, and the + \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c + N is the \l{QRhi::resourceLimit()}{resource limit value} returned for + QRhi::MaxAsyncReadbackFrames. + + \sa readBackBuffer(), QRhi::resourceLimit() */ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result) { diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index d17112a241..8f53808d34 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -681,6 +681,11 @@ public: }; Q_DECLARE_FLAGS(UsageFlags, UsageFlag) + struct NativeBuffer { + const void *objects[3]; + int slotCount; + }; + QRhiResource::Type resourceType() const override; Type type() const { return m_type; } @@ -694,6 +699,8 @@ public: virtual bool build() = 0; + virtual NativeBuffer nativeBuffer(); + protected: QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, int size_); Type m_type; @@ -1430,7 +1437,8 @@ public: BaseInstance, TriangleFanTopology, ReadBackNonUniformBuffer, - ReadBackNonBaseMipLevel + ReadBackNonBaseMipLevel, + TexelFetch }; enum BeginFrameFlag { @@ -1447,7 +1455,8 @@ public: TextureSizeMin = 1, TextureSizeMax, MaxColorAttachments, - FramesInFlight + FramesInFlight, + MaxAsyncReadbackFrames }; ~QRhi(); diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 75b90b6995..f7c7f4a9f2 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -464,6 +464,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::ReadBackNonBaseMipLevel: return true; + case QRhi::TexelFetch: + return true; default: Q_UNREACHABLE(); return false; @@ -480,7 +482,13 @@ int QRhiD3D11::resourceLimit(QRhi::ResourceLimit limit) const case QRhi::MaxColorAttachments: return 8; case QRhi::FramesInFlight: - return 2; // dummy + // From our perspective. What D3D does internally is another question + // (there could be pipelining, helped f.ex. by our MAP_DISCARD based + // uniform buffer update strategy), but that's out of our hands and + // does not concern us here. + return 1; + case QRhi::MaxAsyncReadbackFrames: + return 1; default: Q_UNREACHABLE(); return 0; @@ -2378,6 +2386,11 @@ bool QD3D11Buffer::build() return true; } +QRhiBuffer::NativeBuffer QD3D11Buffer::nativeBuffer() +{ + return { { &buffer }, 1 }; +} + ID3D11UnorderedAccessView *QD3D11Buffer::unorderedAccessView() { if (uav) diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index c3a4021241..04751397f7 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -64,6 +64,7 @@ struct QD3D11Buffer : public QRhiBuffer ~QD3D11Buffer(); void release() override; bool build() override; + QRhiBuffer::NativeBuffer nativeBuffer() override; ID3D11UnorderedAccessView *unorderedAccessView(); diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 3b6c022399..4a442bc582 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -512,6 +512,8 @@ bool QRhiGles2::create(QRhi::Flags flags) else caps.nonBaseLevelFramebufferTexture = true; + caps.texelFetch = caps.ctxMajor >= 3; // 3.0 or ES 3.0 + if (!caps.gles) { f->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); f->glEnable(GL_POINT_SPRITE); @@ -765,6 +767,8 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const return !caps.gles || caps.properMapBuffer; case QRhi::ReadBackNonBaseMipLevel: return caps.nonBaseLevelFramebufferTexture; + case QRhi::TexelFetch: + return caps.texelFetch; default: Q_UNREACHABLE(); return false; @@ -781,7 +785,11 @@ int QRhiGles2::resourceLimit(QRhi::ResourceLimit limit) const case QRhi::MaxColorAttachments: return caps.maxDrawBuffers; case QRhi::FramesInFlight: - return 2; // dummy + // From our perspective. What the GL impl does internally is another + // question, but that's out of our hands and does not concern us here. + return 1; + case QRhi::MaxAsyncReadbackFrames: + return 1; default: Q_UNREACHABLE(); return 0; @@ -3293,6 +3301,14 @@ bool QGles2Buffer::build() return true; } +QRhiBuffer::NativeBuffer QGles2Buffer::nativeBuffer() +{ + if (m_usage.testFlag(QRhiBuffer::UniformBuffer)) + return { {}, 0 }; + + return { { &buffer }, 1 }; +} + QGles2RenderBuffer::QGles2RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags) diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index 00caf40118..8b7d01532a 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -64,6 +64,7 @@ struct QGles2Buffer : public QRhiBuffer ~QGles2Buffer(); void release() override; bool build() override; + QRhiBuffer::NativeBuffer nativeBuffer() override; GLuint buffer = 0; GLenum targetForDataOps; @@ -778,7 +779,8 @@ public: compute(false), textureCompareMode(false), properMapBuffer(false), - nonBaseLevelFramebufferTexture(false) + nonBaseLevelFramebufferTexture(false), + texelFetch(false) { } int ctxMajor; int ctxMinor; @@ -811,6 +813,7 @@ public: uint textureCompareMode : 1; uint properMapBuffer : 1; uint nonBaseLevelFramebufferTexture : 1; + uint texelFetch : 1; } caps; QGles2SwapChain *currentSwapChain = nullptr; QVector<GLint> supportedCompressedFormats; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 9e8f1ac096..48a562ef1d 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -562,6 +562,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::ReadBackNonBaseMipLevel: return true; + case QRhi::TexelFetch: + return true; default: Q_UNREACHABLE(); return false; @@ -579,6 +581,8 @@ int QRhiMetal::resourceLimit(QRhi::ResourceLimit limit) const return 8; case QRhi::FramesInFlight: return QMTL_FRAMES_IN_FLIGHT; + case QRhi::MaxAsyncReadbackFrames: + return QMTL_FRAMES_IN_FLIGHT; default: Q_UNREACHABLE(); return 0; @@ -2196,6 +2200,19 @@ bool QMetalBuffer::build() return true; } +QRhiBuffer::NativeBuffer QMetalBuffer::nativeBuffer() +{ + if (d->slotted) { + NativeBuffer b; + Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QMTL_FRAMES_IN_FLIGHT)); + for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) + b.objects[i] = &d->buf[i]; + b.slotCount = QMTL_FRAMES_IN_FLIGHT; + return b; + } + return { { &d->buf[0] }, 1 }; +} + QMetalRenderBuffer::QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags), diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 58e93e2cdb..212b731b71 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -65,6 +65,7 @@ struct QMetalBuffer : public QRhiBuffer ~QMetalBuffer(); void release() override; bool build() override; + QRhiBuffer::NativeBuffer nativeBuffer() override; QMetalBufferData *d; uint generation = 0; diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index 4c59900aa6..8c07e09b32 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -146,7 +146,9 @@ int QRhiNull::resourceLimit(QRhi::ResourceLimit limit) const case QRhi::MaxColorAttachments: return 8; case QRhi::FramesInFlight: - return 2; // dummy + return 1; + case QRhi::MaxAsyncReadbackFrames: + return 1; default: Q_UNREACHABLE(); return 0; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 84ca835392..d378e2a4ad 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -3990,6 +3990,8 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::ReadBackNonBaseMipLevel: return true; + case QRhi::TexelFetch: + return true; default: Q_UNREACHABLE(); return false; @@ -4007,6 +4009,8 @@ int QRhiVulkan::resourceLimit(QRhi::ResourceLimit limit) const return int(physDevProperties.limits.maxColorAttachments); case QRhi::FramesInFlight: return QVK_FRAMES_IN_FLIGHT; + case QRhi::MaxAsyncReadbackFrames: + return QVK_FRAMES_IN_FLIGHT; default: Q_UNREACHABLE(); return 0; @@ -5181,6 +5185,19 @@ bool QVkBuffer::build() return true; } +QRhiBuffer::NativeBuffer QVkBuffer::nativeBuffer() +{ + if (m_type == Dynamic) { + NativeBuffer b; + Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QVK_FRAMES_IN_FLIGHT)); + for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) + b.objects[i] = &buffers[i]; + b.slotCount = QVK_FRAMES_IN_FLIGHT; + return b; + } + return { { &buffers[0] }, 1 }; +} + QVkRenderBuffer::QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, Flags flags) : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags) diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index d42b83b882..6322882569 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -76,6 +76,7 @@ struct QVkBuffer : public QRhiBuffer ~QVkBuffer(); void release() override; bool build() override; + QRhiBuffer::NativeBuffer nativeBuffer() override; VkBuffer buffers[QVK_FRAMES_IN_FLIGHT]; QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT]; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 46cfc79643..64ba01d4e5 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -904,6 +904,9 @@ int QTextDocument::lineCount() const Returns the number of characters of this document. + \note As a QTextDocument always contains at least one + QChar::ParagraphSeparator, this method will return at least 1. + \sa blockCount(), characterAt() */ int QTextDocument::characterCount() const diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 5e97b312f1..464ff3953b 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -99,7 +99,7 @@ qtConfig(textodfwriter) { qtConfig(textmarkdownreader) { qtConfig(system-textmarkdownreader) { - QMAKE_USE += libmd4c + QMAKE_USE_PRIVATE += libmd4c } else { include($$PWD/../../3rdparty/md4c.pri) } diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index 4beed8ed25..1ec25ccd7b 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -42,6 +42,8 @@ #include "qshaderlanguage_p.h" #include <QRegularExpression> +#include <cctype> + QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(ShaderGenerator, "ShaderGenerator", QtWarningMsg) @@ -344,10 +346,9 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) code << QByteArrayLiteral("void main()"); code << QByteArrayLiteral("{"); - const QRegularExpression localToGlobalRegExp(QStringLiteral("^.*\\s+(\\w+)\\s*=\\s*((?:\\w+\\(.*\\))|(?:\\w+)).*;$")); - const QRegularExpression temporaryVariableToAssignmentRegExp(QStringLiteral("^(.*\\s+(v\\d+))\\s*=\\s*(.*);$")); + const QRegularExpression temporaryVariableToAssignmentRegExp(QStringLiteral("([^;]*\\s+(v\\d+))\\s*=\\s*([^;]*);")); const QRegularExpression temporaryVariableInAssignmentRegExp(QStringLiteral("\\W*(v\\d+)\\W*")); - const QRegularExpression outputToTemporaryAssignmentRegExp(QStringLiteral("^\\s*(\\w+)\\s*=\\s*(.*);$")); + const QRegularExpression statementRegExp(QStringLiteral("\\s*(\\w+)\\s*=\\s*([^;]*);")); struct Variable; @@ -457,6 +458,13 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) QByteArray line = node.rule(format).substitution; const QVector<QShaderNodePort> ports = node.ports(); + struct VariableReplacement { + QByteArray placeholder; + QByteArray variable; + }; + + QVector<VariableReplacement> variableReplacements; + // Generate temporary variable names vN for (const QShaderNodePort &port : ports) { const QString portName = port.name; @@ -472,23 +480,65 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) if (variableIndex < 0) continue; - const auto placeholder = QByteArray(QByteArrayLiteral("$") + portName.toUtf8()); - const auto variable = QByteArray(QByteArrayLiteral("v") + QByteArray::number(variableIndex)); + VariableReplacement replacement; + replacement.placeholder = QByteArrayLiteral("$") + portName.toUtf8(); + replacement.variable = QByteArrayLiteral("v") + QByteArray::number(variableIndex); + + variableReplacements.append(std::move(replacement)); + } + + int begin = 0; + while ((begin = line.indexOf('$', begin)) != -1) { + int end = begin + 1; + char endChar = line.at(end); + const int size = line.size(); + while (end < size && (std::isalnum(endChar) || endChar == '_')) { + ++end; + endChar = line.at(end); + } + + const int placeholderLength = end - begin; + + const QByteArray variableName = line.mid(begin, placeholderLength); + const auto replacementIt = std::find_if(variableReplacements.cbegin(), variableReplacements.cend(), + [&variableName](const VariableReplacement &replacement) { + return variableName == replacement.placeholder; + }); - line.replace(placeholder, variable); + if (replacementIt != variableReplacements.cend()) { + line.replace(begin, placeholderLength, replacementIt->variable); + begin += replacementIt->variable.length(); + } else { + begin = end; + } } // Substitute variable names by generated vN variable names const QByteArray substitutionedLine = replaceParameters(line, node, format); - Variable *v = nullptr; + QRegularExpressionMatchIterator matches; switch (node.type()) { - // Record name of temporary variable that possibly references a global input - // We will replace the temporary variables by the matching global variables later - case QShaderNode::Input: { - const QRegularExpressionMatch match = localToGlobalRegExp.match(QString::fromUtf8(substitutionedLine)); - if (match.hasMatch()) { + case QShaderNode::Input: + case QShaderNode::Output: + matches = statementRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); + break; + case QShaderNode::Function: + matches = temporaryVariableToAssignmentRegExp.globalMatch(QString::fromUtf8(substitutionedLine)); + break; + case QShaderNode::Invalid: + break; + } + + while (matches.hasNext()) { + QRegularExpressionMatch match = matches.next(); + + Variable *v = nullptr; + + switch (node.type()) { + // Record name of temporary variable that possibly references a global input + // We will replace the temporary variables by the matching global variables later + case QShaderNode::Input: { const QString localVariable = match.captured(1); const QString globalVariable = match.captured(2); @@ -499,13 +549,10 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) Assignment assignment; assignment.expression = globalVariable; v->assignment = assignment; + break; } - break; - } - case QShaderNode::Function: { - const QRegularExpressionMatch match = temporaryVariableToAssignmentRegExp.match(QString::fromUtf8(substitutionedLine)); - if (match.hasMatch()) { + case QShaderNode::Function: { const QString localVariableDeclaration = match.captured(1); const QString localVariableName = match.captured(2); const QString assignmentContent = match.captured(3); @@ -518,13 +565,10 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) // Find variables that may be referenced in the assignment gatherTemporaryVariablesFromAssignment(v, assignmentContent); + break; } - break; - } - case QShaderNode::Output: { - const QRegularExpressionMatch match = outputToTemporaryAssignmentRegExp.match(QString::fromUtf8(substitutionedLine)); - if (match.hasMatch()) { + case QShaderNode::Output: { const QString outputDeclaration = match.captured(1); const QString assignmentContent = match.captured(2); @@ -539,17 +583,17 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) // Find variables that may be referenced in the assignment gatherTemporaryVariablesFromAssignment(v, assignmentContent); + break; + } + case QShaderNode::Invalid: + break; } - break; - } - case QShaderNode::Invalid: - break; - } - LineContent lineContent; - lineContent.rawContent = QByteArray(QByteArrayLiteral(" ") + substitutionedLine); - lineContent.var = v; - lines << lineContent; + LineContent lineContent; + lineContent.rawContent = QByteArray(QByteArrayLiteral(" ") + substitutionedLine); + lineContent.var = v; + lines << lineContent; + } } // Go through all lines diff --git a/src/gui/util/qshadergraph.cpp b/src/gui/util/qshadergraph.cpp index b05b710713..611bb4b938 100644 --- a/src/gui/util/qshadergraph.cpp +++ b/src/gui/util/qshadergraph.cpp @@ -44,13 +44,20 @@ QT_BEGIN_NAMESPACE namespace { - QVector<QShaderNode> copyOutputNodes(const QVector<QShaderNode> &nodes) + QVector<QShaderNode> copyOutputNodes(const QVector<QShaderNode> &nodes, const QVector<QShaderGraph::Edge> &edges) { auto res = QVector<QShaderNode>(); std::copy_if(nodes.cbegin(), nodes.cend(), std::back_inserter(res), - [] (const QShaderNode &node) { - return node.type() == QShaderNode::Output; + [&edges] (const QShaderNode &node) { + return node.type() == QShaderNode::Output || + (node.type() == QShaderNode::Function && + !std::any_of(edges.cbegin(), + edges.cend(), + [&node] (const QShaderGraph::Edge &edge) { + return edge.sourceNodeUuid == + node.uuid(); + })); }); return res; } @@ -116,6 +123,50 @@ namespace } return targetStatement; } + + void removeNodesWithUnboundInputs(QVector<QShaderGraph::Statement> &statements, + const QVector<QShaderGraph::Edge> &allEdges) + { + // A node is invalid if any of its input ports is disconected + // or connected to the output port of another invalid node. + + // Keeps track of the edges from the nodes we know to be valid + // to unvisited nodes + auto currentEdges = QVector<QShaderGraph::Edge>(); + + statements.erase(std::remove_if(statements.begin(), + statements.end(), + [¤tEdges, &allEdges] (const QShaderGraph::Statement &statement) { + const QShaderNode &node = statement.node; + const QVector<QShaderGraph::Edge> outgoing = outgoingEdges(currentEdges, node.uuid()); + const QVector<QShaderNodePort> ports = node.ports(); + + bool allInputsConnected = true; + for (const QShaderNodePort &port : node.ports()) { + if (port.direction == QShaderNodePort::Output) + continue; + + const auto edgeIt = std::find_if(outgoing.cbegin(), + outgoing.cend(), + [&port] (const QShaderGraph::Edge &edge) { + return edge.targetPortName == port.name; + }); + + if (edgeIt != outgoing.cend()) + currentEdges.removeAll(*edgeIt); + else + allInputsConnected = false; + } + + if (allInputsConnected) { + const QVector<QShaderGraph::Edge> incoming = incomingEdges(allEdges, node.uuid()); + currentEdges.append(incoming); + } + + return !allInputsConnected; + }), + statements.end()); + } } QUuid QShaderGraph::Statement::uuid() const noexcept @@ -210,8 +261,8 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis auto result = QVector<Statement>(); QVector<Edge> currentEdges = enabledEdges; - QVector<QUuid> currentUuids = [enabledNodes] { - const QVector<QShaderNode> inputs = copyOutputNodes(enabledNodes); + QVector<QUuid> currentUuids = [enabledNodes, enabledEdges] { + const QVector<QShaderNode> inputs = copyOutputNodes(enabledNodes, enabledEdges); auto res = QVector<QUuid>(); std::transform(inputs.cbegin(), inputs.cend(), std::back_inserter(res), @@ -241,6 +292,9 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis } std::reverse(result.begin(), result.end()); + + removeNodesWithUnboundInputs(result, enabledEdges); + return result; } diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index a3c8172a70..65c2ae3054 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -1098,6 +1098,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket if (reply) { reply->d_func()->errorString = errorString; + reply->d_func()->httpErrorCode = errorCode; emit reply->finishedWithError(errorCode, errorString); reply = nullptr; if (protocolHandler) diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 1ba52ac6d6..78413062b4 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -158,6 +158,11 @@ QString QHttpNetworkReply::errorString() const return d_func()->errorString; } +QNetworkReply::NetworkError QHttpNetworkReply::errorCode() const +{ + return d_func()->httpErrorCode; +} + QString QHttpNetworkReply::reasonPhrase() const { return d_func()->reasonPhrase; diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 82128f656e..4638d056de 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -115,6 +115,8 @@ public: QString errorString() const; void setErrorString(const QString &error); + QNetworkReply::NetworkError errorCode() const; + QString reasonPhrase() const; qint64 bytesAvailable() const; @@ -255,6 +257,7 @@ public: qint64 removedContentLength; QPointer<QHttpNetworkConnection> connection; QPointer<QHttpNetworkConnectionChannel> connectionChannel; + QNetworkReply::NetworkError httpErrorCode = QNetworkReply::NoError; bool autoDecompress; diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 5a0940aa24..fa03bf7a11 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -417,6 +417,12 @@ void QHttpThreadDelegate::startRequest() connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)), this, SLOT(cacheCredentialsSlot(QHttpNetworkRequest,QAuthenticator*))); + if (httpReply->errorCode() != QNetworkReply::NoError) { + if (synchronous) + synchronousFinishedWithErrorSlot(httpReply->errorCode(), httpReply->errorString()); + else + finishedWithErrorSlot(httpReply->errorCode(), httpReply->errorString()); + } } // This gets called from the user thread or by the synchronous HTTP timeout timer diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 38807d3cda..85f065223a 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -220,27 +220,6 @@ static void ensureInitialized() can be: \snippet code/src_network_access_qnetworkaccessmanager.cpp 1 - \section1 Network and Roaming Support - - With the addition of the \l {Bearer Management} API to Qt 4.7 - QNetworkAccessManager gained the ability to manage network connections. - QNetworkAccessManager can start the network interface if the device is - offline and terminates the interface if the current process is the last - one to use the uplink. Note that some platforms utilize grace periods from - when the last application stops using a uplink until the system actually - terminates the connectivity link. Roaming is equally transparent. Any - queued/pending network requests are automatically transferred to the new - access point. - - Clients wanting to utilize this feature should not require any changes. In fact - it is likely that existing platform specific connection code can simply be - removed from the application. - - \note The network and roaming support in QNetworkAccessManager is conditional - upon the platform supporting connection management. The - \l QNetworkConfigurationManager::NetworkSessionRequired can be used to - detect whether QNetworkAccessManager utilizes this feature. - \sa QNetworkRequest, QNetworkReply, QNetworkProxy */ @@ -1475,7 +1454,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera // immediately set 'networkAccessible' even before we start // the monitor. #ifdef QT_NO_BEARERMANAGEMENT - if (d->networkAccessible + if (!d->networkAccessible #else if (d->networkAccessible == NotAccessible #endif // QT_NO_BEARERMANAGEMENT diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index cfb75f0f90..5194afb1be 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -170,7 +170,7 @@ public: void setAutoDeleteReplies(bool autoDelete); int transferTimeout() const; - void setTransferTimeout(int timeout = QNetworkRequest::TransferTimeoutPreset); + void setTransferTimeout(int timeout = QNetworkRequest::DefaultTransferTimeoutConstant); Q_SIGNALS: #ifndef QT_NO_NETWORKPROXY diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 473aa42e1e..4765fdc30e 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -414,9 +414,9 @@ QT_BEGIN_NAMESPACE A constant that can be used for enabling transfer timeouts with a preset value. - \value TransferTimeoutPreset The transfer timeout in milliseconds. - Used if setTimeout() is called - without an argument. + \value DefaultTransferTimeoutConstant The transfer timeout in milliseconds. + Used if setTimeout() is called + without an argument. */ class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index cb15ca5aa5..035b5b378a 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -127,7 +127,7 @@ public: }; enum TransferTimeoutConstant { - TransferTimeoutPreset = 30000 + DefaultTransferTimeoutConstant = 30000 }; QNetworkRequest(); @@ -182,7 +182,7 @@ public: void setHttp2Configuration(const QHttp2Configuration &configuration); int transferTimeout() const; - void setTransferTimeout(int timeout = TransferTimeoutPreset); + void setTransferTimeout(int timeout = DefaultTransferTimeoutConstant); #endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) private: QSharedDataPointer<QNetworkRequestPrivate> d; diff --git a/src/network/doc/src/network-programming.qdoc b/src/network/doc/src/network-programming.qdoc index ce99af034b..654227f971 100644 --- a/src/network/doc/src/network-programming.qdoc +++ b/src/network/doc/src/network-programming.qdoc @@ -261,29 +261,4 @@ by passing a factory to QNetworkProxyFactory::setApplicationProxyFactory() and a custom proxying policy can be created by subclassing QNetworkProxyFactory; see the class documentation for details. - - \section1 Bearer Management Support - - Bearer Management controls the connectivity state of the device such that - the application can start or stop network interfaces and roam - transparently between access points. - - The QNetworkConfigurationManager class manages the list of network - configurations known to the device. A network configuration describes the - set of parameters used to start a network interface and is represented by - the QNetworkConfiguration class. - - A network interface is started by openning a QNetworkSession based on a - given network configuration. In most situations creating a network session - based on the platform specified default network configuration is - appropriate. The default network configuration is returned by the - QNetworkConfigurationManager::defaultConfiguration() function. - - On some platforms it is a platform requirement that the application open a - network session before any network operations can be performed. This can be - tested by the presents of the - QNetworkConfigurationManager::NetworkSessionRequired flag in the value - returned by the QNetworkConfigurationManager::capabilities() function. - - \sa {Bearer Management} */ diff --git a/src/network/doc/src/qtnetwork.qdoc b/src/network/doc/src/qtnetwork.qdoc index c931a1c19f..85a3c198a0 100644 --- a/src/network/doc/src/qtnetwork.qdoc +++ b/src/network/doc/src/qtnetwork.qdoc @@ -54,7 +54,6 @@ applications with networking capabilities. \list \li \l{Network Programming with Qt} - Programming applications with networking capabilities - \li \l{Bearer Management} - An API to control the system's connectivity state \li \l{Secure Sockets Layer (SSL) Classes} - Classes for secure communication over network sockets \endlist diff --git a/src/network/kernel/qnetconmonitor_win.cpp b/src/network/kernel/qnetconmonitor_win.cpp index 1566e7f914..59b6cd5b66 100644 --- a/src/network/kernel/qnetconmonitor_win.cpp +++ b/src/network/kernel/qnetconmonitor_win.cpp @@ -163,11 +163,14 @@ private: ComPtr<QNetworkConnectionEvents> connectionEvents; // We can assume we have access to internet/subnet when this class is created because // connection has already been established to the peer: - NLM_CONNECTIVITY connectivity = - NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET - | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET); + NLM_CONNECTIVITY connectivity = NLM_CONNECTIVITY( + NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET + | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET + | NLM_CONNECTIVITY_IPV4_LOCALNETWORK | NLM_CONNECTIVITY_IPV6_LOCALNETWORK + | NLM_CONNECTIVITY_IPV4_NOTRAFFIC | NLM_CONNECTIVITY_IPV6_NOTRAFFIC); bool sameSubnet = false; + bool isLinkLocal = false; bool monitoring = false; bool comInitFailed = false; bool remoteIsIPv6 = false; @@ -370,6 +373,7 @@ bool QNetworkConnectionMonitorPrivate::setTargets(const QHostAddress &local, return false; } sameSubnet = remote.isInSubnet(local, it->prefixLength()); + isLinkLocal = remote.isLinkLocal() && local.isLinkLocal(); remoteIsIPv6 = remote.protocol() == QAbstractSocket::IPv6Protocol; return connectionEvents->setTarget(iface); @@ -461,9 +465,28 @@ void QNetworkConnectionMonitor::stopMonitoring() bool QNetworkConnectionMonitor::isReachable() { Q_D(QNetworkConnectionMonitor); - NLM_CONNECTIVITY required = d->sameSubnet - ? (d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_SUBNET : NLM_CONNECTIVITY_IPV4_SUBNET) - : (d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_INTERNET : NLM_CONNECTIVITY_IPV4_INTERNET); + + const NLM_CONNECTIVITY RequiredSameSubnetIPv6 = + NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV6_SUBNET | NLM_CONNECTIVITY_IPV6_LOCALNETWORK + | NLM_CONNECTIVITY_IPV6_INTERNET); + const NLM_CONNECTIVITY RequiredSameSubnetIPv4 = + NLM_CONNECTIVITY(NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV4_LOCALNETWORK + | NLM_CONNECTIVITY_IPV4_INTERNET); + + NLM_CONNECTIVITY required; + if (d->isLinkLocal) { + required = NLM_CONNECTIVITY( + d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_NOTRAFFIC | RequiredSameSubnetIPv6 + : NLM_CONNECTIVITY_IPV4_NOTRAFFIC | RequiredSameSubnetIPv4); + } else if (d->sameSubnet) { + required = + NLM_CONNECTIVITY(d->remoteIsIPv6 ? RequiredSameSubnetIPv6 : RequiredSameSubnetIPv4); + + } else { + required = NLM_CONNECTIVITY(d->remoteIsIPv6 ? NLM_CONNECTIVITY_IPV6_INTERNET + : NLM_CONNECTIVITY_IPV4_INTERNET); + } + return d_func()->connectivity & required; } @@ -695,7 +718,8 @@ bool QNetworkStatusMonitor::isNetworkAccessible() { return d_func()->connectivity & (NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET - | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET); + | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET + | NLM_CONNECTIVITY_IPV4_LOCALNETWORK | NLM_CONNECTIVITY_IPV6_LOCALNETWORK); } bool QNetworkStatusMonitor::isEnabled() diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 3d88c0337d..5f1ff2fcb8 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -1465,13 +1465,8 @@ QAbstractSocket::QAbstractSocket(SocketType socketType, \sa socketType(), QTcpSocket, QUdpSocket */ QAbstractSocket::QAbstractSocket(SocketType socketType, QObject *parent) - : QIODevice(*new QAbstractSocketPrivate, parent) + : QAbstractSocket(socketType, *new QAbstractSocketPrivate, parent) { - Q_D(QAbstractSocket); -#if defined(QABSTRACTSOCKET_DEBUG) - qDebug("QAbstractSocket::QAbstractSocket(%p)", parent); -#endif - d->socketType = socketType; } /*! diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index 38e47d6e26..18f400fe0b 100644 --- a/src/network/socket/qlocalsocket.cpp +++ b/src/network/socket/qlocalsocket.cpp @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE On Windows this is a named pipe and on Unix this is a local domain socket. - If an error occurs, socketError() returns the type of error, and + If an error occurs, error() returns the type of error, and errorString() can be called to get a human readable description of what happened. diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index dd115c33dc..2581fc048e 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -590,7 +590,8 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() // local address of the socket which bound on both IPv4 and IPv6 interfaces. // This address does not match to any special address and should not be used // to send the data. So, replace it with QHostAddress::Any. - if (socketProtocol == QAbstractSocket::IPv6Protocol) { + const uchar ipv6MappedNet[] = {0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 0,0,0,0}; + if (localAddress.isInSubnet(QHostAddress(ipv6MappedNet), 128 - 32)) { bool ok = false; const quint32 localIPv4 = localAddress.toIPv4Address(&ok); if (ok && localIPv4 == INADDR_ANY) { diff --git a/src/platformsupport/windowsuiautomation/uiapropertyids_p.h b/src/platformsupport/windowsuiautomation/uiapropertyids_p.h index 74e84147f6..9c14a35271 100644 --- a/src/platformsupport/windowsuiautomation/uiapropertyids_p.h +++ b/src/platformsupport/windowsuiautomation/uiapropertyids_p.h @@ -219,5 +219,6 @@ #define UIA_CenterPointPropertyId 30165 #define UIA_RotationPropertyId 30166 #define UIA_SizePropertyId 30167 +#define UIA_IsDialogPropertyId 30174 #endif diff --git a/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h b/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h index fd39b6ee33..fde16206da 100644 --- a/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h +++ b/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h @@ -383,4 +383,21 @@ __CRT_UUID_DECL(IWindowProvider, 0x987df77b, 0xdb06, 0x4d77, 0x8f,0x8a, 0x86,0xa #endif #endif + +#ifndef __IExpandCollapseProvider_INTERFACE_DEFINED__ +#define __IExpandCollapseProvider_INTERFACE_DEFINED__ +DEFINE_GUID(IID_IExpandCollapseProvider, 0xd847d3a5, 0xcab0, 0x4a98, 0x8c,0x32, 0xec,0xb4,0x5c,0x59,0xad,0x24); +MIDL_INTERFACE("d847d3a5-cab0-4a98-8c32-ecb45c59ad24") +IExpandCollapseProvider : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE Expand() = 0; + virtual HRESULT STDMETHODCALLTYPE Collapse() = 0; + virtual HRESULT STDMETHODCALLTYPE get_ExpandCollapseState(__RPC__out enum ExpandCollapseState *pRetVal) = 0; +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IExpandCollapseProvider, 0xd847d3a5, 0xcab0, 0x4a98, 0x8c,0x32, 0xec,0xb4,0x5c,0x59,0xad,0x24) +#endif +#endif + #endif diff --git a/src/platformsupport/windowsuiautomation/uiatypes_p.h b/src/platformsupport/windowsuiautomation/uiatypes_p.h index 8ef71843a3..afbc957094 100644 --- a/src/platformsupport/windowsuiautomation/uiatypes_p.h +++ b/src/platformsupport/windowsuiautomation/uiatypes_p.h @@ -155,6 +155,13 @@ enum WindowInteractionState { WindowInteractionState_NotResponding = 4 }; +enum ExpandCollapseState { + ExpandCollapseState_Collapsed = 0, + ExpandCollapseState_Expanded = 1, + ExpandCollapseState_PartiallyExpanded = 2, + ExpandCollapseState_LeafNode = 3 +}; + struct UiaRect { double left; double top; diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp index fb979ab6cc..7b5f2f16f8 100644 --- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp @@ -40,7 +40,6 @@ #include "qandroidplatformfiledialoghelper.h" #include <androidjnimain.h> -#include <private/qjni_p.h> #include <jni.h> QT_BEGIN_NAMESPACE @@ -50,9 +49,11 @@ namespace QtAndroidFileDialogHelper { #define RESULT_OK -1 #define REQUEST_CODE 1305 // Arbitrary +const char JniIntentClass[] = "android/content/Intent"; + QAndroidPlatformFileDialogHelper::QAndroidPlatformFileDialogHelper() - : QPlatformFileDialogHelper() - , m_selectedFile() + : QPlatformFileDialogHelper(), + m_activity(QtAndroid::activity()) { } @@ -61,92 +62,165 @@ bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, ji if (requestCode != REQUEST_CODE) return false; - if (resultCode == RESULT_OK) { - const QJNIObjectPrivate intent = QJNIObjectPrivate::fromLocalRef(data); - const QJNIObjectPrivate uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;"); - const QString uriStr = uri.callObjectMethod("toString", "()Ljava/lang/String;").toString(); - m_selectedFile = QUrl(uriStr); - Q_EMIT fileSelected(m_selectedFile); - Q_EMIT accept(); - } else { + if (resultCode != RESULT_OK) { Q_EMIT reject(); + return true; } - return true; -} - -bool QAndroidPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) -{ - Q_UNUSED(windowFlags) - Q_UNUSED(windowModality) - Q_UNUSED(parent) - - if (options()->fileMode() != QFileDialogOptions::FileMode::ExistingFile) - return false; + const QJNIObjectPrivate intent = QJNIObjectPrivate::fromLocalRef(data); - QtAndroidPrivate::registerActivityResultListener(this); + const QJNIObjectPrivate uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;"); + if (uri.isValid()) { + takePersistableUriPermission(uri); + m_selectedFile.append(QUrl(uri.toString())); + Q_EMIT fileSelected(m_selectedFile.first()); + Q_EMIT accept(); - const QJNIObjectPrivate ACTION_OPEN_DOCUMENT = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "ACTION_OPEN_DOCUMENT", "Ljava/lang/String;"); - QJNIObjectPrivate intent("android/content/Intent", "(Ljava/lang/String;)V", ACTION_OPEN_DOCUMENT.object()); - const QJNIObjectPrivate CATEGORY_OPENABLE = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "CATEGORY_OPENABLE", "Ljava/lang/String;"); - intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", CATEGORY_OPENABLE.object()); - intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QJNIObjectPrivate::fromString(QStringLiteral("*/*")).object()); + return true; + } - const QJNIObjectPrivate activity(QtAndroid::activity()); - activity.callMethod<void>("startActivityForResult", "(Landroid/content/Intent;I)V", intent.object(), REQUEST_CODE); + const QJNIObjectPrivate uriClipData = + intent.callObjectMethod("getClipData", "()Landroid/content/ClipData;"); + if (uriClipData.isValid()) { + const int size = uriClipData.callMethod<jint>("getItemCount"); + for (int i = 0; i < size; ++i) { + QJNIObjectPrivate item = uriClipData.callObjectMethod( + "getItemAt", "(I)Landroid/content/ClipData$Item;", i); + + QJNIObjectPrivate itemUri = item.callObjectMethod("getUri", "()Landroid/net/Uri;"); + takePersistableUriPermission(itemUri); + m_selectedFile.append(itemUri.toString()); + Q_EMIT filesSelected(m_selectedFile); + Q_EMIT accept(); + } + } return true; } -void QAndroidPlatformFileDialogHelper::exec() +void QAndroidPlatformFileDialogHelper::takePersistableUriPermission(const QJNIObjectPrivate &uri) { - m_eventLoop.exec(QEventLoop::DialogExec); + int modeFlags = QJNIObjectPrivate::getStaticField<jint>( + JniIntentClass, "FLAG_GRANT_READ_URI_PERMISSION"); + + if (options()->acceptMode() == QFileDialogOptions::AcceptSave) { + modeFlags |= QJNIObjectPrivate::getStaticField<jint>( + JniIntentClass, "FLAG_GRANT_WRITE_URI_PERMISSION"); + } + + QJNIObjectPrivate contentResolver = m_activity.callObjectMethod( + "getContentResolver", "()Landroid/content/ContentResolver;"); + contentResolver.callMethod<void>("takePersistableUriPermission", "(Landroid/net/Uri;I)V", + uri.object(), modeFlags); } -void QAndroidPlatformFileDialogHelper::hide() +void QAndroidPlatformFileDialogHelper::setLocalFilesOnly(bool localOnly) { - if (m_eventLoop.isRunning()) - m_eventLoop.exit(); - QtAndroidPrivate::unregisterActivityResultListener(this); + const QJNIObjectPrivate extraLocalOnly = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "EXTRA_LOCAL_ONLY", "Ljava/lang/String;"); + m_intent.callObjectMethod("putExtra", "(Ljava/lang/String;Z)Landroid/content/Intent;", + extraLocalOnly.object(), localOnly); } -QString QAndroidPlatformFileDialogHelper::selectedNameFilter() const +void QAndroidPlatformFileDialogHelper::setIntentTitle(const QString &title) { - return QString(); + const QJNIObjectPrivate extraTitle = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "EXTRA_TITLE", "Ljava/lang/String;"); + m_intent.callObjectMethod("putExtra", + "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;", + extraTitle.object(), QJNIObjectPrivate::fromString(title).object()); } -void QAndroidPlatformFileDialogHelper::selectNameFilter(const QString &filter) +void QAndroidPlatformFileDialogHelper::setOpenableCategory() { - Q_UNUSED(filter) + const QJNIObjectPrivate CATEGORY_OPENABLE = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "CATEGORY_OPENABLE", "Ljava/lang/String;"); + m_intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", + CATEGORY_OPENABLE.object()); } -void QAndroidPlatformFileDialogHelper::setFilter() +void QAndroidPlatformFileDialogHelper::setAllowMultipleSelections(bool allowMultiple) { + const QJNIObjectPrivate allowMultipleSelections = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "EXTRA_ALLOW_MULTIPLE", "Ljava/lang/String;"); + m_intent.callObjectMethod("putExtra", "(Ljava/lang/String;Z)Landroid/content/Intent;", + allowMultipleSelections.object(), allowMultiple); } -QList<QUrl> QAndroidPlatformFileDialogHelper::selectedFiles() const +void QAndroidPlatformFileDialogHelper::setMimeTypes() { - return {m_selectedFile}; + m_intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", + QJNIObjectPrivate::fromString("*/*").object()); + + const QJNIObjectPrivate extraMimeType = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, "EXTRA_MIME_TYPES", "Ljava/lang/String;"); + for (const QString &type : options()->mimeTypeFilters()) { + m_intent.callObjectMethod( + "putExtra", "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;", + extraMimeType.object(), QJNIObjectPrivate::fromString(type).object()); + } } -void QAndroidPlatformFileDialogHelper::selectFile(const QUrl &file) +QJNIObjectPrivate QAndroidPlatformFileDialogHelper::getFileDialogIntent(const QString &intentType) { - Q_UNUSED(file) + const QJNIObjectPrivate ACTION_OPEN_DOCUMENT = QJNIObjectPrivate::getStaticObjectField( + JniIntentClass, intentType.toLatin1(), "Ljava/lang/String;"); + return QJNIObjectPrivate(JniIntentClass, "(Ljava/lang/String;)V", + ACTION_OPEN_DOCUMENT.object()); } -QUrl QAndroidPlatformFileDialogHelper::directory() const +bool QAndroidPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) { - return QUrl(); + Q_UNUSED(windowFlags) + Q_UNUSED(windowModality) + Q_UNUSED(parent) + + bool isDirDialog = false; + + if (options()->acceptMode() == QFileDialogOptions::AcceptSave) { + m_intent = getFileDialogIntent("ACTION_CREATE_DOCUMENT"); + } else if (options()->acceptMode() == QFileDialogOptions::AcceptOpen) { + switch (options()->fileMode()) { + case QFileDialogOptions::FileMode::DirectoryOnly: + case QFileDialogOptions::FileMode::Directory: + m_intent = getFileDialogIntent("ACTION_OPEN_DOCUMENT_TREE"); + isDirDialog = true; + break; + case QFileDialogOptions::FileMode::ExistingFiles: + m_intent = getFileDialogIntent("ACTION_OPEN_DOCUMENT"); + setAllowMultipleSelections(true); + break; + case QFileDialogOptions::FileMode::AnyFile: + case QFileDialogOptions::FileMode::ExistingFile: + m_intent = getFileDialogIntent("ACTION_OPEN_DOCUMENT"); + break; + } + } + + if (!isDirDialog) { + setOpenableCategory(); + setMimeTypes(); + } + + setIntentTitle(options()->windowTitle()); + setLocalFilesOnly(true); + + QtAndroidPrivate::registerActivityResultListener(this); + m_activity.callMethod<void>("startActivityForResult", "(Landroid/content/Intent;I)V", + m_intent.object(), REQUEST_CODE); + return true; } -void QAndroidPlatformFileDialogHelper::setDirectory(const QUrl &directory) +void QAndroidPlatformFileDialogHelper::hide() { - Q_UNUSED(directory) + if (m_eventLoop.isRunning()) + m_eventLoop.exit(); + QtAndroidPrivate::unregisterActivityResultListener(this); } -bool QAndroidPlatformFileDialogHelper::defaultNameFilterDisables() const +void QAndroidPlatformFileDialogHelper::exec() { - return false; + m_eventLoop.exec(QEventLoop::DialogExec); } } diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h index 5cd26af7c9..fa9c3f47b3 100644 --- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h @@ -44,6 +44,8 @@ #include <QEventLoop> #include <qpa/qplatformdialoghelper.h> #include <QtCore/private/qjnihelpers_p.h> +#include <private/qjni_p.h> +#include <QEventLoop> QT_BEGIN_NAMESPACE @@ -55,26 +57,34 @@ class QAndroidPlatformFileDialogHelper: public QPlatformFileDialogHelper, public public: QAndroidPlatformFileDialogHelper(); - void exec() override; - bool show(Qt::WindowFlags windowFlags, - Qt::WindowModality windowModality, - QWindow *parent) override; + void exec() override; + bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override; void hide() override; - QString selectedNameFilter() const override; - void selectNameFilter(const QString &filter) override; - void setFilter() override; - QList<QUrl> selectedFiles() const override; - void selectFile(const QUrl &file) override; - QUrl directory() const override; - void setDirectory(const QUrl &directory) override; - bool defaultNameFilterDisables() const override; + QString selectedNameFilter() const override { return QString(); }; + void selectNameFilter(const QString &filter) override { Q_UNUSED(filter) }; + void setFilter() override {}; + QList<QUrl> selectedFiles() const override { return m_selectedFile; }; + void selectFile(const QUrl &file) override { Q_UNUSED(file) }; + QUrl directory() const override { return QUrl(); }; + void setDirectory(const QUrl &directory) override { Q_UNUSED(directory) }; + bool defaultNameFilterDisables() const override { return false; }; bool handleActivityResult(jint requestCode, jint resultCode, jobject data) override; private: + QJNIObjectPrivate getFileDialogIntent(const QString &intentType); + void takePersistableUriPermission(const QJNIObjectPrivate &uri); + void setLocalFilesOnly(bool localOnly); + void setIntentTitle(const QString &title); + void setOpenableCategory(); + void setAllowMultipleSelections(bool allowMultiple); + void setMimeTypes(); + QEventLoop m_eventLoop; - QUrl m_selectedFile; + QList<QUrl> m_selectedFile; + QJNIObjectPrivate m_intent; + const QJNIObjectPrivate m_activity; }; } diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp index 136637800b..c095613ce7 100644 --- a/src/plugins/platforms/android/qandroidplatformservices.cpp +++ b/src/plugins/platforms/android/qandroidplatformservices.cpp @@ -43,6 +43,7 @@ #include <QDebug> #include <QMimeDatabase> #include <QtCore/private/qjni_p.h> +#include <private/qjnihelpers_p.h> QT_BEGIN_NAMESPACE @@ -57,20 +58,20 @@ bool QAndroidPlatformServices::openUrl(const QUrl &theUrl) // if the file is local, we need to pass the MIME type, otherwise Android // does not start an Intent to view this file - if ((url.scheme().isEmpty() && QFile::exists(url.path())) || url.isLocalFile()) { + QLatin1String fileScheme("file"); + if ((url.scheme().isEmpty() || url.scheme() == fileScheme) && QFile::exists(url.path())) { // a real URL including the scheme is needed, else the Intent can not be started - url.setScheme(QLatin1String("file")); - + url.setScheme(fileScheme); QMimeDatabase mimeDb; mime = mimeDb.mimeTypeForUrl(url).name(); } QJNIObjectPrivate urlString = QJNIObjectPrivate::fromString(url.toString()); QJNIObjectPrivate mimeString = QJNIObjectPrivate::fromString(mime); - return QJNIObjectPrivate::callStaticMethod<jboolean>(QtAndroid::applicationClass(), - "openURL", - "(Ljava/lang/String;Ljava/lang/String;)Z", - urlString.object(), mimeString.object()); + return QJNIObjectPrivate::callStaticMethod<jboolean>( + QtAndroid::applicationClass(), "openURL", + "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Z", + QtAndroidPrivate::context(), urlString.object(), mimeString.object()); } bool QAndroidPlatformServices::openDocument(const QUrl &url) diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 2e15d11564..cb019c3775 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -574,7 +574,8 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, qCInfo(lcQpaBackingStore) << "Flushing" << subImage << "to" << flushedView.layer << "of subview" << flushedView; - QCFType<CGImageRef> cgImage = subImage.toCGImage(); + QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace( + QCFType<CGImageRef>(subImage.toCGImage()), colorSpace()); flushedView.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage); } diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp index ca8db9b215..09acd37abc 100644 --- a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp +++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp @@ -194,6 +194,7 @@ void QWasmEventDispatcher::wakeUp() { #ifdef EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD if (!emscripten_is_main_runtime_thread()) + if (m_hasMainLoop) emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIG_VI, (void*)(&QWasmEventDispatcher::mainThreadWakeUp), this); #endif QEventDispatcherUNIX::wakeUp(); diff --git a/src/plugins/platforms/windows/.prev_CMakeLists.txt b/src/plugins/platforms/windows/.prev_CMakeLists.txt index 299dda24af..92b2ccb217 100644 --- a/src/plugins/platforms/windows/.prev_CMakeLists.txt +++ b/src/plugins/platforms/windows/.prev_CMakeLists.txt @@ -95,6 +95,7 @@ qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility SOURCES uiautomation/qwindowsuiaaccessibility.cpp uiautomation/qwindowsuiaaccessibility.h uiautomation/qwindowsuiabaseprovider.cpp uiautomation/qwindowsuiabaseprovider.h + uiautomation/qwindowsuiaexpandcollapseprovider.cpp uiautomation/qwindowsuiaexpandcollapseprovider.h uiautomation/qwindowsuiagriditemprovider.cpp uiautomation/qwindowsuiagriditemprovider.h uiautomation/qwindowsuiagridprovider.cpp uiautomation/qwindowsuiagridprovider.h uiautomation/qwindowsuiainvokeprovider.cpp uiautomation/qwindowsuiainvokeprovider.h diff --git a/src/plugins/platforms/windows/CMakeLists.txt b/src/plugins/platforms/windows/CMakeLists.txt index 81a8c3bfe9..4cb9608378 100644 --- a/src/plugins/platforms/windows/CMakeLists.txt +++ b/src/plugins/platforms/windows/CMakeLists.txt @@ -96,6 +96,7 @@ qt_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility SOURCES uiautomation/qwindowsuiaaccessibility.cpp uiautomation/qwindowsuiaaccessibility.h uiautomation/qwindowsuiabaseprovider.cpp uiautomation/qwindowsuiabaseprovider.h + uiautomation/qwindowsuiaexpandcollapseprovider.cpp uiautomation/qwindowsuiaexpandcollapseprovider.h uiautomation/qwindowsuiagriditemprovider.cpp uiautomation/qwindowsuiagriditemprovider.h uiautomation/qwindowsuiagridprovider.cpp uiautomation/qwindowsuiagridprovider.h uiautomation/qwindowsuiainvokeprovider.cpp uiautomation/qwindowsuiainvokeprovider.h diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index f1f5d3a96e..7c4ddbd2a1 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -285,7 +285,7 @@ void QWindowsInputContext::showInputPanel() // the Surface seems unnecessary there anyway. But leave it hidden for IME. // Only trigger the native OSK if the Qt OSK is not in use. static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE"); - bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_MSWindowsDisableVirtualKeyboard); + bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_DisableNativeVirtualKeyboard); if ((imModuleEmpty && !nativeVKDisabled) && QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 16299)) { diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 325956b7ba..7f47cd712f 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -248,8 +248,7 @@ enum DarkModeColors : QRgb { darkModeBtnHighlightRgb = 0xc0c0c0, darkModeBtnShadowRgb = 0x808080, darkModeHighlightRgb = 0x0055ff, // deviating from 0x800080 - darkModeMenuHighlightRgb = darkModeHighlightRgb, - darkModeGrayTextRgb = 0x00ff00 + darkModeMenuHighlightRgb = darkModeHighlightRgb }; // from QStyle::standardPalette @@ -386,7 +385,7 @@ static inline QPalette menuPalette(const QPalette &systemPalette, bool light) const QColor menuColor = light ? getSysColor(COLOR_MENU) : QColor(Qt::black); const QColor menuTextColor = light ? getSysColor(COLOR_MENUTEXT) : QColor(Qt::white); const QColor disabled = light - ? getSysColor(COLOR_GRAYTEXT) : QColor(darkModeGrayTextRgb); + ? getSysColor(COLOR_GRAYTEXT) : QColor(darkModeBtnHighlightRgb); // we might need a special color group for the result. result.setColor(QPalette::Active, QPalette::Button, menuColor); result.setColor(QPalette::Active, QPalette::Text, menuTextColor); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index ee65b393d4..e635463951 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -2629,7 +2629,7 @@ static inline DWORD edgesToWinOrientation(Qt::Edges edges) bool QWindowsWindow::startSystemResize(Qt::Edges edges) { - if (Q_UNLIKELY(!(window()->flags() & Qt::MSWindowsFixedSizeDialogHint))) + if (Q_UNLIKELY(window()->flags().testFlag(Qt::MSWindowsFixedSizeDialogHint))) return false; ReleaseCapture(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp new file mode 100644 index 0000000000..6ac8de23fa --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins 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 <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwindowsuiaexpandcollapseprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include <QtGui/qaccessible.h> +#include <QtCore/qloggingcategory.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaExpandCollapseProvider::QWindowsUiaExpandCollapseProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaExpandCollapseProvider::~QWindowsUiaExpandCollapseProvider() = default; + +HRESULT STDMETHODCALLTYPE QWindowsUiaExpandCollapseProvider::Expand() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->childCount() > 0 && accessible->child(0)->state().invisible) + actionInterface->doAction(QAccessibleActionInterface::showMenuAction()); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaExpandCollapseProvider::Collapse() +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + QAccessibleActionInterface *actionInterface = accessible->actionInterface(); + if (!actionInterface) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->childCount() > 0 && !accessible->child(0)->state().invisible) + actionInterface->doAction(QAccessibleActionInterface::showMenuAction()); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaExpandCollapseProvider::get_ExpandCollapseState(__RPC__out ExpandCollapseState *pRetVal) +{ + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + + if (!pRetVal) + return E_INVALIDARG; + *pRetVal = ExpandCollapseState_LeafNode; + + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (accessible->childCount() > 0) + *pRetVal = accessible->child(0)->state().invisible ? + ExpandCollapseState_Collapsed : ExpandCollapseState_Expanded; + + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h new file mode 100644 index 0000000000..f5b4c2e78b --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAEXPANDCOLLAPSEPROVIDER_H +#define QWINDOWSUIAEXPANDCOLLAPSEPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +// Implements the Expand/Collapse control pattern provider. Used for menu items with submenus. +class QWindowsUiaExpandCollapseProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase<IExpandCollapseProvider> +{ + Q_DISABLE_COPY_MOVE(QWindowsUiaExpandCollapseProvider) +public: + explicit QWindowsUiaExpandCollapseProvider(QAccessible::Id id); + virtual ~QWindowsUiaExpandCollapseProvider() override; + + // IExpandCollapseProvider + HRESULT STDMETHODCALLTYPE Expand() override; + HRESULT STDMETHODCALLTYPE Collapse() override; + HRESULT STDMETHODCALLTYPE get_ExpandCollapseState(__RPC__out ExpandCollapseState *pRetVal) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINDOWSUIAEXPANDCOLLAPSEPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 5f564f81c2..9adc5c78dd 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -53,6 +53,7 @@ #include "qwindowsuiagridprovider.h" #include "qwindowsuiagriditemprovider.h" #include "qwindowsuiawindowprovider.h" +#include "qwindowsuiaexpandcollapseprovider.h" #include "qwindowscombase.h" #include "qwindowscontext.h" #include "qwindowsuiautils.h" @@ -341,6 +342,14 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow *pRetVal = new QWindowsUiaInvokeProvider(id()); } break; + case UIA_ExpandCollapsePatternId: + // Menu items with submenus. + if (accessible->role() == QAccessible::MenuItem + && accessible->childCount() > 0 + && accessible->child(0)->role() == QAccessible::PopupMenu) { + *pRetVal = new QWindowsUiaExpandCollapseProvider(id()); + } + break; default: break; } @@ -396,7 +405,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR // The native OSK should be disbled if the Qt OSK is in use, // or if disabled via application attribute. static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE"); - bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_MSWindowsDisableVirtualKeyboard); + bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_DisableNativeVirtualKeyboard); // If we want to disable the native OSK auto-showing // we have to report text fields as non-editable. @@ -448,6 +457,10 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR setVariantBool(wt == Qt::Popup || wt == Qt::ToolTip || wt == Qt::SplashScreen, pRetVal); } break; + case UIA_IsDialogPropertyId: + setVariantBool(accessible->role() == QAccessible::Dialog + || accessible->role() == QAccessible::AlertMessage, pRetVal); + break; case UIA_FullDescriptionPropertyId: setVariantString(accessible->text(QAccessible::Description), pRetVal); break; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp index ab04384616..682b8c19c0 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp @@ -161,7 +161,7 @@ long roleToControlTypeId(QAccessible::Role role) {QAccessible::Sound, UIA_CustomControlTypeId}, {QAccessible::Cursor, UIA_CustomControlTypeId}, {QAccessible::Caret, UIA_CustomControlTypeId}, - {QAccessible::AlertMessage, UIA_CustomControlTypeId}, + {QAccessible::AlertMessage, UIA_WindowControlTypeId}, {QAccessible::Window, UIA_WindowControlTypeId}, {QAccessible::Client, UIA_GroupControlTypeId}, {QAccessible::PopupMenu, UIA_MenuControlTypeId}, diff --git a/src/plugins/platforms/windows/uiautomation/uiautomation.pri b/src/plugins/platforms/windows/uiautomation/uiautomation.pri index ee9332e7ea..1c4b018d1c 100644 --- a/src/plugins/platforms/windows/uiautomation/uiautomation.pri +++ b/src/plugins/platforms/windows/uiautomation/uiautomation.pri @@ -19,6 +19,7 @@ SOURCES += \ $$PWD/qwindowsuiagridprovider.cpp \ $$PWD/qwindowsuiagriditemprovider.cpp \ $$PWD/qwindowsuiawindowprovider.cpp \ + $$PWD/qwindowsuiaexpandcollapseprovider.cpp \ $$PWD/qwindowsuiautils.cpp HEADERS += \ @@ -39,6 +40,7 @@ HEADERS += \ $$PWD/qwindowsuiagridprovider.h \ $$PWD/qwindowsuiagriditemprovider.h \ $$PWD/qwindowsuiawindowprovider.h \ + $$PWD/qwindowsuiaexpandcollapseprovider.h \ $$PWD/qwindowsuiautils.h mingw: QMAKE_USE *= uuid diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 4620f0fd1d..27a2526df1 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -514,12 +514,10 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info return isTouchDevice ? &m_touchDevices[deviceinfo->deviceid] : nullptr; } -#if QT_CONFIG(tabletevent) static inline qreal fixed1616ToReal(xcb_input_fp1616_t val) { return qreal(val) / 0x10000; } -#endif // QT_CONFIG(tabletevent) void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 698be45aa8..505f7343ce 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -665,7 +665,9 @@ QImage::Format QXcbScreen::format() const bool needsRgbSwap; qt_xcb_imageFormatForVisual(connection(), screen()->root_depth, visualForId(screen()->root_visual), &format, &needsRgbSwap); // We are ignoring needsRgbSwap here and just assumes the backing-store will handle it. - return format; + if (format != QImage::Format_Invalid) + return format; + return QImage::Format_RGB32; } int QXcbScreen::forcedDpi() const diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index 2930df7261..41141e1dd4 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -78,17 +78,14 @@ class QMYSQLDriverPrivate : public QSqlDriverPrivate Q_DECLARE_PUBLIC(QMYSQLDriver) public: - QMYSQLDriverPrivate() : QSqlDriverPrivate(), mysql(0), + QMYSQLDriverPrivate() : QSqlDriverPrivate(QSqlDriver::MySqlServer) #if QT_CONFIG(textcodec) - tc(QTextCodec::codecForLocale()), -#else - tc(0), + , tc(QTextCodec::codecForLocale()) #endif - preparedQuerysEnabled(false) { dbmsType = QSqlDriver::MySqlServer; } - MYSQL *mysql; - QTextCodec *tc; - - bool preparedQuerysEnabled; + {} + MYSQL *mysql = nullptr; + QTextCodec *tc = nullptr; + bool preparedQuerysEnabled = false; }; static inline QString toUnicode(QTextCodec *tc, const char *str) @@ -201,46 +198,34 @@ class QMYSQLResultPrivate: public QSqlResultPrivate public: Q_DECLARE_SQLDRIVER_PRIVATE(QMYSQLDriver) - QMYSQLResultPrivate(QMYSQLResult *q, const QMYSQLDriver *drv) - : QSqlResultPrivate(q, drv), - result(0), - rowsAffected(0), - hasBlobs(false) - , stmt(0), meta(0), inBinds(0), outBinds(0) - , preparedQuery(false) - { } - - MYSQL_RES *result; - MYSQL_ROW row; - - int rowsAffected; + using QSqlResultPrivate::QSqlResultPrivate; bool bindInValues(); void bindBlobs(); - bool hasBlobs; + MYSQL_RES *result = nullptr; + MYSQL_ROW row; + struct QMyField { - QMyField() - : outField(0), nullIndicator(false), bufLength(0ul), - myField(0), type(QMetaType::UnknownType) - {} - char *outField; - my_bool nullIndicator; - ulong bufLength; - MYSQL_FIELD *myField; - QMetaType::Type type; + char *outField = nullptr; + MYSQL_FIELD *myField = nullptr; + QMetaType::Type type = QMetaType::UnknownType; + my_bool nullIndicator = false; + ulong bufLength = 0ul; }; QVector<QMyField> fields; - MYSQL_STMT* stmt; - MYSQL_RES* meta; + MYSQL_STMT *stmt = nullptr; + MYSQL_RES *meta = nullptr; - MYSQL_BIND *inBinds; - MYSQL_BIND *outBinds; + MYSQL_BIND *inBinds = nullptr; + MYSQL_BIND *outBinds = nullptr; - bool preparedQuery; + int rowsAffected = 0; + bool hasBlobs = false; + bool preparedQuery = false; }; #if QT_CONFIG(textcodec) diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp index 72b2133327..63e8f9f9fe 100644 --- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp +++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp @@ -118,23 +118,19 @@ class QODBCDriverPrivate : public QSqlDriverPrivate Q_DECLARE_PUBLIC(QODBCDriver) public: - enum DefaultCase{Lower, Mixed, Upper, Sensitive}; - QODBCDriverPrivate() - : QSqlDriverPrivate(), hEnv(0), hDbc(0), unicode(false), useSchema(false), disconnectCount(0), datetime_precision(19), - isFreeTDSDriver(false), hasSQLFetchScroll(true), hasMultiResultSets(false), isQuoteInitialized(false), quote(QLatin1Char('"')) - { - } + enum DefaultCase {Lower, Mixed, Upper, Sensitive}; + using QSqlDriverPrivate::QSqlDriverPrivate; - SQLHANDLE hEnv; - SQLHANDLE hDbc; + SQLHANDLE hEnv = nullptr; + SQLHANDLE hDbc = nullptr; - bool unicode; - bool useSchema; - int disconnectCount; - int datetime_precision; - bool isFreeTDSDriver; - bool hasSQLFetchScroll; - bool hasMultiResultSets; + int disconnectCount = 0; + int datetimePrecision = 19; + bool unicode = false; + bool useSchema = false; + bool isFreeTDSDriver = false; + bool hasSQLFetchScroll = true; + bool hasMultiResultSets = false; bool checkDriver() const; void checkUnicode(); @@ -150,8 +146,8 @@ public: QString adjustCase(const QString&) const; QChar quoteChar(); private: - bool isQuoteInitialized; - QChar quote; + bool isQuoteInitialized = false; + QChar quote = QLatin1Char('"'); }; class QODBCResultPrivate; @@ -194,10 +190,7 @@ class QODBCResultPrivate: public QSqlResultPrivate public: Q_DECLARE_SQLDRIVER_PRIVATE(QODBCDriver) QODBCResultPrivate(QODBCResult *q, const QODBCDriver *db) - : QSqlResultPrivate(q, db), - hStmt(0), - useSchema(false), - hasSQLFetchScroll(true) + : QSqlResultPrivate(q, db) { unicode = drv_d_func()->unicode; useSchema = drv_d_func()->useSchema; @@ -210,16 +203,15 @@ public: SQLHANDLE dpEnv() const { return drv_d_func() ? drv_d_func()->hEnv : 0;} SQLHANDLE dpDbc() const { return drv_d_func() ? drv_d_func()->hDbc : 0;} - SQLHANDLE hStmt; - - bool unicode; - bool useSchema; + SQLHANDLE hStmt = nullptr; QSqlRecord rInf; QVector<QVariant> fieldCache; - int fieldCacheIdx; - int disconnectCount; - bool hasSQLFetchScroll; + int fieldCacheIdx = 0; + int disconnectCount = 0; + bool hasSQLFetchScroll = true; + bool unicode = false; + bool useSchema = false; bool isStmtHandleValid() const; void updateStmtHandleState(); @@ -1464,20 +1456,22 @@ bool QODBCResult::exec() case QVariant::DateTime: { QByteArray &ba = tmpStorage[i]; ba.resize(sizeof(TIMESTAMP_STRUCT)); - TIMESTAMP_STRUCT * dt = (TIMESTAMP_STRUCT *)const_cast<char *>(ba.constData()); - QDateTime qdt = val.toDateTime(); - dt->year = qdt.date().year(); - dt->month = qdt.date().month(); - dt->day = qdt.date().day(); - dt->hour = qdt.time().hour(); - dt->minute = qdt.time().minute(); - dt->second = qdt.time().second(); - - int precision = d->drv_d_func()->datetime_precision - 20; // (20 includes a separating period) + TIMESTAMP_STRUCT *dt = reinterpret_cast<TIMESTAMP_STRUCT *>(const_cast<char *>(ba.constData())); + const QDateTime qdt = val.toDateTime(); + const QDate qdate = qdt.date(); + const QTime qtime = qdt.time(); + dt->year = qdate.year(); + dt->month = qdate.month(); + dt->day = qdate.day(); + dt->hour = qtime.hour(); + dt->minute = qtime.minute(); + dt->second = qtime.second(); + // (20 includes a separating period) + const int precision = d->drv_d_func()->datetimePrecision - 20; if (precision <= 0) { dt->fraction = 0; } else { - dt->fraction = qdt.time().msec() * 1000000; + dt->fraction = qtime.msec() * 1000000; // (How many leading digits do we want to keep? With SQL Server 2005, this should be 3: 123000000) int keep = (int)qPow(10.0, 9 - qMin(9, precision)); @@ -1489,7 +1483,7 @@ bool QODBCResult::exec() qParamType[bindValueType(i) & QSql::InOut], SQL_C_TIMESTAMP, SQL_TIMESTAMP, - d->drv_d_func()->datetime_precision, + d->drv_d_func()->datetimePrecision, precision, (void *) dt, 0, @@ -2245,7 +2239,7 @@ void QODBCDriverPrivate::checkDateTimePrecision() if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) { if (SQLGetData(hStmt, 3, SQL_INTEGER, &columnSize, sizeof(columnSize), 0) == SQL_SUCCESS) { - datetime_precision = (int)columnSize; + datetimePrecision = (int)columnSize; } } } diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 27841d9494..d2c57bcddc 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -149,26 +149,17 @@ class QPSQLDriverPrivate final : public QSqlDriverPrivate { Q_DECLARE_PUBLIC(QPSQLDriver) public: - QPSQLDriverPrivate() : QSqlDriverPrivate(), - connection(nullptr), - isUtf8(false), - pro(QPSQLDriver::Version6), - sn(nullptr), - pendingNotifyCheck(false), - hasBackslashEscape(false), - stmtCount(0), - currentStmtId(InvalidStatementId) - { dbmsType = QSqlDriver::PostgreSQL; } - - PGconn *connection; - bool isUtf8; - QPSQLDriver::Protocol pro; - QSocketNotifier *sn; + QPSQLDriverPrivate() : QSqlDriverPrivate(QSqlDriver::PostgreSQL) {} + QStringList seid; - mutable bool pendingNotifyCheck; - bool hasBackslashEscape; - int stmtCount; - StatementId currentStmtId; + PGconn *connection = nullptr; + QSocketNotifier *sn = nullptr; + QPSQLDriver::Protocol pro = QPSQLDriver::Version6; + StatementId currentStmtId = InvalidStatementId; + int stmtCount = 0; + mutable bool pendingNotifyCheck = false; + bool hasBackslashEscape = false; + bool isUtf8 = false; void appendTables(QStringList &tl, QSqlQuery &t, QChar type); PGresult *exec(const char *stmt); @@ -297,25 +288,18 @@ class QPSQLResultPrivate : public QSqlResultPrivate Q_DECLARE_PUBLIC(QPSQLResult) public: Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver) - QPSQLResultPrivate(QPSQLResult *q, const QPSQLDriver *drv) - : QSqlResultPrivate(q, drv), - result(nullptr), - stmtId(InvalidStatementId), - currentSize(-1), - canFetchMoreRows(false), - preparedQueriesEnabled(false) - { } + using QSqlResultPrivate::QSqlResultPrivate; QString fieldSerial(int i) const override { return QLatin1Char('$') + QString::number(i + 1); } void deallocatePreparedStmt(); - PGresult *result; std::queue<PGresult*> nextResultSets; QString preparedStmtId; - StatementId stmtId; - int currentSize; - bool canFetchMoreRows; - bool preparedQueriesEnabled; + PGresult *result = nullptr; + StatementId stmtId = InvalidStatementId; + int currentSize = -1; + bool canFetchMoreRows = false; + bool preparedQueriesEnabled = false; bool processResults(); }; diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp index 009e8a39ef..27e7d02472 100644 --- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp +++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp @@ -144,42 +144,33 @@ class QSQLiteDriverPrivate : public QSqlDriverPrivate Q_DECLARE_PUBLIC(QSQLiteDriver) public: - inline QSQLiteDriverPrivate() : QSqlDriverPrivate(), access(0) { dbmsType = QSqlDriver::SQLite; } - sqlite3 *access; - QList <QSQLiteResult *> results; + inline QSQLiteDriverPrivate() : QSqlDriverPrivate(QSqlDriver::SQLite) {} + sqlite3 *access = nullptr; + QVector<QSQLiteResult *> results; QStringList notificationid; }; -class QSQLiteResultPrivate: public QSqlCachedResultPrivate +class QSQLiteResultPrivate : public QSqlCachedResultPrivate { Q_DECLARE_PUBLIC(QSQLiteResult) public: Q_DECLARE_SQLDRIVER_PRIVATE(QSQLiteDriver) - QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv); + using QSqlCachedResultPrivate::QSqlCachedResultPrivate; void cleanup(); bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch); // initializes the recordInfo and the cache void initColumns(bool emptyResultset); void finalize(); - sqlite3_stmt *stmt; - - bool skippedStatus; // the status of the fetchNext() that's skipped - bool skipRow; // skip the next fetchNext()? + sqlite3_stmt *stmt = nullptr; QSqlRecord rInf; QVector<QVariant> firstRow; + bool skippedStatus = false; // the status of the fetchNext() that's skipped + bool skipRow = false; // skip the next fetchNext()? }; -QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult *q, const QSQLiteDriver *drv) - : QSqlCachedResultPrivate(q, drv), - stmt(0), - skippedStatus(false), - skipRow(false) -{ -} - void QSQLiteResultPrivate::cleanup() { Q_Q(QSQLiteResult); diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 3cd04603e8..f473c3cbe3 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3959,7 +3959,20 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter CGContextRotateCTM(ctx, M_PI_2); } + // Now, if it's a trick with a popup button, it has an arrow + // which makes no sense on tabs. + NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter; + NSPopUpButtonCell *pbCell = nil; + if (isPopupButton) { + pbCell = static_cast<NSPopUpButtonCell *>(pb.cell); + oldPosition = pbCell.arrowPosition; + pbCell.arrowPosition = NSPopUpNoArrow; + } + [pb.cell drawBezelWithFrame:r inView:pb.superview]; + + if (pbCell) // Restore, we may reuse it for a ComboBox. + pbCell.arrowPosition = oldPosition; }; if (needsInactiveHack) { diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp index e8d74180cd..30b3786a80 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp @@ -2217,7 +2217,7 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt { const int controlTop = int(6 * factor); const int controlHeight = int(height - controlTop - 3 * factor); - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option); QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent)); if (tb->icon.isNull()) iconSize = QSize(controlHeight, controlHeight); diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index 9d143da169..e43746e79f 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -3453,7 +3453,7 @@ QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionCompl { const int controlTop = 6; const int controlHeight = height - controlTop - 3; - const int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + const int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option); QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent)); if (tb->icon.isNull()) iconSize = QSize(controlHeight, controlHeight); @@ -3575,7 +3575,7 @@ QSize QWindowsXPStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt sz.rheight() += int(borderSize.bottom() + borderSize.top() - margin + qreal(1) / factor - 1); } - const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin) + 1); + const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin, option) + 1); sz += QSize(qMax(pixelMetric(QStyle::PM_ScrollBarExtent, option, widget) + textMargins, 23), 0); //arrow button } diff --git a/src/sql/kernel/qsqldriver_p.h b/src/sql/kernel/qsqldriver_p.h index 614fbf69a1..c2cdb25ac2 100644 --- a/src/sql/kernel/qsqldriver_p.h +++ b/src/sql/kernel/qsqldriver_p.h @@ -63,10 +63,10 @@ class QSqlDriverPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QSqlDriver) public: - QSqlDriverPrivate(QSqlDriver::DbmsType dbmstype = QSqlDriver::UnknownDbms) - : QObjectPrivate() - , dbmsType(dbmstype) - {} + QSqlDriverPrivate(QSqlDriver::DbmsType type = QSqlDriver::UnknownDbms) + : QObjectPrivate(), + dbmsType(type) + { } QSqlError error; QSql::NumericalPrecisionPolicy precisionPolicy = QSql::LowPrecisionDouble; diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp index 7bd108ab00..a388780532 100644 --- a/src/testlib/qtestlog.cpp +++ b/src/testlib/qtestlog.cpp @@ -597,6 +597,6 @@ qint64 QTestLog::nsecsFunctionTime() return elapsedFunctionTime.nsecsElapsed(); } -#include "moc_qtestlog_p.cpp" - QT_END_NAMESPACE + +#include "moc_qtestlog_p.cpp" diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index b4fe6a765e..078eea257d 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -377,7 +377,7 @@ void Generator::generateCode() isConstructible ? index : 0); int flags = 0; - if (cdef->hasQGadget) { + if (cdef->hasQGadget || cdef->hasQNamespace) { // Ideally, all the classes could have that flag. But this broke classes generated // by qdbusxml2cpp which generate code that require that we call qt_metacall for properties flags |= PropertyAccessInStaticMetaCall; @@ -534,7 +534,7 @@ void Generator::generateCode() if (isQObject) fprintf(out, " nullptr,\n"); - else if (cdef->superclassList.size() && !cdef->hasQGadget) // for qobject, we know the super class must have a static metaobject + else if (cdef->superclassList.size() && !cdef->hasQGadget && !cdef->hasQNamespace) // for qobject, we know the super class must have a static metaobject fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", purestSuperClass.constData()); else if (cdef->superclassList.size()) // for gadgets we need to query at compile time for it fprintf(out, " QtPrivate::MetaObjectForType<%s>::value(),\n", purestSuperClass.constData()); @@ -1181,7 +1181,7 @@ void Generator::generateStaticMetacall() } fprintf(out, ");\n"); fprintf(out, " if (_a[0]) *reinterpret_cast<%s**>(_a[0]) = _r; } break;\n", - cdef->hasQGadget ? "void" : "QObject"); + (cdef->hasQGadget || cdef->hasQNamespace) ? "void" : "QObject"); } fprintf(out, " default: break;\n"); fprintf(out, " }\n"); diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index b37674320d..03976771e5 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -943,7 +943,7 @@ void Moc::parse() ClassDef def; static_cast<BaseDef &>(def) = static_cast<BaseDef>(n); def.qualified += def.classname; - def.hasQGadget = true; + def.hasQNamespace = true; auto it = std::find_if(classList.begin(), classList.end(), [&def](const ClassDef &val) { return def.classname == val.classname && def.qualified == val.qualified; }); @@ -1867,8 +1867,12 @@ QJsonObject ClassDef::toJson() const if (!props.isEmpty()) cls[QLatin1String("properties")] = props; + if (hasQObject) + cls[QLatin1String("object")] = true; if (hasQGadget) cls[QLatin1String("gadget")] = true; + if (hasQNamespace) + cls[QLatin1String("namespace")] = true; QJsonArray superClasses; diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 63caf36d61..743749433f 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -194,6 +194,7 @@ struct ClassDef : BaseDef { bool hasQObject = false; bool hasQGadget = false; + bool hasQNamespace = false; QJsonObject toJson() const; }; diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index 689002b589..4247731275 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -346,7 +346,8 @@ void QWellArray::paintCell(QPainter* p, int row, int col, const QRect &rect) const QPalette & g = palette(); QStyleOptionFrame opt; - int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + opt.initFrom(this); + int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt); opt.lineWidth = dfw; opt.midLineWidth = 1; opt.rect = rect.adjusted(b, b, -b, -b); diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 044401ac13..437ce4a114 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -2200,8 +2200,12 @@ QString QFileDialog::getOpenFileName(QWidget *parent, Options options) { const QStringList schemes = QStringList(QStringLiteral("file")); - const QUrl selectedUrl = getOpenFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter, selectedFilter, options, schemes); - return selectedUrl.toLocalFile(); + const QUrl selectedUrl = getOpenFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter, + selectedFilter, options, schemes); + if (selectedUrl.isLocalFile() || selectedUrl.isEmpty()) + return selectedUrl.toLocalFile(); + else + return selectedUrl.toString(); } /*! @@ -2310,11 +2314,16 @@ QStringList QFileDialog::getOpenFileNames(QWidget *parent, Options options) { const QStringList schemes = QStringList(QStringLiteral("file")); - const QList<QUrl> selectedUrls = getOpenFileUrls(parent, caption, QUrl::fromLocalFile(dir), filter, selectedFilter, options, schemes); + const QList<QUrl> selectedUrls = getOpenFileUrls(parent, caption, QUrl::fromLocalFile(dir), + filter, selectedFilter, options, schemes); QStringList fileNames; fileNames.reserve(selectedUrls.size()); - for (const QUrl &url : selectedUrls) - fileNames << url.toLocalFile(); + for (const QUrl &url : selectedUrls) { + if (url.isLocalFile() || url.isEmpty()) + fileNames << url.toLocalFile(); + else + fileNames << url.toString(); + } return fileNames; } @@ -2556,8 +2565,12 @@ QString QFileDialog::getSaveFileName(QWidget *parent, Options options) { const QStringList schemes = QStringList(QStringLiteral("file")); - const QUrl selectedUrl = getSaveFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter, selectedFilter, options, schemes); - return selectedUrl.toLocalFile(); + const QUrl selectedUrl = getSaveFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter, + selectedFilter, options, schemes); + if (selectedUrl.isLocalFile() || selectedUrl.isEmpty()) + return selectedUrl.toLocalFile(); + else + return selectedUrl.toString(); } /*! @@ -2664,8 +2677,12 @@ QString QFileDialog::getExistingDirectory(QWidget *parent, Options options) { const QStringList schemes = QStringList(QStringLiteral("file")); - const QUrl selectedUrl = getExistingDirectoryUrl(parent, caption, QUrl::fromLocalFile(dir), options, schemes); - return selectedUrl.toLocalFile(); + const QUrl selectedUrl = + getExistingDirectoryUrl(parent, caption, QUrl::fromLocalFile(dir), options, schemes); + if (selectedUrl.isLocalFile() || selectedUrl.isEmpty()) + return selectedUrl.toLocalFile(); + else + return selectedUrl.toString(); } /*! diff --git a/src/widgets/dialogs/qwizard.cpp b/src/widgets/dialogs/qwizard.cpp index 87f6875c8c..31e32bb931 100644 --- a/src/widgets/dialogs/qwizard.cpp +++ b/src/widgets/dialogs/qwizard.cpp @@ -64,6 +64,7 @@ # include "qshortcut.h" #endif #include "qstyle.h" +#include "qstyleoption.h" #include "qvarlengtharray.h" #if defined(Q_OS_MACX) #include <QtCore/QMetaMethod> @@ -897,7 +898,9 @@ QWizardLayoutInfo QWizardPrivate::layoutInfoForCurrentPage() QWizardLayoutInfo info; - const int layoutHorizontalSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + QStyleOption option; + option.initFrom(q); + const int layoutHorizontalSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &option); info.topLevelMarginLeft = style->pixelMetric(QStyle::PM_LayoutLeftMargin, nullptr, q); info.topLevelMarginRight = style->pixelMetric(QStyle::PM_LayoutRightMargin, nullptr, q); info.topLevelMarginTop = style->pixelMetric(QStyle::PM_LayoutTopMargin, nullptr, q); @@ -909,7 +912,7 @@ QWizardLayoutInfo QWizardPrivate::layoutInfoForCurrentPage() info.hspacing = (layoutHorizontalSpacing == -1) ? style->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Horizontal) : layoutHorizontalSpacing; - info.vspacing = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing); + info.vspacing = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &option); info.buttonSpacing = (layoutHorizontalSpacing == -1) ? style->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal) : layoutHorizontalSpacing; diff --git a/src/widgets/graphicsview/qgraphicslayout_p.h b/src/widgets/graphicsview/qgraphicslayout_p.h index 0d91151e22..9e86ae2f76 100644 --- a/src/widgets/graphicsview/qgraphicslayout_p.h +++ b/src/widgets/graphicsview/qgraphicslayout_p.h @@ -87,8 +87,8 @@ public: Q_ASSERT(style); if (widget) //### m_styleOption.initFrom(widget); - m_defaultSpacing[0] = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); - m_defaultSpacing[1] = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing); + m_defaultSpacing[0] = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &m_styleOption); + m_defaultSpacing[1] = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &m_styleOption); } inline void invalidate() { m_valid = false; m_style = nullptr; m_widget = nullptr; } diff --git a/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp b/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp index 2f1526cc78..58b9f8bb9d 100644 --- a/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp +++ b/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp @@ -80,7 +80,9 @@ qreal QGraphicsLayoutStyleInfo::perItemSpacing(QLayoutPolicy::ControlType contro qreal QGraphicsLayoutStyleInfo::spacing(Qt::Orientation orientation) const { Q_ASSERT(style()); - return style()->pixelMetric(orientation == Qt::Horizontal ? QStyle::PM_LayoutHorizontalSpacing : QStyle::PM_LayoutVerticalSpacing); + return style()->pixelMetric(orientation == Qt::Horizontal + ? QStyle::PM_LayoutHorizontalSpacing : QStyle::PM_LayoutVerticalSpacing, + &m_styleOption); } qreal QGraphicsLayoutStyleInfo::windowMargin(Qt::Orientation orientation) const diff --git a/src/widgets/graphicsview/qgraphicsproxywidget.cpp b/src/widgets/graphicsview/qgraphicsproxywidget.cpp index a9a57c57fa..fe3475e6bb 100644 --- a/src/widgets/graphicsview/qgraphicsproxywidget.cpp +++ b/src/widgets/graphicsview/qgraphicsproxywidget.cpp @@ -183,7 +183,9 @@ QT_BEGIN_NAMESPACE \warning This class is provided for convenience when bridging QWidgets and QGraphicsItems, it should not be used for - high-performance scenarios. + high-performance scenarios. In particular, embedding widgets into a scene + that is then displayed through a QGraphicsView that uses an OpenGL viewport + will not work for all combinations. \sa QGraphicsScene::addWidget(), QGraphicsWidget */ diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp index 686b41960a..a75f1ab24b 100644 --- a/src/widgets/graphicsview/qgraphicsview.cpp +++ b/src/widgets/graphicsview/qgraphicsview.cpp @@ -123,6 +123,10 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < \image graphicsview-view.png + \note Using an OpenGL viewport limits the ability to use QGraphicsProxyWidget. + Not all combinations of widgets and styles can be supported with such a setup. + You should carefully test your UI and make the necessary adjustments. + \sa QGraphicsScene, QGraphicsItem, QGraphicsSceneEvent */ @@ -782,6 +786,27 @@ void QGraphicsViewPrivate::updateRubberBand(const QMouseEvent *event) if (scene) scene->setSelectionArea(selectionArea, rubberBandSelectionOperation, rubberBandSelectionMode, q->viewportTransform()); } + +void QGraphicsViewPrivate::clearRubberBand() +{ + Q_Q(QGraphicsView); + if (dragMode != QGraphicsView::RubberBandDrag || !sceneInteractionAllowed || !rubberBanding) + return; + + if (viewportUpdateMode != QGraphicsView::NoViewportUpdate) { + if (viewportUpdateMode != QGraphicsView::FullViewportUpdate) + q->viewport()->update(rubberBandRegion(q->viewport(), rubberBandRect)); + else + updateAll(); + } + + rubberBanding = false; + rubberBandSelectionOperation = Qt::ReplaceSelection; + if (!rubberBandRect.isNull()) { + rubberBandRect = QRect(); + emit q->rubberBandChanged(rubberBandRect, QPointF(), QPointF()); + } +} #endif /*! @@ -1485,6 +1510,10 @@ void QGraphicsView::setDragMode(DragMode mode) if (d->dragMode == mode) return; +#if QT_CONFIG(rubberband) + d->clearRubberBand(); +#endif + #ifndef QT_NO_CURSOR if (d->dragMode == ScrollHandDrag) viewport()->unsetCursor(); @@ -3354,20 +3383,7 @@ void QGraphicsView::mouseReleaseEvent(QMouseEvent *event) #if QT_CONFIG(rubberband) if (d->dragMode == QGraphicsView::RubberBandDrag && d->sceneInteractionAllowed && !event->buttons()) { - if (d->rubberBanding) { - if (d->viewportUpdateMode != QGraphicsView::NoViewportUpdate){ - if (d->viewportUpdateMode != FullViewportUpdate) - viewport()->update(d->rubberBandRegion(viewport(), d->rubberBandRect)); - else - d->updateAll(); - } - d->rubberBanding = false; - d->rubberBandSelectionOperation = Qt::ReplaceSelection; - if (!d->rubberBandRect.isNull()) { - d->rubberBandRect = QRect(); - emit rubberBandChanged(d->rubberBandRect, QPointF(), QPointF()); - } - } + d->clearRubberBand(); } else #endif if (d->dragMode == QGraphicsView::ScrollHandDrag && event->button() == Qt::LeftButton) { diff --git a/src/widgets/graphicsview/qgraphicsview_p.h b/src/widgets/graphicsview/qgraphicsview_p.h index 01af61d6ba..e877e6e887 100644 --- a/src/widgets/graphicsview/qgraphicsview_p.h +++ b/src/widgets/graphicsview/qgraphicsview_p.h @@ -140,6 +140,7 @@ public: QRect rubberBandRect; QRegion rubberBandRegion(const QWidget *widget, const QRect &rect) const; void updateRubberBand(const QMouseEvent *event); + void clearRubberBand(); bool rubberBanding; Qt::ItemSelectionMode rubberBandSelectionMode; Qt::ItemSelectionOperation rubberBandSelectionOperation; diff --git a/src/widgets/graphicsview/qgraphicswidget.cpp b/src/widgets/graphicsview/qgraphicswidget.cpp index 1035ed3575..6242314e1d 100644 --- a/src/widgets/graphicsview/qgraphicswidget.cpp +++ b/src/widgets/graphicsview/qgraphicswidget.cpp @@ -615,7 +615,7 @@ void QGraphicsWidget::unsetWindowFrameMargins() QStyleOptionTitleBar bar; d->initStyleOptionTitleBar(&bar); QStyle *style = this->style(); - qreal margin = style->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth); + const qreal margin = style->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, &bar); qreal titleBarHeight = d->titleBarHeight(bar); setWindowFrameMargins(margin, titleBarHeight, margin, margin); } else { diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 2524d4acfa..ebef36d033 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -705,15 +705,6 @@ void QAbstractItemView::setModel(QAbstractItemModel *model) } d->model = (model ? model : QAbstractItemModelPrivate::staticEmptyModel()); - // These asserts do basic sanity checking of the model - Q_ASSERT_X(d->model->index(0,0) == d->model->index(0,0), - "QAbstractItemView::setModel", - "A model should return the exact same index " - "(including its internal id/pointer) when asked for it twice in a row."); - Q_ASSERT_X(!d->model->index(0,0).parent().isValid(), - "QAbstractItemView::setModel", - "The parent of a top level index should be invalid"); - if (d->model != QAbstractItemModelPrivate::staticEmptyModel()) { connect(d->model, SIGNAL(destroyed()), this, SLOT(_q_modelDestroyed())); @@ -3244,8 +3235,10 @@ void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget widget->installEventFilter(this); widget->show(); dataChanged(index, index); // update the geometry - if (!d->delayedPendingLayout) + if (!d->delayedPendingLayout) { widget->setGeometry(visualRect(index)); + d->doDelayedItemsLayout(); // relayout due to updated geometry + } } } diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp index 4420d39b8e..40ad48c655 100644 --- a/src/widgets/itemviews/qitemdelegate.cpp +++ b/src/widgets/itemviews/qitemdelegate.cpp @@ -1122,7 +1122,7 @@ QRect QItemDelegate::textRectangle(QPainter * /*painter*/, const QRect &rect, QSizeF fpSize = d->doTextLayout(rect.width()); const QSize size = QSize(qCeil(fpSize.width()), qCeil(fpSize.height())); // ###: textRectangle should take style option as argument - const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; + const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr) + 1; return QRect(0, 0, size.width() + 2 * textMargin, size.height()); } diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index ec01922746..4cb9214ff4 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1728,8 +1728,11 @@ void QListViewPrivate::prepareItemsLayout() layoutBounds = QRect(QPoint(), q->maximumViewportSize()); int frameAroundContents = 0; - if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) - frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2; + if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) { + QStyleOption option; + option.initFrom(q); + frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option) * 2; + } // maximumViewportSize() already takes scrollbar into account if policy is // Qt::ScrollBarAlwaysOn but scrollbar extent must be deduced if policy diff --git a/src/widgets/itemviews/qtablewidget.cpp b/src/widgets/itemviews/qtablewidget.cpp index 60abd02564..7b1f1a1caf 100644 --- a/src/widgets/itemviews/qtablewidget.cpp +++ b/src/widgets/itemviews/qtablewidget.cpp @@ -247,8 +247,8 @@ void QTableModel::removeItem(QTableWidgetItem *item) { int i = tableItems.indexOf(item); if (i != -1) { - tableItems[i] = 0; QModelIndex idx = index(item); + tableItems[i] = nullptr; emit dataChanged(idx, idx); return; } diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 129569a466..f49461b2d0 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -1904,9 +1904,12 @@ bool QApplication::event(QEvent *e) } if(e->type() == QEvent::LanguageChange) { + // QGuiApplication::event does not account for the cases where + // there is a top level widget without a window handle. So they + // need to have the event posted here const QWidgetList list = topLevelWidgets(); for (auto *w : list) { - if (!(w->windowType() == Qt::Desktop)) + if (!w->windowHandle() && (w->windowType() != Qt::Desktop)) postEvent(w, new QEvent(QEvent::LanguageChange)); } } @@ -3299,7 +3302,7 @@ QT_WARNING_POP bool eventAccepted = tablet->isAccepted(); while (w) { QTabletEvent te(tablet->type(), relpos, tablet->globalPosF(), - tablet->device(), tablet->pointerType(), + tablet->deviceType(), tablet->pointerType(), tablet->pressure(), tablet->xTilt(), tablet->yTilt(), tablet->tangentialPressure(), tablet->rotation(), tablet->z(), tablet->modifiers(), tablet->uniqueId(), tablet->button(), tablet->buttons()); diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index c5379941ef..b4699ae040 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -152,6 +152,7 @@ QWidgetPrivate::QWidgetPrivate(int version) #endif , directFontResolveMask(0) , inheritedFontResolveMask(0) + , directPaletteResolveMask(0) , inheritedPaletteResolveMask(0) , leftmargin(0) , topmargin(0) @@ -1850,7 +1851,9 @@ void QWidgetPrivate::propagatePaletteChange() if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) { inheritedPaletteResolveMask = 0; } - QPalette::ResolveMask mask = data.pal.resolve() | inheritedPaletteResolveMask; + + directPaletteResolveMask = data.pal.resolve(); + auto mask = directPaletteResolveMask | inheritedPaletteResolveMask; const bool useStyleSheetPropagationInWidgetStyles = QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); @@ -10454,6 +10457,12 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) if (!useStyleSheetPropagationInWidgetStyles && !testAttribute(Qt::WA_StyleSheet) && (!parent || !parent->testAttribute(Qt::WA_StyleSheet))) { + // if the parent has a font set or inherited, then propagate the mask to the new child + if (parent) { + const auto pd = parent->d_func(); + d->inheritedFontResolveMask = pd->directFontResolveMask | pd->inheritedFontResolveMask; + d->inheritedPaletteResolveMask = pd->directPaletteResolveMask | pd->inheritedPaletteResolveMask; + } d->resolveFont(); d->resolvePalette(); } diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 0d0077548c..3c29b48973 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -672,6 +672,7 @@ public: // Other variables. uint directFontResolveMask; uint inheritedFontResolveMask; + decltype(std::declval<QPalette>().resolve()) directPaletteResolveMask; QPalette::ResolveMask inheritedPaletteResolveMask; short leftmargin; short topmargin; diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 904067afda..4ba5469e9d 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -727,19 +727,6 @@ bool QWidgetWindow::updateSize() return changed; } -bool QWidgetWindow::updatePos() -{ - bool changed = false; - if (m_widget->testAttribute(Qt::WA_OutsideWSRange)) - return changed; - if (m_widget->data->crect.topLeft() != geometry().topLeft()) { - changed = true; - m_widget->data->crect.moveTopLeft(geometry().topLeft()); - } - updateMargins(); - return changed; -} - void QWidgetWindow::updateMargins() { const QMargins margins = frameMargins(); @@ -800,8 +787,28 @@ void QWidgetWindow::updateNormalGeometry() void QWidgetWindow::handleMoveEvent(QMoveEvent *event) { - if (updatePos()) - QGuiApplication::forwardEvent(m_widget, event); + if (m_widget->testAttribute(Qt::WA_OutsideWSRange)) + return; + + auto oldPosition = m_widget->data->crect.topLeft(); + auto newPosition = geometry().topLeft(); + + if (!m_widget->isTopLevel()) { + if (auto *nativeParent = m_widget->nativeParentWidget()) + newPosition = m_widget->parentWidget()->mapFrom(nativeParent, newPosition); + } + + bool changed = newPosition != oldPosition; + + if (changed) + m_widget->data->crect.moveTopLeft(newPosition); + + updateMargins(); // FIXME: Only do when changed? + + if (changed) { + QMoveEvent widgetEvent(newPosition, oldPosition); + QGuiApplication::forwardEvent(m_widget, &widgetEvent, event); + } } void QWidgetWindow::handleResizeEvent(QResizeEvent *event) diff --git a/src/widgets/kernel/qwidgetwindow_p.h b/src/widgets/kernel/qwidgetwindow_p.h index 80a345465d..5689e129c3 100644 --- a/src/widgets/kernel/qwidgetwindow_p.h +++ b/src/widgets/kernel/qwidgetwindow_p.h @@ -125,7 +125,6 @@ private slots: private: void repaintWindow(); bool updateSize(); - bool updatePos(); void updateMargins(); void updateNormalGeometry(); diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index f4a53c9dfe..4b0094e578 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -431,7 +431,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q QIcon::Active, QIcon::Off); } - int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize); + const int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize, opt); QIcon::Mode mode = opt->state & State_Enabled ? (opt->state & State_Raised ? QIcon::Active : QIcon::Normal) : QIcon::Disabled; @@ -477,7 +477,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { int lw = frame->lineWidth; if (lw <= 0) - lw = proxy()->pixelMetric(PM_DockWidgetFrameWidth); + lw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, opt); qDrawShadePanel(p, frame->rect, frame->palette, false, lw); } @@ -563,8 +563,8 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q int bsx = 0; int bsy = 0; if (opt->state & State_Sunken) { - bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal); - bsy = proxy()->pixelMetric(PM_ButtonShiftVertical); + bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt); + bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt); } p->save(); p->translate(sx + bsx, sy + bsy); @@ -994,7 +994,7 @@ QSize QCommonStylePrivate::viewItemSize(const QStyleOptionViewItem *option, int } if (wrapText && option->features & QStyleOptionViewItem::HasCheckIndicator) - bounds.setWidth(bounds.width() - proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth) - 2 * textMargin); + bounds.setWidth(bounds.width() - proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth, option) - 2 * textMargin); const int lineWidth = bounds.width(); const QSizeF size = viewItemTextLayout(textLayout, lineWidth); @@ -1240,7 +1240,7 @@ void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *w if (!opt->icon.isNull()) { QSize iconSize = opt->iconSize; if (!iconSize.isValid()) { - int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize); + int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize, opt); iconSize = QSize(iconExtent, iconExtent); } QSize tabIconSize = opt->icon.actualSize(iconSize, @@ -1490,7 +1490,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, | Qt::TextSingleLine; if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget)) alignment |= Qt::TextHideMnemonic; - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt); QPixmap pix = mbi->icon.pixmap(qt_getWindow(widget), QSize(iconExtent, iconExtent), (mbi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); if (!pix.isNull()) proxy()->drawItemPixmap(p,mbi->rect, alignment, pix); @@ -1646,7 +1646,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) { QRect rect = header->rect; if (!header->icon.isNull()) { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt); QPixmap pixmap = header->icon.pixmap(qt_getWindow(widget), QSize(iconExtent, iconExtent), (header->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); int pixw = pixmap.width() / pixmap.devicePixelRatio(); @@ -3863,8 +3863,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl if (opt->activeSubControls & QStyle::SC_MdiCloseButton && (opt->state & State_Sunken)) { btnOpt.state |= State_Sunken; btnOpt.state &= ~State_Raised; - bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal); - bsy = proxy()->pixelMetric(PM_ButtonShiftVertical); + bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt); + bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt); } else { btnOpt.state |= State_Raised; btnOpt.state &= ~State_Sunken; @@ -3880,8 +3880,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl if (opt->activeSubControls & QStyle::SC_MdiNormalButton && (opt->state & State_Sunken)) { btnOpt.state |= State_Sunken; btnOpt.state &= ~State_Raised; - bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal); - bsy = proxy()->pixelMetric(PM_ButtonShiftVertical); + bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt); + bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt); } else { btnOpt.state |= State_Raised; btnOpt.state &= ~State_Sunken; @@ -3897,8 +3897,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl if (opt->activeSubControls & QStyle::SC_MdiMinButton && (opt->state & State_Sunken)) { btnOpt.state |= State_Sunken; btnOpt.state &= ~State_Raised; - bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal); - bsy = proxy()->pixelMetric(PM_ButtonShiftVertical); + bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt); + bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt); } else { btnOpt.state |= State_Raised; btnOpt.state &= ~State_Sunken; @@ -4781,12 +4781,12 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid } else if (widget) { isWindow = widget->isWindow(); } - ret = proxy()->pixelMetric(isWindow ? PM_DefaultTopLevelMargin : PM_DefaultChildMargin); + ret = proxy()->pixelMetric(isWindow ? PM_DefaultTopLevelMargin : PM_DefaultChildMargin, opt); } break; case PM_LayoutHorizontalSpacing: case PM_LayoutVerticalSpacing: - ret = proxy()->pixelMetric(PM_DefaultLayoutSpacing); + ret = proxy()->pixelMetric(PM_DefaultLayoutSpacing, opt); break; case PM_DefaultTopLevelMargin: @@ -4937,7 +4937,7 @@ QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, } else { h = mi->fontMetrics.height() + 8; if (!mi->icon.isNull()) { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt); h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4); } } @@ -4963,7 +4963,7 @@ QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, case CT_ComboBox: if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) { int fw = cmb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, opt, widget) * 2 : 0; - const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin) + 1); + const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin, opt) + 1); // QItemDelegate::sizeHint expands the textMargins two times, thus the 2*textMargins... int other = qMax(23, 2*textMargins + proxy()->pixelMetric(QStyle::PM_ScrollBarExtent, opt, widget)); sz = QSize(sz.width() + fw + other, sz.height() + fw); @@ -5214,8 +5214,8 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget if (widget) { if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) { mask->region = widget->rect(); - int vmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin), - hmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin); + const int vmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt); + const int hmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt); mask->region -= QRect(widget->rect().adjusted(hmargin, vmargin, -hmargin, -vmargin)); } } @@ -5228,7 +5228,7 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget ret = true; if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) { mask->region = opt->rect; - int margin = proxy()->pixelMetric(PM_DefaultFrameWidth) * 2; + const int margin = proxy()->pixelMetric(PM_DefaultFrameWidth, opt) * 2; mask->region -= opt->rect.adjusted(margin, margin, -margin, -margin); } } diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 2b59e5736b..4427d69944 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -3349,8 +3349,8 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom switch (subControl) { case SC_SliderHandle: { if (slider->orientation == Qt::Horizontal) { - rect.setHeight(proxy()->pixelMetric(PM_SliderThickness)); - rect.setWidth(proxy()->pixelMetric(PM_SliderLength)); + rect.setHeight(proxy()->pixelMetric(PM_SliderThickness, option)); + rect.setWidth(proxy()->pixelMetric(PM_SliderLength, option)); int centerY = slider->rect.center().y() - rect.height() / 2; if (slider->tickPosition & QSlider::TicksAbove) centerY += tickSize; @@ -3358,8 +3358,8 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom centerY -= tickSize; rect.moveTop(centerY); } else { - rect.setWidth(proxy()->pixelMetric(PM_SliderThickness)); - rect.setHeight(proxy()->pixelMetric(PM_SliderLength)); + rect.setWidth(proxy()->pixelMetric(PM_SliderThickness, option)); + rect.setHeight(proxy()->pixelMetric(PM_SliderLength, option)); int centerX = slider->rect.center().x() - rect.width() / 2; if (slider->tickPosition & QSlider::TicksAbove) centerX += tickSize; diff --git a/src/widgets/styles/qpixmapstyle.cpp b/src/widgets/styles/qpixmapstyle.cpp index 05e8467528..7cc32b2039 100644 --- a/src/widgets/styles/qpixmapstyle.cpp +++ b/src/widgets/styles/qpixmapstyle.cpp @@ -1003,13 +1003,13 @@ QSize QPixmapStyle::pushButtonSizeFromContents(const QStyleOption *option, return d->computeSize(desc, w, h); } -QSize QPixmapStyle::lineEditSizeFromContents(const QStyleOption *, +QSize QPixmapStyle::lineEditSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const { Q_D(const QPixmapStyle); const QPixmapStyleDescriptor &desc = d->descriptors.value(LE_Enabled); - const int border = 2 * proxy()->pixelMetric(PM_DefaultFrameWidth); + const int border = 2 * proxy()->pixelMetric(PM_DefaultFrameWidth, option); int w = contentsSize.width() + border + desc.margins.left() + desc.margins.right(); int h = contentsSize.height() + border + desc.margins.top() + desc.margins.bottom(); diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index 4ac0a11a36..69167a1fe2 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -1074,7 +1074,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SE_TreeViewDisclosureItem Area for the actual disclosure item in a tree branch. - \value SE_DialogButtonBoxLayoutItem Area that counts for the parent layout. + \omitvalue SE_DialogButtonBoxLayoutItem \value SE_GroupBoxLayoutItem Area that counts for the parent layout. diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h index f37604e0fa..5844251ae5 100644 --- a/src/widgets/styles/qstyle.h +++ b/src/widgets/styles/qstyle.h @@ -185,7 +185,7 @@ public: PE_IndicatorItemViewItemDrop, PE_PanelItemViewItem, - PE_PanelItemViewRow, // ### Qt 6: remove + PE_PanelItemViewRow, PE_PanelStatusBar, @@ -326,8 +326,10 @@ public: SE_CheckBoxLayoutItem, SE_ComboBoxLayoutItem, SE_DateTimeEditLayoutItem, - SE_DialogButtonBoxLayoutItem, // ### Qt 6: remove - SE_LabelLayoutItem, +#if QT_DEPRECATED_SINCE(5, 15) // ### Qt 6: remove + SE_DialogButtonBoxLayoutItem Q_DECL_ENUMERATOR_DEPRECATED, +#endif + SE_LabelLayoutItem = SE_DateTimeEditLayoutItem + 2, SE_ProgressBarLayoutItem, SE_PushButtonLayoutItem, SE_RadioButtonLayoutItem, @@ -529,11 +531,13 @@ public: PM_SpinBoxSliderHeight, - PM_DefaultTopLevelMargin, // ### Qt 6: remove - PM_DefaultChildMargin, // ### Qt 6: remove - PM_DefaultLayoutSpacing, // ### Qt 6: remove +#if QT_DEPRECATED_SINCE(5, 15) // ### Qt 6: remove + PM_DefaultTopLevelMargin Q_DECL_ENUMERATOR_DEPRECATED, + PM_DefaultChildMargin Q_DECL_ENUMERATOR_DEPRECATED, + PM_DefaultLayoutSpacing Q_DECL_ENUMERATOR_DEPRECATED, +#endif - PM_ToolBarIconSize, + PM_ToolBarIconSize = PM_SpinBoxSliderHeight + 4, PM_ListViewIconSize, PM_IconViewIconSize, PM_SmallIconSize, diff --git a/src/widgets/styles/qstylehelper.cpp b/src/widgets/styles/qstylehelper.cpp index 61a59b03c1..ea65227fd5 100644 --- a/src/widgets/styles/qstylehelper.cpp +++ b/src/widgets/styles/qstylehelper.cpp @@ -101,7 +101,13 @@ Q_WIDGETS_EXPORT qreal dpi(const QStyleOption *option) if (option) return option->fontMetrics.fontDpi(); + // Fall back to historical Qt behavior: hardocded 72 DPI on mac, + // primary screen DPI on other platforms. +#ifdef Q_OS_DARWIN return qstyleBaseDpi; +#else + return qt_defaultDpiX(); +#endif } Q_WIDGETS_EXPORT qreal dpiScaled(qreal value, qreal dpi) diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 8eb24d7557..4965d146b0 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -548,6 +548,8 @@ int QWindowsStyle::styleHint(StyleHint hint, const QStyleOption *opt, const QWid switch (hint) { case SH_EtchDisabledText: + ret = d_func()->isDarkMode() ? 0 : 1; + break; case SH_Slider_SnapToValue: case SH_PrintDialog_RightAlignButtons: case SH_FontDialog_SelectAssociatedText: diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp index fe1133c6c7..570ec72377 100644 --- a/src/widgets/widgets/qcalendarwidget.cpp +++ b/src/widgets/widgets/qcalendarwidget.cpp @@ -2232,7 +2232,9 @@ QSize QCalendarWidget::minimumSizeHint() const int rows = 7; int cols = 8; - const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1) * 2; + QStyleOption option; + option.initFrom(this); + const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option) + 1) * 2; if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) { rows = 6; diff --git a/src/widgets/widgets/qcombobox_p.h b/src/widgets/widgets/qcombobox_p.h index 3e78e756a6..d7b2457c49 100644 --- a/src/widgets/widgets/qcombobox_p.h +++ b/src/widgets/widgets/qcombobox_p.h @@ -142,7 +142,7 @@ public: setAttribute(Qt::WA_NoMousePropagation); } QSize sizeHint() const override { - return QSize(20, style()->pixelMetric(QStyle::PM_MenuScrollerHeight)); + return QSize(20, style()->pixelMetric(QStyle::PM_MenuScrollerHeight, nullptr, this)); } protected: diff --git a/src/widgets/widgets/qcommandlinkbutton.cpp b/src/widgets/widgets/qcommandlinkbutton.cpp index 2b9258fd91..e9462ed229 100644 --- a/src/widgets/widgets/qcommandlinkbutton.cpp +++ b/src/widgets/widgets/qcommandlinkbutton.cpp @@ -208,7 +208,7 @@ bool QCommandLinkButtonPrivate::usingVistaStyle() const //### This is a hack to detect if we are indeed running Vista style themed and not in classic // When we add api to query for this, we should change this implementation to use it. return q->style()->inherits("QWindowsVistaStyle") - && !q->style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal); + && q->style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, nullptr) == 0; } void QCommandLinkButtonPrivate::init() @@ -355,8 +355,10 @@ void QCommandLinkButton::paintEvent(QPaintEvent *) option.icon = QIcon(); //we draw this ourselves QSize pixmapSize = icon().actualSize(iconSize()); - int vOffset = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical) : 0; - int hOffset = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal) : 0; + const int vOffset = isDown() + ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option) : 0; + const int hOffset = isDown() + ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option) : 0; //Draw icon p.drawControl(QStyle::CE_PushButton, option); diff --git a/src/widgets/widgets/qeffects.cpp b/src/widgets/widgets/qeffects.cpp index 5cb8bb3c50..1f2d3517e8 100644 --- a/src/widgets/widgets/qeffects.cpp +++ b/src/widgets/widgets/qeffects.cpp @@ -54,6 +54,15 @@ QT_BEGIN_NAMESPACE +static QWidget *effectParent(const QWidget* w) +{ + const int screenNumber = w ? QGuiApplication::screens().indexOf(w->screen()) : 0; + QT_WARNING_PUSH // ### Qt 6: Find a replacement for QDesktopWidget::screen() + QT_WARNING_DISABLE_DEPRECATED + return QApplication::desktop()->screen(screenNumber); + QT_WARNING_POP +} + /* Internal class QAlphaWidget. @@ -98,12 +107,9 @@ static QAlphaWidget* q_blend = nullptr; /* Constructs a QAlphaWidget. */ -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED // ### Qt 6: Find a replacement for QDesktopWidget::screen() QAlphaWidget::QAlphaWidget(QWidget* w, Qt::WindowFlags f) - : QWidget(QApplication::desktop()->screen(QDesktopWidgetPrivate::screenNumber(w)), f) + : QWidget(effectParent(w), f) { -QT_WARNING_POP #ifndef Q_OS_WIN setEnabled(false); #endif @@ -383,7 +389,7 @@ static QRollEffect* q_roll = nullptr; Construct a QRollEffect widget. */ QRollEffect::QRollEffect(QWidget* w, Qt::WindowFlags f, DirFlags orient) - : QWidget(nullptr, f), orientation(orient) + : QWidget(effectParent(w), f), orientation(orient) { #ifndef Q_OS_WIN setEnabled(false); diff --git a/src/widgets/widgets/qfocusframe.cpp b/src/widgets/widgets/qfocusframe.cpp index 4d64c24db3..4e793d7a29 100644 --- a/src/widgets/widgets/qfocusframe.cpp +++ b/src/widgets/widgets/qfocusframe.cpp @@ -86,8 +86,10 @@ void QFocusFramePrivate::updateSize() if (!widget) return; - int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin), - hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + QStyleOption opt; + q->initStyleOption(&opt); + int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &opt), + hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &opt); QPoint pos(widget->x(), widget->y()); if (q->parentWidget() != widget->parentWidget()) pos = widget->parentWidget()->mapTo(q->parentWidget(), pos); @@ -98,8 +100,6 @@ void QFocusFramePrivate::updateSize() q->setGeometry(geom); QStyleHintReturnMask mask; - QStyleOption opt; - q->initStyleOption(&opt); if (q->style()->styleHint(QStyle::SH_FocusFrame_Mask, &opt, q, &mask)) q->setMask(mask.region); } @@ -263,8 +263,8 @@ QFocusFrame::paintEvent(QPaintEvent *) QStylePainter p(this); QStyleOption option; initStyleOption(&option); - int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin); - int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + const int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &option); + const int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option); QWidgetPrivate *wd = qt_widget_private(d->widget); QRect rect = wd->clipRect().adjusted(0, 0, hmargin*2, vmargin*2); p.setClipRect(rect); diff --git a/src/widgets/widgets/qgroupbox.cpp b/src/widgets/widgets/qgroupbox.cpp index 048fe42948..02a0bed325 100644 --- a/src/widgets/widgets/qgroupbox.cpp +++ b/src/widgets/widgets/qgroupbox.cpp @@ -491,9 +491,9 @@ QSize QGroupBox::minimumSizeHint() const int baseWidth = metrics.horizontalAdvance(d->title) + metrics.horizontalAdvance(QLatin1Char(' ')); int baseHeight = metrics.height(); if (d->checkable) { - baseWidth += style()->pixelMetric(QStyle::PM_IndicatorWidth); - baseWidth += style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing); - baseHeight = qMax(baseHeight, style()->pixelMetric(QStyle::PM_IndicatorHeight)); + baseWidth += style()->pixelMetric(QStyle::PM_IndicatorWidth, &option); + baseWidth += style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, &option); + baseHeight = qMax(baseHeight, style()->pixelMetric(QStyle::PM_IndicatorHeight, &option)); } QSize size = style()->sizeFromContents(QStyle::CT_GroupBox, &option, QSize(baseWidth, baseHeight), this); diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index bd5e0b047e..9faf161cb1 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -2075,7 +2075,7 @@ void QLineEdit::paintEvent(QPaintEvent *) if (d->cursorVisible && !d->control->isReadOnly()) flags |= QWidgetLineControl::DrawCursor; - d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth)); + d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth, &panel)); d->control->draw(&p, topLeft, r, flags); } diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index daa50aa8ee..cae776159d 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -2851,7 +2851,7 @@ void QMenu::paintEvent(QPaintEvent *e) frame.rect = rect(); frame.palette = palette(); frame.state = QStyle::State_None; - frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth); + frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &frame); frame.midLineWidth = 0; style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, &p, this); } diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 59c8af30b4..c8124468df 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -1014,7 +1014,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) frame.rect = rect(); frame.palette = palette(); frame.state = QStyle::State_None; - frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth); + frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame); frame.midLineWidth = 0; style()->drawPrimitive(QStyle::PE_PanelMenuBar, &frame, &p, this); } diff --git a/src/widgets/widgets/qtoolbarextension.cpp b/src/widgets/widgets/qtoolbarextension.cpp index bbe7eddaa4..165c7f274b 100644 --- a/src/widgets/widgets/qtoolbarextension.cpp +++ b/src/widgets/widgets/qtoolbarextension.cpp @@ -81,7 +81,9 @@ void QToolBarExtension::paintEvent(QPaintEvent *) QSize QToolBarExtension::sizeHint() const { - int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent); + QStyleOption opt; + opt.initFrom(this); + const int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt); return QSize(ext, ext); } diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index f8bccfbfa3..b68a216af5 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -2463,7 +2463,7 @@ void QWidgetTextControl::setCursorWidth(int width) Q_UNUSED(width); #else if (width == -1) - width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth); + width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth, nullptr); d->doc->documentLayout()->setProperty("cursorWidth", width); #endif d->repaintCursor(); diff --git a/src/xml/dom/qdom.cpp b/src/xml/dom/qdom.cpp index 1ac13b380a..39cf0c2653 100644 --- a/src/xml/dom/qdom.cpp +++ b/src/xml/dom/qdom.cpp @@ -39,12 +39,13 @@ #include <qplatformdefs.h> #include <qdom.h> -#include "qdom_p.h" -#include "qdomhelpers_p.h" #include "private/qxmlutils_p.h" #ifndef QT_NO_DOM +#include "qdom_p.h" +#include "qdomhelpers_p.h" + #include <qatomic.h> #include <qbuffer.h> #include <qiodevice.h> diff --git a/src/xml/dom/qdomhelpers.cpp b/src/xml/dom/qdomhelpers.cpp index 10e37f7c0f..63c2db929a 100644 --- a/src/xml/dom/qdomhelpers.cpp +++ b/src/xml/dom/qdomhelpers.cpp @@ -37,6 +37,10 @@ ** ****************************************************************************/ +#include <QtXml/qtxmlglobal.h> + +#ifndef QT_NO_DOM + #include "qdomhelpers_p.h" #include "qdom_p.h" #include "qxmlstream.h" @@ -661,3 +665,5 @@ bool QDomParser::parseMarkupDecl() } QT_END_NAMESPACE + +#endif // QT_NO_DOM diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index ca58b664a0..2c02fb2264 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -4684,6 +4684,12 @@ void tst_QString::fromUcs4() s = QString::fromUcs4(U"\u221212\U000020AC\U00010000"); QCOMPARE(s, QString::fromUtf8("\342\210\222" "12" "\342\202\254" "\360\220\200\200")); #endif + + // QTBUG-62011: don't mistake ZWNBS for BOM + // Start with one BOM, to ensure we use the right endianness: + const uint text[] = { 0xfeff, 97, 0xfeff, 98, 0xfeff, 99, 0xfeff, 100 }; + s = QString::fromUcs4(text, 8); + QCOMPARE(s, QStringView(u"a\xfeff" u"b\xfeff" u"c\xfeff" "d")); } void tst_QString::toUcs4() diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp index 22d96e76f9..771a4d0a32 100644 --- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -45,6 +45,8 @@ #include <algorithm> +// #define DEBUG_WRITE_OUTPUT + typedef QMap<QString, QString> QStringMap; typedef QList<int> QIntList; Q_DECLARE_METATYPE(QImage::Format) @@ -462,24 +464,24 @@ void tst_QImageReader::setScaledClipRect_data() QTest::addColumn<QRect>("newRect"); QTest::addColumn<QByteArray>("format"); - QTest::newRow("BMP: colorful") << "colorful" << QRect(0, 0, 50, 50) << QByteArray("bmp"); - QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(0, 0, 50, 50) << QByteArray("bmp"); - QTest::newRow("BMP: test32v5") << "test32v5" << QRect(0, 0, 50, 50) << QByteArray("bmp"); - QTest::newRow("BMP: font") << "font" << QRect(0, 0, 50, 50) << QByteArray("bmp"); - QTest::newRow("XPM: marble") << "marble" << QRect(0, 0, 50, 50) << QByteArray("xpm"); - QTest::newRow("PNG: kollada") << "kollada" << QRect(0, 0, 50, 50) << QByteArray("png"); - QTest::newRow("PPM: teapot") << "teapot" << QRect(0, 0, 50, 50) << QByteArray("ppm"); - QTest::newRow("PPM: runners") << "runners.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); - QTest::newRow("PPM: test") << "test.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); - QTest::newRow("XBM: gnus") << "gnus" << QRect(0, 0, 50, 50) << QByteArray("xbm"); + QTest::newRow("BMP: colorful") << "colorful" << QRect(50, 20, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(50, 20, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << "test32v5" << QRect(50, 20, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: font") << "font" << QRect(50, 20, 50, 50) << QByteArray("bmp"); + QTest::newRow("XPM: marble") << "marble" << QRect(50, 20, 50, 50) << QByteArray("xpm"); + QTest::newRow("PNG: kollada") << "kollada" << QRect(50, 20, 50, 50) << QByteArray("png"); + QTest::newRow("PPM: teapot") << "teapot" << QRect(50, 20, 50, 50) << QByteArray("ppm"); + QTest::newRow("PPM: runners") << "runners.ppm" << QRect(50, 20, 50, 50) << QByteArray("ppm"); + QTest::newRow("PPM: test") << "test.ppm" << QRect(50, 20, 50, 50) << QByteArray("ppm"); + QTest::newRow("XBM: gnus") << "gnus" << QRect(50, 20, 50, 50) << QByteArray("xbm"); - QTest::newRow("JPEG: beavis") << "beavis" << QRect(0, 0, 50, 50) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis") << "beavis" << QRect(50, 20, 50, 50) << QByteArray("jpeg"); - QTest::newRow("GIF: earth") << "earth" << QRect(0, 0, 50, 50) << QByteArray("gif"); - QTest::newRow("GIF: trolltech") << "trolltech" << QRect(0, 0, 50, 50) << QByteArray("gif"); + QTest::newRow("GIF: earth") << "earth" << QRect(50, 20, 50, 50) << QByteArray("gif"); + QTest::newRow("GIF: trolltech") << "trolltech" << QRect(50, 20, 50, 50) << QByteArray("gif"); - QTest::newRow("SVG: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svg"); - QTest::newRow("SVGZ: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svgz"); + QTest::newRow("SVG: rect") << "rect" << QRect(50, 20, 50, 50) << QByteArray("svg"); + QTest::newRow("SVGZ: rect") << "rect" << QRect(50, 20, 50, 50) << QByteArray("svgz"); } void tst_QImageReader::setScaledClipRect() @@ -495,7 +497,11 @@ void tst_QImageReader::setScaledClipRect() reader.setScaledClipRect(newRect); QImage image = reader.read(); QVERIFY(!image.isNull()); - QCOMPARE(image.rect(), newRect); + QCOMPARE(image.rect().translated(50, 20), newRect); +#ifdef DEBUG_WRITE_OUTPUT + QString tempPath = QDir::temp().filePath(fileName) + QLatin1String(".png"); + image.save(tempPath); +#endif QImageReader originalReader(prefix + fileName); originalReader.setScaledSize(QSize(300, 300)); diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index 191260fd41..549481aa21 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -75,6 +75,8 @@ private slots: void nativeHandles(); void nativeTexture_data(); void nativeTexture(); + void nativeBuffer_data(); + void nativeBuffer(); void resourceUpdateBatchBuffer_data(); void resourceUpdateBatchBuffer(); void resourceUpdateBatchRGBATextureUpload_data(); @@ -294,7 +296,8 @@ void tst_QRhi::create() QRhi::BaseInstance, QRhi::TriangleFanTopology, QRhi::ReadBackNonUniformBuffer, - QRhi::ReadBackNonBaseMipLevel + QRhi::ReadBackNonBaseMipLevel, + QRhi::TexelFetch }; for (size_t i = 0; i <sizeof(features) / sizeof(QRhi::Feature); ++i) rhi->isFeatureSupported(features[i]); @@ -545,6 +548,86 @@ void tst_QRhi::nativeTexture() } } +void tst_QRhi::nativeBuffer_data() +{ + rhiTestData(); +} + +void tst_QRhi::nativeBuffer() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing native buffer query"); + + const QRhiBuffer::Type types[3] = { QRhiBuffer::Immutable, QRhiBuffer::Static, QRhiBuffer::Dynamic }; + const QRhiBuffer::UsageFlags usages[3] = { QRhiBuffer::VertexBuffer, QRhiBuffer::IndexBuffer, QRhiBuffer::UniformBuffer }; + for (int typeUsageIdx = 0; typeUsageIdx < 3; ++typeUsageIdx) { + QScopedPointer<QRhiBuffer> buf(rhi->newBuffer(types[typeUsageIdx], usages[typeUsageIdx], 256)); + QVERIFY(buf->build()); + + const QRhiBuffer::NativeBuffer nativeBuf = buf->nativeBuffer(); + QVERIFY(nativeBuf.slotCount <= rhi->resourceLimit(QRhi::FramesInFlight)); + + switch (impl) { + case QRhi::Null: + break; + #ifdef TST_VK + case QRhi::Vulkan: + { + QVERIFY(nativeBuf.slotCount >= 1); // always backed by native buffers + for (int i = 0; i < nativeBuf.slotCount; ++i) { + auto *buffer = static_cast<const VkBuffer *>(nativeBuf.objects[i]); + QVERIFY(buffer); + QVERIFY(*buffer); + } + } + break; + #endif + #ifdef TST_GL + case QRhi::OpenGLES2: + { + QVERIFY(nativeBuf.slotCount >= 0); // UniformBuffers are not backed by native buffers, so 0 is perfectly valid + for (int i = 0; i < nativeBuf.slotCount; ++i) { + auto *bufferId = static_cast<const uint *>(nativeBuf.objects[i]); + QVERIFY(bufferId); + QVERIFY(*bufferId); + } + } + break; + #endif + #ifdef TST_D3D11 + case QRhi::D3D11: + { + QVERIFY(nativeBuf.slotCount >= 1); // always backed by native buffers + for (int i = 0; i < nativeBuf.slotCount; ++i) { + auto *buffer = static_cast<void * const *>(nativeBuf.objects[i]); + QVERIFY(buffer); + QVERIFY(*buffer); + } + } + break; + #endif + #ifdef TST_MTL + case QRhi::Metal: + { + QVERIFY(nativeBuf.slotCount >= 1); // always backed by native buffers + for (int i = 0; i < nativeBuf.slotCount; ++i) { + void * const * buffer = (void * const *) nativeBuf.objects[i]; + QVERIFY(buffer); + QVERIFY(*buffer); + } + } + break; + #endif + default: + Q_ASSERT(false); + } + } +} + static bool submitResourceUpdates(QRhi *rhi, QRhiResourceUpdateBatch *batch) { QRhiCommandBuffer *cb = nullptr; @@ -1671,9 +1754,9 @@ void tst_QRhi::renderToWindowSimple() QVERIFY(pipeline->build()); - const int framesInFlight = rhi->resourceLimit(QRhi::FramesInFlight); - QVERIFY(framesInFlight >= 1); - const int FRAME_COUNT = framesInFlight + 1; + const int asyncReadbackFrames = rhi->resourceLimit(QRhi::MaxAsyncReadbackFrames); + // one frame issues the readback, then we do MaxAsyncReadbackFrames more to ensure the readback completes + const int FRAME_COUNT = asyncReadbackFrames + 1; bool readCompleted = false; QRhiReadbackResult readResult; QImage result; @@ -1720,8 +1803,8 @@ void tst_QRhi::renderToWindowSimple() } // The readback is asynchronous here. However it is guaranteed that it - // finished at latest after rendering QRhi::FramesInFlight frames after the - // one that enqueues the readback. + // finished at latest after rendering QRhi::MaxAsyncReadbackFrames frames + // after the one that enqueues the readback. QVERIFY(readCompleted); QVERIFY(readbackWidth > 0); diff --git a/tests/auto/gui/text/qfont/tst_qfont.cpp b/tests/auto/gui/text/qfont/tst_qfont.cpp index 9487436336..2d72eef459 100644 --- a/tests/auto/gui/text/qfont/tst_qfont.cpp +++ b/tests/auto/gui/text/qfont/tst_qfont.cpp @@ -314,27 +314,33 @@ void tst_QFont::resolve() void tst_QFont::resetFont() { QWidget parent; + QWidget firstChild(&parent); QFont parentFont = parent.font(); parentFont.setPointSize(parentFont.pointSize() + 2); parent.setFont(parentFont); - QWidget *child = new QWidget(&parent); - - QFont childFont = child->font(); + QFont childFont = firstChild.font(); childFont.setBold(!childFont.bold()); - child->setFont(childFont); + firstChild.setFont(childFont); + + QWidget secondChild(&parent); + secondChild.setFont(childFont); QVERIFY(parentFont.resolve() != 0); QVERIFY(childFont.resolve() != 0); QVERIFY(childFont != parentFont); - child->setFont(QFont()); // reset font + // reset font on both children + firstChild.setFont(QFont()); + secondChild.setFont(QFont()); - QCOMPARE(child->font().resolve(), uint(0)); + QCOMPARE(firstChild.font().resolve(), QFont::SizeResolved); + QCOMPARE(secondChild.font().resolve(), QFont::SizeResolved); #ifdef Q_OS_ANDROID QEXPECT_FAIL("", "QTBUG-69214", Continue); #endif - QCOMPARE(child->font().pointSize(), parent.font().pointSize()); + QCOMPARE(firstChild.font().pointSize(), parent.font().pointSize()); + QCOMPARE(secondChild.font().pointSize(), parent.font().pointSize()); QVERIFY(parent.font().resolve() != 0); } #endif diff --git a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp index 59e93d127f..56df69dde8 100644 --- a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp +++ b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp @@ -198,6 +198,9 @@ private slots: void shouldGenerateDifferentCodeDependingOnActiveLayers(); void shouldUseGlobalVariableRatherThanTemporaries(); void shouldGenerateTemporariesWisely(); + void shouldHandlePortNamesPrefixingOneAnother(); + void shouldHandleNodesWithMultipleOutputPorts(); + void shouldHandleExpressionsInInputNodes(); }; void tst_QShaderGenerator::shouldHaveDefaultState() @@ -1229,6 +1232,196 @@ void tst_QShaderGenerator::shouldGenerateTemporariesWisely() } } +void tst_QShaderGenerator::shouldHandlePortNamesPrefixingOneAnother() +{ + // GIVEN + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + auto color1 = createNode({ + createPort(QShaderNodePort::Output, "output") + }); + color1.addRule(gl4, QShaderNode::Rule("vec4 $output = color1;", + QByteArrayList() << "in vec4 color1;")); + + auto color2 = createNode({ + createPort(QShaderNodePort::Output, "output") + }); + color2.addRule(gl4, QShaderNode::Rule("vec4 $output = color2;", + QByteArrayList() << "in vec4 color2;")); + + auto addColor = createNode({ + createPort(QShaderNodePort::Output, "color"), + createPort(QShaderNodePort::Input, "color1"), + createPort(QShaderNodePort::Input, "color2"), + }); + addColor.addRule(gl4, QShaderNode::Rule("vec4 $color = $color1 + $color2;")); + + auto shaderOutput = createNode({ + createPort(QShaderNodePort::Input, "input") + }); + + shaderOutput.addRule(gl4, QShaderNode::Rule("shaderOutput = $input;", + QByteArrayList() << "out vec4 shaderOutput;")); + + // WHEN + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(color1); + res.addNode(color2); + res.addNode(addColor); + res.addNode(shaderOutput); + + res.addEdge(createEdge(color1.uuid(), "output", addColor.uuid(), "color1")); + res.addEdge(createEdge(color2.uuid(), "output", addColor.uuid(), "color2")); + res.addEdge(createEdge(addColor.uuid(), "color", shaderOutput.uuid(), "input")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode(); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "in vec4 color1;" + << "in vec4 color2;" + << "out vec4 shaderOutput;" + << "" + << "void main()" + << "{" + << " shaderOutput = ((color1 + color2));" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); +} + +void tst_QShaderGenerator::shouldHandleNodesWithMultipleOutputPorts() +{ + // GIVEN + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + auto input = createNode({ + createPort(QShaderNodePort::Output, "output0"), + createPort(QShaderNodePort::Output, "output1") + }); + input.addRule(gl4, QShaderNode::Rule("vec4 $output0 = globalIn0;" + "float $output1 = globalIn1;", + QByteArrayList() << "in vec4 globalIn0;" << "in float globalIn1;")); + + auto function = createNode({ + createPort(QShaderNodePort::Input, "input0"), + createPort(QShaderNodePort::Input, "input1"), + createPort(QShaderNodePort::Output, "output0"), + createPort(QShaderNodePort::Output, "output1") + }); + function.addRule(gl4, QShaderNode::Rule("vec4 $output0 = $input0;" + "float $output1 = $input1;")); + + auto output = createNode({ + createPort(QShaderNodePort::Input, "input0"), + createPort(QShaderNodePort::Input, "input1") + }); + + output.addRule(gl4, QShaderNode::Rule("globalOut0 = $input0;" + "globalOut1 = $input1;", + QByteArrayList() << "out vec4 globalOut0;" << "out float globalOut1;")); + + // WHEN + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(input); + res.addNode(function); + res.addNode(output); + + res.addEdge(createEdge(input.uuid(), "output0", function.uuid(), "input0")); + res.addEdge(createEdge(input.uuid(), "output1", function.uuid(), "input1")); + + res.addEdge(createEdge(function.uuid(), "output0", output.uuid(), "input0")); + res.addEdge(createEdge(function.uuid(), "output1", output.uuid(), "input1")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode(); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "in vec4 globalIn0;" + << "in float globalIn1;" + << "out vec4 globalOut0;" + << "out float globalOut1;" + << "" + << "void main()" + << "{" + << " globalOut0 = globalIn0;" + << " globalOut1 = globalIn1;" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); +} + +void tst_QShaderGenerator::shouldHandleExpressionsInInputNodes() +{ + // GIVEN + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + auto input = createNode({ + createPort(QShaderNodePort::Output, "output") + }); + input.addRule(gl4, QShaderNode::Rule("float $output = 3 + 4;")); + + auto output = createNode({ + createPort(QShaderNodePort::Input, "input") + }); + + output.addRule(gl4, QShaderNode::Rule("globalOut = $input;", + QByteArrayList() << "out float globalOut;")); + + // WHEN + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(input); + res.addNode(output); + + res.addEdge(createEdge(input.uuid(), "output", output.uuid(), "input")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode(); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "out float globalOut;" + << "" + << "void main()" + << "{" + << " globalOut = 3 + 4;" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); +} + QTEST_MAIN(tst_QShaderGenerator) #include "tst_qshadergenerator.moc" diff --git a/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp b/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp index ce2d38c24f..014a163f58 100644 --- a/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp +++ b/tests/auto/gui/util/qshadergraph/tst_qshadergraph.cpp @@ -114,6 +114,7 @@ private slots: void shouldSurviveCyclesDuringGraphSerialization(); void shouldDealWithEdgesJumpingOverLayers(); void shouldGenerateDifferentStatementsDependingOnActiveLayers(); + void shouldDealWithBranchesWithoutOutput(); }; void tst_QShaderGraph::shouldHaveEdgeDefaultState() @@ -515,12 +516,9 @@ void tst_QShaderGraph::shouldHandleUnboundPortsDuringGraphSerialization() const auto statements = graph.createStatements(); // THEN - // Note that no edge leads to the unbound input + // Note that no statement has any unbound input const auto expected = QVector<QShaderGraph::Statement>() - << createStatement(input, {}, {0}) - << createStatement(function, {-1, 0, -1}, {2, 3, 4}) - << createStatement(unboundOutput, {-1}, {}) - << createStatement(output, {3}, {}); + << createStatement(input, {}, {0}); dumpStatementsIfNeeded(statements, expected); QCOMPARE(statements, expected); } @@ -567,9 +565,8 @@ void tst_QShaderGraph::shouldSurviveCyclesDuringGraphSerialization() const auto statements = graph.createStatements(); // THEN - // Obviously will lead to a compile failure later on since it cuts everything beyond the cycle - const auto expected = QVector<QShaderGraph::Statement>() - << createStatement(output, {2}, {}); + // The cycle is ignored + const auto expected = QVector<QShaderGraph::Statement>(); dumpStatementsIfNeeded(statements, expected); QCOMPARE(statements, expected); } @@ -774,6 +771,50 @@ void tst_QShaderGraph::shouldGenerateDifferentStatementsDependingOnActiveLayers( } } +void tst_QShaderGraph::shouldDealWithBranchesWithoutOutput() +{ + // GIVEN + const auto input = createNode({ + createPort(QShaderNodePort::Output, "input") + }); + const auto output = createNode({ + createPort(QShaderNodePort::Input, "output") + }); + const auto danglingFunction = createNode({ + createPort(QShaderNodePort::Input, "functionInput"), + createPort(QShaderNodePort::Output, "unbound") + }); + const auto function = createNode({ + createPort(QShaderNodePort::Input, "functionInput"), + createPort(QShaderNodePort::Output, "functionOutput") + }); + + const auto graph = [=] { + auto res = QShaderGraph(); + res.addNode(input); + res.addNode(function); + res.addNode(danglingFunction); + res.addNode(output); + res.addEdge(createEdge(input.uuid(), "input", function.uuid(), "functionInput")); + res.addEdge(createEdge(input.uuid(), "input", danglingFunction.uuid(), "functionInput")); + res.addEdge(createEdge(function.uuid(), "functionOutput", output.uuid(), "output")); + return res; + }(); + + // WHEN + const auto statements = graph.createStatements(); + + // THEN + // Note that no edge leads to the unbound input + const auto expected = QVector<QShaderGraph::Statement>() + << createStatement(input, {}, {0}) + << createStatement(function, {0}, {1}) + << createStatement(output, {1}, {}) + << createStatement(danglingFunction, {0}, {2}); + dumpStatementsIfNeeded(statements, expected); + QCOMPARE(statements, expected); +} + QTEST_MAIN(tst_QShaderGraph) #include "tst_qshadergraph.moc" diff --git a/tests/auto/network-settings.h b/tests/auto/network-settings.h index 65d4bb5cea..641bf1d672 100644 --- a/tests/auto/network-settings.h +++ b/tests/auto/network-settings.h @@ -134,6 +134,22 @@ public: return true; } + static bool canBindToLowPorts() + { +#ifdef Q_OS_UNIX + if (geteuid() == 0) + return true; + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) + return true; + // ### Which versions of iOS, watchOS and such does Apple's opening of + // all ports apply to? + return false; +#else + // Windows + return true; +#endif + } + #ifdef QT_NETWORK_LIB static bool verifyTestNetworkSettings() diff --git a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp index 1ef9382f0a..68c913ecfc 100644 --- a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp @@ -529,18 +529,11 @@ void tst_PlatformSocketEngine::tooManySockets() //--------------------------------------------------------------------------- void tst_PlatformSocketEngine::bind() { -#if !defined Q_OS_WIN -#if defined Q_OS_MACOS - // On macOS >= 10.14 the bind on this port is successful. - if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave) -#endif // Q_OS_MACOS - { - PLATFORMSOCKETENGINE binder; - QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - QVERIFY(!binder.bind(QHostAddress::AnyIPv4, 82)); + PLATFORMSOCKETENGINE binder; + QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); + QCOMPARE(binder.bind(QHostAddress::AnyIPv4, 82), QtNetworkSettings::canBindToLowPorts()); + if (!QtNetworkSettings::canBindToLowPorts()) QCOMPARE(binder.error(), QAbstractSocket::SocketAccessError); - } -#endif // Q_OS_WIN PLATFORMSOCKETENGINE binder2; QVERIFY(binder2.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); @@ -552,6 +545,12 @@ void tst_PlatformSocketEngine::bind() QCOMPARE(binder3.error(), QAbstractSocket::AddressInUseError); if (QtNetworkSettings::hasIPv6()) { + PLATFORMSOCKETENGINE binder; + QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv6Protocol)); + QCOMPARE(binder.bind(QHostAddress::AnyIPv6, 82), QtNetworkSettings::canBindToLowPorts()); + if (!QtNetworkSettings::canBindToLowPorts()) + QCOMPARE(binder.error(), QAbstractSocket::SocketAccessError); + PLATFORMSOCKETENGINE binder4; QVERIFY(binder4.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv6Protocol)); QVERIFY(binder4.bind(QHostAddress::AnyIPv6, 31180)); diff --git a/tests/auto/network/socket/qtcpsocket/BLACKLIST b/tests/auto/network/socket/qtcpsocket/BLACKLIST index 07532710b3..129e9f0b4e 100644 --- a/tests/auto/network/socket/qtcpsocket/BLACKLIST +++ b/tests/auto/network/socket/qtcpsocket/BLACKLIST @@ -1,10 +1,3 @@ -[bind] -windows-10 msvc-2015 -windows-7sp1 -[bind:[::]] -windows -[bind:[::]:randomport] -windows [timeoutConnect:ip] windows # QTBUG-66247 diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index bf08d70eb3..099aa5fb51 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -523,7 +523,7 @@ void tst_QTcpSocket::bind_data() continue; // link-local bind will fail, at least on Linux, so skip it. QString ip(entry.ip().toString()); - QTest::newRow(ip.toLatin1().constData()) << ip << 0 << true << ip; + QTest::addRow("%s:0", ip.toLatin1().constData()) << ip << 0 << true << ip; if (!testIpv6 && entry.ip().protocol() == QAbstractSocket::IPv6Protocol) testIpv6 = true; @@ -531,9 +531,9 @@ void tst_QTcpSocket::bind_data() } // test binding to localhost - QTest::newRow("0.0.0.0") << "0.0.0.0" << 0 << true << "0.0.0.0"; + QTest::newRow("0.0.0.0:0") << "0.0.0.0" << 0 << true << "0.0.0.0"; if (testIpv6) - QTest::newRow("[::]") << "::" << 0 << true << "::"; + QTest::newRow("[::]:0") << "::" << 0 << true << "::"; // and binding with a port number... // Since we want to test that we got the port number we asked for, we need a random port number. @@ -551,26 +551,22 @@ void tst_QTcpSocket::bind_data() knownBad << "198.51.100.1"; knownBad << "2001:0DB8::1"; foreach (const QString &badAddress, knownBad) { - QTest::newRow(badAddress.toLatin1().constData()) << badAddress << 0 << false << QString(); + QTest::addRow("%s:0", badAddress.toLatin1().constData()) << badAddress << 0 << false << QString(); } -#ifdef Q_OS_UNIX // try to bind to a privileged ports // we should fail if we're not root (unless the ports are in use!) - QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << !geteuid() << (geteuid() ? QString() : "127.0.0.1"); - if (testIpv6) { #ifdef Q_OS_DARWIN - // This case is faling in different ways, first, it manages to bind to - // port 1 on macOS >= 10.14, but if we change the logic to not fail, - // it's becoming flaky and sometimes fails to bind, with error 'port in use' - // (apparently inflicted by the previous test row with 127.0.0.1). Amen. - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) - QTest::qWarn("Skipping [::]:1, see QTBUG-81905", __FILE__, __LINE__); - else + // Alas, some quirk (starting from macOS 10.14): bind with port number 1 + // fails with IPv4 (not IPv6 though, see below). + QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << false << QString(); +#else + QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << QtNetworkSettings::canBindToLowPorts() + << (QtNetworkSettings::canBindToLowPorts() ? "127.0.0.1" : QString()); #endif // Q_OS_DARWIN - QTest::newRow("[::]:1") << "::" << 1 << !geteuid() << (geteuid() ? QString() : "::"); - } -#endif + if (testIpv6) + QTest::newRow("[::]:1") << "::" << 1 << QtNetworkSettings::canBindToLowPorts() + << (QtNetworkSettings::canBindToLowPorts() ? "::" : QString()); } void tst_QTcpSocket::bind() @@ -589,13 +585,13 @@ void tst_QTcpSocket::bind() QTcpSocket dummySocket; // used only to "use up" a file descriptor dummySocket.bind(); - QTcpSocket *socket = newSocket(); + std::unique_ptr<QTcpSocket> socket(newSocket()); quint16 boundPort; qintptr fd; if (successExpected) { bool randomPort = port == -1; - int attemptsLeft = 5; // only used with randomPort + int attemptsLeft = 5; // only used with randomPort or Windows do { if (randomPort) { // try to get a random port number @@ -655,9 +651,24 @@ void tst_QTcpSocket::bind() QCOMPARE(acceptedSocket->peerPort(), boundPort); QCOMPARE(socket->localAddress(), remoteAddr); QCOMPARE(socket->socketDescriptor(), fd); +#ifdef Q_OS_DARWIN + // Normally, we don't see this problem: macOS sometimes does not + // allow us to immediately re-use a port, thinking connection is + // still alive. With fixed port 1 (we testing starting from + // macOS 10.14), this problem shows, making the test flaky: + // we run this 'bind' with port 1 several times (different + // test cases) and the problem manifests itself as + // "The bound address is already in use, tried port 1". + QTestEventLoop cleanupHelper; + auto client = socket.get(); + connect(client, &QTcpSocket::disconnected, [&cleanupHelper, client](){ + client->close(); + cleanupHelper.exitLoop(); + }); + acceptedSocket->close(); + cleanupHelper.enterLoopMSecs(100); +#endif // Q_OS_DARWIN } - - delete socket; } //---------------------------------------------------------------------------------- diff --git a/tests/auto/tools/moc/allmocs_baseline_in.json b/tests/auto/tools/moc/allmocs_baseline_in.json index 4f57fad5a8..9cc06dc7bc 100644 --- a/tests/auto/tools/moc/allmocs_baseline_in.json +++ b/tests/auto/tools/moc/allmocs_baseline_in.json @@ -3,6 +3,7 @@ "classes": [ { "className": "BackslashNewlines", + "object": true, "qualifiedClassName": "BackslashNewlines", "slots": [ { @@ -26,6 +27,7 @@ "classes": [ { "className": "IfdefedClass", + "object": true, "qualifiedClassName": "IfdefedClass", "superClasses": [ { @@ -239,6 +241,7 @@ "classes": [ { "className": "ExplicitOverrideControlBase", + "object": true, "qualifiedClassName": "ExplicitOverrideControlBase", "slots": [ { @@ -271,6 +274,7 @@ }, { "className": "ExplicitOverrideControlFinalQt", + "object": true, "qualifiedClassName": "ExplicitOverrideControlFinalQt", "slots": [ { @@ -303,6 +307,7 @@ }, { "className": "ExplicitOverrideControlFinalCxx11", + "object": true, "qualifiedClassName": "ExplicitOverrideControlFinalCxx11", "slots": [ { @@ -335,6 +340,7 @@ }, { "className": "ExplicitOverrideControlSealed", + "object": true, "qualifiedClassName": "ExplicitOverrideControlSealed", "slots": [ { @@ -367,6 +373,7 @@ }, { "className": "ExplicitOverrideControlOverrideQt", + "object": true, "qualifiedClassName": "ExplicitOverrideControlOverrideQt", "slots": [ { @@ -399,6 +406,7 @@ }, { "className": "ExplicitOverrideControlOverrideCxx11", + "object": true, "qualifiedClassName": "ExplicitOverrideControlOverrideCxx11", "slots": [ { @@ -431,6 +439,7 @@ }, { "className": "ExplicitOverrideControlFinalQtOverrideQt", + "object": true, "qualifiedClassName": "ExplicitOverrideControlFinalQtOverrideQt", "slots": [ { @@ -463,6 +472,7 @@ }, { "className": "ExplicitOverrideControlFinalCxx11OverrideCxx11", + "object": true, "qualifiedClassName": "ExplicitOverrideControlFinalCxx11OverrideCxx11", "slots": [ { @@ -495,6 +505,7 @@ }, { "className": "ExplicitOverrideControlSealedOverride", + "object": true, "qualifiedClassName": "ExplicitOverrideControlSealedOverride", "slots": [ { @@ -533,6 +544,7 @@ "classes": [ { "className": "FinalTestClassQt", + "object": true, "qualifiedClassName": "FinalTestClassQt", "superClasses": [ { @@ -543,6 +555,7 @@ }, { "className": "ExportedFinalTestClassQt", + "object": true, "qualifiedClassName": "ExportedFinalTestClassQt", "superClasses": [ { @@ -553,6 +566,7 @@ }, { "className": "ExportedFinalTestClassQtX", + "object": true, "qualifiedClassName": "ExportedFinalTestClassQtX", "superClasses": [ { @@ -563,6 +577,7 @@ }, { "className": "FinalTestClassCpp11", + "object": true, "qualifiedClassName": "FinalTestClassCpp11", "superClasses": [ { @@ -573,6 +588,7 @@ }, { "className": "ExportedFinalTestClassCpp11", + "object": true, "qualifiedClassName": "ExportedFinalTestClassCpp11", "superClasses": [ { @@ -583,6 +599,7 @@ }, { "className": "ExportedFinalTestClassCpp11X", + "object": true, "qualifiedClassName": "ExportedFinalTestClassCpp11X", "superClasses": [ { @@ -593,6 +610,7 @@ }, { "className": "SealedTestClass", + "object": true, "qualifiedClassName": "SealedTestClass", "superClasses": [ { @@ -603,6 +621,7 @@ }, { "className": "ExportedSealedTestClass", + "object": true, "qualifiedClassName": "ExportedSealedTestClass", "superClasses": [ { @@ -613,6 +632,7 @@ }, { "className": "ExportedSealedTestClassX", + "object": true, "qualifiedClassName": "ExportedSealedTestClassX", "superClasses": [ { @@ -654,7 +674,7 @@ ] } ], - "gadget": true, + "namespace": true, "qualifiedClassName": "CXX17Namespace::A::B::C::D" } ], @@ -673,6 +693,7 @@ } ] ], + "object": true, "qualifiedClassName": "DirInIncludePath", "superClasses": [ { @@ -707,6 +728,7 @@ } ], "className": "StringLiterals", + "object": true, "qualifiedClassName": "StringLiterals", "superClasses": [ { @@ -723,6 +745,7 @@ "classes": [ { "className": "ForwardDeclaredParamClass", + "object": true, "qualifiedClassName": "ForwardDeclaredParamClass", "signals": [ { @@ -923,6 +946,7 @@ "classes": [ { "className": "FunctionWithAttributes", + "object": true, "qualifiedClassName": "FunctionWithAttributes", "slots": [ { @@ -1016,6 +1040,7 @@ "classes": [ { "className": "TestFwdProperties", + "object": true, "properties": [ { "constant": false, @@ -1067,7 +1092,7 @@ }, { "className": "SomeRandomNamespace", - "gadget": true, + "namespace": true, "qualifiedClassName": "SomeRandomNamespace" } ], @@ -1089,7 +1114,7 @@ ] } ], - "gadget": true, + "namespace": true, "qualifiedClassName": "FooNamespace" }, { @@ -1114,7 +1139,7 @@ ] } ], - "gadget": true, + "namespace": true, "qualifiedClassName": "FooNamespace::FooNestedNamespace" }, { @@ -1130,7 +1155,7 @@ ] } ], - "gadget": true, + "namespace": true, "qualifiedClassName": "FooNamespace::FooNestedNamespace::FooMoreNestedNamespace" } ], @@ -1153,6 +1178,7 @@ ] } ], + "object": true, "properties": [ { "constant": false, @@ -1178,6 +1204,7 @@ }, { "className": "Baz", + "object": true, "properties": [ { "constant": false, @@ -1222,6 +1249,7 @@ "classes": [ { "className": "MyBooooooostishClass", + "object": true, "qualifiedClassName": "MyBooooooostishClass", "signals": [ { @@ -1269,6 +1297,7 @@ "classes": [ { "className": "OldStyleCast", + "object": true, "qualifiedClassName": "OldStyleCast", "slots": [ { @@ -1341,6 +1370,7 @@ } ], "className": "ParseDefine", + "object": true, "qualifiedClassName": "PD::ParseDefine", "signals": [ { @@ -1526,6 +1556,7 @@ "classes": [ { "className": "TestPluginMetaData", + "object": true, "qualifiedClassName": "TestPluginMetaData", "superClasses": [ { @@ -1542,6 +1573,7 @@ "classes": [ { "className": "PureVirtualSignalsTest", + "object": true, "qualifiedClassName": "PureVirtualSignalsTest", "signals": [ { @@ -1575,6 +1607,7 @@ }, { "className": "PureVirtualSignalsImpl", + "object": true, "qualifiedClassName": "PureVirtualSignalsImpl", "signals": [ { @@ -1616,6 +1649,7 @@ "returnType": "const char*" } ], + "object": true, "qualifiedClassName": "InvokableBeforeReturnType", "superClasses": [ { @@ -1638,6 +1672,7 @@ "returnType": "void" } ], + "object": true, "qualifiedClassName": "InvokableBeforeInline", "superClasses": [ { @@ -1661,6 +1696,7 @@ "returnType": "void" } ], + "object": true, "qualifiedClassName": "TestQPrivateSlots", "slots": [ { @@ -1705,6 +1741,7 @@ "classes": [ { "className": "B", + "object": true, "properties": [ { "constant": false, @@ -1745,6 +1782,7 @@ ] } ], + "object": true, "qualifiedClassName": "QTBUG_2151::A", "superClasses": [ { @@ -1755,6 +1793,7 @@ }, { "className": "B", + "object": true, "properties": [ { "constant": false, @@ -1810,6 +1849,7 @@ ] } ], + "object": true, "qualifiedClassName": "Unsused::Object", "superClasses": [ { @@ -1845,6 +1885,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS1::Nested::Object", "superClasses": [ { @@ -1880,6 +1921,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS1::NestedUnsused::Object", "superClasses": [ { @@ -1915,6 +1957,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS1::Object", "superClasses": [ { @@ -1925,6 +1968,7 @@ }, { "className": "DependingObject", + "object": true, "properties": [ { "constant": false, @@ -1961,6 +2005,7 @@ }, { "className": "DependingNestedGadget", + "object": true, "properties": [ { "constant": false, @@ -1985,6 +2030,7 @@ }, { "className": "DependingNestedObject", + "object": true, "properties": [ { "constant": false, @@ -2034,6 +2080,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS2::Nested::Object", "superClasses": [ { @@ -2069,6 +2116,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS2::NestedUnsused::Object", "superClasses": [ { @@ -2104,6 +2152,7 @@ ] } ], + "object": true, "qualifiedClassName": "NS2::Object", "superClasses": [ { @@ -2114,6 +2163,7 @@ }, { "className": "DependingObject", + "object": true, "properties": [ { "constant": false, @@ -2150,6 +2200,7 @@ }, { "className": "DependingNestedGadget", + "object": true, "properties": [ { "constant": false, @@ -2174,6 +2225,7 @@ }, { "className": "DependingNestedObject", + "object": true, "properties": [ { "constant": false, @@ -2214,6 +2266,7 @@ ] } ], + "object": true, "qualifiedClassName": "KDAB", "superClasses": [ { @@ -2230,6 +2283,7 @@ "classes": [ { "className": "SingleFunctionKeywordBeforeReturnType", + "object": true, "qualifiedClassName": "SingleFunctionKeywordBeforeReturnType", "signals": [ { @@ -2254,6 +2308,7 @@ }, { "className": "SingleFunctionKeywordBeforeInline", + "object": true, "qualifiedClassName": "SingleFunctionKeywordBeforeInline", "signals": [ { @@ -2278,6 +2333,7 @@ }, { "className": "SingleFunctionKeywordAfterInline", + "object": true, "qualifiedClassName": "SingleFunctionKeywordAfterInline", "signals": [ { @@ -2308,6 +2364,7 @@ "classes": [ { "className": "SlotsWithVoidTemplateTest", + "object": true, "qualifiedClassName": "SlotsWithVoidTemplateTest", "signals": [ { @@ -2373,6 +2430,7 @@ "classes": [ { "className": "Task192552", + "object": true, "qualifiedClassName": "Task192552", "superClasses": [ { @@ -2389,6 +2447,7 @@ "classes": [ { "className": "TestObject", + "object": true, "qualifiedClassName": "NS_A::NS_B::TestObject", "superClasses": [ { @@ -2399,6 +2458,7 @@ }, { "className": "TestMain", + "object": true, "qualifiedClassName": "NS_A::NS_Main::TestMain", "superClasses": [ { @@ -2415,6 +2475,7 @@ "classes": [ { "className": "TypenameWithUnsigned", + "object": true, "qualifiedClassName": "TypenameWithUnsigned", "slots": [ { @@ -2564,6 +2625,7 @@ "classes": [ { "className": "Task87883", + "object": true, "qualifiedClassName": "Task87883", "superClasses": [ { @@ -2580,6 +2642,7 @@ "classes": [ { "className": "Foo", + "object": true, "qualifiedClassName": "BBB::Foo", "signals": [ { diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST b/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST index aae2cacc3b..d9d7786314 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/BLACKLIST @@ -8,9 +8,5 @@ b2qt b2qt [dirsBeforeFiles] winrt -b2qt -ubuntu -windows-10 -rhel [drives] winrt diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index 8396fd4ec7..7259fa1ab0 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -976,6 +976,7 @@ void tst_QTreeView::indexWidget() QStandardItemModel treeModel; initStandardTreeModel(&treeModel); view.setModel(&treeModel); + view.resize(300, 400); // make sure the width of the view is larger than the widgets below QModelIndex index = view.model()->index(0, 0); @@ -1004,6 +1005,7 @@ void tst_QTreeView::indexWidget() //now let's try to do that later when the widget is already shown view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); index = view.model()->index(1, 0); QVERIFY(!view.indexWidget(index)); diff --git a/tests/auto/widgets/kernel/qwidget/hellotr_la.qm b/tests/auto/widgets/kernel/qwidget/hellotr_la.qm Binary files differnew file mode 100644 index 0000000000..25c0aad583 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget/hellotr_la.qm diff --git a/tests/auto/widgets/kernel/qwidget/qwidget.qrc b/tests/auto/widgets/kernel/qwidget/qwidget.qrc index 1399c4c9db..597ea872a5 100644 --- a/tests/auto/widgets/kernel/qwidget/qwidget.qrc +++ b/tests/auto/widgets/kernel/qwidget/qwidget.qrc @@ -3,5 +3,6 @@ <file>geometry.dat</file> <file>geometry-maximized.dat</file> <file>geometry-fullscreen.dat</file> + <file>hellotr_la.qm</file> </qresource> </RCC> diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 9c16b1a00a..f0c490b598 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -162,8 +162,10 @@ private slots: void fontPropagation(); void fontPropagation2(); void fontPropagation3(); + void fontPropagationDynamic(); void palettePropagation(); void palettePropagation2(); + void palettePropagationDynamic(); void enabledPropagation(); void ignoreKeyEventsWhenDisabled_QTBUG27417(); void properTabHandlingWhenDisabled_QTBUG27417(); @@ -310,6 +312,8 @@ private slots: void hideOpaqueChildWhileHidden(); void updateWhileMinimized(); void alienWidgets(); + void nativeWindowPosition_data(); + void nativeWindowPosition(); void adjustSize(); void adjustSize_data(); void updateGeometry(); @@ -410,6 +414,7 @@ private slots: void closeWithChildWindow(); void winIdAfterClose(); + void receivesLanguageChangeEvent(); private: bool ensureScreenSize(int width, int height); @@ -828,6 +833,66 @@ void tst_QWidget::fontPropagation3() QCOMPARE(p.font().pointSize(), child->font().pointSize()); } +/*! + This tests that children that are added to a widget with an explicitly + defined font inherit that font correctly, merging (and overriding) + with the font that might be defined by the platform theme. +*/ +void tst_QWidget::fontPropagationDynamic() +{ + // override side effects from previous tests + QFont themedFont; + themedFont.setBold(true); + themedFont.setPointSize(42); + QApplication::setFont(themedFont, "QPropagationTestWidget"); + + QWidget parent; + QWidget firstChild(&parent); + + const QFont defaultFont = parent.font(); + QFont appFont = defaultFont; + appFont.setPointSize(72); + + // sanity check + QVERIFY(themedFont != defaultFont); + QVERIFY(themedFont != appFont); + + // palette propagates to existing children + parent.setFont(appFont); + QCOMPARE(firstChild.font().pointSize(), appFont.pointSize()); + + // palatte propagates to children added later + QWidget secondChild(&parent); + QCOMPARE(secondChild.font().pointSize(), appFont.pointSize()); + QWidget thirdChild; + QCOMPARE(thirdChild.font().pointSize(), defaultFont.pointSize()); + thirdChild.setParent(&parent); + QCOMPARE(thirdChild.font().pointSize(), appFont.pointSize()); + + // even if the child has an override in QApplication::font + QPropagationTestWidget themedChild; + themedChild.ensurePolished(); // needed for default font to be set up + QCOMPARE(themedChild.font().pointSize(), themedFont.pointSize()); + QCOMPARE(themedChild.font().bold(), themedFont.bold()); + themedChild.setParent(&parent); + QCOMPARE(themedChild.font().pointSize(), appFont.pointSize()); + QCOMPARE(themedChild.font().bold(), themedFont.bold()); + + // grand children as well + QPropagationTestWidget themedGrandChild; + themedGrandChild.setParent(&themedChild); + QCOMPARE(themedGrandChild.font().pointSize(), appFont.pointSize()); + QCOMPARE(themedGrandChild.font().bold(), themedFont.bold()); + + // child with own font attribute does not inherit from parent + QFont childFont = defaultFont; + childFont.setPointSize(9); + QWidget modifiedChild; + modifiedChild.setFont(childFont); + modifiedChild.setParent(&parent); + QCOMPARE(modifiedChild.font().pointSize(), childFont.pointSize()); +} + void tst_QWidget::palettePropagation() { QScopedPointer<QWidget> testWidget(new QWidget); @@ -872,8 +937,8 @@ void tst_QWidget::palettePropagation2() // ! Note, the code below is executed in tst_QWidget's constructor. // QPalette palette; - // font.setColor(QPalette::ToolTipBase, QColor(12, 13, 14)); - // font.setColor(QPalette::Text, QColor(21, 22, 23)); + // palette.setColor(QPalette::ToolTipBase, QColor(12, 13, 14)); + // palette.setColor(QPalette::Text, QColor(21, 22, 23)); // qApp->setPalette(palette, "QPropagationTestWidget"); QScopedPointer<QWidget> root(new QWidget); @@ -972,6 +1037,68 @@ void tst_QWidget::palettePropagation2() QCOMPARE(child5->palette().color(QPalette::ToolTipText), sysPalButton); } +/*! + This tests that children that are added to a widget with an explicitly + defined palette inherit that palette correctly, merging (and overriding) + with the palette that might be defined by the platform theme. +*/ +void tst_QWidget::palettePropagationDynamic() +{ + // override side effects from previous tests + QPalette themedPalette; + themedPalette.setColor(QPalette::ToolTipBase, QColor(12, 13, 14)); + themedPalette.setColor(QPalette::Text, QColor(21, 22, 23)); + QApplication::setPalette(themedPalette, "QPropagationTestWidget"); + + QWidget parent; + QWidget firstChild(&parent); + + const QPalette defaultPalette = parent.palette(); + QPalette appPalette = defaultPalette; + const QColor appColor(1, 2, 3); + appPalette.setColor(QPalette::Text, appColor); + + // sanity check + QVERIFY(themedPalette != defaultPalette); + QVERIFY(themedPalette != appPalette); + + // palette propagates to existing children + parent.setPalette(appPalette); + QCOMPARE(firstChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + + // palatte propagates to children added later + QWidget secondChild(&parent); + QCOMPARE(secondChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + QWidget thirdChild; + QCOMPARE(thirdChild.palette().color(QPalette::Text), defaultPalette.color(QPalette::Text)); + thirdChild.setParent(&parent); + QCOMPARE(thirdChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + + // even if the child has an override in QApplication::palette + QPropagationTestWidget themedChild; + themedChild.ensurePolished(); // needed for default palette to be set up + QCOMPARE(themedChild.palette().color(QPalette::Text), themedPalette.color(QPalette::Text)); + QCOMPARE(themedChild.palette().color(QPalette::ToolTipBase), themedPalette.color(QPalette::ToolTipBase)); + themedChild.setParent(&parent); + QCOMPARE(themedChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + QCOMPARE(themedChild.palette().color(QPalette::ToolTipBase), themedPalette.color(QPalette::ToolTipBase)); + + // grand children as well + QPropagationTestWidget themedGrandChild; + themedGrandChild.setParent(&themedChild); + QCOMPARE(themedGrandChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text)); + QCOMPARE(themedGrandChild.palette().color(QPalette::ToolTipBase), themedPalette.color(QPalette::ToolTipBase)); + + // child with own color does not inherit from parent + QPalette childPalette = defaultPalette; + childPalette.setColor(QPalette::Text, Qt::red); + QWidget modifiedChild; + modifiedChild.setPalette(childPalette); + modifiedChild.setParent(&parent); + QCOMPARE(modifiedChild.palette().color(QPalette::Text), childPalette.color(QPalette::Text)); + +} + void tst_QWidget::enabledPropagation() { QScopedPointer<QWidget> testWidget(new QWidget); @@ -8210,6 +8337,40 @@ void tst_QWidget::alienWidgets() } } +using WidgetAttributes = QVector<Qt::WidgetAttribute>; + +void tst_QWidget::nativeWindowPosition_data() +{ + QTest::addColumn<WidgetAttributes>("attributes"); + + QTest::newRow("non-native all the way") + << WidgetAttributes{}; + QTest::newRow("native all the way") + << WidgetAttributes{ Qt::WA_NativeWindow }; + QTest::newRow("native with non-native ancestor") + << WidgetAttributes{ Qt::WA_NativeWindow, Qt::WA_DontCreateNativeAncestors }; +} + +void tst_QWidget::nativeWindowPosition() +{ + QWidget topLevel; + QWidget child(&topLevel); + child.move(5, 5); + + QWidget grandChild(&child); + grandChild.move(10, 10); + + QFETCH(WidgetAttributes, attributes); + for (auto attribute : attributes) + grandChild.setAttribute(attribute); + + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(child.pos(), QPoint(5, 5)); + QCOMPARE(grandChild.pos(), QPoint(10, 10)); +} + class ASWidget : public QWidget { public: @@ -11360,5 +11521,55 @@ void tst_QWidget::winIdAfterClose() delete spy; } +class LanguageChangeEventWidget : public QWidget +{ +public: + LanguageChangeEventWidget(QWidget *parent = nullptr) : QWidget(parent) {} + int languageChangeCount = 0; +protected: + bool event(QEvent *e) override + { + if (e->type() == QEvent::LanguageChange) + languageChangeCount++; + return QWidget::event(e); + } +}; + +class LanguageChangeEventWindow : public QWindow +{ +public: + LanguageChangeEventWindow(QWindow *parent = nullptr) : QWindow(parent) {} + int languageChangeCount = 0; +protected: + bool event(QEvent *e) override + { + if (e->type() == QEvent::LanguageChange) + languageChangeCount++; + return QWindow::event(e); + } +}; + +void tst_QWidget::receivesLanguageChangeEvent() +{ + // Confirm that any QWindow or QWidget only gets a single + // LanguageChange event when a translator is installed + LanguageChangeEventWidget topLevel; + auto childWidget = new LanguageChangeEventWidget(&topLevel); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + LanguageChangeEventWindow ww; + ww.show(); + QVERIFY(QTest::qWaitForWindowExposed(&ww)); + LanguageChangeEventWidget topLevelNotShown; + QTranslator t; + QVERIFY(t.load("hellotr_la.qm", ":/")); + QVERIFY(qApp->installTranslator(&t)); + QCoreApplication::sendPostedEvents(0, QEvent::LanguageChange); + QCOMPARE(topLevel.languageChangeCount, 1); + QCOMPARE(topLevelNotShown.languageChangeCount, 1); + QCOMPARE(childWidget->languageChangeCount, 1); + QCOMPARE(ww.languageChangeCount, 1); +} + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index dd3e2f844b..f42e2d777b 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -968,6 +968,7 @@ void tst_QWidget_window::tst_resize_count() { { ResizeWidget resize; + resize.setWindowFlags(Qt::X11BypassWindowManagerHint); resize.show(); QVERIFY(QTest::qWaitForWindowExposed(&resize)); #ifdef Q_OS_WINRT @@ -1000,6 +1001,7 @@ void tst_QWidget_window::tst_resize_count() } { ResizeWidget parent; + parent.setWindowFlag(Qt::X11BypassWindowManagerHint); ResizeWidget child(&parent); child.resize(m_testWidgetSize); child.winId(); diff --git a/tests/libfuzzer/gui/text/qtextdocument/setHtml/main.cpp b/tests/libfuzzer/gui/text/qtextdocument/sethtml/main.cpp index 51fa3c9e0f..51fa3c9e0f 100644 --- a/tests/libfuzzer/gui/text/qtextdocument/setHtml/main.cpp +++ b/tests/libfuzzer/gui/text/qtextdocument/sethtml/main.cpp diff --git a/tests/libfuzzer/gui/text/qtextdocument/setHtml/setHtml.pro b/tests/libfuzzer/gui/text/qtextdocument/sethtml/sethtml.pro index af5ef9e940..af5ef9e940 100644 --- a/tests/libfuzzer/gui/text/qtextdocument/setHtml/setHtml.pro +++ b/tests/libfuzzer/gui/text/qtextdocument/sethtml/sethtml.pro diff --git a/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/main.cpp b/tests/libfuzzer/gui/text/qtextdocument/setmarkdown/main.cpp index 66ddf738f2..66ddf738f2 100644 --- a/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/main.cpp +++ b/tests/libfuzzer/gui/text/qtextdocument/setmarkdown/main.cpp diff --git a/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/setMarkdown.pro b/tests/libfuzzer/gui/text/qtextdocument/setmarkdown/setmarkdown.pro index 758622e1af..758622e1af 100644 --- a/tests/libfuzzer/gui/text/qtextdocument/setMarkdown/setMarkdown.pro +++ b/tests/libfuzzer/gui/text/qtextdocument/setmarkdown/setmarkdown.pro diff --git a/tests/libfuzzer/gui/text/qtextlayout/beginLayout/beginLayout.pro b/tests/libfuzzer/gui/text/qtextlayout/beginlayout/beginlayout.pro index af5ef9e940..af5ef9e940 100644 --- a/tests/libfuzzer/gui/text/qtextlayout/beginLayout/beginLayout.pro +++ b/tests/libfuzzer/gui/text/qtextlayout/beginlayout/beginlayout.pro diff --git a/tests/libfuzzer/gui/text/qtextlayout/beginLayout/main.cpp b/tests/libfuzzer/gui/text/qtextlayout/beginlayout/main.cpp index dfb9559241..dfb9559241 100644 --- a/tests/libfuzzer/gui/text/qtextlayout/beginLayout/main.cpp +++ b/tests/libfuzzer/gui/text/qtextlayout/beginlayout/main.cpp diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp b/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp index f3f00e0255..fc7bdff3de 100644 --- a/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp +++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp @@ -167,7 +167,7 @@ void Window::init() #if defined(Q_OS_MACOS) || defined(Q_OS_IOS) if (m_graphicsApi == QRhi::Metal) { QRhiMetalInitParams params; - m_rhi = QRhi::create(QRhi::Metal, ¶ms, rhiFlags); + m_rhi.reset(QRhi::create(QRhi::Metal, ¶ms, rhiFlags)); } #endif |