#include "backlogsettingspage.h"
-#include "qtui.h"
#include "backlogsettings.h"
-
-// For backlog requester types
#include "backlogrequester.h"
+#include "qtui.h"
+#include "widgethelpers.h"
BacklogSettingsPage::BacklogSettingsPage(QWidget *parent)
: SettingsPage(tr("Interface"), tr("Backlog Fetching"), parent)
// FIXME: global backlog requester disabled until issues ruled out
ui.requesterType->removeItem(2);
- connect(ui.requesterType, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BacklogSettingsPage::widgetHasChanged);
+ connectToWidgetChangedSignal(ui.requesterType, this, &BacklogSettingsPage::widgetHasChanged);
}
#include "presetnetworks.h"
#include "settingspagedlg.h"
#include "util.h"
+#include "widgethelpers.h"
// IRCv3 capabilities
#include "irccap.h"
ui.downServer->setIcon(icon::get("go-down"));
ui.editIdentities->setIcon(icon::get("configure"));
- _ignoreWidgetChanges = false;
-
connectedIcon = icon::get("network-connect");
connectingIcon = icon::get("network-wired"); // FIXME network-connecting
disconnectedIcon = icon::get("network-disconnect");
currentId = 0;
setEnabled(Client::isConnected()); // need a core connection!
setWidgetStates();
+
+ connectToWidgetsChangedSignals({
+ ui.identityList,
+ ui.performEdit,
+ ui.sasl,
+ ui.saslAccount,
+ ui.saslPassword,
+ ui.autoIdentify,
+ ui.autoIdentifyService,
+ ui.autoIdentifyPassword,
+ ui.useCustomEncodings,
+ ui.sendEncoding,
+ ui.recvEncoding,
+ ui.serverEncoding,
+ ui.autoReconnect,
+ ui.reconnectInterval,
+ ui.reconnectRetries,
+ ui.unlimitedRetries,
+ ui.rejoinOnReconnect,
+ ui.useCustomMessageRate,
+ ui.messageRateBurstSize,
+ ui.messageRateDelay,
+ ui.unlimitedMessageRate
+ }, this, &NetworksSettingsPage::widgetHasChanged);
+
connect(Client::instance(), &Client::coreConnectionStateChanged, this, &NetworksSettingsPage::coreConnectionStateChanged);
connect(Client::instance(), &Client::networkCreated, this, &NetworksSettingsPage::clientNetworkAdded);
connect(Client::instance(), &Client::networkRemoved, this, &NetworksSettingsPage::clientNetworkRemoved);
connect(Client::instance(), &Client::identityCreated, this, &NetworksSettingsPage::clientIdentityAdded);
connect(Client::instance(), &Client::identityRemoved, this, &NetworksSettingsPage::clientIdentityRemoved);
- connect(ui.identityList, selectOverload<int>(&QComboBox::currentIndexChanged), this, &NetworksSettingsPage::widgetHasChanged);
- //connect(ui.randomServer, &QAbstractButton::clicked, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.performEdit, &QTextEdit::textChanged, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.sasl, &QGroupBox::clicked, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.saslAccount, &QLineEdit::textEdited, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.saslPassword, &QLineEdit::textEdited, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.autoIdentify, &QGroupBox::clicked, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.autoIdentifyService, &QLineEdit::textEdited, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.autoIdentifyPassword, &QLineEdit::textEdited, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.useCustomEncodings, &QGroupBox::clicked, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.sendEncoding, selectOverload<int>(&QComboBox::currentIndexChanged), this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.recvEncoding, selectOverload<int>(&QComboBox::currentIndexChanged), this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.serverEncoding, selectOverload<int>(&QComboBox::currentIndexChanged), this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.autoReconnect, &QGroupBox::clicked, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.reconnectInterval, selectOverload<int>(&QSpinBox::valueChanged), this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.reconnectRetries, selectOverload<int>(&QSpinBox::valueChanged), this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.unlimitedRetries, &QAbstractButton::clicked, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.rejoinOnReconnect, &QAbstractButton::clicked, this, &NetworksSettingsPage::widgetHasChanged);
-
- // Core features can change during a reconnect. Always connect these here, delaying testing for
- // the core feature flag in load().
- connect(ui.useCustomMessageRate, &QGroupBox::clicked, this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.messageRateBurstSize, selectOverload<int>(&QSpinBox::valueChanged), this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.messageRateDelay, selectOverload<double>(&QDoubleSpinBox::valueChanged), this, &NetworksSettingsPage::widgetHasChanged);
- connect(ui.unlimitedMessageRate, &QAbstractButton::clicked, this, &NetworksSettingsPage::widgetHasChanged);
-
foreach(IdentityId id, Client::identityIds()) {
clientIdentityAdded(id);
}
NetworkId currentId;
QHash<NetworkId, NetworkInfo> networkInfos;
- bool _ignoreWidgetChanges;
+ bool _ignoreWidgetChanges{false};
#ifdef HAVE_SSL
CertIdentity *_cid{nullptr};
#endif
treeviewtouch.cpp
uisettings.cpp
uistyle.cpp
+ widgethelpers.h
# needed for automoc
abstractnotificationbackend.h
#include <utility>
#include "fontselector.h"
-
#include "uisettings.h"
+#include "widgethelpers.h"
SettingsPage::SettingsPage(QString category, QString title, QWidget *parent)
: QWidget(parent),
// we need to climb the QObject tree recursively
findAutoWidgets(this, &_autoWidgets);
- foreach(QObject *widget, _autoWidgets) {
- if (widget->inherits("ColorButton"))
- connect(widget, SIGNAL(colorChanged(QColor)), SLOT(autoWidgetHasChanged()));
- else if (widget->inherits("QAbstractButton") || widget->inherits("QGroupBox"))
- connect(widget, SIGNAL(toggled(bool)), SLOT(autoWidgetHasChanged()));
- else if (widget->inherits("QLineEdit") || widget->inherits("QTextEdit"))
- connect(widget, SIGNAL(textChanged(const QString &)), SLOT(autoWidgetHasChanged()));
- else if (widget->inherits("QComboBox"))
- connect(widget, SIGNAL(currentIndexChanged(int)), SLOT(autoWidgetHasChanged()));
- else if (widget->inherits("QSpinBox"))
- connect(widget, SIGNAL(valueChanged(int)), SLOT(autoWidgetHasChanged()));
- else if (widget->inherits("FontSelector"))
- connect(widget, SIGNAL(fontChanged(QFont)), SLOT(autoWidgetHasChanged()));
- else
- qWarning() << "SettingsPage::init(): Unknown autoWidget type" << widget->metaObject()->className();
+ if (!connectToWidgetsChangedSignals(_autoWidgets, this, &SettingsPage::autoWidgetHasChanged)) {
+ qWarning() << "SettingsPage::initAutoWidgets(): Unsupported auto widget type(s)!";
}
}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-2018 by the Quassel Project *
+ * devel@quassel-irc.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) version 3. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#pragma once
+
+#include <algorithm>
+#include <initializer_list>
+#include <tuple>
+#include <utility>
+
+#include <QAbstractButton>
+#include <QComboBox>
+#include <QDoubleSpinBox>
+#include <QGroupBox>
+#include <QLineEdit>
+#include <QObject>
+#include <QSpinBox>
+#include <QTextEdit>
+
+#include "colorbutton.h"
+#include "fontselector.h"
+#include "funchelpers.h"
+#include "util.h"
+
+namespace detail {
+
+/**
+ * Contains all supported widget changed signals.
+ */
+static const auto supportedWidgetChangedSignals = std::make_tuple(
+ &ColorButton::colorChanged,
+ &FontSelector::fontChanged,
+ &QAbstractButton::toggled,
+ selectOverload<int>(&QComboBox::currentIndexChanged),
+ selectOverload<double>(&QDoubleSpinBox::valueChanged),
+ &QGroupBox::toggled,
+ &QLineEdit::textChanged,
+ selectOverload<int>(&QSpinBox::valueChanged),
+ &QTextEdit::textChanged
+);
+
+/**
+ * Tries to find a changed signal that matches the given widget type, and connects that to the given receiver/slot.
+ */
+template<typename Receiver, typename Slot, std::size_t ...Is>
+bool tryConnectChangedSignal(const QObject* widget, const Receiver* receiver, Slot slot, std::index_sequence<Is...>)
+{
+ // Tries to cast the given QObject to the given signal's class type, and connects to receiver/slot if successful.
+ // If *alreadyConnected is true, just returns false to prevent multiple connections.
+ static const auto tryConnect = [](const QObject* object, auto sig, auto receiver, auto slot, bool* alreadyConnected) {
+ if (!*alreadyConnected) {
+ auto widget = qobject_cast<const typename MemberFunction<decltype(sig)>::ClassType *>(object);
+ if (widget) {
+ *alreadyConnected = QObject::connect(widget, sig, receiver, slot);
+ return *alreadyConnected;
+ }
+ }
+ return false;
+ };
+
+ // Unpack the tuple and try to connect to each contained signal in order
+ bool alreadyConnected{false};
+ auto results = { tryConnect(widget, std::get<Is>(supportedWidgetChangedSignals), receiver, slot, &alreadyConnected)... };
+ return std::any_of(results.begin(), results.end(), [](bool result) { return result; });
+}
+
+} //detail
+
+/**
+ * Connects the given widget's changed signal to the given receiver/context and slot.
+ *
+ * Changed signals for supported widgets are listed in detail::supportedWidgetChangedSignals.
+ *
+ * @note The slot must not take any arguments.
+ *
+ * @param widget Pointer to the widget
+ * @param receiver Receiver of the signal (or context for the connection)
+ * @param slot Receiving slot (or functor, or whatever)
+ * @returns true if the widget type is supported, false otherwise
+ */
+template<typename Receiver, typename Slot>
+bool connectToWidgetChangedSignal(const QObject* widget, const Receiver* receiver, Slot slot)
+{
+ return detail::tryConnectChangedSignal(widget, receiver, slot,
+ std::make_index_sequence<std::tuple_size<decltype(detail::supportedWidgetChangedSignals)>::value>{});
+}
+
+/**
+ * Connects the given widgets' changed signals to the given receiver/context and slot.
+ *
+ * Changed signals for supported widgets are listed in detail::supportedWidgetChangedSignals.
+ *
+ * @note The slot must not take any arguments.
+ *
+ * @param widget Pointer to the widget
+ * @param receiver Receiver of the signal (or context for the connection)
+ * @param slot Receiving slot (or functor, or whatever)
+ * @returns true if all given widget types are supported, false otherwise
+ */
+template<typename Container, typename Receiver, typename Slot>
+bool connectToWidgetsChangedSignals(const Container& widgets, const Receiver* receiver, Slot slot)
+{
+ bool success = true;
+ for (auto&& widget : widgets) {
+ success &= detail::tryConnectChangedSignal(widget, receiver, slot,
+ std::make_index_sequence<std::tuple_size<decltype(detail::supportedWidgetChangedSignals)>::value>{});
+ }
+ return success;
+}
+
+/**
+ * @overload
+ * Convenience overload that allows brace-initializing the list of widgets.
+ */
+template<typename Receiver, typename Slot>
+bool connectToWidgetsChangedSignals(const std::initializer_list<const QObject*>& widgets, const Receiver* receiver, Slot slot)
+{
+ return connectToWidgetsChangedSignals(std::vector<const QObject*>{widgets}, receiver, slot);
+}