1 /***************************************************************************
2 * Copyright (C) 2005-2022 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
24 #include <initializer_list>
28 #include <QAbstractButton>
30 #include <QDoubleSpinBox>
37 #include "colorbutton.h"
38 #include "fontselector.h"
39 #include "funchelpers.h"
45 * Contains all supported widget changed signals.
47 static const auto supportedWidgetChangedSignals = std::make_tuple(
48 &ColorButton::colorChanged,
49 &FontSelector::fontChanged,
50 &QAbstractButton::toggled,
51 selectOverload<int>(&QComboBox::currentIndexChanged),
52 selectOverload<double>(&QDoubleSpinBox::valueChanged),
54 &QLineEdit::textChanged,
55 selectOverload<int>(&QSpinBox::valueChanged),
56 &QTextEdit::textChanged
60 * Tries to find a changed signal that matches the given widget type, and connects that to the given receiver/slot.
62 template<typename Receiver, typename Slot, std::size_t... Is>
63 bool tryConnectChangedSignal(const QObject* widget, const Receiver* receiver, Slot slot, std::index_sequence<Is...>)
65 // Tries to cast the given QObject to the given signal's class type, and connects to receiver/slot if successful.
66 // If *alreadyConnected is true, just returns false to prevent multiple connections.
67 static const auto tryConnect = [](const QObject* object, auto sig, auto receiver, auto slot, bool* alreadyConnected) {
68 if (!*alreadyConnected) {
69 auto widget = qobject_cast<const typename FunctionTraits<decltype(sig)>::ClassType*>(object);
71 *alreadyConnected = QObject::connect(widget, sig, receiver, slot);
72 return *alreadyConnected;
78 // Unpack the tuple and try to connect to each contained signal in order
79 bool alreadyConnected{false};
80 auto results = {tryConnect(widget, std::get<Is>(supportedWidgetChangedSignals), receiver, slot, &alreadyConnected)...};
81 return std::any_of(results.begin(), results.end(), [](bool result) { return result; });
87 * Connects the given widget's changed signal to the given receiver/context and slot.
89 * Changed signals for supported widgets are listed in detail::supportedWidgetChangedSignals.
91 * @note The slot must not take any arguments.
93 * @param widget Pointer to the widget
94 * @param receiver Receiver of the signal (or context for the connection)
95 * @param slot Receiving slot (or functor, or whatever)
96 * @returns true if the widget type is supported, false otherwise
98 template<typename Receiver, typename Slot>
99 bool connectToWidgetChangedSignal(const QObject* widget, const Receiver* receiver, Slot slot)
101 return detail::tryConnectChangedSignal(widget,
104 std::make_index_sequence<std::tuple_size<decltype(detail::supportedWidgetChangedSignals)>::value>{});
108 * Connects the given widgets' changed signals to the given receiver/context and slot.
110 * Changed signals for supported widgets are listed in detail::supportedWidgetChangedSignals.
112 * @note The slot must not take any arguments.
114 * @param widget Pointer to the widget
115 * @param receiver Receiver of the signal (or context for the connection)
116 * @param slot Receiving slot (or functor, or whatever)
117 * @returns true if all given widget types are supported, false otherwise
119 template<typename Container, typename Receiver, typename Slot>
120 bool connectToWidgetsChangedSignals(const Container& widgets, const Receiver* receiver, Slot slot)
123 for (auto&& widget : widgets) {
124 success &= detail::tryConnectChangedSignal(widget,
127 std::make_index_sequence<
128 std::tuple_size<decltype(detail::supportedWidgetChangedSignals)>::value>{});
135 * Convenience overload that allows brace-initializing the list of widgets.
137 template<typename Receiver, typename Slot>
138 bool connectToWidgetsChangedSignals(const std::initializer_list<const QObject*>& widgets, const Receiver* receiver, Slot slot)
140 return connectToWidgetsChangedSignals(std::vector<const QObject*>{widgets}, receiver, slot);