summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/widgets/kernel/qwidget.h17
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp67
-rw-r--r--tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp90
3 files changed, 150 insertions, 24 deletions
diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h
index ee6e7d5fe6..6c30e018df 100644
--- a/src/widgets/kernel/qwidget.h
+++ b/src/widgets/kernel/qwidget.h
@@ -211,11 +211,28 @@ class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice
Q_PROPERTY(QString windowFilePath READ windowFilePath WRITE setWindowFilePath)
Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints)
+#if 0
+ // ### TODO: make this work (requires SFINAE-friendly connect())
template <typename...Args>
using compatible_action_slot_args = std::void_t<
decltype(QObject::connect(std::declval<QAction*>(), &QAction::triggered,
std::declval<Args>()...))
>;
+#else
+ // good-enough compromise for now
+ template <typename...Args>
+ using compatible_action_slot_args = std::enable_if_t<std::conjunction_v<
+#if QT_CONFIG(shortcut)
+ std::disjunction<
+ std::is_same<Args, Qt::ConnectionType>,
+ std::negation<std::is_convertible<Args, QKeySequence>>
+ >...,
+#endif
+ std::negation<std::is_convertible<Args, QIcon>>...,
+ std::negation<std::is_convertible<Args, const char*>>...,
+ std::negation<std::is_convertible<Args, QString>>...
+ >>;
+#endif
public:
enum RenderFlag {
DrawWindowBackground = 0x1,
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
index 7ca08993ab..4fa568228a 100644
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
+++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
@@ -160,6 +160,7 @@ public slots:
void initTestCase();
void cleanup();
private slots:
+ void addActionOverloads();
void getSetCheck();
void fontPropagation();
void fontPropagation2();
@@ -644,6 +645,72 @@ void tst_QWidget::cleanup()
QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty());
}
+template <typename T>
+struct ImplicitlyConvertibleTo {
+ T t;
+ operator const T() const { return t; }
+ operator T() { return t; }
+};
+
+void testFunction0() {}
+void testFunction1(bool) {}
+
+void tst_QWidget::addActionOverloads()
+{
+ // almost exhaustive check of addAction() overloads:
+ // (text), (icon, text), (icon, text, shortcut), (text, shortcut)
+ // each with a good sample of ways to QObject::connect() to
+ // QAction::triggered(bool)
+ QWidget w;
+
+ // don't just pass QString etc - that'd be too easy (think QStringBuilder)
+ ImplicitlyConvertibleTo<QString> text = {QStringLiteral("foo")};
+ ImplicitlyConvertibleTo<QIcon> icon;
+
+ const auto check = [&](auto &...args) { // don't need to perfectly-forward, only lvalues passed
+ w.addAction(args...);
+
+ w.addAction(args..., &w, SLOT(deleteLater()));
+ w.addAction(args..., &w, &QObject::deleteLater);
+ w.addAction(args..., testFunction0);
+ w.addAction(args..., &w, testFunction0);
+ w.addAction(args..., testFunction1);
+ w.addAction(args..., &w, testFunction1);
+ w.addAction(args..., [&](bool b) { w.setEnabled(b); });
+ w.addAction(args..., &w, [&](bool b) { w.setEnabled(b); });
+
+ w.addAction(args..., &w, SLOT(deleteLater()), Qt::QueuedConnection);
+ w.addAction(args..., &w, &QObject::deleteLater, Qt::QueuedConnection);
+ // doesn't exist: w.addAction(args..., testFunction0, Qt::QueuedConnection);
+ w.addAction(args..., &w, testFunction0, Qt::QueuedConnection);
+ // doesn't exist: w.addAction(args..., testFunction1, Qt::QueuedConnection);
+ w.addAction(args..., &w, testFunction1, Qt::QueuedConnection);
+ // doesn't exist: w.addAction(args..., [&](bool b) { w.setEnabled(b); }, Qt::QueuedConnection);
+ w.addAction(args..., &w, [&](bool b) { w.setEnabled(b); }, Qt::QueuedConnection);
+ };
+ const auto check1 = [&](auto &arg, auto &...args) {
+ check(arg, args...);
+ check(std::as_const(arg), args...);
+ };
+ const auto check2 = [&](auto &arg1, auto &arg2, auto &...args) {
+ check1(arg1, arg2, args...);
+ check1(arg1, std::as_const(arg2), args...);
+ };
+ [[maybe_unused]]
+ const auto check3 = [&](auto &arg1, auto &arg2, auto &arg3) {
+ check2(arg1, arg2, arg3);
+ check2(arg1, arg2, std::as_const(arg3));
+ };
+
+ check1(text);
+ check2(icon, text);
+#ifndef QT_NO_SHORTCUT
+ ImplicitlyConvertibleTo<QKeySequence> keySequence = {Qt::CTRL | Qt::Key_C};
+ check2(text, keySequence);
+ check3(icon, text, keySequence);
+#endif
+}
+
void tst_QWidget::fontPropagation()
{
QScopedPointer<QWidget> testWidget(new QWidget);
diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
index 55345f2ae5..0dc4c07069 100644
--- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
+++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
@@ -287,44 +287,86 @@ void tst_QMenu::addActionsAndClear()
QCOMPARE(menus[0]->actions().count(), 0);
}
-static void testFunction() { }
+static void testFunction0() {}
+static void testFunction1(bool) {}
+
+template <typename T>
+struct ImplicitlyConvertibleTo {
+ T t;
+ operator const T() const { return t; }
+ operator T() { return t; }
+};
void tst_QMenu::addActionsConnect()
{
+ // almost exhaustive check of addAction() overloads:
+ // (text), (icon, text), (icon, text, shortcut), (text, shortcut)
+ // each with a good sample of ways to QObject::connect() to
+ // QAction::triggered(bool)
QMenu menu;
- const QString text = QLatin1String("bla");
- const QIcon icon;
- menu.addAction(text, &menu, SLOT(deleteLater()));
- menu.addAction(text, &menu, &QMenu::deleteLater);
- menu.addAction(text, testFunction);
- menu.addAction(text, &menu, testFunction);
- menu.addAction(icon, text, &menu, SLOT(deleteLater()));
- menu.addAction(icon, text, &menu, &QMenu::deleteLater);
- menu.addAction(icon, text, testFunction);
- menu.addAction(icon, text, &menu, testFunction);
+
+ // don't just pass QString etc - that'd be too easy (think QStringBuilder)
+ ImplicitlyConvertibleTo<QString> text = {QLatin1String("bla")};
+ ImplicitlyConvertibleTo<QIcon> icon;
+
+ const auto check = [&](auto &...args) { // don't need to perfectly-forward, only lvalues passed
+ menu.addAction(args...);
+
+ menu.addAction(args..., &menu, SLOT(deleteLater()));
+ menu.addAction(args..., &menu, &QMenu::deleteLater);
+ menu.addAction(args..., testFunction0);
+ menu.addAction(args..., &menu, testFunction0);
+ menu.addAction(args..., testFunction1);
+ menu.addAction(args..., &menu, testFunction1);
+ menu.addAction(args..., [&](bool b) { menu.setEnabled(b); });
+ menu.addAction(args..., &menu, [&](bool b) { menu.setEnabled(b); });
+
+ menu.addAction(args..., &menu, SLOT(deleteLater()), Qt::QueuedConnection);
+ menu.addAction(args..., &menu, &QMenu::deleteLater, Qt::QueuedConnection);
+ // doesn't exist: menu.addAction(args..., testFunction0, Qt::QueuedConnection);
+ menu.addAction(args..., &menu, testFunction0, Qt::QueuedConnection);
+ // doesn't exist: menu.addAction(args..., testFunction1, Qt::QueuedConnection);
+ menu.addAction(args..., &menu, testFunction1, Qt::QueuedConnection);
+ // doesn't exist: menu.addAction(args..., [&](bool b) { menu.setEnabled(b); }, Qt::QueuedConnection);
+ menu.addAction(args..., &menu, [&](bool b) { menu.setEnabled(b); }, Qt::QueuedConnection);
+ };
+ const auto check1 = [&](auto &arg, auto &...args) {
+ check(arg, args...);
+ check(std::as_const(arg), args...);
+ };
+ const auto check2 = [&](auto &arg1, auto &arg2, auto &...args) {
+ check1(arg1, arg2, args...);
+ check1(arg1, std::as_const(arg2), args...);
+ };
+ [[maybe_unused]]
+ const auto check3 = [&](auto &arg1, auto &arg2, auto &arg3) {
+ check2(arg1, arg2, arg3);
+ check2(arg1, arg2, std::as_const(arg3));
+ };
+
+ check1(text);
+ check2(icon, text);
#ifndef QT_NO_SHORTCUT
- const QKeySequence keySequence(Qt::CTRL | Qt::Key_C);
+ ImplicitlyConvertibleTo<QKeySequence> keySequence = {Qt::CTRL | Qt::Key_C};
+ check2(text, keySequence);
+ check3(icon, text, keySequence);
#if QT_DEPRECATED_SINCE(6, 4)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
menu.addAction(text, &menu, SLOT(deleteLater()), keySequence);
menu.addAction(text, &menu, &QMenu::deleteLater, keySequence);
- menu.addAction(text, testFunction, keySequence);
- menu.addAction(text, &menu, testFunction, keySequence);
+ menu.addAction(text, testFunction0, keySequence);
+ menu.addAction(text, &menu, testFunction0, keySequence);
+ menu.addAction(text, testFunction1, keySequence);
+ menu.addAction(text, &menu, testFunction1, keySequence);
menu.addAction(icon, text, &menu, SLOT(deleteLater()), keySequence);
menu.addAction(icon, text, &menu, &QMenu::deleteLater, keySequence);
- menu.addAction(icon, text, testFunction, keySequence);
- menu.addAction(icon, text, &menu, testFunction, keySequence);
+ menu.addAction(icon, text, testFunction0, keySequence);
+ menu.addAction(icon, text, &menu, testFunction0, keySequence);
+ menu.addAction(icon, text, testFunction1, keySequence);
+ menu.addAction(icon, text, &menu, testFunction1, keySequence);
QT_WARNING_POP
#endif
- menu.addAction(text, keySequence, &menu, SLOT(deleteLater()));
- menu.addAction(text, keySequence, &menu, &QMenu::deleteLater);
- menu.addAction(text, keySequence, testFunction);
- menu.addAction(text, keySequence, &menu, testFunction);
- menu.addAction(icon, text, keySequence, &menu, SLOT(deleteLater()));
- menu.addAction(icon, text, keySequence, &menu, &QMenu::deleteLater);
- menu.addAction(icon, text, keySequence, testFunction);
- menu.addAction(icon, text, keySequence, &menu, testFunction);
#endif // !QT_NO_SHORTCUT
}