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/qcolordialog.cpp4
-rw-r--r--src/widgets/dialogs/qdialog.h1
-rw-r--r--src/widgets/dialogs/qfontdialog.cpp2
-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/snippets/code/src_gui_widgets_qmenu.cpp4
-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/itemviews/qtableview.cpp32
-rw-r--r--src/widgets/kernel/qapplication.cpp6
-rw-r--r--src/widgets/kernel/qgesturemanager.cpp3
-rw-r--r--src/widgets/kernel/qlayout.cpp5
-rw-r--r--src/widgets/kernel/qwidget.cpp580
-rw-r--r--src/widgets/kernel/qwidget_p.h35
-rw-r--r--src/widgets/kernel/qwidgetrepaintmanager.cpp6
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp33
-rw-r--r--src/widgets/kernel/qwindowcontainer.cpp54
-rw-r--r--src/widgets/kernel/qwindowcontainer_p.h4
-rw-r--r--src/widgets/styles/qcommonstyle.cpp106
-rw-r--r--src/widgets/styles/qfusionstyle.cpp45
-rw-r--r--src/widgets/styles/qstyle.h10
-rw-r--r--src/widgets/styles/qstyle_p.h26
-rw-r--r--src/widgets/styles/qstylehelper.cpp5
-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/qcombobox.cpp18
-rw-r--r--src/widgets/widgets/qdatetimeedit.cpp18
-rw-r--r--src/widgets/widgets/qdatetimeedit_p.h2
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.cpp8
-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
-rw-r--r--src/widgets/widgets/qtoolbutton.cpp4
47 files changed, 1284 insertions, 359 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/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp
index 27315fe53c..22efecedc9 100644
--- a/src/widgets/dialogs/qcolordialog.cpp
+++ b/src/widgets/dialogs/qcolordialog.cpp
@@ -1398,8 +1398,8 @@ void QColorShower::htmlEd()
if (t.isEmpty())
return;
- if (!t.startsWith(QStringLiteral("#"))) {
- t = QStringLiteral("#") + t;
+ if (!t.startsWith(u"#")) {
+ t.prepend(u"#");
QSignalBlocker blocker(htEd);
htEd->setText(t);
}
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/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp
index afc46e7506..628297d22b 100644
--- a/src/widgets/dialogs/qfontdialog.cpp
+++ b/src/widgets/dialogs/qfontdialog.cpp
@@ -509,7 +509,7 @@ void QFontDialogPrivate::updateFamilies()
//and try some fall backs
match_t type = MATCH_NONE;
- if (bestFamilyType <= MATCH_NONE && familyName2 == QStringLiteral("helvetica"))
+ if (bestFamilyType <= MATCH_NONE && familyName2 == "helvetica"_L1)
type = MATCH_LAST_RESORT;
if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.families().constFirst())
type = MATCH_APP;
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/snippets/code/src_gui_widgets_qmenu.cpp b/src/widgets/doc/snippets/code/src_gui_widgets_qmenu.cpp
index b0b0500fab..eb0897d5c5 100644
--- a/src/widgets/doc/snippets/code/src_gui_widgets_qmenu.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_widgets_qmenu.cpp
@@ -12,7 +12,7 @@ exec(somewidget.mapToGlobal(QPoint(0,0)));
//! [2]
-exec(e->globalPos());
+exec(e->globalPosition().toPoint());
//! [2]
@@ -27,7 +27,7 @@ exec(somewidget.mapToGlobal(QPoint(0, 0)));
//! [5]
-exec(e->globalPos());
+exec(e->globalPosition().toPoint());
//! [5]
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/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp
index 1c2184620a..5726348bc5 100644
--- a/src/widgets/itemviews/qtableview.cpp
+++ b/src/widgets/itemviews/qtableview.cpp
@@ -595,7 +595,7 @@ void QTableViewPrivate::init()
cornerWidget->setFocusPolicy(Qt::NoFocus);
cornerWidgetConnection = QObject::connect(
cornerWidget, &QTableCornerButton::clicked,
- q, &QTableView::reset);
+ q, &QTableView::selectAll);
#endif
}
@@ -2432,12 +2432,12 @@ int QTableView::sizeHintForRow(int row) const
break;
}
- int actualRight = d->model->columnCount(d->root) - 1;
+ const int actualRight = d->model->columnCount(d->root) - 1;
int idxLeft = left;
int idxRight = column - 1;
- if (maximumProcessCols == 0)
- columnsProcessed = 0; // skip the while loop
+ if (maximumProcessCols == 0 || actualRight < idxLeft)
+ columnsProcessed = maximumProcessCols; // skip the while loop
while (columnsProcessed != maximumProcessCols && (idxLeft > 0 || idxRight < actualRight)) {
int logicalIdx = -1;
@@ -2461,11 +2461,10 @@ int QTableView::sizeHintForRow(int row) const
break;
}
}
- if (logicalIdx < 0)
- continue;
-
- index = d->model->index(row, logicalIdx, d->root);
- hint = d->heightHintForIndex(index, hint, option);
+ if (logicalIdx >= 0) {
+ index = d->model->index(row, logicalIdx, d->root);
+ hint = d->heightHintForIndex(index, hint, option);
+ }
++columnsProcessed;
}
@@ -2521,12 +2520,12 @@ int QTableView::sizeHintForColumn(int column) const
break;
}
- int actualBottom = d->model->rowCount(d->root) - 1;
+ const int actualBottom = d->model->rowCount(d->root) - 1;
int idxTop = top;
int idxBottom = row - 1;
- if (maximumProcessRows == 0)
- rowsProcessed = 0; // skip the while loop
+ if (maximumProcessRows == 0 || actualBottom < idxTop)
+ rowsProcessed = maximumProcessRows; // skip the while loop
while (rowsProcessed != maximumProcessRows && (idxTop > 0 || idxBottom < actualBottom)) {
int logicalIdx = -1;
@@ -2550,11 +2549,10 @@ int QTableView::sizeHintForColumn(int column) const
break;
}
}
- if (logicalIdx < 0)
- continue;
-
- index = d->model->index(logicalIdx, column, d->root);
- hint = d->widthHintForIndex(index, hint, option);
+ if (logicalIdx >= 0) {
+ index = d->model->index(logicalIdx, column, d->root);
+ hint = d->widthHintForIndex(index, hint, option);
+ }
++rowsProcessed;
}
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/qlayout.cpp b/src/widgets/kernel/qlayout.cpp
index 0251ecd7fd..a826ea75bc 100644
--- a/src/widgets/kernel/qlayout.cpp
+++ b/src/widgets/kernel/qlayout.cpp
@@ -520,10 +520,11 @@ void QLayoutPrivate::doResize()
void QLayout::widgetEvent(QEvent *e)
{
Q_D(QLayout);
- if (!d->enabled)
+ const QEvent::Type type = e->type();
+ if (!d->enabled && type != QEvent::ChildRemoved)
return;
- switch (e->type()) {
+ switch (type) {
case QEvent::Resize:
if (d->activated)
d->doResize();
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 30daee1b79..e8342a4788 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -6,6 +6,7 @@
#include "qapplication_p.h"
#include "qbrush.h"
#include "qcursor.h"
+#include "private/qduplicatetracker_p.h"
#include "qevent.h"
#include "qlayout.h"
#if QT_CONFIG(menu)
@@ -84,6 +85,7 @@ using namespace Qt::StringLiterals;
Q_LOGGING_CATEGORY(lcWidgetPainting, "qt.widgets.painting", QtWarningMsg);
Q_LOGGING_CATEGORY(lcWidgetShowHide, "qt.widgets.showhide", QtWarningMsg);
Q_LOGGING_CATEGORY(lcWidgetWindow, "qt.widgets.window", QtWarningMsg);
+Q_LOGGING_CATEGORY(lcWidgetFocus, "qt.widgets.focus")
#ifndef QT_NO_DEBUG_STREAM
namespace {
@@ -818,12 +820,7 @@ struct QWidgetExceptionCleaner
Q_UNUSED(d);
#else
QWidgetPrivate::allWidgets->remove(that);
- if (d->focus_next != that) {
- if (d->focus_next)
- d->focus_next->d_func()->focus_prev = d->focus_prev;
- if (d->focus_prev)
- d->focus_prev->d_func()->focus_next = d->focus_next;
- }
+ d->removeFromFocusChain();
#endif
}
};
@@ -991,7 +988,7 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
//give potential windows a bigger "pre-initial" size; create() will give them a new size later
data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,640,480);
- focus_next = focus_prev = q;
+ initFocusChain();
if ((f & Qt::WindowType_Mask) == Qt::Desktop)
q->create();
@@ -1292,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
@@ -1477,17 +1474,9 @@ QWidget::~QWidget()
// delete layout while we still are a valid widget
delete d->layout;
d->layout = nullptr;
- // Remove myself from focus list
-
- Q_ASSERT(d->focus_next->d_func()->focus_prev == this);
- Q_ASSERT(d->focus_prev->d_func()->focus_next == this);
-
- if (d->focus_next != this) {
- d->focus_next->d_func()->focus_prev = d->focus_prev;
- d->focus_prev->d_func()->focus_next = d->focus_next;
- d->focus_next = d->focus_prev = nullptr;
- }
+ // Remove this from focus list
+ d->removeFromFocusChain(QWidgetPrivate::FocusChainRemovalRule::AssertConsistency);
QT_TRY {
#if QT_CONFIG(graphicsview)
@@ -6406,39 +6395,18 @@ void QWidget::setFocusProxy(QWidget * w)
break;
}
Q_ASSERT(firstChild); // can't be nullptr since w is a child
- QWidget *oldNext = d->focus_next;
- QWidget *oldPrev = d->focus_prev;
- oldNext->d_func()->focus_prev = oldPrev;
- oldPrev->d_func()->focus_next = oldNext;
-
- oldPrev = firstChild->d_func()->focus_prev;
- d->focus_next = firstChild;
- d->focus_prev = oldPrev;
- oldPrev->d_func()->focus_next = this;
- firstChild->d_func()->focus_prev = this;
+ d->insertIntoFocusChainBefore(firstChild);
} else if (w && w->isAncestorOf(this)) {
// If the focus proxy is a parent, 'this' has to be inserted directly after its parent in the focus chain
// remove it from the chain and insert this into the focus chain after its parent
// is this the case already?
- QWidget *parentsNext = w->d_func()->focus_next;
+ QWidget *parentsNext = w->nextInFocusChain();
if (parentsNext == this) {
// nothing to do.
- Q_ASSERT(d->focus_prev == w);
+ Q_ASSERT(previousInFocusChain() == w);
} else {
- // Remove 'this' from the focus chain by making prev and next point directly to each other
- QWidget *myOldNext = d->focus_next;
- QWidget *myOldPrev = d->focus_prev;
- if (myOldNext && myOldPrev) {
- myOldNext->d_func()->focus_prev = myOldPrev;
- myOldPrev->d_func()->focus_next = myOldNext;
- }
-
- // Insert 'this' behind the parent
- w->d_func()->focus_next = this;
- d->focus_prev = w;
- d->focus_next = parentsNext;
- parentsNext->d_func()->focus_prev = this;
+ d->QWidgetPrivate::insertIntoFocusChainAfter(w);
}
}
@@ -6648,7 +6616,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) {
@@ -6871,7 +6841,8 @@ QObject *QWidgetPrivate::focusObject()
*/
QWidget *QWidget::nextInFocusChain() const
{
- return const_cast<QWidget *>(d_func()->focus_next);
+ Q_D(const QWidget);
+ return d->nextPrevElementInFocusChain(QWidgetPrivate::FocusDirection::Next);
}
/*!
@@ -6884,7 +6855,8 @@ QWidget *QWidget::nextInFocusChain() const
*/
QWidget *QWidget::previousInFocusChain() const
{
- return const_cast<QWidget *>(d_func()->focus_prev);
+ Q_D(const QWidget);
+ return d->nextPrevElementInFocusChain(QWidgetPrivate::FocusDirection::Previous);
}
/*!
@@ -7039,9 +7011,9 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second)
}
} else if (target->isAncestorOf(focusProxy)) {
lastFocusChild = focusProxy;
- for (QWidget *focusNext = lastFocusChild->d_func()->focus_next;
+ for (QWidget *focusNext = lastFocusChild->nextInFocusChain();
focusNext != focusProxy && target->isAncestorOf(focusNext) && focusNext->window() == focusProxy->window();
- focusNext = focusNext->d_func()->focus_next) {
+ focusNext = focusNext->nextInFocusChain()) {
if (focusNext == noFurtherThan)
break;
if (focusNext->focusPolicy() != Qt::NoFocus)
@@ -7050,13 +7022,6 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second)
}
return lastFocusChild;
};
- auto setPrev = [](QWidget *w, QWidget *prev) {
- w->d_func()->focus_prev = prev;
- };
- auto setNext = [](QWidget *w, QWidget *next) {
- w->d_func()->focus_next = next;
- };
-
// detect inflection in case we have compound widgets
QWidget *lastFocusChildOfFirst = determineLastFocusChild(first, second);
if (lastFocusChildOfFirst == second)
@@ -7065,28 +7030,15 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second)
if (lastFocusChildOfSecond == first)
lastFocusChildOfSecond = second;
- // remove the second widget from the chain
- {
- QWidget *oldPrev = second->d_func()->focus_prev;
- QWidget *prevWithFocus = oldPrev;
- while (prevWithFocus->focusPolicy() == Qt::NoFocus)
- prevWithFocus = prevWithFocus->d_func()->focus_prev;
- // only widgets between first and second -> all is fine
- if (prevWithFocus == first)
- return;
- QWidget *oldNext = lastFocusChildOfSecond->d_func()->focus_next;
- setPrev(oldNext, oldPrev);
- setNext(oldPrev, oldNext);
- }
-
- // insert the second widget into the chain
- {
- QWidget *oldNext = lastFocusChildOfFirst->d_func()->focus_next;
- setPrev(second, lastFocusChildOfFirst);
- setNext(lastFocusChildOfFirst, second);
- setPrev(oldNext, lastFocusChildOfSecond);
- setNext(lastFocusChildOfSecond, oldNext);
- }
+ // Return if only NoFocus widgets are between first and second
+ QWidget *oldPrev = second->previousInFocusChain();
+ QWidget *prevWithFocus = oldPrev;
+ while (prevWithFocus->focusPolicy() == Qt::NoFocus)
+ prevWithFocus = prevWithFocus->previousInFocusChain();
+ if (prevWithFocus == first)
+ return;
+ const QWidgetList chain = QWidgetPrivate::takeFromFocusChain(second, lastFocusChildOfSecond);
+ QWidgetPrivate::insertIntoFocusChain(chain, QWidgetPrivate::FocusDirection::Next, lastFocusChildOfFirst);
}
void QWidget::setTabOrder(std::initializer_list<QWidget *> widgets)
@@ -7124,67 +7076,8 @@ void QWidgetPrivate::reparentFocusWidgets(QWidget * oldtlw)
if (focus_child)
focus_child->clearFocus();
- // separate the focus chain into new (children of myself) and old (the rest)
- QWidget *firstOld = nullptr;
- //QWidget *firstNew = q; //invariant
- QWidget *o = nullptr; // last in the old list
- QWidget *n = q; // last in the new list
-
- bool prevWasNew = true;
- QWidget *w = focus_next;
-
- //Note: for efficiency, we do not maintain the list invariant inside the loop
- //we append items to the relevant list, and we optimize by not changing pointers
- //when subsequent items are going into the same list.
- while (w != q) {
- bool currentIsNew = q->isAncestorOf(w);
- if (currentIsNew) {
- if (!prevWasNew) {
- //prev was old -- append to new list
- n->d_func()->focus_next = w;
- w->d_func()->focus_prev = n;
- }
- n = w;
- } else {
- if (prevWasNew) {
- //prev was new -- append to old list, if there is one
- if (o) {
- o->d_func()->focus_next = w;
- w->d_func()->focus_prev = o;
- } else {
- // "create" the old list
- firstOld = w;
- }
- }
- o = w;
- }
- w = w->d_func()->focus_next;
- prevWasNew = currentIsNew;
- }
-
- //repair the old list:
- if (firstOld) {
- o->d_func()->focus_next = firstOld;
- firstOld->d_func()->focus_prev = o;
- }
-
- if (!q->isWindow()) {
- QWidget *topLevel = q->window();
- //insert new chain into toplevel's chain
-
- QWidget *prev = topLevel->d_func()->focus_prev;
-
- topLevel->d_func()->focus_prev = n;
- prev->d_func()->focus_next = q;
-
- focus_prev = prev;
- n->d_func()->focus_next = topLevel;
- } else {
- //repair the new list
- n->d_func()->focus_next = q;
- focus_prev = n;
- }
-
+ insertIntoFocusChain(QWidgetPrivate::FocusDirection::Previous, q->window());
+ reparentFocusChildren(QWidgetPrivate::FocusDirection::Next);
}
/*!
@@ -10720,9 +10613,15 @@ void qSendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent::Type
for (int i = 0; i < d->children.size(); ++i) {
QWidget *w = qobject_cast<QWidget *>(d->children.at(i));
- if (w && !w->isWindow() && QWidgetPrivate::get(w)->textureChildSeen)
+ if (w && !w->isWindow())
qSendWindowChangeToTextureChildrenRecursively(w, eventType);
}
+
+ // Notify QWidgetWindow after we've notified all child QWidgets
+ if (auto *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::Direct)) {
+ QEvent e(eventType);
+ QCoreApplication::sendEvent(window, &e);
+ }
}
/*!
@@ -10753,6 +10652,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;
@@ -10795,7 +10695,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 (d->textureChildSeen && ((!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
@@ -10876,7 +10776,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 (d->textureChildSeen && oldtlw != window())
+ if (oldtlw->d_func()->usesRhiFlush && oldtlw != window())
qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowChangeInternal);
if (!wasCreated) {
@@ -13371,6 +13271,404 @@ QDebug operator<<(QDebug debug, const QWidget *widget)
}
#endif // !QT_NO_DEBUG_STREAM
+
+// *************************** Focus abstraction ************************************
+
+#define FOCUS_NEXT(w) w->d_func()->focus_next
+#define FOCUS_PREV(w) w->d_func()->focus_prev
+
+/*!
+ \internal
+ \return next or previous element in the focus chain, depending on
+ \param direction, irrespective of focus proxies or widgets with Qt::NoFocus.
+ */
+QWidget *QWidgetPrivate::nextPrevElementInFocusChain(FocusDirection direction) const
+{
+ Q_Q(const QWidget);
+ return direction == FocusDirection::Next ? FOCUS_NEXT(q) : FOCUS_PREV(q);
+}
+
+/*!
+ \internal
+ Removes a widget from the focus chain, respecting the flags set in \param rules.
+ \list
+ \li EnsureFocusOut: If the widget has input focus, transfer focus to the next or previous widget
+ in the focus chain, depending on \param direction.
+ \li RemoveInconsistent: Remove the widget, even if its focus chain is inconsistent.
+ \li AssertConsistency: qFatal, if the focus chain is inconsistent. This is used in the QWidget destructor.
+ \endlist
+ \return \c true if the widget has been removed, otherwise \c false.
+ */
+bool QWidgetPrivate::removeFromFocusChain(FocusChainRemovalRules rules, FocusDirection direction)
+{
+ Q_Q(QWidget);
+ if (!isFocusChainConsistent()) {
+#ifdef QT_DEBUG
+ if (rules.testFlag(FocusChainRemovalRule::AssertConsistency))
+ qFatal() << q << "has inconsistent focus chain.";
+#endif
+ qCDebug(lcWidgetFocus) << q << "wasn't removed, because of inconsistent focus chain.";
+ return false;
+ }
+
+ if (!isInFocusChain()) {
+ qCDebug(lcWidgetFocus) << q << "wasn't removed, because it is not part of a focus chain.";
+ return false;
+ }
+
+ if (rules.testFlag(FocusChainRemovalRule::EnsureFocusOut))
+ q->focusNextPrevChild(direction == FocusDirection::Next);
+
+ FOCUS_NEXT(FOCUS_PREV(q)) = FOCUS_NEXT(q);
+ FOCUS_PREV(FOCUS_NEXT(q)) = FOCUS_PREV(q);
+ initFocusChain();
+ qCDebug(lcWidgetFocus) << q << "removed from focus chain.";
+ return true;
+}
+
+/*!
+ \internal
+ Initialises the focus chain by making the widget point to itself.
+ */
+void QWidgetPrivate::initFocusChain()
+{
+ Q_Q(QWidget);
+ qCDebug(lcWidgetFocus) << "Initializing focus chain of" << q;
+ FOCUS_PREV(q) = q;
+ FOCUS_NEXT(q) = q;
+}
+
+/*!
+ \internal
+ Reads QWidget children, which are not part of a focus chain yet.
+ Inserts them into the focus chain before or after the widget,
+ depending on \param direction and in the order of their creation.
+ This is used, when QWidget::setParent() causes a widget to change toplevel windows.
+ */
+void QWidgetPrivate::reparentFocusChildren(FocusDirection direction)
+{
+ Q_Q(QWidget);
+ QWidgetList focusChildrenInsideChain;
+ QDuplicateTracker<QWidget *> seen;
+ QWidget *widget = q->nextInFocusChain();
+ while (q->isAncestorOf(widget)
+ && !seen.hasSeen(widget)
+ && widget != q->window()) {
+ if (widget->focusPolicy() != Qt::NoFocus)
+ focusChildrenInsideChain << widget;
+
+ widget = direction == FocusDirection::Next ? widget->nextInFocusChain()
+ : widget->previousInFocusChain();
+ }
+
+ const QWidgetList children = q->findChildren<QWidget *>(Qt::FindDirectChildrenOnly);
+ QWidgetList focusChildrenOutsideChain;
+ for (auto *child : children) {
+ if (!focusChildrenInsideChain.contains(child))
+ focusChildrenOutsideChain << child;
+ }
+ if (focusChildrenOutsideChain.isEmpty())
+ return;
+
+ QWidget *previous = q;
+ for (auto *child : focusChildrenOutsideChain) {
+ child->d_func()->insertIntoFocusChain(direction, previous);
+ previous = child;
+ }
+}
+
+/*!
+ \internal
+ Inserts a widget into the focus chain before or after \param position, depending on
+ \param direction.
+ \return \c true, if the insertion has changed the focus chain, otherwise \c false.
+ */
+bool QWidgetPrivate::insertIntoFocusChain(FocusDirection direction, QWidget *position)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(position);
+ QWidget *next = FOCUS_NEXT(q);
+ QWidget *previous = FOCUS_PREV(q);
+
+ switch (direction) {
+ case FocusDirection::Next:
+ if (previous == position) {
+ qCDebug(lcWidgetFocus) << "No-op insertion." << q << "is already before" << position;
+ return false;
+ }
+
+ removeFromFocusChain(FocusChainRemovalRule::AssertConsistency);
+
+ FOCUS_NEXT(q) = FOCUS_NEXT(position);
+ FOCUS_PREV(FOCUS_NEXT(position)) = q;
+ FOCUS_NEXT(position) = q;
+ FOCUS_PREV(q) = position;
+ qCDebug(lcWidgetFocus) << q << "inserted after" << position;
+ break;
+
+ case FocusDirection::Previous:
+ if (next == position) {
+ qCDebug(lcWidgetFocus) << "No-op insertion." << q << "is already after" << position;
+ return false;
+ }
+
+ removeFromFocusChain(FocusChainRemovalRule::AssertConsistency);
+
+ FOCUS_PREV(q) = FOCUS_PREV(position);
+ FOCUS_NEXT(FOCUS_PREV(position)) = q;
+ FOCUS_PREV(position) = q;
+ FOCUS_NEXT(q) = position;
+ qCDebug(lcWidgetFocus) << q << "inserted before" << position;
+ break;
+ }
+
+ Q_ASSERT(isFocusChainConsistent());
+ return true;
+}
+
+/*!
+ \internal
+ Convenience override to insert a QWidgetList \param toBeInserted into the focus chain
+ before or after \param position, depending on \param direction.
+ \return \c true, if the insertion has changed the focus chain, otherwise \c false.
+ \note
+ \param toBeInserted must be a consistent focus chain.
+ */
+bool QWidgetPrivate::insertIntoFocusChain(const QWidgetList &toBeInserted,
+ FocusDirection direction, QWidget *position)
+{
+ if (toBeInserted.isEmpty()) {
+ qCDebug(lcWidgetFocus) << "No-op insertion of an empty list";
+ return false;
+ }
+
+ Q_ASSERT_X(!toBeInserted.contains(position),
+ Q_FUNC_INFO,
+ "Coding error: toBeInserted contains position");
+
+ QWidget *first = toBeInserted.constFirst();
+ QWidget *last = toBeInserted.constLast();
+
+ // Call QWidget override to log accordingly
+ if (toBeInserted.count() == 1)
+ return first->d_func()->insertIntoFocusChain(direction, position);
+
+ Q_ASSERT(first != last);
+ switch (direction) {
+ case FocusDirection::Previous:
+ if (FOCUS_PREV(position) == last) {
+ qCDebug(lcWidgetFocus) << "No-op insertion." << toBeInserted << "is already before"
+ << position;
+ return false;
+ }
+ FOCUS_NEXT(FOCUS_PREV(position)) = first;
+ FOCUS_PREV(first) = FOCUS_PREV(position);
+ FOCUS_NEXT(last) = position;
+ FOCUS_PREV(position) = last;
+ qCDebug(lcWidgetFocus) << toBeInserted << "inserted before" << position;
+ break;
+ case FocusDirection::Next:
+ if (FOCUS_PREV(position) == last) {
+ qCDebug(lcWidgetFocus) << "No-op insertion." << toBeInserted << "is already after"
+ << position;
+ return false;
+ }
+ FOCUS_PREV(FOCUS_NEXT(position)) = last;
+ FOCUS_NEXT(last) = FOCUS_NEXT(position);
+ FOCUS_PREV(first) = position;
+ FOCUS_NEXT(position) = first;
+ qCDebug(lcWidgetFocus) << toBeInserted << "inserted after" << position;
+ break;
+ }
+
+ Q_ASSERT(position->d_func()->isFocusChainConsistent());
+ return true;
+}
+
+/*!
+ \internal
+ \return a QWidgetList, representing the part of the focus chain,
+ starting with \param from and ending with \param to, in \param direction.
+ */
+QWidgetList focusPath(QWidget *from, QWidget *to, QWidgetPrivate::FocusDirection direction)
+{
+ QWidgetList path({from});
+ if (from == to)
+ return path;
+
+ QWidget *current = from;
+ do {
+ switch (direction) {
+ case QWidgetPrivate::FocusDirection::Previous:
+ current = current->previousInFocusChain();
+ break;
+ case QWidgetPrivate::FocusDirection::Next:
+ current = current->nextInFocusChain();
+ break;
+ }
+ if (path.contains(current))
+ return QWidgetList();
+ path << current;
+ } while (current != to);
+
+ return path;
+}
+
+/*!
+ \internal
+ Removes the part from the focus chain starting with \param from and ending with \param to,
+ in \param direction.
+ \return removed part as a QWidgetList.
+ */
+QWidgetList QWidgetPrivate::takeFromFocusChain(QWidget *from,
+ QWidget *to,
+ FocusDirection direction)
+{
+ // Check if there is a path from->to in direction
+ const QWidgetList path = focusPath(from, to , direction);
+ if (path.isEmpty()) {
+ qCDebug(lcWidgetFocus) << "No-op removal. Focus chain from" << from << "doesn't lead to " << to;
+ return QWidgetList();
+ }
+
+ QWidget *first = path.constFirst();
+ QWidget *last = path.constLast();
+ if (first == last) {
+ first->d_func()->removeFromFocusChain();
+ return QWidgetList({first});
+ }
+
+ FOCUS_NEXT(FOCUS_PREV(first)) = FOCUS_NEXT(last);
+ FOCUS_PREV(FOCUS_NEXT(last)) = FOCUS_PREV(first);
+ FOCUS_PREV(first) = last;
+ FOCUS_NEXT(last) = first;
+ qCDebug(lcWidgetFocus) << path << "removed from focus chain";
+ return path;
+}
+
+/*!
+ \internal
+ \return The last focus child of the widget, traversing the focus chain no further than
+ \param noFurtherThan.
+ */
+QWidget *QWidgetPrivate::determineLastFocusChild(QWidget *noFurtherThan)
+{
+ Q_Q(QWidget);
+ // Since we need to repeat the same logic for both 'first' and 'second', we add a function
+ // that determines the last focus child for a widget, taking proxies and compound widgets into
+ // account. If the target is not a compound widget (it doesn't have a focus proxy that points
+ // to a child), 'lastFocusChild' will be set to the target itself.
+ QWidget *lastFocusChild = q;
+
+ QWidget *focusProxy = deepestFocusProxy();
+ if (!focusProxy) {
+ // QTBUG-81097: Another case is possible here. We can have a child
+ // widget, that sets its focusProxy() to the parent (target).
+ // An example of such widget is a QLineEdit, nested into
+ // a QAbstractSpinBox. In this case such widget should be considered
+ // the last focus child.
+ for (auto *object : std::as_const(q->children())) {
+ QWidget *w = qobject_cast<QWidget *>(object);
+ if (w && w->focusProxy() == q) {
+ lastFocusChild = w;
+ break;
+ }
+ }
+ } else if (q->isAncestorOf(focusProxy)) {
+ lastFocusChild = focusProxy;
+ for (QWidget *focusNext = lastFocusChild->nextInFocusChain();
+ focusNext != focusProxy && q->isAncestorOf(focusNext)
+ && focusNext->window() == focusProxy->window();
+ focusNext = focusNext->nextInFocusChain()) {
+ if (focusNext == noFurtherThan)
+ break;
+ if (focusNext->focusPolicy() != Qt::NoFocus)
+ lastFocusChild = focusNext;
+ }
+ }
+ return lastFocusChild;
+};
+
+/*!
+ \internal
+ \return \c true, if the widget is part of a focus chain and \c false otherwise.
+ A widget is considered to be part of a focus chain, neither FOCUS_NEXT, nor FOCUS_PREV
+ are pointing to the widget itself.
+
+ \note
+ This method doesn't check the consistency of the focus chain.
+ If multiple widgets have been removed from the focus chain by takeFromFocusChain(),
+ isInFocusChain() will return \c true for all of those widgets, even if they represent
+ an inconsistent focus chain.
+ */
+bool QWidgetPrivate::isInFocusChain() const
+{
+ Q_Q(const QWidget);
+ return !(FOCUS_NEXT(q) == q && FOCUS_PREV(q) == q);
+}
+
+/*!
+ \internal
+ A focus chain is consistent, when it is circular: Following the chain in either direction
+ has to return to the beginning. This is why a newly constructed widget points to itself,
+ 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.
+
+ 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.
+ \li broken chain: widget A is B's previous, but B isn't A's next.
+ \li chain isn't closed: starting at A doesn't lead back to A.
+ \endlist
+ It return \c true, if none of the above is observed.
+
+ \note
+ The focus chain is checked only in forward direction.
+ This is sufficient, because the check for a broken chain asserts consistent paths
+ in both directions.
+ */
+bool QWidgetPrivate::isFocusChainConsistent() const
+{
+ Q_Q(const QWidget);
+ const bool skip = !QLoggingCategory("qt.widgets.focus").isDebugEnabled();
+ if (skip)
+ return true;
+
+ if (!isInFocusChain())
+ return true;
+
+ const QWidget *position = q;
+
+ for (int i = 0; i < QApplication::allWidgets().count(); ++i) {
+ if (!FOCUS_PREV(position) || !FOCUS_NEXT(position)) {
+ qCDebug(lcWidgetFocus) << "Nullptr found at:" << position
+ << "Previous pointing to" << FOCUS_PREV(position)
+ << "Next pointing to" << FOCUS_NEXT(position);
+ return false;
+ }
+ if (!(FOCUS_PREV(FOCUS_NEXT(position)) == position
+ && FOCUS_NEXT(FOCUS_PREV(position)) == position)) {
+ qCDebug(lcWidgetFocus) << "Inconsistent focus chain at:" << position
+ << "Previous pointing to" << FOCUS_PREV(FOCUS_NEXT(position))
+ << "Next pointing to" << FOCUS_NEXT(FOCUS_PREV(position));
+ return false;
+ }
+ position = FOCUS_NEXT(position);
+ if (position == q)
+ return true;
+
+ }
+
+ qCDebug(lcWidgetFocus) << "Focus chain leading from" << q << "to" << position << "is not closed.";
+ return false;
+}
+
+#undef FOCUS_NEXT
+#undef FOCUS_PREV
+
+
QT_END_NAMESPACE
#include "moc_qwidget.cpp"
diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h
index d16d0f438c..9fab9efa62 100644
--- a/src/widgets/kernel/qwidget_p.h
+++ b/src/widgets/kernel/qwidget_p.h
@@ -41,6 +41,7 @@
#include <private/qgesture_p.h>
#include <qpa/qplatformbackingstore.h>
#include <QtGui/private/qbackingstorerhisupport_p.h>
+#include <private/qapplication_p.h>
#include <QtCore/qpointer.h>
@@ -733,6 +734,40 @@ public:
uint childrenHiddenByWState : 1;
uint childrenShownByExpose : 1;
+ // *************************** Focus abstraction ************************************
+ enum class FocusDirection {
+ Previous,
+ Next,
+ };
+
+ enum class FocusChainRemovalRule {
+ EnsureFocusOut = 0x01,
+ AssertConsistency = 0x02,
+ };
+ Q_DECLARE_FLAGS(FocusChainRemovalRules, FocusChainRemovalRule)
+
+ // Getters
+ QWidget *nextPrevElementInFocusChain(FocusDirection direction) const;
+
+ // manipulators
+ bool removeFromFocusChain(FocusChainRemovalRules rules = FocusChainRemovalRules(),
+ FocusDirection direction = FocusDirection::Next);
+ bool insertIntoFocusChain(FocusDirection direction, QWidget *position);
+ static bool insertIntoFocusChain(const QWidgetList &toBeInserted, FocusDirection direction, QWidget *position);
+ bool insertIntoFocusChainBefore(QWidget *position)
+ { return insertIntoFocusChain(FocusDirection::Previous, position); }
+ bool insertIntoFocusChainAfter(QWidget *position)
+ { return insertIntoFocusChain(FocusDirection::Next, position); }
+ static QWidgetList takeFromFocusChain(QWidget *from, QWidget *to,
+ FocusDirection direction = FocusDirection::Next);
+ void reparentFocusChildren(FocusDirection direction);
+ QWidget *determineLastFocusChild(QWidget *noFurtherThan);
+
+ // Initialization and tests
+ void initFocusChain();
+ bool isInFocusChain() const;
+ bool isFocusChainConsistent() const;
+
// *************************** Platform specific ************************************
#if defined(Q_OS_WIN)
uint noPaintOnScreen : 1; // see qwidget.cpp ::paintEngine()
diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp
index abe5e8016e..607a767a20 100644
--- a/src/widgets/kernel/qwidgetrepaintmanager.cpp
+++ b/src/widgets/kernel/qwidgetrepaintmanager.cpp
@@ -355,7 +355,11 @@ void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime update
switch (updateTime) {
case UpdateLater:
- updateRequestSent = true;
+ // Prevent redundant update request events, unless it's a
+ // paint on screen widget, as these don't go through the
+ // normal backingstore sync machinery.
+ if (!widget->d_func()->shouldPaintOnScreen())
+ updateRequestSent = true;
QCoreApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
break;
case UpdateNow: {
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index f51baba88b..e7f0a84004 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
diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp
index cfd785a82c..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,8 +219,8 @@ 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);
}
QWindow *QWindowContainer::containedWindow() const
@@ -241,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();
- }
}
/*!
@@ -281,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;
}
@@ -332,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;
@@ -373,6 +364,11 @@ bool QWindowContainer::event(QEvent *e)
return QWidget::event(e);
}
+QSize QWindowContainer::minimumSizeHint() const
+{
+ return containedWindow() ? containedWindow()->minimumSize() : QSize(0, 0);
+}
+
typedef void (*qwindowcontainer_traverse_callback)(QWidget *parent);
static void qwindowcontainer_traverse(QWidget *parent, qwindowcontainer_traverse_callback callback)
{
diff --git a/src/widgets/kernel/qwindowcontainer_p.h b/src/widgets/kernel/qwindowcontainer_p.h
index 8dc5c64af4..0cbcc5321d 100644
--- a/src/widgets/kernel/qwindowcontainer_p.h
+++ b/src/widgets/kernel/qwindowcontainer_p.h
@@ -31,6 +31,7 @@ public:
explicit QWindowContainer(QWindow *embeddedWindow, QWidget *parent = nullptr, Qt::WindowFlags f = { });
~QWindowContainer();
QWindow *containedWindow() const;
+ QSize minimumSizeHint() const override;
static void toplevelAboutToBeDestroyed(QWidget *parent);
static void parentWasChanged(QWidget *parent);
@@ -41,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 e2d0e5227b..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;
@@ -1679,9 +1684,12 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
QFontMetrics fm(header->fontMetrics);
if (header->state & QStyle::State_On) {
QFont fnt = p->font();
- fnt.setBold(true);
- p->setFont(fnt);
- fm = QFontMetrics((p->font()));
+ // the font already has a weight set; don't override that
+ if (!(fnt.resolveMask() & QFont::WeightResolved)) {
+ fnt.setBold(true);
+ p->setFont(fnt);
+ fm = QFontMetrics((p->font()));
+ }
}
QString text = header->text;
if (const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(header)) {
@@ -4518,15 +4526,6 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid
case PM_MenuBarHMargin:
ret = 0;
break;
- case PM_DialogButtonsSeparator:
- ret = int(QStyleHelper::dpiScaled(5, opt));
- break;
- case PM_DialogButtonsButtonWidth:
- ret = int(QStyleHelper::dpiScaled(70, opt));
- break;
- case PM_DialogButtonsButtonHeight:
- ret = int(QStyleHelper::dpiScaled(30, opt));
- break;
case PM_TitleBarHeight:
{
if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
@@ -5501,8 +5500,8 @@ static inline QPixmap titleBarMenuCachedPixmapFromXPM() { return cachedPixmapFro
#endif // QT_CONFIG(imageformat_xpm)
#if QT_CONFIG(imageformat_png)
-static inline QString iconResourcePrefix() { return QStringLiteral(":/qt-project.org/styles/commonstyle/images/"); }
-static inline QString iconPngSuffix() { return QStringLiteral(".png"); }
+static constexpr QLatin1StringView iconResourcePrefix() noexcept { return ":/qt-project.org/styles/commonstyle/images/"_L1; }
+static constexpr QLatin1StringView iconPngSuffix() noexcept { return ".png"_L1; }
template <typename T>
static void addIconFiles(QStringView prefix, std::initializer_list<T> sizes, QIcon &icon,
@@ -5817,14 +5816,15 @@ QIcon QCommonStylePrivate::iconFromMacTheme(QCommonStyle::StandardPixmap standar
case QStyle::SP_TitleBarNormalButton:
case QStyle::SP_TitleBarCloseButton: {
QIcon titleBarIcon;
- QString prefix = standardIcon == QStyle::SP_TitleBarCloseButton
- ? QStringLiteral(":/qt-project.org/styles/macstyle/images/closedock-")
- : QStringLiteral(":/qt-project.org/styles/macstyle/images/dockdock-");
+ constexpr auto imagesPrefix = ":/qt-project.org/styles/macstyle/images/"_L1;
+ const auto namePrefix = standardIcon == QStyle::SP_TitleBarCloseButton
+ ? "closedock-"_L1
+ : "dockdock-"_L1;
for (const auto size : dockTitleIconSizes) {
- titleBarIcon.addFile(prefix + QStringLiteral("macstyle-") + QString::number(size) + iconPngSuffix(),
- QSize(size, size), QIcon::Normal, QIcon::Off);
- titleBarIcon.addFile(prefix + QStringLiteral("down-macstyle-") + QString::number(size) + iconPngSuffix(),
- QSize(size, size), QIcon::Normal, QIcon::On);
+ titleBarIcon.addFile(imagesPrefix + namePrefix + "macstyle-"_L1 + QString::number(size)
+ + iconPngSuffix(), QSize(size, size), QIcon::Normal, QIcon::Off);
+ titleBarIcon.addFile(imagesPrefix + namePrefix + "down-macstyle-"_L1 + QString::number(size)
+ + iconPngSuffix(), QSize(size, size), QIcon::Normal, QIcon::On);
}
return titleBarIcon;
}
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index d2b1524796..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;
@@ -800,7 +800,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
if (isDefault)
buttonColor = mergedColors(buttonColor, highlightedOutline.lighter(130), 90);
- BEGIN_STYLE_PIXMAPCACHE(QStringLiteral("pushbutton-") + buttonColor.name(QColor::HexArgb))
+ BEGIN_STYLE_PIXMAPCACHE(u"pushbutton-" + buttonColor.name(QColor::HexArgb))
r = rect.adjusted(0, 1, -1, 0);
p->setRenderHint(QPainter::Antialiasing, true);
@@ -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);
@@ -2926,7 +2926,6 @@ int QFusionStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, co
case PM_ListViewIconSize:
val = 24;
break;
- case PM_DialogButtonsSeparator:
case PM_ScrollBarSliderMin:
val = 26;
break;
@@ -3661,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.h b/src/widgets/styles/qstyle.h
index 23a5bd5ac2..198aea9557 100644
--- a/src/widgets/styles/qstyle.h
+++ b/src/widgets/styles/qstyle.h
@@ -464,11 +464,13 @@ public:
PM_ExclusiveIndicatorWidth,
PM_ExclusiveIndicatorHeight,
- PM_DialogButtonsSeparator,
- PM_DialogButtonsButtonWidth,
- PM_DialogButtonsButtonHeight,
+#if QT_DEPRECATED_SINCE(6, 8)
+ PM_DialogButtonsSeparator Q_DECL_ENUMERATOR_DEPRECATED_X("Not used and no effect since Qt 4"),
+ PM_DialogButtonsButtonWidth Q_DECL_ENUMERATOR_DEPRECATED_X("Not used and no effect since Qt 4"),
+ PM_DialogButtonsButtonHeight Q_DECL_ENUMERATOR_DEPRECATED_X("Not used and no effect since Qt 4"),
+#endif
- PM_MdiSubWindowFrameWidth,
+ PM_MdiSubWindowFrameWidth = 44,
PM_MdiSubWindowMinimizedWidth,
PM_HeaderMargin,
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..02827de847 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)) {
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/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp
index 06de5566ff..1fe9a8d7be 100644
--- a/src/widgets/widgets/qcombobox.cpp
+++ b/src/widgets/widgets/qcombobox.cpp
@@ -3003,24 +3003,8 @@ void QComboBox::changeEvent(QEvent *e)
Q_D(QComboBox);
switch (e->type()) {
case QEvent::StyleChange:
- if (d->container) {
-// If on Windows, force recreation of ComboBox container, since
-// windows11 style depends on WA_TranslucentBackground
-#ifdef Q_OS_WIN
- auto delegate = itemDelegate();
- d->container->deleteLater();
- // d->container needs to be set explicitly to nullptr
- // since QComboBoxPrivate::viewContainer() only
- // creates a new QComboBoxPrivateContainer when
- // d->container has the value of nullptr
- d->container = nullptr;
- d->container = d->viewContainer();
- delegate->setParent(d->container);
- setItemDelegate(delegate);
-
-#endif
+ if (d->container)
d->container->updateStyleSettings();
- }
d->updateDelegate();
#ifdef Q_OS_MAC
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..30c68ad18b 100644
--- a/src/widgets/widgets/qdialogbuttonbox.cpp
+++ b/src/widgets/widgets/qdialogbuttonbox.cpp
@@ -647,12 +647,12 @@ void QDialogButtonBox::clear()
d->standardButtonHash.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();
}
}
@@ -818,8 +818,8 @@ 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 toDelete = std::exchange(d->standardButtonHash, {});
+ qDeleteAll(toDelete.keyBegin(), toDelete.keyEnd());
d->createStandardButtons(buttons);
}
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
*/
diff --git a/src/widgets/widgets/qtoolbutton.cpp b/src/widgets/widgets/qtoolbutton.cpp
index f3e3c8261e..e0775afd26 100644
--- a/src/widgets/widgets/qtoolbutton.cpp
+++ b/src/widgets/widgets/qtoolbutton.cpp
@@ -584,8 +584,10 @@ void QToolButton::mousePressEvent(QMouseEvent *e)
void QToolButton::mouseReleaseEvent(QMouseEvent *e)
{
Q_D(QToolButton);
+ QPointer<QAbstractButton> guard(this);
QAbstractButton::mouseReleaseEvent(e);
- d->buttonPressed = QToolButtonPrivate::NoButtonPressed;
+ if (guard)
+ d->buttonPressed = QToolButtonPrivate::NoButtonPressed;
}
/*!