summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/QtFrameworkHelpers.cmake13
-rw-r--r--src/3rdparty/emoji-segmenter/qt_attribution.json2
-rw-r--r--src/corelib/tools/qarraydataops.h4
-rw-r--r--src/gui/CMakeLists.txt1
-rw-r--r--src/gui/text/qfont.cpp53
-rw-r--r--src/plugins/platforms/cocoa/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/cocoa/qcocoa_plugin_pch.h16
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp28
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp121
-rw-r--r--src/widgets/doc/images/qfiledialog.pngbin0 -> 56037 bytes
-rw-r--r--src/widgets/doc/images/qtquickdialogs-filedialog-gtk.pngbin39560 -> 0 bytes
-rw-r--r--src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp6
-rw-r--r--tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp2
-rw-r--r--tests/auto/gui/text/qfont/tst_qfont.cpp112
14 files changed, 245 insertions, 115 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/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/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
new file mode 100644
index 00000000000..62c27c7917a
--- /dev/null
+++ b/src/widgets/doc/images/qfiledialog.png
Binary files differ
diff --git a/src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png b/src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png
deleted file mode 100644
index 9360d747a2b..00000000000
--- a/src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png
+++ /dev/null
Binary files differ
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()