diff options
| -rw-r--r-- | cmake/QtFrameworkHelpers.cmake | 13 | ||||
| -rw-r--r-- | src/3rdparty/emoji-segmenter/qt_attribution.json | 2 | ||||
| -rw-r--r-- | src/corelib/tools/qarraydataops.h | 4 | ||||
| -rw-r--r-- | src/corelib/tools/qhash.h | 8 | ||||
| -rw-r--r-- | src/gui/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/gui/text/qfont.cpp | 53 | ||||
| -rw-r--r-- | src/plugins/platforms/cocoa/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/plugins/platforms/cocoa/qcocoa_plugin_pch.h | 16 | ||||
| -rw-r--r-- | src/plugins/styles/modernwindows/qwindows11style.cpp | 28 | ||||
| -rw-r--r-- | src/testlib/qtestblacklist.cpp | 4 | ||||
| -rw-r--r-- | src/widgets/dialogs/qfiledialog.cpp | 121 | ||||
| -rw-r--r-- | src/widgets/doc/images/qfiledialog.png | bin | 0 -> 56037 bytes | |||
| -rw-r--r-- | src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png | bin | 39560 -> 0 bytes | |||
| -rw-r--r-- | src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp | 6 | ||||
| -rw-r--r-- | tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp | 2 | ||||
| -rw-r--r-- | tests/auto/gui/text/qfont/tst_qfont.cpp | 112 |
16 files changed, 254 insertions, 118 deletions
diff --git a/cmake/QtFrameworkHelpers.cmake b/cmake/QtFrameworkHelpers.cmake index ade4630626b..39a08f2b9c1 100644 --- a/cmake/QtFrameworkHelpers.cmake +++ b/cmake/QtFrameworkHelpers.cmake @@ -136,11 +136,12 @@ function(qt_copy_framework_headers target) ) if(NOT UIKIT) - set(create_headers_symlink_command - "${CMAKE_COMMAND}" -E create_symlink - "Versions/Current/Headers" - "${output_dir}/${fw_header_dir}" - ) + # Create the framework's basic layout at configure time already. This is necessary, because + # we don't rely on the PUBLIC_HEADER property to create the QtFoo.framework/Headers symlink. + # See QTBUG-142119 for details. + file(MAKE_DIRECTORY "${output_dir}/${fw_dir}/Versions/${fw_version}/Headers") + file(CREATE_LINK "${fw_version}" "${output_dir}/${fw_dir}/Versions/Current" SYMBOLIC) + file(CREATE_LINK "Versions/Current/Headers" "${output_dir}/${fw_header_dir}" SYMBOLIC) endif() if(CMAKE_GENERATOR MATCHES "^Ninja") @@ -151,7 +152,6 @@ function(qt_copy_framework_headers target) DEPENDS ${target}_sync_headers COMMAND ${copy_fw_sync_headers_command} COMMAND ${copy_fw_sync_headers_marker_file_command} - COMMAND ${create_headers_symlink_command} VERBATIM ) add_custom_target(${target}_copy_fw_sync_headers @@ -160,7 +160,6 @@ function(qt_copy_framework_headers target) add_custom_target(${target}_copy_fw_sync_headers COMMAND ${copy_fw_sync_headers_command} COMMAND ${copy_fw_sync_headers_marker_file_command} - COMMAND ${create_headers_symlink_command} DEPENDS ${target}_sync_headers ) endif() diff --git a/src/3rdparty/emoji-segmenter/qt_attribution.json b/src/3rdparty/emoji-segmenter/qt_attribution.json index 64083381d4e..91dca1f4620 100644 --- a/src/3rdparty/emoji-segmenter/qt_attribution.json +++ b/src/3rdparty/emoji-segmenter/qt_attribution.json @@ -9,6 +9,8 @@ "Homepage": "https://github.com/google/emoji-segmenter", "Version": "0.4.0", "DownloadLocation": "https://github.com/google/emoji-segmenter/releases/tag/0.4.0", + "PURL": "pkg:github/google/emoji-segmenter@$<VERSION>", + "Comment": "no relevant CPE found", "License": "Apache License 2.0", "LicenseId": "Apache-2.0", diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 9e205815c7a..f1771c70d56 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -941,7 +941,9 @@ public: } } - if constexpr (!std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) { + if constexpr (!std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))> + || !std::is_nothrow_invocable_v<Projection, decltype(*first)>) + { // If construction can throw, and we have freeSpaceAtBegin(), // it's easiest to just clear the container and start fresh. // The alternative would be to keep track of two active, disjoint ranges. diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 76729917f6b..6509048da0c 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -23,7 +23,13 @@ QT_BEGIN_NAMESPACE struct QHashDummyValue { - bool operator==(const QHashDummyValue &) const noexcept { return true; } + explicit QHashDummyValue() = default; + friend constexpr bool operator==(QHashDummyValue, QHashDummyValue) noexcept { return true; } +#ifndef __cpp_impl_three_way_comparison + friend constexpr bool operator!=(QHashDummyValue, QHashDummyValue) noexcept { return false; } +#endif + friend constexpr size_t qHash(QHashDummyValue) noexcept = delete; + friend constexpr size_t qHash(QHashDummyValue, size_t) noexcept = delete; }; namespace QHashPrivate { diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 5e625ae9005..b40bc1ed0f9 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -307,6 +307,7 @@ qt_internal_add_module(Gui painting text ../3rdparty/VulkanMemoryAllocator + ../3rdparty/emoji-segmenter # Used by qbrush.cpp -> painting/webgradients.cpp which is generated by the JS script ../../util/gradientgen ELF_LINKER_DYNAMIC_LIST diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index a54dba7666f..7ffb688c035 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2166,7 +2166,8 @@ QString QFont::key() const \li Word spacing \li Stretch \li Style strategy - \li Font style (omitted when unavailable) + \li Font style + \li Font features \endlist \sa fromString() @@ -2189,11 +2190,16 @@ QString QFont::toString() const QString::number(letterSpacing()) + comma + QString::number(wordSpacing()) + comma + QString::number(stretch()) + comma + - QString::number((int)styleStrategy()); + QString::number((int)styleStrategy()) + comma + + styleName(); + + QMap<Tag, quint32> sortedFeatures; + for (const auto &[tag, value] : std::as_const(d->features).asKeyValueRange()) + sortedFeatures.insert(tag, value); - QString fontStyle = styleName(); - if (!fontStyle.isEmpty()) - fontDescription += comma + fontStyle; + fontDescription += comma + QString::number(sortedFeatures.size()); + for (const auto &[tag, value] : std::as_const(sortedFeatures).asKeyValueRange()) + fontDescription += comma + tag.toString() + u'=' + QString::number(value); return fontDescription; } @@ -2208,6 +2214,23 @@ size_t qHash(const QFont &font, size_t seed) noexcept return qHash(QFontPrivate::get(font)->request, seed); } +static std::optional<std::pair<QFont::Tag, quint32>> tagAndValueFromString(QStringView view) +{ + const int separator = view.indexOf(u'='); + if (separator == -1) + return std::nullopt; + + const std::optional<QFont::Tag> tag = QFont::Tag::fromString(view.sliced(0, separator)); + if (!tag) + return std::nullopt; + + bool valueOk = false; + const quint32 value = view.sliced(separator + 1).toUInt(&valueOk); + if (!valueOk) + return std::nullopt; + + return std::make_pair(*tag, value); +} /*! Sets this font to match the description \a descrip. The description @@ -2221,7 +2244,7 @@ bool QFont::fromString(const QString &descrip) const auto sr = QStringView(descrip).trimmed(); const auto l = sr.split(u','); const int count = l.size(); - if (!count || (count > 2 && count < 9) || count == 9 || count > 17 || + if (!count || (count > 2 && count < 9) || count == 9 || l.first().isEmpty()) { qWarning("QFont::fromString: Invalid description '%s'", descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data()); @@ -2257,10 +2280,24 @@ bool QFont::fromString(const QString &descrip) setStretch(l[14].toInt()); setStyleStrategy((StyleStrategy)l[15].toInt()); } - if (count == 11 || count == 17) - d->request.styleName = l[count - 1].toString(); + + if (count == 11) + d->request.styleName = l[10].toString(); + else if (count >= 17) + d->request.styleName = l[16].toString(); else d->request.styleName.clear(); + + clearFeatures(); + if (count >= 18) { + const int featureCount = l[17].toInt(); + if (count >= featureCount + 18) { + for (int i = 0; i < featureCount; ++i) { + if (const auto feature = tagAndValueFromString(l[18 + i])) + setFeature(feature->first, feature->second); + } + } + } } if (count >= 9 && !d->request.fixedPitch) // assume 'false' fixedPitch equals default diff --git a/src/plugins/platforms/cocoa/CMakeLists.txt b/src/plugins/platforms/cocoa/CMakeLists.txt index 07cffb24726..72d55c0791a 100644 --- a/src/plugins/platforms/cocoa/CMakeLists.txt +++ b/src/plugins/platforms/cocoa/CMakeLists.txt @@ -57,6 +57,8 @@ qt_internal_add_plugin(QCocoaIntegrationPlugin qcocoamessagedialog.h qcocoamessagedialog.mm DEFINES QT_NO_FOREACH + PRECOMPILED_HEADER + $<$<COMPILE_LANGUAGE:OBJCXX>:qcocoa_plugin_pch.h> LIBRARIES ${FWFoundation} ${FWAppKit} diff --git a/src/plugins/platforms/cocoa/qcocoa_plugin_pch.h b/src/plugins/platforms/cocoa/qcocoa_plugin_pch.h new file mode 100644 index 00000000000..05d4bae299f --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoa_plugin_pch.h @@ -0,0 +1,16 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include <QtCore/QtCore> +#include <QtGui/QtGui> + +#include <Carbon/Carbon.h> +#include <CoreGraphics/CoreGraphics.h> +#include <CoreVideo/CoreVideo.h> +#include <IOKit/graphics/IOGraphicsLib.h> +#include <IOSurface/IOSurface.h> +#include <QuartzCore/QuartzCore.h> + +#import <AppKit/AppKit.h> +#import <MetalKit/MetalKit.h> +#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h> diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp index b37140cba5e..bf4b3c6a9bc 100644 --- a/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -236,7 +236,7 @@ static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbut } #endif // QT_CONFIG(toolbutton) -static qreal radioButtonInnerRadius(int state) +static qreal radioButtonInnerRadius(QStyle::State state) { qreal radius = 7.0; if (state & QStyle::State_Sunken) @@ -353,7 +353,7 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow()) flags |= State_MouseOver; - painter->save(); + QPainterStateGuard psg(painter); painter->setRenderHint(QPainter::Antialiasing); if (d->transitionsEnabled() && option->styleObject) { if (control == CC_Slider) { @@ -536,10 +536,9 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt v = nextInterval; } if (!lines.isEmpty()) { - painter->save(); + QPainterStateGuard psg(painter); painter->translate(slrect.topLeft()); painter->drawLines(lines.constData(), lines.size()); - painter->restore(); } } if (sub & SC_SliderHandle) { @@ -765,7 +764,6 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt default: QWindowsVistaStyle::drawComplexControl(control, option, painter, widget); } - painter->restore(); } void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption *option, @@ -773,8 +771,8 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption const QWidget *widget) const { QWindows11StylePrivate *d = const_cast<QWindows11StylePrivate*>(d_func()); - int state = option->state; - painter->save(); + const State state = option->state; + QPainterStateGuard psg(painter); painter->setRenderHint(QPainter::Antialiasing); if (d->transitionsEnabled() && option->styleObject && (element == PE_IndicatorCheckBox || element == PE_IndicatorRadioButton)) { QObject *styleObject = option->styleObject; // Can be widget or qquickitem @@ -1095,17 +1093,15 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption painter->setBrush(view->alternatingRowColors() ? vopt->palette.highlight() : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]); painter->setPen(Qt::NoPen); if (isFirst) { - painter->save(); + QPainterStateGuard psg(painter); painter->setClipRect(rect); painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)), secondLevelRoundingRadius, secondLevelRoundingRadius); - painter->restore(); } else if (isLast) { - painter->save(); + QPainterStateGuard psg(painter); painter->setClipRect(rect); painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)), secondLevelRoundingRadius, secondLevelRoundingRadius); - painter->restore(); } else { painter->drawRect(vopt->rect.marginsRemoved(QMargins(0, 2, 0, 2))); } @@ -1185,7 +1181,6 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption default: QWindowsVistaStyle::drawPrimitive(element, option, painter, widget); } - painter->restore(); } /*! @@ -1197,7 +1192,7 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op Q_D(const QWindows11Style); State flags = option->state; - painter->save(); + QPainterStateGuard psg(painter); painter->setRenderHint(QPainter::Antialiasing); switch (element) { case QStyle::CE_ComboBoxLabel: @@ -1794,17 +1789,15 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)), secondLevelRoundingRadius, secondLevelRoundingRadius); } else if (isFirst) { - painter->save(); + QPainterStateGuard psg(painter); painter->setClipRect(rect); painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)), secondLevelRoundingRadius, secondLevelRoundingRadius); - painter->restore(); } else if (isLast) { - painter->save(); + QPainterStateGuard psg(painter); painter->setClipRect(rect); painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)), secondLevelRoundingRadius, secondLevelRoundingRadius); - painter->restore(); } else { painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2))); } @@ -1864,7 +1857,6 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op default: QWindowsVistaStyle::drawControl(element, option, painter, widget); } - painter->restore(); } int QWindows11Style::styleHint(StyleHint hint, const QStyleOption *opt, diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp index 8198137427c..0b3ae404012 100644 --- a/src/testlib/qtestblacklist.cpp +++ b/src/testlib/qtestblacklist.cpp @@ -240,7 +240,7 @@ static bool checkCondition(const QByteArray &condition) } static bool ignoreAll = false; -static std::set<QByteArray> *ignoredTests = nullptr; +static std::unique_ptr<std::set<QByteArray>> ignoredTests; namespace QTestPrivate { @@ -278,7 +278,7 @@ void parseBlackList() ignoreAll = true; } else { if (!ignoredTests) - ignoredTests = new std::set<QByteArray>; + ignoredTests = std::make_unique<std::set<QByteArray>>(); ignoredTests->insert(function); } } diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index b86f8c15c8b..03a42e321d2 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -57,89 +57,102 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir) /*! \class QFileDialog - \brief The QFileDialog class provides a dialog that allows users to select files or directories. + \brief Provides a dialog that allows users to select files or directories. \ingroup standard-dialogs \inmodule QtWidgets - The QFileDialog class enables a user to traverse the file system - to select one or many files or a directory. + The QFileDialog class enables users to browse the file system and select one + or more files or directories. - \image qtquickdialogs-filedialog-gtk.png {Open file dialog} + \image qfiledialog.png {Open file dialog} - The easiest way to create a QFileDialog is to use the static functions, - such as \l getOpenFileName(). + QFileDialog is commonly used to prompt users to open or save files, or to + select directories. The easiest way to use QFileDialog is through its static + convenience functions, such as \l getOpenFileName(). \snippet code/src_gui_dialogs_qfiledialog.cpp 0 - In the above example, a modal QFileDialog is created using a static - function. The dialog initially displays the contents of the "/home/jana" - directory, and displays files matching the patterns given in the - string "Image Files (*.png *.jpg *.bmp)". The parent of the file dialog - is set to \e this, and the window title is set to "Open Image". + In this example, a modal QFileDialog is created using a static function. The + dialog initially displays the contents of the \c{/home/jana} directory and + shows files matching the patterns in \c {"Image Files (*.png *.jpg *.bmp)"}. + The window title is set to \c{Open Image}. - If you want to use multiple filters, separate each one with - \e two semicolons. For example: + \section1 File filters + + \section2 Filtering files by name or extension + + To filter the displayed files by name or extension, use the setNameFilter() + or setNameFilters() functions. Multiple filters can be specified by + separating them with two semicolons (;;): \snippet code/src_gui_dialogs_qfiledialog.cpp 1 - You can create your own QFileDialog without using the static - functions. By calling setFileMode(), you can specify what the user must - select in the dialog: + \section2 Filtering files by MIME type + + To filter the displayed files by MIME type, use the setMimeTypeFilters() + function: + + \snippet code/src_gui_dialogs_qfiledialog.cpp 13 + + \section2 File filter case sensitivity + + Depending on target platform, file filters can be case-sensitive or + case-insensitive. + + \section1 File modes + + QFileDialog supports several file modes, which determine what the user can + select: \snippet code/src_gui_dialogs_qfiledialog.cpp 2 - In the above example, the mode of the file dialog is set to - AnyFile, meaning that the user can select any file, or even specify a - file that doesn't exist. This mode is useful for creating a - "Save As" file dialog. Use ExistingFile if the user must select an - existing file, or \l Directory if only a directory can be selected. + \list + \li \b AnyFile: The user can select any file, including files that do not + exist (useful for \c{Save As} dialogs). + \li \b ExistingFile: The user must select an existing file. + \li \b Directory: The user can select a directory. + \endlist + See the \l QFileDialog::FileMode enum for the complete list of modes. - The fileMode property contains the mode of operation for the dialog; - this indicates what types of objects the user is expected to select. - Use setNameFilter() to set the dialog's file filter. For example: + The fileMode property contains the current mode of operation. Use + setFileMode() to change it. - \snippet code/src_gui_dialogs_qfiledialog.cpp 3 + \section1 View modes - In the above example, the filter is set to \c{"Images (*.png *.xpm *.jpg)"}. - This means that only files with the extension \c png, \c xpm, - or \c jpg are shown in the QFileDialog. You can apply - several filters by using setNameFilters(). Use selectNameFilter() to select - one of the filters you've given as the file dialog's default filter. + QFileDialog provides two view modes: - The file dialog has two view modes: \l{QFileDialog::}{List} and - \l{QFileDialog::}{Detail}. - \l{QFileDialog::}{List} presents the contents of the current directory - as a list of file and directory names. \l{QFileDialog::}{Detail} also - displays a list of file and directory names, but provides additional - information alongside each name, such as the file size and modification - date. Set the mode with setViewMode(): + \list + \li \b List: Displays files and directories as a simple list. + \li \b Detail: Displays additional information such as file size and + modification date. + \endlist + + Set the view mode with setViewMode(): \snippet code/src_gui_dialogs_qfiledialog.cpp 4 - The last important function you need to use when creating your - own file dialog is selectedFiles(). + \section1 Retrieving selected files + + After the dialog is accepted, use selectedFiles() to retrieve the user's + selection: \snippet code/src_gui_dialogs_qfiledialog.cpp 5 - In the above example, a modal file dialog is created and shown. If - the user clicked OK, the file they selected is put in \c fileName. + The dialog's working directory can be set with setDirectory(). You can + pre-select a file using selectFile(). - The dialog's working directory can be set with setDirectory(). - Each file in the current directory can be selected using - the selectFile() function. + \section1 Platform notes - The \l{dialogs/standarddialogs}{Standard Dialogs} example shows - how to use QFileDialog as well as other built-in Qt dialogs. + By default, QFileDialog uses the platform's native file dialog if available. + In this case, some widget-specific APIs (such as layout() and itemDelegate()) + may return \c null. Also, not all platforms display file dialogs with a title + bar, so the caption text may not be visible. - By default, a platform-native file dialog is used if the platform has - one. In that case, the widgets that would otherwise be used to construct the - dialog are not instantiated, so related accessors such as layout() and - itemDelegate() return null. Also, not all platforms show file dialogs - with a title bar, so be aware that the caption text might not be visible to - the user. You can set the \l DontUseNativeDialog option or set the - \l{Qt::AA_DontUseNativeDialogs}{AA_DontUseNativeDialogs} application attribute - to ensure that the widget-based implementation is used instead of the native dialog. + To force the use of the Qt widget-based dialog, set the + \l DontUseNativeDialog option or the + \l{Qt::AA_DontUseNativeDialogs}{AA_DontUseNativeDialogs} application + attribute. \sa QDir, QFileInfo, QFile, QColorDialog, QFontDialog, {Standard Dialogs Example} */ diff --git a/src/widgets/doc/images/qfiledialog.png b/src/widgets/doc/images/qfiledialog.png Binary files differnew file mode 100644 index 00000000000..62c27c7917a --- /dev/null +++ b/src/widgets/doc/images/qfiledialog.png diff --git a/src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png b/src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png Binary files differdeleted file mode 100644 index 9360d747a2b..00000000000 --- a/src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png +++ /dev/null diff --git a/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp b/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp index 0325109c1f1..0cf6f62093e 100644 --- a/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp +++ b/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp @@ -24,11 +24,11 @@ FileDialogExample::FileDialogExample() } { - /* For convinient quoting. //! [1] - "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" + QFileDialog dialog(this); + dialog.setNameFilter(tr("Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)")); + dialog.exec(); //! [1] - */ } { diff --git a/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp b/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp index cb22024f769..ff78d1a1d1f 100644 --- a/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp +++ b/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp @@ -359,7 +359,7 @@ void tst_QGuiVariant::toString_data() #endif QFont font( "times", 12 ); - QTest::newRow("qfont") << QVariant::fromValue(font) << QString("times,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1"); + QTest::newRow("qfont") << QVariant::fromValue(font) << QString("times,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,0"); QTest::newRow( "qcolor" ) << QVariant::fromValue( QColor( 10, 10, 10 ) ) << QString( "#0a0a0a" ); } diff --git a/tests/auto/gui/text/qfont/tst_qfont.cpp b/tests/auto/gui/text/qfont/tst_qfont.cpp index 215ce412d98..8c4b8c75a26 100644 --- a/tests/auto/gui/text/qfont/tst_qfont.cpp +++ b/tests/auto/gui/text/qfont/tst_qfont.cpp @@ -50,7 +50,10 @@ private slots: void defaultFamily_data(); void defaultFamily(); void toAndFromString(); + void fromStringCompatibility_data(); + void fromStringCompatibility(); void fromStringWithoutStyleName(); + void fromStringWithoutFeatures(); void fromDegenerateString_data(); void fromDegenerateString(); @@ -645,51 +648,114 @@ void tst_QFont::toAndFromString() QCOMPARE(result, initial); } +} + +void tst_QFont::fromStringCompatibility_data() +{ + QTest::addColumn<bool>("current"); + QTest::addColumn<QString>("description"); + QTest::addColumn<QFont>("font"); - // Since Qt 6.0 it was changed to include more information in the description, so - // this checks for compatibility - const QString fontStringFrom515(QLatin1String("Times New Roman,18,-1,5,75,1,0,0,1,0,Regular")); QFont fontFrom515("Times New Roman", 18); fontFrom515.setBold(true); fontFrom515.setItalic(true); fontFrom515.setFixedPitch(true); fontFrom515.setStyleName("Regular"); - QFont from515String; - from515String.fromString(fontStringFrom515); - QCOMPARE(from515String, fontFrom515); + QTest::addRow("Times New Roman, Qt 5.15") << false << QStringLiteral("Times New Roman,18,-1,5,75,1,0,0,1,0,Regular") << fontFrom515; - const QString fontStringFrom60( - QLatin1String("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular")); QFont fontFrom60 = fontFrom515; fontFrom60.setStyleStrategy(QFont::PreferBitmap); fontFrom60.setCapitalization(QFont::AllUppercase); fontFrom60.setLetterSpacing(QFont::PercentageSpacing, 150.5); fontFrom60.setWordSpacing(2.5); fontFrom60.setStretch(50); - QFont from60String; - from60String.fromString(fontStringFrom60); - QCOMPARE(fontFrom60.toString(), fontStringFrom60); - QCOMPARE(from60String, fontFrom60); + QTest::addRow("Times New Roman, Qt 6.0") << false << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular") << fontFrom60; + + QFont fontFrom611 = fontFrom60; + QTest::addRow("Times New Roman, Qt 6.11") << true << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular,0") << fontFrom611; + + QFont fontFrom611WithFeatures = fontFrom60; + fontFrom611WithFeatures.setFeature("frac", 1); + fontFrom611WithFeatures.setFeature("liga", 0); + QTest::addRow("Times New Roman (with features), Qt 6.11") << true << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular,2,frac=1,liga=0") << fontFrom611WithFeatures; +} + +void tst_QFont::fromStringCompatibility() +{ + // This test verifies that font descriptions from older Qt releases are handled as expected. + + QFETCH(bool, current); + QFETCH(QString, description); + + QFont font; + font.fromString(description); + QTEST(font, "font"); + + if (current) { + QCOMPARE(font.toString(), description); + } } void tst_QFont::fromStringWithoutStyleName() { - QFont font1; - font1.fromString("Noto Sans,12,-1,5,50,0,0,0,0,0,Regular"); + // This test verifies that the style name will be reset if the from string contains no style. + + const QString fontString(QLatin1String("Times,16,-1,5,400,0,0,0,0,0,0,0,0,0,0,1")); + { + QFont font; + font.fromString("Noto Sans,12,-1,5,50,0,0,0,0,0,Regular"); - QFont font2 = font1; - const QString str = "Times,16,-1,5,400,0,0,0,0,0,0,0,0,0,0,1"; - font2.fromString(str); + QFont from = font; + from.fromString(fontString); - QCOMPARE(font2.toString(), str); + QFont clean; + clean.fromString(fontString); + + QCOMPARE(from, clean); + } const QString fontStringFrom60( QLatin1String("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2")); - QFont font3; - font3.fromString("Noto Sans,12,-1,5,50,0,0,0,0,0,Regular"); - QFont font4 = font3; - font4.fromString(fontStringFrom60); - QCOMPARE(font4.toString(), fontStringFrom60); + { + QFont font; + font.fromString("Noto Sans,12,-1,5,50,0,0,0,0,0,Regular"); + + QFont from = font; + from.fromString(fontStringFrom60); + + QFont clean; + clean.fromString(fontStringFrom60); + + QCOMPARE(from, clean); + } + + const QString fontStringFrom611( + QLatin1String("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,,0")); + { + QFont font; + font.fromString("Noto Sans,12,-1,5,50,0,0,0,0,0,Regular"); + + QFont from = font; + from.fromString(fontStringFrom611); + + QFont clean; + clean.fromString(fontStringFrom611); + + QCOMPARE(from, clean); + } +} + +void tst_QFont::fromStringWithoutFeatures() +{ + // This test verifies that the font feature list will be reset if the from string contains no features. + + const QString fontStringWithoutFeatures = QStringLiteral("Noto Sans,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1"); + const QString fontStringWithFeatures = QStringLiteral("Noto Sans,18,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,2,calt=0,frac=1"); + + QFont font; + font.fromString(fontStringWithFeatures); + font.fromString(fontStringWithoutFeatures); + QVERIFY(font.featureTags().isEmpty()); } void tst_QFont::fromDegenerateString_data() |
