summaryrefslogtreecommitdiffstats
path: root/src/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets')
-rw-r--r--src/widgets/CMakeLists.txt1
-rw-r--r--src/widgets/Qt6WidgetsMacros.cmake290
-rw-r--r--src/widgets/accessible/itemviews_p.h2
-rw-r--r--src/widgets/accessible/qaccessiblewidgetfactory.cpp1
-rw-r--r--src/widgets/accessible/qaccessiblewidgets.cpp4
-rw-r--r--src/widgets/dialogs/qdialog.h1
-rw-r--r--src/widgets/doc/snippets/cmake-macros/examples.cmake27
-rw-r--r--src/widgets/doc/snippets/cmake-macros/examples.cpp26
-rw-r--r--src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp4
-rw-r--r--src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp17
-rw-r--r--src/widgets/doc/src/cmake-macros.qdoc133
-rw-r--r--src/widgets/itemviews/qitemdelegate.cpp22
-rw-r--r--src/widgets/itemviews/qitemeditorfactory.cpp8
-rw-r--r--src/widgets/itemviews/qstyleditemdelegate.cpp19
-rw-r--r--src/widgets/kernel/qapplication.cpp6
-rw-r--r--src/widgets/kernel/qgesturemanager.cpp3
-rw-r--r--src/widgets/kernel/qwidget.cpp29
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp42
-rw-r--r--src/widgets/kernel/qwindowcontainer.cpp48
-rw-r--r--src/widgets/kernel/qwindowcontainer_p.h3
-rw-r--r--src/widgets/styles/qcommonstyle.cpp69
-rw-r--r--src/widgets/styles/qfusionstyle.cpp42
-rw-r--r--src/widgets/styles/qstyle_p.h26
-rw-r--r--src/widgets/styles/qstylehelper.cpp7
-rw-r--r--src/widgets/styles/qstylehelper_p.h2
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp3
-rw-r--r--src/widgets/styles/qstylesheetstyle_default.cpp3
-rw-r--r--src/widgets/util/qcompleter.cpp19
-rw-r--r--src/widgets/widgets/qcalendarwidget.cpp17
-rw-r--r--src/widgets/widgets/qcheckbox.cpp5
-rw-r--r--src/widgets/widgets/qdatetimeedit.cpp18
-rw-r--r--src/widgets/widgets/qdatetimeedit_p.h2
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.cpp58
-rw-r--r--src/widgets/widgets/qdialogbuttonbox_p.h5
-rw-r--r--src/widgets/widgets/qgroupbox.cpp4
-rw-r--r--src/widgets/widgets/qlineedit.cpp7
-rw-r--r--src/widgets/widgets/qmainwindowlayout.cpp16
-rw-r--r--src/widgets/widgets/qradiobutton.cpp2
38 files changed, 803 insertions, 188 deletions
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index 2ba8e4719a..fdef309a4a 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -55,6 +55,7 @@ qt_internal_add_module(Widgets
QT_NO_CONTEXTLESS_CONNECT
QT_NO_USING_NAMESPACE
QT_NO_FOREACH
+ QT_USE_NODISCARD_FILE_OPEN
INCLUDE_DIRECTORIES
dialogs
LIBRARIES
diff --git a/src/widgets/Qt6WidgetsMacros.cmake b/src/widgets/Qt6WidgetsMacros.cmake
index b15d1fe81d..a7ff7af2f3 100644
--- a/src/widgets/Qt6WidgetsMacros.cmake
+++ b/src/widgets/Qt6WidgetsMacros.cmake
@@ -49,3 +49,293 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()
endif()
+
+function(qt6_add_ui target)
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "Target \"${target}\" does not exist.")
+ endif()
+
+ set(options)
+ set(oneValueArgs INCLUDE_PREFIX)
+ set(multiValueArgs SOURCES OPTIONS)
+
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}"
+ ${ARGN})
+
+ set(sources ${arg_SOURCES})
+ set(ui_options ${arg_OPTIONS})
+ set(raw_include_prefix "${arg_INCLUDE_PREFIX}")
+
+ if("${sources}" STREQUAL "")
+ message(FATAL_ERROR "The \"SOURCES\" parameter is empty.")
+ endif()
+
+
+ # Disable AUTOUIC for the target explicitly to avoid the AUTOUIC
+ # error message when the AUTOUIC is enabled for the target.
+ set_target_properties(${target} PROPERTIES AUTOUIC OFF)
+
+ if(NOT "${raw_include_prefix}" STREQUAL "")
+ # generate dummy `_` folders from the given path
+ # e.g. if the given path is `../a/b/c`, then the generated path will be
+ # `_`. if the given path is ``../a/../b/c`, then the generated path will
+ # be `_/_`
+ function(_qt_internal_generate_dash_path_from_input input_path
+ out_generated_dash_path)
+ string(REGEX MATCHALL "\\.\\." upper_folder_list "${input_path}")
+
+ list(JOIN upper_folder_list "" upper_folder_list)
+ string(REGEX REPLACE "\\.\\." "_/" additional_path
+ "${upper_folder_list}")
+
+ # remove last / character
+ if(NOT "${additional_path}" STREQUAL "")
+ string(LENGTH "${additional_path}" additional_path_length)
+ math(EXPR additional_path_length "${additional_path_length} - 1")
+ string(SUBSTRING "${additional_path}" 0 ${additional_path_length}
+ additional_path)
+ endif()
+
+ set(${out_generated_dash_path} "${additional_path}" PARENT_SCOPE)
+ endfunction()
+ # NOTE: If previous folders are less than ../ folder count in
+ # ${raw_include_prefix}, relative path calculation will miscalculate,
+ # so we need to add dummy folders to calculate the relative path
+ # correctly
+ _qt_internal_generate_dash_path_from_input("${raw_include_prefix}"
+ dummy_path_for_relative_calculation)
+ if(NOT "${dummy_path_for_relative_calculation}" STREQUAL "")
+ set(dummy_path_for_relative_calculation
+ "/${dummy_path_for_relative_calculation}")
+ set(raw_include_prefix_to_compare
+ "${dummy_path_for_relative_calculation}/${raw_include_prefix}")
+ else()
+ set(dummy_path_for_relative_calculation "/")
+ set(raw_include_prefix_to_compare "/${raw_include_prefix}")
+ endif()
+ # NOTE: This relative path calculation could be done just by using the
+ # below code
+ # cmake_path(RELATIVE_PATH normalized_include_prefix "${CMAKE_CURRENT_SOURCE_DIR}"
+ # but due to the backward compatibility, we need to use
+ # file(RELATIVE_PATH) and ../ folder calculation the with
+ # _qt_internal_generate_dash_path_from_input() function
+ if(WIN32)
+ set(dummy_path_for_relative_calculation
+ "${CMAKE_CURRENT_SOURCE_DIR}/${dummy_path_for_relative_calculation}")
+ set(raw_include_prefix_to_compare
+ "${CMAKE_CURRENT_SOURCE_DIR}/${raw_include_prefix_to_compare}")
+ string(REGEX REPLACE "//" "/" dummy_path_for_relative_calculation
+ "${dummy_path_for_relative_calculation}")
+ string(REGEX REPLACE "//" "/" raw_include_prefix_to_compare
+ "${raw_include_prefix_to_compare}")
+ endif()
+
+ file(RELATIVE_PATH normalized_include_prefix
+ "${dummy_path_for_relative_calculation}"
+ "${raw_include_prefix_to_compare}")
+
+ # if normalized_include_prefix ends with `/` remove it
+ string(REGEX REPLACE "/$" "" normalized_include_prefix
+ "${normalized_include_prefix}")
+
+ _qt_internal_generate_dash_path_from_input("${normalized_include_prefix}"
+ additional_path)
+ endif()
+
+ if(ui_options MATCHES "\\$<CONFIG")
+ set(is_ui_options_contains_config true)
+ endif()
+ get_property(is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi AND is_ui_options_contains_config)
+ set(include_folder "$<CONFIG>")
+ endif()
+
+ set(include_folder_to_add "${include_folder}")
+ if(NOT "${additional_path}" STREQUAL "")
+ set(include_folder_to_add "${include_folder_to_add}/${additional_path}")
+ endif()
+
+ set(prefix_info_file_cmake
+ "${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen/prefix_info.cmake")
+ if(EXISTS ${prefix_info_file_cmake})
+ include(${prefix_info_file_cmake})
+ set(prefix_info_file_cmake_exists true)
+ else()
+ set(prefix_info_file_cmake_exists false)
+ endif()
+
+ foreach(source_file ${sources})
+ get_filename_component(outfile "${source_file}" NAME_WE)
+ get_filename_component(infile "${source_file}" ABSOLUTE)
+ string(SHA1 infile_hash "${target}${infile}")
+ string(SUBSTRING "${infile_hash}" 0 6 short_hash)
+ set(file_ui_folder "${CMAKE_CURRENT_BINARY_DIR}/.qt/${short_hash}")
+ target_include_directories(${target} SYSTEM PRIVATE
+ "${file_ui_folder}/${include_folder_to_add}")
+
+ set(target_include_folder_with_add_path
+ "${file_ui_folder}/${include_folder}")
+ # Add additional path to include folder if it is not empty
+ if(NOT "${additional_path}" STREQUAL "")
+ set(target_include_folder_with_add_path
+ "${target_include_folder_with_add_path}/${additional_path}")
+ endif()
+
+ set(inc_dir_to_create "${target_include_folder_with_add_path}")
+ if(NOT "${raw_include_prefix}" STREQUAL "")
+ set(inc_dir_to_create
+ "${target_include_folder_with_add_path}/${raw_include_prefix}")
+ endif()
+
+ set(output_directory "${target_include_folder_with_add_path}")
+ if(NOT "${normalized_include_prefix}" STREQUAL "")
+ set(output_directory
+ "${output_directory}/${normalized_include_prefix}")
+ endif()
+
+ if(NOT EXISTS "${infile}")
+ message(FATAL_ERROR "${infile} does not exist.")
+ endif()
+ set_source_files_properties(${infile} PROPERTIES SKIP_AUTOUIC ON)
+
+ macro(_qt_internal_set_output_file_properties file)
+ set_source_files_properties(${file} PROPERTIES
+ SKIP_AUTOMOC TRUE
+ SKIP_AUTOUIC TRUE
+ SKIP_LINTING TRUE)
+ endmacro()
+
+ set(outfile "${output_directory}/ui_${outfile}.h")
+ # Before CMake 3.27, there is a bug for using $<CONFIG> in a generated
+ # file with Ninja Multi-Config generator. To avoid this issue, we need
+ # to add the generated file for each configuration.
+ # Explicitly set the output file properties for each configuration
+ # to avoid Policy CMP0071 warnings.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/24848
+ # Xcode generator cannot handle $<CONFIG> in the output file name.
+ # it changes $<CONFIG> with NOCONFIG. That's why we need to add the
+ # generated file for each configuration for Xcode generator as well.
+ if(is_multi AND outfile MATCHES "\\$<CONFIG>"
+ AND CMAKE_VERSION VERSION_LESS "3.27"
+ OR CMAKE_GENERATOR MATCHES "Xcode")
+ foreach(config ${CMAKE_CONFIGURATION_TYPES})
+ string(REPLACE "$<CONFIG>" "${config}" outfile_with_config
+ "${outfile}")
+ _qt_internal_set_output_file_properties(
+ ${outfile_with_config})
+ target_sources(${target} PRIVATE ${outfile_with_config})
+ endforeach()
+ else()
+ _qt_internal_set_output_file_properties(${outfile})
+ target_sources(${target} PRIVATE ${outfile})
+ endif()
+ # remove double slashes
+ string(REGEX REPLACE "//" "/" outfile "${outfile}")
+
+ # Note: If INCLUDE_PREFIX is changed without changing the corresponding
+ # include path in the source file and Ninja generator is used, this
+ # casues the double build issue. To avoid this issue, we need to
+ # remove the output file in configure step if the include_prefix is
+ # changed.
+ if(CMAKE_GENERATOR MATCHES "Ninja")
+ if(prefix_info_file_cmake_exists)
+ if(NOT "${${short_hash}_prefix}" STREQUAL
+ "${normalized_include_prefix}")
+ file(REMOVE_RECURSE "${file_ui_folder}")
+ list(APPEND prefix_info_list
+ "set(${short_hash}_prefix \"${normalized_include_prefix}\")")
+ elseif(NOT DEFINED ${short_hash}_prefix)
+ list(APPEND prefix_info_list
+ "set(${short_hash}_prefix \"${normalized_include_prefix}\")")
+ endif()
+ else()
+ set(prefix_info_list "")
+ list(APPEND prefix_info_list
+ "set(${short_hash}_prefix \"${normalized_include_prefix}\")")
+ endif()
+ file(MAKE_DIRECTORY ${file_ui_folder})
+ endif()
+
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.17")
+ set(remove_command rm -rf)
+ else()
+ set(remove_command "remove_directory")
+ endif()
+
+ add_custom_command(OUTPUT ${outfile}
+ DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::uic
+ COMMAND ${CMAKE_COMMAND} -E ${remove_command} "${file_ui_folder}/${include_folder}"
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${inc_dir_to_create}
+ COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::uic ${ui_options} -o
+ ${outfile} ${infile}
+ COMMAND_EXPAND_LISTS
+ MAIN_DEPENDENCY ${infile} VERBATIM)
+ endforeach()
+
+
+ get_target_property(is_guard_on ${target} _qt_ui_property_check_guard)
+ if(NOT is_guard_on)
+ # Ninja fails when a newline is used. That's why message is
+ # divided into parts.
+ set(error_message_1
+ "Error: The target \"${target}\" has \"AUTOUIC\" enabled.")
+ set(error_message_2
+ "Error: Please disable \"AUTOUIC\" for the target \"${target}\".")
+
+ set(ui_property_check_dummy_file
+ "${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen/ui_property_check_timestamp")
+
+ add_custom_command(OUTPUT ${ui_property_check_dummy_file}
+ COMMAND ${CMAKE_COMMAND} -E make_directory
+ "${CMAKE_CURRENT_BINARY_DIR}/${target}_autogen"
+ COMMAND ${CMAKE_COMMAND} -E touch ${ui_property_check_dummy_file}
+ COMMAND
+ "$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
+;-E;echo;${error_message_1}>"
+ COMMAND
+ "$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
+;-E;echo;${error_message_2}>"
+ # Remove the dummy file so that the error message is shown until
+ # the AUTOUIC is disabled. Otherwise, the error message is shown
+ # only once when the AUTOUIC is enabled with Visual Studio generator.
+ COMMAND
+ "$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
+;-E;remove;${ui_property_check_dummy_file}>"
+ COMMAND
+ "$<$<BOOL:$<TARGET_PROPERTY:${target},AUTOUIC>>:${CMAKE_COMMAND}\
+;-E;false>"
+ COMMAND_EXPAND_LISTS
+ VERBATIM)
+
+ # When AUTOUIC is enabled, AUTOUIC runs before ${target}_ui_property_check
+ # target. So we need to add ${target}_ui_property_check as a dependency
+ # to ${target} to make sure that AUTOUIC runs after ${target}_ui_property_check
+ if (NOT QT_NO_MIX_UI_AUTOUIC_CHECK)
+ set_target_properties(${target} PROPERTIES
+ _qt_ui_property_check_guard ON)
+ add_custom_target(${target}_ui_property_check
+ ALL DEPENDS ${ui_property_check_dummy_file})
+ _qt_internal_assign_to_internal_targets_folder(
+ ${target}_ui_property_check)
+ add_dependencies(${target} ${target}_ui_property_check)
+ endif()
+ endif()
+
+ # write prefix info file
+ if(CMAKE_GENERATOR MATCHES "Ninja")
+ list(PREPEND prefix_info_list "include_guard()")
+ string(REPLACE ";" "\n" prefix_info_list "${prefix_info_list}")
+ file(WRITE "${prefix_info_file_cmake}" "${prefix_info_list}")
+ endif()
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_add_ui)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_add_ui(${ARGN})
+ else()
+ message(FATAL_ERROR "qt_add_ui() is only available in Qt 6.")
+ endif()
+ endfunction()
+endif()
+
diff --git a/src/widgets/accessible/itemviews_p.h b/src/widgets/accessible/itemviews_p.h
index ddc97baba1..077f14de1d 100644
--- a/src/widgets/accessible/itemviews_p.h
+++ b/src/widgets/accessible/itemviews_p.h
@@ -144,8 +144,6 @@ public:
private:
QModelIndex indexFromLogical(int row, int column = 0) const;
-
- inline int logicalIndex(const QModelIndex &index) const;
};
#endif
diff --git a/src/widgets/accessible/qaccessiblewidgetfactory.cpp b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
index e13b7ebcf7..664e35a6e7 100644
--- a/src/widgets/accessible/qaccessiblewidgetfactory.cpp
+++ b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
@@ -121,7 +121,6 @@ QAccessibleInterface *qAccessibleFactory(const QString &classname, QObject *obje
#if QT_CONFIG(itemviews)
} else if (classname == "QTableView"_L1 || classname == "QListView"_L1) {
iface = new QAccessibleTable(widget);
- // ### This should be cleaned up. We return the parent for the scrollarea to hide it.
#endif // QT_CONFIG(itemviews)
#if QT_CONFIG(tabbar)
} else if (classname == "QTabBar"_L1) {
diff --git a/src/widgets/accessible/qaccessiblewidgets.cpp b/src/widgets/accessible/qaccessiblewidgets.cpp
index 1c29de8caf..5c2a3bd02b 100644
--- a/src/widgets/accessible/qaccessiblewidgets.cpp
+++ b/src/widgets/accessible/qaccessiblewidgets.cpp
@@ -95,7 +95,7 @@ QWidgetList _q_ac_childWidgets(const QWidget *widget)
QAccessiblePlainTextEdit::QAccessiblePlainTextEdit(QWidget* o)
:QAccessibleTextWidget(o)
{
- Q_ASSERT(widget()->inherits("QPlainTextEdit"));
+ Q_ASSERT(qobject_cast<QPlainTextEdit *>(widget()));
}
QPlainTextEdit* QAccessiblePlainTextEdit::plainTextEdit() const
@@ -192,7 +192,7 @@ void QAccessiblePlainTextEdit::scrollToSubstring(int startIndex, int endIndex)
QAccessibleTextEdit::QAccessibleTextEdit(QWidget *o)
: QAccessibleTextWidget(o, QAccessible::EditableText)
{
- Q_ASSERT(widget()->inherits("QTextEdit"));
+ Q_ASSERT(qobject_cast<QTextEdit *>(widget()));
}
/*! Returns the text edit. */
diff --git a/src/widgets/dialogs/qdialog.h b/src/widgets/dialogs/qdialog.h
index 4d11fe2d8d..22360bc358 100644
--- a/src/widgets/dialogs/qdialog.h
+++ b/src/widgets/dialogs/qdialog.h
@@ -28,6 +28,7 @@ public:
~QDialog();
enum DialogCode { Rejected, Accepted };
+ Q_ENUM(DialogCode)
int result() const;
diff --git a/src/widgets/doc/snippets/cmake-macros/examples.cmake b/src/widgets/doc/snippets/cmake-macros/examples.cmake
index 3c58509fdf..7d0023aed4 100644
--- a/src/widgets/doc/snippets/cmake-macros/examples.cmake
+++ b/src/widgets/doc/snippets/cmake-macros/examples.cmake
@@ -6,3 +6,30 @@ set(SOURCES mainwindow.cpp main.cpp)
qt_wrap_ui(SOURCES mainwindow.ui)
qt_add_executable(myapp ${SOURCES})
#! [qt_wrap_ui]
+
+#! [qt6_add_ui_1]
+qt_add_executable(myapp mainwindow.cpp main.cpp)
+qt6_add_ui(myapp SOURCES mainwindow.ui)
+#! [qt6_add_ui_1]
+
+#! [qt6_add_ui_2]
+qt_add_executable(myapp mainwindow.cpp main.cpp)
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files" SOURCES mainwindow.ui)
+#! [qt6_add_ui_2]
+
+#! [qt6_add_ui_3]
+qt_add_executable(myapp widget1.cpp widget2.cpp main.cpp)
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files" SOURCES widget1.ui widget2.ui)
+#! [qt6_add_ui_3]
+
+#! [qt6_add_ui_4]
+qt_add_executable(myapp widget1.cpp widget2.cpp main.cpp)
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files"
+ SOURCES "my_ui_files_1/widget1.ui" "my_ui_files_2/widget2.ui")
+#! [qt6_add_ui_4]
+
+#! [qt6_add_ui_5]
+qt_add_executable(myapp widget1.cpp widget2.cpp main.cpp)
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files_1" SOURCES "my_ui_files/widget1.ui")
+qt6_add_ui(myapp INCLUDE_PREFIX "src/files_2" SOURCES "my_ui_files/widget2.ui")
+#! [qt6_add_ui_5]
diff --git a/src/widgets/doc/snippets/cmake-macros/examples.cpp b/src/widgets/doc/snippets/cmake-macros/examples.cpp
new file mode 100644
index 0000000000..683f8453e4
--- /dev/null
+++ b/src/widgets/doc/snippets/cmake-macros/examples.cpp
@@ -0,0 +1,26 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+//! [qt6_add_ui_1]
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+//! [qt6_add_ui_1]
+
+//! [qt6_add_ui_2]
+#include "mainwindow.h"
+#include "src/files/ui_mainwindow.h"
+//! [qt6_add_ui_2]
+
+//! [qt6_add_ui_3_1]
+#include "src/files/ui_widget1.h"
+//! [qt6_add_ui_3_1]
+
+//! [qt6_add_ui_3_2]
+#include "src/files/ui_widget2.h"
+//! [qt6_add_ui_3_2]
+
+//! [qt6_add_ui_5]
+#include "src/files_1/ui_widget1.h"
+#include "src/files_2/ui_widget2.h"
+//! [qt6_add_ui_5]
diff --git a/src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp b/src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp
index d314c88fd9..1a311015c4 100644
--- a/src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp
@@ -14,12 +14,16 @@ QItemEditorFactory *factory = new QItemEditorFactory;
//! [1]
+//! [setDefaultFactory]
//! [2]
QItemEditorFactory *editorFactory = new QItemEditorFactory;
QItemEditorCreatorBase *creator = new QStandardItemEditorCreator<MyFancyDateTimeEdit>();
editorFactory->registerEditor(QMetaType::QDateTime, creator);
//! [2]
+QItemEditorFactory::setDefaultFactory(editorFactory);
+//! [setDefaultFactory]
+
//! [3]
Q_PROPERTY(QColor color READ color WRITE setColor USER true)
diff --git a/src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp b/src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp
index 1298147de1..cff537c862 100644
--- a/src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp
@@ -4,3 +4,20 @@
//! [0]
g->setTitle("&User information");
//! [0]
+
+//! [Set up QGroupBox with layout]
+QGroupBox *groupBox = new QGroupBox(tr("Group Box with Layout"));
+
+QRadioButton *radio1 = new QRadioButton(tr("&Radio button 1"));
+QRadioButton *radio2 = new QRadioButton(tr("R&adio button 2"));
+QRadioButton *radio3 = new QRadioButton(tr("Ra&dio button 3"));
+
+radio1->setChecked(true);
+
+QVBoxLayout *vbox = new QVBoxLayout;
+vbox->addWidget(radio1);
+vbox->addWidget(radio2);
+vbox->addWidget(radio3);
+vbox->addStretch(1);
+groupBox->setLayout(vbox);
+//! [Set up QGroupBox with layout]
diff --git a/src/widgets/doc/src/cmake-macros.qdoc b/src/widgets/doc/src/cmake-macros.qdoc
index 13bdcca67b..906a18b2b0 100644
--- a/src/widgets/doc/src/cmake-macros.qdoc
+++ b/src/widgets/doc/src/cmake-macros.qdoc
@@ -30,6 +30,10 @@ directory. The paths of the generated header files are added to \c{<VAR>}.
\note This is a low-level macro. See the \l{CMake AUTOUIC Documentation} for a
more convenient way to process \c{.ui} files with \c{uic}.
+Since 6.8:
+\note \l{qt6_add_ui}{qt_add_ui} is the recommended way to process \c{.ui}
+files.
+
\section1 Options
You can set additional \c{OPTIONS} that should be added to the \c{uic} calls.
@@ -39,3 +43,132 @@ You can find possible options in the \l{uic}{uic documentation}.
\snippet cmake-macros/examples.cmake qt_wrap_ui
*/
+
+/*!
+\page qt-add-ui.html
+\ingroup cmake-macros-qtwidgets
+
+\title qt_add_ui
+\keyword qt6_add_ui
+
+\summary {Adds .ui files to a target.}
+
+\include cmake-find-package-widgets.qdocinc
+
+\section1 Synopsis
+
+\badcode
+qt_add_ui(<TARGET>
+ SOURCES file1.ui [file2.ui ...]
+ [INCLUDE_PREFIX <PREFIX>]
+ [OPTIONS ...])
+\endcode
+
+\versionlessCMakeCommandsNote qt6_add_ui()
+
+\cmakecommandsince 6.8
+
+\section1 Description
+
+Creates rules for calling the \l{uic}{User Interface Compiler (uic)} on the
+\c{.ui} files. For each input file, a header file is generated in the build
+directory. The generated header files are added to sources of the target.
+
+\section1 Arguments
+
+\section2 TARGET
+
+The \c{TARGET} argument specifies the CMake target to which the generated header
+files will be added.
+
+\section2 SOURCES
+
+The \c{SOURCES} argument specifies the list of \c{.ui} files to process.
+
+\section2 INCLUDE_PREFIX
+
+\c INCLUDE_PREFIX specifies the include prefix for the generated header files.
+Use the same include prefix as in the \c{#include} directive in the source
+files. If \c{ui_<basename>.h} is included without a prefix, then this argument
+can be omitted.
+
+\section2 OPTIONS
+
+You can set additional \c{OPTIONS} that should be added to the \c{uic} calls.
+You can find possible options in the \l{uic}{uic documentation}.
+
+\section1 Examples
+
+\section2 Without INCLUDE_PREFIX
+
+In the following snippet, the \c{mainwindow.cpp} file includes
+\c{ui_mainwindow.h} and \c{mainwindow.h}.
+
+\snippet cmake-macros/examples.cpp qt6_add_ui_1
+
+\c{CMakeLists.txt} is implemented as follows and it calls
+\l{qt6_add_ui}{qt_add_ui} to add \c{ui_mainwindow.h} to the \c{myapp} target.
+
+\snippet cmake-macros/examples.cmake qt6_add_ui_1
+
+In the above example, \c{ui_mainwindow.h} is included without a prefix. So the
+\c{INCLUDE_PREFIX} argument is not specified.
+
+\section2 With INCLUDE_PREFIX
+
+\snippet cmake-macros/examples.cpp qt6_add_ui_2
+
+In the above snippet, \c{mainwindow.cpp} includes \c{ui_mainwindow.h} with a
+prefix.
+
+\snippet cmake-macros/examples.cmake qt6_add_ui_2
+
+Since \c{ui_mainwindow.h} is included with a prefix, the \c{INCLUDE_PREFIX}
+argument is specified as \c{src/files} in the above example.
+
+\section2 Multiple .ui files
+
+In the following snippets, both \c{widget1.cpp} and \c{widget2.cpp} include
+\c{ui_widget1.h} and \c{ui_widget2.h} respectively.
+
+\c{widget1.cpp}:
+
+\snippet cmake-macros/examples.cpp qt6_add_ui_3_1
+
+\c{widget2.cpp}:
+
+\snippet cmake-macros/examples.cpp qt6_add_ui_3_2
+
+Both \c{ui_widget1.h} and \c{ui_widget2.h} are included with the same prefix
+
+\snippet cmake-macros/examples.cmake qt6_add_ui_3
+
+In this case, the \c{INCLUDE_PREFIX} argument can be specified as \c{src/files}
+for both files in the above snippet.
+
+\section1 When to prefer \l{qt6_add_ui}{qt_add_ui} over \c{AUTOUIC}?
+
+\l{qt6_add_ui}{qt_add_ui} has some advantages over \c{AUTOUIC}:
+
+\list
+\li \l{qt6_add_ui}{qt_add_ui} ensures that the \c{.ui} files are generated
+correctly during the first build, for the \c{Ninja} and \c{Ninja Multi-Config}
+generators.
+
+\li \l{qt6_add_ui}{qt_add_ui} guarantees that the generated \c{.h} files are
+not leaked outside the build directory.
+
+\li Since \l{qt6_add_ui}{qt_add_ui} does not scan source files, it provides a
+faster build than \c{AUTOUIC}.
+
+\endlist
+
+\section1 When to prefer \l{qt6_add_ui}{qt_add_ui} over \c{qt_wrap_ui}?
+
+\l{qt6_add_ui}{qt_add_ui} has the \c{INCLUDE_PREFIX} argument, which can be used to
+specify the include prefix for the generated header files.
+
+\note It is not recommended to use both \l{qt6_add_ui}{qt_add_ui} and
+\c{AUTOUIC} for the same target.
+
+*/
diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp
index e4a90278b4..d1c7bb3d58 100644
--- a/src/widgets/itemviews/qitemdelegate.cpp
+++ b/src/widgets/itemviews/qitemdelegate.cpp
@@ -257,15 +257,25 @@ QSizeF QItemDelegatePrivate::doTextLayout(int lineWidth) const
When subclassing QItemDelegate to create a delegate that displays items
using a custom renderer, it is important to ensure that the delegate can
- render items suitably for all the required states; e.g. selected,
+ render items suitably for all the required states; such as selected,
disabled, checked. The documentation for the paint() function contains
some hints to show how this can be achieved.
- You can provide custom editors by using a QItemEditorFactory. The
- \l{Color Editor Factory Example} shows how a custom editor can be
- made available to delegates with the default item editor
- factory. This way, there is no need to subclass QItemDelegate. An
- alternative is to reimplement createEditor(), setEditorData(),
+ You can provide custom editors by using a QItemEditorFactory. The following
+ code shows how a custom editor can be made available to delegates with the
+ default item editor factory.
+
+ \snippet code/src_gui_itemviews_qitemeditorfactory.cpp setDefaultFactory
+
+ After the default factory has been set, all standard item delegates
+ will use it (also the delegates that were created before setting the
+ default factory).
+
+ This way, you can avoid subclassing QItemDelegate, and all values of the
+ specified type (for example QMetaType::QDateTime) will be edited using the
+ provided editor (like \c{MyFancyDateTimeEdit} in the above example).
+
+ An alternative is to reimplement createEditor(), setEditorData(),
setModelData(), and updateEditorGeometry(). This process is described
in the \l{A simple delegate}{Model/View Programming overview documentation}.
diff --git a/src/widgets/itemviews/qitemeditorfactory.cpp b/src/widgets/itemviews/qitemeditorfactory.cpp
index 609df364cf..70d11e1b38 100644
--- a/src/widgets/itemviews/qitemeditorfactory.cpp
+++ b/src/widgets/itemviews/qitemeditorfactory.cpp
@@ -120,7 +120,7 @@ Q_SIGNALS:
Additional editors can be registered with the registerEditor() function.
- \sa QStyledItemDelegate, {Model/View Programming}, {Color Editor Factory Example}
+ \sa QStyledItemDelegate, {Model/View Programming}
*/
/*!
@@ -363,7 +363,7 @@ void QItemEditorFactory::setDefaultFactory(QItemEditorFactory *factory)
to register widgets without the need to subclass QItemEditorCreatorBase.
\sa QStandardItemEditorCreator, QItemEditorFactory,
- {Model/View Programming}, {Color Editor Factory Example}
+ {Model/View Programming}
*/
/*!
@@ -432,7 +432,7 @@ QItemEditorCreatorBase::~QItemEditorCreatorBase()
property, you should use QStandardItemEditorCreator instead.
\sa QItemEditorCreatorBase, QStandardItemEditorCreator,
- QItemEditorFactory, {Color Editor Factory Example}
+ QItemEditorFactory
*/
/*!
@@ -488,7 +488,7 @@ QItemEditorCreatorBase::~QItemEditorCreatorBase()
\snippet code/src_gui_itemviews_qitemeditorfactory.cpp 3
\sa QItemEditorCreatorBase, QItemEditorCreator,
- QItemEditorFactory, QStyledItemDelegate, {Color Editor Factory Example}
+ QItemEditorFactory, QStyledItemDelegate
*/
/*!
diff --git a/src/widgets/itemviews/qstyleditemdelegate.cpp b/src/widgets/itemviews/qstyleditemdelegate.cpp
index 0587e8d0be..54c1fb4f52 100644
--- a/src/widgets/itemviews/qstyleditemdelegate.cpp
+++ b/src/widgets/itemviews/qstyleditemdelegate.cpp
@@ -137,12 +137,17 @@ public:
instance provided by QItemEditorFactory is installed on all item
delegates. You can set a custom factory using
setItemEditorFactory() or set a new default factory with
- QItemEditorFactory::setDefaultFactory(). It is the data stored in
- the item model with the \l{Qt::}{EditRole} that is edited. See the
- QItemEditorFactory class for a more high-level introduction to
- item editor factories. The \l{Color Editor Factory Example}{Color
- Editor Factory} example shows how to create custom editors with a
- factory.
+ QItemEditorFactory::setDefaultFactory().
+
+ \snippet code/src_gui_itemviews_qitemeditorfactory.cpp setDefaultFactory
+
+ After the new factory has been set, all standard item delegates
+ will use it (i.e, also delegates that were created before the new
+ default factory was set).
+
+ It is the data stored in the item model with the \l{Qt::}{EditRole}
+ that is edited. See the QItemEditorFactory class for a more
+ high-level introduction to item editor factories.
\section1 Subclassing QStyledItemDelegate
@@ -204,7 +209,7 @@ public:
documentation for details.
\sa {Delegate Classes}, QItemDelegate, QAbstractItemDelegate, QStyle,
- {Star Delegate Example}, {Color Editor Factory Example}
+ {Star Delegate Example}
*/
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index de7d93ce20..a1392e10dc 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -1094,6 +1094,12 @@ QPalette QApplicationPrivate::basePalette() const
if (const QPalette *themePalette = platformTheme() ? platformTheme()->palette() : nullptr)
palette = themePalette->resolve(palette);
+ // This palette now is Qt-generated, so reset the resolve mask. This allows
+ // QStyle::polish implementations to respect palettes that are user provided,
+ // by checking if the palette has a brush set for a color that the style might
+ // otherwise overwrite.
+ palette.setResolveMask(0);
+
// Finish off by letting the application style polish the palette. This will
// not result in the polished palette becoming a user-set palette, as the
// resulting base palette is only used as a fallback, with the resolve mask
diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp
index c93876c500..edb159bbbf 100644
--- a/src/widgets/kernel/qgesturemanager.cpp
+++ b/src/widgets/kernel/qgesturemanager.cpp
@@ -610,7 +610,8 @@ void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
QWidget *child = topLevel->childAt(topLevel->mapFromGlobal(pt));
target = child ? child : topLevel;
}
- } else {
+ }
+ if (!target) {
// or use the context of the gesture
QObject *context = m_gestureOwners.value(gesture, 0);
if (context->isWidgetType())
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 1be158af63..ead633cda3 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1289,7 +1289,7 @@ void QWidgetPrivate::create()
Qt::WindowFlags &flags = data.window_flags;
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
+#if defined(QT_PLATFORM_UIKIT)
if (q->testAttribute(Qt::WA_ContentsMarginsRespectsSafeArea))
flags |= Qt::MaximizeUsingFullscreenGeometryHint;
#endif
@@ -5160,6 +5160,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
const QRegion oldSystemClip = enginePriv->systemClip;
const QRegion oldBaseClip = enginePriv->baseSystemClip;
const QRegion oldSystemViewport = enginePriv->systemViewport;
+ const Qt::LayoutDirection oldLayoutDirection = painter->layoutDirection();
// This ensures that all painting triggered by render() is clipped to the current engine clip.
if (painter->hasClipping()) {
@@ -5168,6 +5169,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
} else {
enginePriv->setSystemViewport(oldSystemClip);
}
+ painter->setLayoutDirection(layoutDirection());
d->render(target, targetOffset, toBePainted, renderFlags);
@@ -5175,6 +5177,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
enginePriv->baseSystemClip = oldBaseClip;
enginePriv->setSystemTransformAndViewport(oldTransform, oldSystemViewport);
enginePriv->systemStateChanged();
+ painter->setLayoutDirection(oldLayoutDirection);
// Restore shared painter.
d->setSharedPainter(oldPainter);
@@ -6616,7 +6619,9 @@ void QWidgetPrivate::setFocus_sys()
{
Q_Q(QWidget);
// Embedded native widget may have taken the focus; get it back to toplevel
- // if that is the case (QTBUG-25852)
+ // if that is the case (QTBUG-25852), unless widget is a window container.
+ if (extra && extra->hasWindowContainer)
+ return;
// Do not activate in case the popup menu opens another application (QTBUG-70810)
// unless the application is embedded (QTBUG-71991).
if (QWindow *nativeWindow = q->testAttribute(Qt::WA_WState_Created) ? q->window()->windowHandle() : nullptr) {
@@ -7689,11 +7694,15 @@ QMargins QWidgetPrivate::safeAreaMargins() const
return QMargins();
// Or, if one of our ancestors are in a layout that does not have WA_LayoutOnEntireRect
- // set, then we know that the layout has already taken care of placing us inside the
- // safe area, by taking the contents rect of its parent widget into account.
+ // set, and the widget respects the safe area, then we know that the layout has already
+ // taken care of placing us inside the safe area, by taking the contents rect of its
+ // parent widget into account.
const QWidget *assumedSafeWidget = nullptr;
for (const QWidget *w = q; w != nativeWidget; w = w->parentWidget()) {
QWidget *parentWidget = w->parentWidget();
+ if (!parentWidget->testAttribute(Qt::WA_ContentsMarginsRespectsSafeArea))
+ continue; // Layout can't help us
+
if (parentWidget->testAttribute(Qt::WA_LayoutOnEntireRect))
continue; // Layout not going to help us
@@ -10650,6 +10659,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
const bool resized = testAttribute(Qt::WA_Resized);
const bool wasCreated = testAttribute(Qt::WA_WState_Created);
QWidget *oldtlw = window();
+ Q_ASSERT(oldtlw);
if (f & Qt::Window) // Frame geometry likely changes, refresh.
d->data.fstrut_dirty = true;
@@ -10692,7 +10702,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
// texture-based widgets need a pre-notification when their associated top-level window changes
// This is not under the wasCreated/newParent conditions above in order to also play nice with QDockWidget.
- if ((oldtlw && oldtlw->d_func()->usesRhiFlush) && ((!parent && parentWidget()) || (parent && parent->window() != oldtlw)))
+ if (oldtlw->d_func()->usesRhiFlush && ((!parent && parentWidget()) || (parent && parent->window() != oldtlw)))
qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowAboutToChangeInternal);
// If we get parented into another window, children will be folded
@@ -10773,7 +10783,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
// texture-based widgets need another event when their top-level window
// changes (more precisely, has already changed at this point)
- if ((oldtlw && oldtlw->d_func()->usesRhiFlush) && oldtlw != window())
+ if (oldtlw->d_func()->usesRhiFlush && oldtlw != window())
qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowChangeInternal);
if (!wasCreated) {
@@ -13611,7 +13621,8 @@ bool QWidgetPrivate::isInFocusChain() const
when the focus chain has been initialized. A newly constructed widget is considered to have
a consistent focus chain, while not being part of a focus chain.
- This method returns \c true early, if a widget is pointing to itself.
+ The method always returns \c true, when the logging category "qt.widgets.focus" is disabled.
+ When it is enabled, the method returns \c true early, if a widget is pointing to itself.
It returns \c false, if one of the following is detected:
\list
\li nullptr found in a previous/next pointer.
@@ -13628,6 +13639,10 @@ bool QWidgetPrivate::isInFocusChain() const
bool QWidgetPrivate::isFocusChainConsistent() const
{
Q_Q(const QWidget);
+ const bool skip = !QLoggingCategory("qt.widgets.focus").isDebugEnabled();
+ if (skip)
+ return true;
+
if (!isInFocusChain())
return true;
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index f51baba88b..03dde9ca69 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -77,6 +77,39 @@ public:
widget->focusWidget()->clearFocus();
}
+ void setFocusToTarget(FocusTarget target, Qt::FocusReason reason) override
+ {
+ Q_Q(QWidgetWindow);
+ QWidget *widget = q->widget();
+ if (!widget)
+ return;
+ QWidget *newFocusWidget = nullptr;
+
+ switch (target) {
+ case FocusTarget::First:
+ newFocusWidget = q->getFocusWidget(QWidgetWindow::FirstFocusWidget);
+ break;
+ case FocusTarget::Last:
+ newFocusWidget = q->getFocusWidget(QWidgetWindow::LastFocusWidget);
+ break;
+ case FocusTarget::Next: {
+ QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget;
+ newFocusWidget = focusWidget->nextInFocusChain() ? focusWidget->nextInFocusChain() : focusWidget;
+ break;
+ }
+ case FocusTarget::Prev: {
+ QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget;
+ newFocusWidget = focusWidget->previousInFocusChain() ? focusWidget->previousInFocusChain() : focusWidget;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (newFocusWidget)
+ newFocusWidget->setFocus(reason);
+ }
+
QRectF closestAcceptableGeometry(const QRectF &rect) const override;
void processSafeAreaMarginsChanged() override
@@ -472,9 +505,6 @@ void QWidgetWindow::handleNonClientAreaMouseEvent(QMouseEvent *e)
void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
{
- static const QEvent::Type contextMenuTrigger =
- QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
- QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
if (QApplicationPrivate::inPopupMode()) {
QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
QPointF mapped = event->position();
@@ -591,7 +621,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
}
qt_replay_popup_mouse_event = false;
#ifndef QT_NO_CONTEXTMENU
- } else if (event->type() == contextMenuTrigger
+ } else if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
&& event->button() == Qt::RightButton
&& (openPopupCount == oldOpenPopupCount)) {
QWidget *receiver = activePopupWidget;
@@ -604,7 +634,6 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
QApplication::forwardEvent(receiver, &e, event);
}
#else
- Q_UNUSED(contextMenuTrigger);
Q_UNUSED(oldOpenPopupCount);
}
#endif
@@ -651,7 +680,8 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
event->setAccepted(translated.isAccepted());
}
#ifndef QT_NO_CONTEXTMENU
- if (event->type() == contextMenuTrigger && event->button() == Qt::RightButton
+ if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
+ && event->button() == Qt::RightButton
&& m_widget->rect().contains(event->position().toPoint())) {
QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPosition().toPoint(), event->modifiers());
QGuiApplication::forwardEvent(receiver, &e, event);
diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp
index c15ec54f35..1aaf04af43 100644
--- a/src/widgets/kernel/qwindowcontainer.cpp
+++ b/src/widgets/kernel/qwindowcontainer.cpp
@@ -5,6 +5,7 @@
#include "qwidget_p.h"
#include "qwidgetwindow_p.h"
#include <QtGui/qwindow.h>
+#include <QtGui/private/qwindow_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#include <QDebug>
@@ -28,7 +29,6 @@ public:
QWindowContainerPrivate()
: window(nullptr)
- , oldFocusWindow(nullptr)
, usesNativeWidgets(false)
{
}
@@ -103,7 +103,6 @@ public:
}
QPointer<QWindow> window;
- QWindow *oldFocusWindow;
QWindow fakeParent;
uint usesNativeWidgets : 1;
@@ -207,6 +206,7 @@ QWindowContainer::QWindowContainer(QWindow *embeddedWindow, QWidget *parent, Qt:
}
d->window = embeddedWindow;
+ d->window->installEventFilter(this);
QString windowName = d->window->objectName();
if (windowName.isEmpty())
@@ -219,9 +219,6 @@ QWindowContainer::QWindowContainer(QWindow *embeddedWindow, QWidget *parent, Qt:
setAcceptDrops(true);
- connect(qGuiApp, &QGuiApplication::focusWindowChanged,
- this, &QWindowContainer::focusWindowChanged);
-
connect(containedWindow(), &QWindow::minimumHeightChanged, this, &QWindowContainer::updateGeometry);
connect(containedWindow(), &QWindow::minimumWidthChanged, this, &QWindowContainer::updateGeometry);
}
@@ -244,30 +241,12 @@ QWindowContainer::~QWindowContainer()
// QEvent::PlatformSurface delivery relies on virtuals. Getting
// SurfaceAboutToBeDestroyed can be essential for OpenGL, Vulkan, etc.
// QWindow subclasses in particular. Keep these working.
- if (d->window)
+ if (d->window) {
+ d->window->removeEventFilter(this);
d->window->destroy();
+ }
delete d->window;
-
- disconnect(qGuiApp, &QGuiApplication::focusWindowChanged,
- this, &QWindowContainer::focusWindowChanged);
-}
-
-
-
-/*!
- \internal
- */
-
-void QWindowContainer::focusWindowChanged(QWindow *focusWindow)
-{
- Q_D(QWindowContainer);
- d->oldFocusWindow = focusWindow;
- if (focusWindow == d->window) {
- QWidget *widget = QApplication::focusWidget();
- if (widget)
- widget->clearFocus();
- }
}
/*!
@@ -284,8 +263,12 @@ bool QWindowContainer::eventFilter(QObject *o, QEvent *e)
QChildEvent *ce = static_cast<QChildEvent *>(e);
if (ce->child() == d->window) {
o->removeEventFilter(this);
+ d->window->removeEventFilter(this);
d->window = nullptr;
}
+ } else if (e->type() == QEvent::FocusIn) {
+ if (o == d->window)
+ setFocus(Qt::ActiveWindowFocusReason);
}
return false;
}
@@ -335,11 +318,16 @@ bool QWindowContainer::event(QEvent *e)
break;
case QEvent::FocusIn:
if (d->window->parent()) {
- if (d->oldFocusWindow != d->window) {
+ if (QGuiApplication::focusWindow() != d->window) {
+ QFocusEvent *event = static_cast<QFocusEvent *>(e);
+ const auto reason = event->reason();
+ QWindowPrivate::FocusTarget target = QWindowPrivate::FocusTarget::Current;
+ if (reason == Qt::TabFocusReason)
+ target = QWindowPrivate::FocusTarget::First;
+ else if (reason == Qt::BacktabFocusReason)
+ target = QWindowPrivate::FocusTarget::Last;
+ qt_window_private(d->window)->setFocusToTarget(target, reason);
d->window->requestActivate();
- } else {
- QWidget *next = nextInFocusChain();
- next->setFocus();
}
}
break;
diff --git a/src/widgets/kernel/qwindowcontainer_p.h b/src/widgets/kernel/qwindowcontainer_p.h
index a303f25424..0cbcc5321d 100644
--- a/src/widgets/kernel/qwindowcontainer_p.h
+++ b/src/widgets/kernel/qwindowcontainer_p.h
@@ -42,9 +42,6 @@ public:
protected:
bool event(QEvent *ev) override;
bool eventFilter(QObject *, QEvent *ev) override;
-
-private slots:
- void focusWindowChanged(QWindow *focusWindow);
};
QT_END_NAMESPACE
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index 046af3a073..aab1192d50 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -750,70 +750,75 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
case PE_IndicatorArrowRight:
case PE_IndicatorArrowLeft:
{
- if (opt->rect.width() <= 1 || opt->rect.height() <= 1)
+ const QRect &r = opt->rect;
+ if (r.width() <= 1 || r.height() <= 1)
break;
- QRect r = opt->rect;
int size = qMin(r.height(), r.width());
QPixmap pixmap;
+ const qreal dpr = p->device()->devicePixelRatio();
const QString pixmapName = QStyleHelper::uniqueName("$qt_ia-"_L1
% QLatin1StringView(metaObject()->className())
% HexString<uint>(pe),
- opt, QSize(size, size));
+ opt, QSize(size, size), dpr);
if (!QPixmapCache::find(pixmapName, &pixmap)) {
- const qreal pixelRatio = p->device()->devicePixelRatio();
- const qreal border = pixelRatio * (size / 5.);
- const qreal sqsize = pixelRatio * size;
- QImage image(sqsize, sqsize, QImage::Format_ARGB32_Premultiplied);
- image.fill(Qt::transparent);
- QPainter imagePainter(&image);
-
- QPolygonF poly;
+ // dpr scaling does not work well on such small pixel sizes, do it on our own
+ const int border = 1 * dpr;
+ const int sizeDpr = size * dpr;
+ int width = sizeDpr - 2 * border - 1;
+ int height = width / 2;
+ const int add = ((width & 1) == 1);
+ if (pe == PE_IndicatorArrowRight || pe == PE_IndicatorArrowLeft)
+ std::swap(width, height);
+ pixmap = styleCachePixmap(QSize(sizeDpr, sizeDpr), 1);
+
+ std::array<QPointF, 4> poly;
switch (pe) {
case PE_IndicatorArrowUp:
- poly = {QPointF(border, sqsize / 2), QPointF(sqsize / 2, border), QPointF(sqsize - border, sqsize / 2)};
+ poly = {QPointF(0, height), QPointF(width, height),
+ QPointF(width / 2 + add, 0), QPointF(width / 2, 0)};
break;
case PE_IndicatorArrowDown:
- poly = {QPointF(border, sqsize / 2), QPointF(sqsize / 2, sqsize - border), QPointF(sqsize - border, sqsize / 2)};
+ poly = {QPointF(0, 0), QPointF(width, 0),
+ QPointF(width / 2 + add, height), QPointF(width / 2, height)};
break;
case PE_IndicatorArrowRight:
- poly = {QPointF(sqsize - border, sqsize / 2), QPointF(sqsize / 2, border), QPointF(sqsize / 2, sqsize - border)};
+ poly = {QPointF(0, 0), QPointF(0, height),
+ QPointF(width, height / 2 + add), QPointF(width, height / 2)};
break;
case PE_IndicatorArrowLeft:
- poly = {QPointF(border, sqsize / 2), QPointF(sqsize / 2, border), QPointF(sqsize / 2, sqsize - border)};
+ poly = {QPointF(width, 0), QPointF(width, height),
+ QPointF(0, height / 2 + add), QPointF(0, height / 2)};
break;
default:
break;
}
- int bsx = 0;
- int bsy = 0;
-
+ QPainter imagePainter(&pixmap);
+ imagePainter.translate((sizeDpr - width) / 2, (sizeDpr - height) / 2);
if (opt->state & State_Sunken) {
- bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
- bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
+ const auto bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
+ const auto bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
+ imagePainter.translate(bsx, bsy);
}
-
- const QRectF bounds = poly.boundingRect();
- const qreal sx = sqsize / 2 - bounds.center().x() - 1;
- const qreal sy = sqsize / 2 - bounds.center().y() - 1;
- imagePainter.translate(sx + bsx, sy + bsy);
imagePainter.setPen(opt->palette.buttonText().color());
imagePainter.setBrush(opt->palette.buttonText());
if (!(opt->state & State_Enabled)) {
- imagePainter.translate(1, 1);
+ const int ofs = qRound(1 * dpr);
+ imagePainter.translate(ofs, ofs);
imagePainter.setBrush(opt->palette.light().color());
imagePainter.setPen(opt->palette.light().color());
- imagePainter.drawPolygon(poly);
- imagePainter.translate(-1, -1);
+ imagePainter.drawPolygon(poly.data(), int(poly.size()));
+ imagePainter.drawPoints(poly.data(), int(poly.size()));
+ imagePainter.translate(-ofs, -ofs);
imagePainter.setBrush(opt->palette.mid().color());
imagePainter.setPen(opt->palette.mid().color());
}
-
- imagePainter.drawPolygon(poly);
+ imagePainter.drawPolygon(poly.data(), int(poly.size()));
+ // sometimes the corners are not drawn by drawPolygon for unknown reaons, so re-draw them again
+ imagePainter.drawPoints(poly.data(), int(poly.size()));
imagePainter.end();
- pixmap = QPixmap::fromImage(image);
- pixmap.setDevicePixelRatio(pixelRatio);
+ pixmap.setDevicePixelRatio(dpr);
QPixmapCache::insert(pixmapName, pixmap);
}
int xOffset = r.x() + (r.width() - size)/2;
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index 8328459976..6b8fd979a9 100644
--- a/src/widgets/styles/qfusionstyle.cpp
+++ b/src/widgets/styles/qfusionstyle.cpp
@@ -145,6 +145,7 @@ static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QS
return;
const qreal dpi = QStyleHelper::dpi(option);
+ const qreal dpr = painter->device()->devicePixelRatio();
const int arrowWidth = int(QStyleHelper::dpiScaled(14, dpi));
const int arrowHeight = int(QStyleHelper::dpiScaled(8, dpi));
@@ -156,10 +157,9 @@ static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QS
const QString cacheKey = QStyleHelper::uniqueName("fusion-arrow"_L1
% HexString<uint>(type)
% HexString<uint>(color.rgba()),
- option, rect.size());
+ option, rect.size(), dpr);
if (!QPixmapCache::find(cacheKey, &cachePixmap)) {
- cachePixmap = styleCachePixmap(rect.size());
- cachePixmap.fill(Qt::transparent);
+ cachePixmap = styleCachePixmap(rect.size(), dpr);
QPainter cachePainter(&cachePixmap);
QRectF arrowRect;
@@ -1138,15 +1138,15 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(option);
const bool isSectionDragTarget = headerV2 ? headerV2->isSectionDragTarget : false;
+ const qreal dpr = painter->device()->devicePixelRatio();
const QString pixmapName = QStyleHelper::uniqueName("headersection-"_L1
% HexString(header->position)
% HexString(header->orientation)
% QLatin1Char(isSectionDragTarget ? '1' : '0'),
- option, option->rect.size());
+ option, option->rect.size(), dpr);
QPixmap cache;
if (!QPixmapCache::find(pixmapName, &cache)) {
- cache = styleCachePixmap(rect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(rect.size(), dpr);
QRect pixmapRect(0, 0, rect.width(), rect.height());
QPainter cachePainter(&cache);
QColor buttonColor = d->buttonColor(option->palette);
@@ -1879,12 +1879,12 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
#if QT_CONFIG(spinbox)
case CC_SpinBox:
if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
+ const qreal dpr = painter->device()->devicePixelRatio();
QPixmap cache;
- QString pixmapName = QStyleHelper::uniqueName("spinbox"_L1, spinBox, spinBox->rect.size());
+ QString pixmapName = QStyleHelper::uniqueName("spinbox"_L1, spinBox, spinBox->rect.size(), dpr);
if (!QPixmapCache::find(pixmapName, &cache)) {
- cache = styleCachePixmap(spinBox->rect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(spinBox->rect.size(), dpr);
QRect pixmapRect(0, 0, spinBox->rect.width(), spinBox->rect.height());
QRect rect = pixmapRect;
@@ -2576,16 +2576,16 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
bool hasFocus = option->state & State_HasFocus && option->state & State_KeyboardFocusChange;
bool sunken = comboBox->state & State_On; // play dead, if combobox has no items
bool isEnabled = (comboBox->state & State_Enabled);
+ const qreal dpr = painter->device()->devicePixelRatio();
QPixmap cache;
const QString pixmapName = QStyleHelper::uniqueName("combobox"_L1
% QLatin1StringView(sunken ? "-sunken" : "")
% QLatin1StringView(comboBox->editable ? "-editable" : "")
% QLatin1StringView(isEnabled ? "-enabled" : "")
% QLatin1StringView(!comboBox->frame ? "-frameless" : ""),
- option, comboBox->rect.size());
+ option, comboBox->rect.size(), dpr);
if (!QPixmapCache::find(pixmapName, &cache)) {
- cache = styleCachePixmap(comboBox->rect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(comboBox->rect.size(), dpr);
QPainter cachePainter(&cache);
QRect pixmapRect(0, 0, comboBox->rect.width(), comboBox->rect.height());
QStyleOptionComboBox comboBoxCopy = *comboBox;
@@ -2673,6 +2673,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
#if QT_CONFIG(slider)
case CC_Slider:
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ const qreal dpr = painter->device()->devicePixelRatio();
QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
@@ -2694,13 +2695,13 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
grooveColor.setHsv(buttonColor.hue(),
qMin(255, (int)(buttonColor.saturation())),
qMin(255, (int)(buttonColor.value()*0.9)));
- QString groovePixmapName = QStyleHelper::uniqueName("slider_groove"_L1, option, groove.size());
+ QString groovePixmapName = QStyleHelper::uniqueName("slider_groove"_L1, option,
+ groove.size(), dpr);
QRect pixmapRect(0, 0, groove.width(), groove.height());
// draw background groove
if (!QPixmapCache::find(groovePixmapName, &cache)) {
- cache = styleCachePixmap(pixmapRect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(pixmapRect.size(), dpr);
QPainter groovePainter(&cache);
groovePainter.setRenderHint(QPainter::Antialiasing, true);
groovePainter.translate(0.5, 0.5);
@@ -2728,8 +2729,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
if (!groovePixmapName.isEmpty())
groovePixmapName += "_blue"_L1;
if (!QPixmapCache::find(groovePixmapName, &cache)) {
- cache = styleCachePixmap(pixmapRect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(pixmapRect.size(), dpr);
QPainter groovePainter(&cache);
QLinearGradient gradient;
if (horizontal) {
@@ -2839,10 +2839,10 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
}
// draw handle
if ((option->subControls & SC_SliderHandle) ) {
- QString handlePixmapName = QStyleHelper::uniqueName("slider_handle"_L1, option, handle.size());
+ QString handlePixmapName = QStyleHelper::uniqueName("slider_handle"_L1, option,
+ handle.size(), dpr);
if (!QPixmapCache::find(handlePixmapName, &cache)) {
- cache = styleCachePixmap(handle.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(handle.size(), dpr);
QRect pixmapRect(0, 0, handle.width(), handle.height());
QPainter handlePainter(&cache);
QRect gradRect = pixmapRect.adjusted(2, 2, -2, -2);
@@ -3660,7 +3660,7 @@ QRect QFusionStyle::subElementRect(SubElement sr, const QStyleOption *opt, const
}
/*!
- \reimp
+ \internal
*/
QIcon QFusionStyle::iconFromTheme(StandardPixmap standardIcon) const
{
diff --git a/src/widgets/styles/qstyle_p.h b/src/widgets/styles/qstyle_p.h
index c4daa09c11..59e87810c5 100644
--- a/src/widgets/styles/qstyle_p.h
+++ b/src/widgets/styles/qstyle_p.h
@@ -29,38 +29,26 @@ class QStylePrivate: public QObjectPrivate
{
Q_DECLARE_PUBLIC(QStyle)
public:
- inline QStylePrivate()
- : layoutSpacingIndex(-1), proxyStyle(nullptr) {}
-
static bool useFullScreenForPopup();
- mutable int layoutSpacingIndex;
QStyle *proxyStyle;
QString name;
};
-inline QImage styleCacheImage(const QSize &size)
-{
- const qreal pixelRatio = qApp->devicePixelRatio();
- QImage cacheImage = QImage(size * pixelRatio, QImage::Format_ARGB32_Premultiplied);
- cacheImage.setDevicePixelRatio(pixelRatio);
- return cacheImage;
-}
-
-inline QPixmap styleCachePixmap(const QSize &size)
+inline QPixmap styleCachePixmap(const QSize &size, qreal pixelRatio)
{
- const qreal pixelRatio = qApp->devicePixelRatio();
QPixmap cachePixmap = QPixmap(size * pixelRatio);
cachePixmap.setDevicePixelRatio(pixelRatio);
+ cachePixmap.fill(Qt::transparent);
return cachePixmap;
}
#define BEGIN_STYLE_PIXMAPCACHE(a) \
QRect rect = option->rect; \
QPixmap internalPixmapCache; \
- QImage imageCache; \
QPainter *p = painter; \
- const QString unique = QStyleHelper::uniqueName((a), option, option->rect.size()); \
+ const auto dpr = p->device()->devicePixelRatio(); \
+ const QString unique = QStyleHelper::uniqueName((a), option, option->rect.size(), dpr); \
int txType = painter->deviceTransform().type() | painter->worldTransform().type(); \
const bool doPixmapCache = (!option->rect.isEmpty()) \
&& ((txType <= QTransform::TxTranslate) || (painter->deviceTransform().type() == QTransform::TxScale)); \
@@ -69,9 +57,8 @@ inline QPixmap styleCachePixmap(const QSize &size)
} else { \
if (doPixmapCache) { \
rect.setRect(0, 0, option->rect.width(), option->rect.height()); \
- imageCache = styleCacheImage(option->rect.size()); \
- imageCache.fill(0); \
- p = new QPainter(&imageCache); \
+ internalPixmapCache = styleCachePixmap(option->rect.size(), dpr); \
+ p = new QPainter(&internalPixmapCache); \
}
@@ -80,7 +67,6 @@ inline QPixmap styleCachePixmap(const QSize &size)
if (doPixmapCache) { \
p->end(); \
delete p; \
- internalPixmapCache = QPixmap::fromImage(imageCache); \
painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
QPixmapCache::insert(unique, internalPixmapCache); \
} \
diff --git a/src/widgets/styles/qstylehelper.cpp b/src/widgets/styles/qstylehelper.cpp
index 1084761d30..b4616b8c24 100644
--- a/src/widgets/styles/qstylehelper.cpp
+++ b/src/widgets/styles/qstylehelper.cpp
@@ -32,7 +32,7 @@ static inline bool usePixmapCache(const QStyleOption *opt)
return true;
}
-QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size)
+QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size, qreal dpr)
{
if (!usePixmapCache(option))
return {};
@@ -43,7 +43,8 @@ QString uniqueName(const QString &key, const QStyleOption *option, const QSize &
% HexString<uint>(complexOption ? uint(complexOption->activeSubControls) : 0u)
% HexString<quint64>(option->palette.cacheKey())
% HexString<uint>(size.width())
- % HexString<uint>(size.height());
+ % HexString<uint>(size.height())
+ % HexString<qreal>(dpr);
#if QT_CONFIG(spinbox)
if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
@@ -201,7 +202,7 @@ QPolygonF calcLines(const QStyleOptionSlider *dial)
qreal xc = width / 2 + 0.5;
qreal yc = height / 2 + 0.5;
const int ns = dial->tickInterval;
- if (!ns) // Invalid values may be set by Qt Designer.
+ if (!ns) // Invalid values may be set by Qt Widgets Designer.
return poly;
int notches = (dial->maximum + ns - 1 - dial->minimum) / ns;
if (notches <= 0)
diff --git a/src/widgets/styles/qstylehelper_p.h b/src/widgets/styles/qstylehelper_p.h
index 524417e405..98470ad1ce 100644
--- a/src/widgets/styles/qstylehelper_p.h
+++ b/src/widgets/styles/qstylehelper_p.h
@@ -39,7 +39,7 @@ class QWindow;
namespace QStyleHelper
{
- QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size);
+ QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size, qreal dpr);
Q_WIDGETS_EXPORT qreal dpi(const QStyleOption *option);
diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp
index 7602217f24..655b224617 100644
--- a/src/widgets/styles/qstylesheetstyle.cpp
+++ b/src/widgets/styles/qstylesheetstyle.cpp
@@ -6512,6 +6512,9 @@ bool QStyleSheetStyle::isNaturalChild(const QObject *obj)
QPixmap QStyleSheetStyle::loadPixmap(const QString &fileName, const QObject *context)
{
+ if (fileName.isEmpty())
+ return {};
+
qreal ratio = -1.0;
if (const QWidget *widget = qobject_cast<const QWidget *>(context)) {
if (QScreen *screen = QApplication::screenAt(widget->mapToGlobal(QPoint(0, 0))))
diff --git a/src/widgets/styles/qstylesheetstyle_default.cpp b/src/widgets/styles/qstylesheetstyle_default.cpp
index e50e18f291..6356835ff4 100644
--- a/src/widgets/styles/qstylesheetstyle_default.cpp
+++ b/src/widgets/styles/qstylesheetstyle_default.cpp
@@ -122,7 +122,8 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
// pixmap based style doesn't support any features
bool styleIsPixmapBased = baseStyle()->inherits("QMacStyle")
- || baseStyle()->inherits("QWindowsVistaStyle");
+ || (baseStyle()->inherits("QWindowsVistaStyle")
+ && !baseStyle()->inherits("QWindows11Style"));
/*QLineEdit {
diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp
index 394a968aad..f52321a3e1 100644
--- a/src/widgets/util/qcompleter.cpp
+++ b/src/widgets/util/qcompleter.cpp
@@ -1296,10 +1296,21 @@ bool QCompleter::eventFilter(QObject *o, QEvent *e)
{
Q_D(QCompleter);
- if (d->eatFocusOut && o == d->widget && e->type() == QEvent::FocusOut) {
- d->hiddenBecauseNoMatch = false;
- if (d->popup && d->popup->isVisible())
- return true;
+ if (o == d->widget) {
+ switch (e->type()) {
+ case QEvent::FocusOut:
+ if (d->eatFocusOut) {
+ d->hiddenBecauseNoMatch = false;
+ if (d->popup && d->popup->isVisible())
+ return true;
+ }
+ break;
+ case QEvent::Hide:
+ if (d->popup)
+ d->popup->hide();
+ default:
+ break;
+ }
}
if (o != d->popup)
diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp
index 034127b4f3..0495b20422 100644
--- a/src/widgets/widgets/qcalendarwidget.cpp
+++ b/src/widgets/widgets/qcalendarwidget.cpp
@@ -2731,12 +2731,29 @@ bool QCalendarWidget::isGridVisible() const
return d->m_view->showGrid();
}
+/*!
+ \since 5.14
+ Report the calendar system in use by this widget.
+
+ \sa setCalendar()
+*/
+
QCalendar QCalendarWidget::calendar() const
{
Q_D(const QCalendarWidget);
return d->m_model->m_calendar;
}
+/*!
+ \since 5.14
+ Set \a c as the calendar system to be used by this widget.
+
+ The widget can use any supported calendar system.
+ By default, it uses the Gregorian calendar.
+
+ \sa calendar()
+*/
+
void QCalendarWidget::setCalendar(QCalendar c)
{
Q_D(QCalendarWidget);
diff --git a/src/widgets/widgets/qcheckbox.cpp b/src/widgets/widgets/qcheckbox.cpp
index 88cd603d70..3c03e9efa5 100644
--- a/src/widgets/widgets/qcheckbox.cpp
+++ b/src/widgets/widgets/qcheckbox.cpp
@@ -93,6 +93,11 @@ public:
\fn void QCheckBox::stateChanged(int state)
\deprecated [6.9] Use checkStateChanged(Qt::CheckState) instead.
+
+ This signal is emitted whenever the checkbox's state changes, i.e.,
+ whenever the user checks or unchecks it.
+
+ \a state contains the checkbox's new Qt::CheckState.
*/
/*!
diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp
index 01e52b2fa6..a9b5babde5 100644
--- a/src/widgets/widgets/qdatetimeedit.cpp
+++ b/src/widgets/widgets/qdatetimeedit.cpp
@@ -303,6 +303,12 @@ void QDateTimeEdit::setTime(QTime time)
}
}
+/*!
+ \since 5.14
+ Report the calendar system in use by this widget.
+
+ \sa setCalendar()
+*/
QCalendar QDateTimeEdit::calendar() const
{
@@ -310,6 +316,16 @@ QCalendar QDateTimeEdit::calendar() const
return d->calendar;
}
+/*!
+ \since 5.14
+ Set \a calendar as the calendar system to be used by this widget.
+
+ The widget can use any supported calendar system.
+ By default, it uses the Gregorian calendar.
+
+ \sa calendar()
+*/
+
void QDateTimeEdit::setCalendar(QCalendar calendar)
{
Q_D(QDateTimeEdit);
@@ -2462,7 +2478,7 @@ int QDateTimeEditPrivate::absoluteIndex(QDateTimeEdit::Section s, int index) con
return NoSectionIndex;
}
-int QDateTimeEditPrivate::absoluteIndex(const SectionNode &s) const
+int QDateTimeEditPrivate::absoluteIndex(SectionNode s) const
{
return sectionNodes.indexOf(s);
}
diff --git a/src/widgets/widgets/qdatetimeedit_p.h b/src/widgets/widgets/qdatetimeedit_p.h
index 215ee75bfe..f93afd1519 100644
--- a/src/widgets/widgets/qdatetimeedit_p.h
+++ b/src/widgets/widgets/qdatetimeedit_p.h
@@ -67,7 +67,7 @@ public:
int cursorPosition() const override { return edit ? edit->cursorPosition() : -1; }
int absoluteIndex(QDateTimeEdit::Section s, int index) const;
- int absoluteIndex(const SectionNode &s) const;
+ int absoluteIndex(SectionNode s) const;
QDateTime stepBy(int index, int steps, bool test = false) const;
int sectionAt(int pos) const;
int closestSection(int index, bool forward) const;
diff --git a/src/widgets/widgets/qdialogbuttonbox.cpp b/src/widgets/widgets/qdialogbuttonbox.cpp
index 30ace89fa8..0b6a4df41a 100644
--- a/src/widgets/widgets/qdialogbuttonbox.cpp
+++ b/src/widgets/widgets/qdialogbuttonbox.cpp
@@ -374,7 +374,7 @@ QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardBut
button->setIcon(style->standardIcon(QStyle::StandardPixmap(icon), nullptr, q));
if (style != QApplication::style()) // Propagate style
button->setStyle(style);
- standardButtonHash.insert(button, sbutton);
+ standardButtonMap.insert(button, sbutton);
QPlatformDialogHelper::ButtonRole role = QPlatformDialogHelper::buttonRole(static_cast<QPlatformDialogHelper::StandardButton>(sbutton));
if (Q_UNLIKELY(role == QPlatformDialogHelper::InvalidRole))
qWarning("QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
@@ -426,10 +426,10 @@ void QDialogButtonBoxPrivate::createStandardButtons(QDialogButtonBox::StandardBu
void QDialogButtonBoxPrivate::retranslateStrings()
{
- for (auto &&[key, value] : std::as_const(standardButtonHash).asKeyValueRange()) {
- const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(value);
+ for (const auto &it : std::as_const(standardButtonMap)) {
+ const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(it.second);
if (!text.isEmpty())
- key->setText(text);
+ it.first->setText(text);
}
}
@@ -644,15 +644,15 @@ void QDialogButtonBox::clear()
Q_D(QDialogButtonBox);
// Remove the created standard buttons, they should be in the other lists, which will
// do the deletion
- d->standardButtonHash.clear();
+ d->standardButtonMap.clear();
for (int i = 0; i < NRoles; ++i) {
QList<QAbstractButton *> &list = d->buttonLists[i];
- while (list.size()) {
- QAbstractButton *button = list.takeAt(0);
+ for (auto button : std::as_const(list)) {
QObjectPrivate::disconnect(button, &QAbstractButton::destroyed,
d, &QDialogButtonBoxPrivate::handleButtonDestroyed);
delete button;
}
+ list.clear();
}
}
@@ -680,7 +680,11 @@ QList<QAbstractButton *> QDialogButtonBoxPrivate::visibleButtons() const
QList<QAbstractButton *> QDialogButtonBoxPrivate::allButtons() const
{
- return visibleButtons() << hiddenButtons.keys();
+ QList<QAbstractButton *> ret(visibleButtons());
+ ret.reserve(ret.size() + hiddenButtons.size());
+ for (const auto &it : hiddenButtons)
+ ret.push_back(it.first);
+ return ret;
}
/*!
@@ -718,9 +722,9 @@ void QDialogButtonBox::removeButton(QAbstractButton *button)
Removes \param button.
\param reason determines the behavior following the removal:
\list
- \li \c ManualRemove disconnects all signals and removes the button from standardButtonHash.
- \li \c HideEvent keeps connections alive, standard buttons remain in standardButtonHash.
- \li \c Destroyed removes the button from standardButtonHash. Signals remain untouched, because
+ \li \c ManualRemove disconnects all signals and removes the button from standardButtonMap.
+ \li \c HideEvent keeps connections alive, standard buttons remain in standardButtonMap.
+ \li \c Destroyed removes the button from standardButtonMap. Signals remain untouched, because
the button might already be only a QObject, the destructor of which handles disconnecting.
\endlist
*/
@@ -744,7 +748,7 @@ void QDialogButtonBoxPrivate::removeButton(QAbstractButton *button, RemoveReason
button->removeEventFilter(filter.get());
Q_FALLTHROUGH();
case RemoveReason::Destroyed:
- standardButtonHash.remove(reinterpret_cast<QPushButton *>(button));
+ standardButtonMap.remove(reinterpret_cast<QPushButton *>(button));
break;
case RemoveReason::HideEvent:
break;
@@ -818,8 +822,9 @@ void QDialogButtonBox::setStandardButtons(StandardButtons buttons)
{
Q_D(QDialogButtonBox);
// Clear out all the old standard buttons, then recreate them.
- qDeleteAll(d->standardButtonHash.keyBegin(), d->standardButtonHash.keyEnd());
- d->standardButtonHash.clear();
+ const auto oldButtons = d->standardButtonMap.keys();
+ d->standardButtonMap.clear();
+ qDeleteAll(oldButtons);
d->createStandardButtons(buttons);
}
@@ -828,11 +833,8 @@ QDialogButtonBox::StandardButtons QDialogButtonBox::standardButtons() const
{
Q_D(const QDialogButtonBox);
StandardButtons standardButtons = NoButton;
- QHash<QPushButton *, StandardButton>::const_iterator it = d->standardButtonHash.constBegin();
- while (it != d->standardButtonHash.constEnd()) {
- standardButtons |= it.value();
- ++it;
- }
+ for (const auto value : d->standardButtonMap.values())
+ standardButtons |= value;
return standardButtons;
}
@@ -845,7 +847,12 @@ QDialogButtonBox::StandardButtons QDialogButtonBox::standardButtons() const
QPushButton *QDialogButtonBox::button(StandardButton which) const
{
Q_D(const QDialogButtonBox);
- return d->standardButtonHash.key(which);
+
+ for (const auto &it : std::as_const(d->standardButtonMap)) {
+ if (it.second == which)
+ return it.first;
+ }
+ return nullptr;
}
/*!
@@ -857,7 +864,7 @@ QPushButton *QDialogButtonBox::button(StandardButton which) const
QDialogButtonBox::StandardButton QDialogButtonBox::standardButton(QAbstractButton *button) const
{
Q_D(const QDialogButtonBox);
- return d->standardButtonHash.value(static_cast<QPushButton *>(button));
+ return d->standardButtonMap.value(static_cast<QPushButton *>(button));
}
void QDialogButtonBoxPrivate::handleButtonClicked()
@@ -965,16 +972,13 @@ bool QDialogButtonBox::centerButtons() const
*/
void QDialogButtonBox::changeEvent(QEvent *event)
{
- typedef QHash<QPushButton *, QDialogButtonBox::StandardButton> StandardButtonHash;
-
Q_D(QDialogButtonBox);
switch (event->type()) {
case QEvent::StyleChange: // Propagate style
- if (!d->standardButtonHash.empty()) {
+ if (!d->standardButtonMap.empty()) {
QStyle *newStyle = style();
- const StandardButtonHash::iterator end = d->standardButtonHash.end();
- for (StandardButtonHash::iterator it = d->standardButtonHash.begin(); it != end; ++it)
- it.key()->setStyle(newStyle);
+ for (auto key : d->standardButtonMap.keys())
+ key->setStyle(newStyle);
}
#ifdef Q_OS_MAC
Q_FALLTHROUGH();
diff --git a/src/widgets/widgets/qdialogbuttonbox_p.h b/src/widgets/widgets/qdialogbuttonbox_p.h
index c3d7e03489..e439819c49 100644
--- a/src/widgets/widgets/qdialogbuttonbox_p.h
+++ b/src/widgets/widgets/qdialogbuttonbox_p.h
@@ -16,6 +16,7 @@
//
#include <private/qwidget_p.h>
+#include <private/qflatmap_p.h>
#include <qdialogbuttonbox.h>
QT_BEGIN_NAMESPACE
@@ -42,8 +43,8 @@ public:
QDialogButtonBoxPrivate(Qt::Orientation orient);
QList<QAbstractButton *> buttonLists[QDialogButtonBox::NRoles];
- QHash<QPushButton *, QDialogButtonBox::StandardButton> standardButtonHash;
- QHash<QAbstractButton *, QDialogButtonBox::ButtonRole> hiddenButtons;
+ QVarLengthFlatMap<QPushButton *, QDialogButtonBox::StandardButton, 8> standardButtonMap;
+ QVarLengthFlatMap<QAbstractButton *, QDialogButtonBox::ButtonRole, 8> hiddenButtons;
Qt::Orientation orientation;
QDialogButtonBox::ButtonLayout layoutPolicy;
diff --git a/src/widgets/widgets/qgroupbox.cpp b/src/widgets/widgets/qgroupbox.cpp
index 25dcee95c8..eb37599382 100644
--- a/src/widgets/widgets/qgroupbox.cpp
+++ b/src/widgets/widgets/qgroupbox.cpp
@@ -133,9 +133,9 @@ void QGroupBoxPrivate::click()
widgets). The following example shows how we can set up a
QGroupBox with a layout:
- \snippet widgets/groupbox/window.cpp 2
+ \snippet code/src_gui_widgets_qgroupbox.cpp Set up QGroupBox with layout
- \sa QButtonGroup, {Group Box Example}
+ \sa QButtonGroup
*/
diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp
index 8909ac80d9..0db46bf175 100644
--- a/src/widgets/widgets/qlineedit.cpp
+++ b/src/widgets/widgets/qlineedit.cpp
@@ -2211,11 +2211,13 @@ QMenu *QLineEdit::createStandardContextMenu()
if (!isReadOnly()) {
action = popup->addAction(QLineEdit::tr("&Undo") + ACCEL_KEY(QKeySequence::Undo));
action->setEnabled(d->control->isUndoAvailable());
+ action->setObjectName(QStringLiteral("edit-undo"));
setActionIcon(action, QStringLiteral("edit-undo"));
connect(action, &QAction::triggered, this, &QLineEdit::undo);
action = popup->addAction(QLineEdit::tr("&Redo") + ACCEL_KEY(QKeySequence::Redo));
action->setEnabled(d->control->isRedoAvailable());
+ action->setObjectName(QStringLiteral("edit-redo"));
setActionIcon(action, QStringLiteral("edit-redo"));
connect(action, &QAction::triggered, this, &QLineEdit::redo);
@@ -2227,6 +2229,7 @@ QMenu *QLineEdit::createStandardContextMenu()
action = popup->addAction(QLineEdit::tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut));
action->setEnabled(!d->control->isReadOnly() && d->control->hasSelectedText()
&& d->control->echoMode() == QLineEdit::Normal);
+ action->setObjectName(QStringLiteral("edit-cut"));
setActionIcon(action, QStringLiteral("edit-cut"));
connect(action, &QAction::triggered, this, &QLineEdit::cut);
}
@@ -2234,12 +2237,14 @@ QMenu *QLineEdit::createStandardContextMenu()
action = popup->addAction(QLineEdit::tr("&Copy") + ACCEL_KEY(QKeySequence::Copy));
action->setEnabled(d->control->hasSelectedText()
&& d->control->echoMode() == QLineEdit::Normal);
+ action->setObjectName(QStringLiteral("edit-copy"));
setActionIcon(action, QStringLiteral("edit-copy"));
connect(action, &QAction::triggered, this, &QLineEdit::copy);
if (!isReadOnly()) {
action = popup->addAction(QLineEdit::tr("&Paste") + ACCEL_KEY(QKeySequence::Paste));
action->setEnabled(!d->control->isReadOnly() && !QGuiApplication::clipboard()->text().isEmpty());
+ action->setObjectName(QStringLiteral("edit-paste"));
setActionIcon(action, QStringLiteral("edit-paste"));
connect(action, &QAction::triggered, this, &QLineEdit::paste);
}
@@ -2248,6 +2253,7 @@ QMenu *QLineEdit::createStandardContextMenu()
if (!isReadOnly()) {
action = popup->addAction(QLineEdit::tr("Delete"));
action->setEnabled(!d->control->isReadOnly() && !d->control->text().isEmpty() && d->control->hasSelectedText());
+ action->setObjectName(QStringLiteral("edit-delete"));
setActionIcon(action, QStringLiteral("edit-delete"));
connect(action, &QAction::triggered,
d->control, &QWidgetLineControl::_q_deleteSelected);
@@ -2258,6 +2264,7 @@ QMenu *QLineEdit::createStandardContextMenu()
action = popup->addAction(QLineEdit::tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll));
action->setEnabled(!d->control->text().isEmpty() && !d->control->allSelected());
+ action->setObjectName(QStringLiteral("select-all"));
setActionIcon(action, QStringLiteral("edit-select-all"));
d->selectAllAction = action;
connect(action, &QAction::triggered, this, &QLineEdit::selectAll);
diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp
index db17e50d5c..85c58fd70f 100644
--- a/src/widgets/widgets/qmainwindowlayout.cpp
+++ b/src/widgets/widgets/qmainwindowlayout.cpp
@@ -1931,6 +1931,11 @@ bool QMainWindowTabBar::contains(const QDockWidget *dockWidget) const
return false;
}
+// When a dock widget is removed from a floating tab,
+// Events need to be processed for the tab bar to realize that the dock widget is gone.
+// In this case count() counts the dock widget in transition and accesses dockAt
+// with an out-of-bounds index.
+// => return nullptr in contrast to other xxxxxAt() functions
QDockWidget *QMainWindowTabBar::dockAt(int index) const
{
QMainWindowTabBar *that = const_cast<QMainWindowTabBar *>(this);
@@ -1938,10 +1943,15 @@ QDockWidget *QMainWindowTabBar::dockAt(int index) const
QDockAreaLayoutInfo *info = mlayout->dockInfo(that);
if (!info)
return nullptr;
+
const int itemIndex = info->tabIndexToListIndex(index);
- Q_ASSERT(itemIndex >= 0 && itemIndex < info->item_list.count());
- const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
- return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) : nullptr;
+ if (itemIndex >= 0) {
+ Q_ASSERT(itemIndex < info->item_list.count());
+ const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
+ return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) : nullptr;
+ }
+
+ return nullptr;
}
void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
diff --git a/src/widgets/widgets/qradiobutton.cpp b/src/widgets/widgets/qradiobutton.cpp
index e34b04e5ee..af1bd3f649 100644
--- a/src/widgets/widgets/qradiobutton.cpp
+++ b/src/widgets/widgets/qradiobutton.cpp
@@ -82,7 +82,7 @@ void QRadioButtonPrivate::init()
setDown(), isDown(), autoRepeat(), group(), setAutoRepeat(),
toggle(), pressed(), released(), clicked(), and toggled().
- \sa QPushButton, QToolButton, QCheckBox, {Group Box Example}
+ \sa QPushButton, QToolButton, QCheckBox
*/