diff --git a/libs/global/kis_acyclic_signal_connector.cpp b/libs/global/kis_acyclic_signal_connector.cpp index 85b9afeae8..b7c7a77c9e 100644 --- a/libs/global/kis_acyclic_signal_connector.cpp +++ b/libs/global/kis_acyclic_signal_connector.cpp @@ -1,307 +1,312 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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) any later version. * * 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. */ #include "kis_acyclic_signal_connector.h" #include "kis_debug.h" KisAcyclicSignalConnector::KisAcyclicSignalConnector(QObject *parent) : QObject(parent), m_signalsBlocked(0) { } KisAcyclicSignalConnector::~KisAcyclicSignalConnector() { } void KisAcyclicSignalConnector::connectForwardDouble(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(forwardSlotDouble(double)), Qt::UniqueConnection); connect(this, SIGNAL(forwardSignalDouble(double)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectBackwardDouble(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(backwardSlotDouble(double)), Qt::UniqueConnection); connect(this, SIGNAL(backwardSignalDouble(double)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectForwardInt(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(forwardSlotInt(int)), Qt::UniqueConnection); connect(this, SIGNAL(forwardSignalInt(int)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectBackwardInt(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(backwardSlotInt(int)), Qt::UniqueConnection); connect(this, SIGNAL(backwardSignalInt(int)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectForwardBool(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(forwardSlotBool(bool)), Qt::UniqueConnection); connect(this, SIGNAL(forwardSignalBool(bool)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectBackwardBool(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(backwardSlotBool(bool)), Qt::UniqueConnection); connect(this, SIGNAL(backwardSignalBool(bool)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectForwardVoid(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(forwardSlotVoid()), Qt::UniqueConnection); connect(this, SIGNAL(forwardSignalVoid()), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectBackwardVoid(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(backwardSlotVoid()), Qt::UniqueConnection); connect(this, SIGNAL(backwardSignalVoid()), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectForwardVariant(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(forwardSlotVariant(QVariant)), Qt::UniqueConnection); connect(this, SIGNAL(forwardSignalVariant(QVariant)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectBackwardVariant(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(backwardSlotVariant(QVariant)), Qt::UniqueConnection); connect(this, SIGNAL(backwardSignalVariant(QVariant)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectForwardResourcePair(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(forwardSlotResourcePair(int,QVariant)), Qt::UniqueConnection); connect(this, SIGNAL(forwardSignalResourcePair(int,QVariant)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectBackwardResourcePair(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(backwardSlotResourcePair(int,QVariant)), Qt::UniqueConnection); connect(this, SIGNAL(backwardSignalResourcePair(int,QVariant)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectForwardKoColor(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(forwardSlotKoColor(KoColor)), Qt::UniqueConnection); connect(this, SIGNAL(forwardSignalKoColor(KoColor)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::connectBackwardKoColor(QObject *sender, const char *signal, QObject *receiver, const char *method) { connect(sender, signal, this, SLOT(backwardSlotKoColor(KoColor)), Qt::UniqueConnection); connect(this, SIGNAL(backwardSignalKoColor(KoColor)), receiver, method, Qt::UniqueConnection); } void KisAcyclicSignalConnector::lock() { if (m_parentConnector) { m_parentConnector->lock(); } else { coordinatedLock(); Q_FOREACH(QPointer conn, m_coordinatedConnectors) { if (!conn) continue; conn->coordinatedLock(); } } } void KisAcyclicSignalConnector::unlock() { if (m_parentConnector) { m_parentConnector->unlock(); } else { Q_FOREACH(QPointer conn, m_coordinatedConnectors) { if (!conn) continue; conn->coordinatedUnlock(); } coordinatedUnlock(); } } +bool KisAcyclicSignalConnector::isLocked() const +{ + return m_signalsBlocked; +} + void KisAcyclicSignalConnector::coordinatedLock() { m_signalsBlocked++; } void KisAcyclicSignalConnector::coordinatedUnlock() { m_signalsBlocked--; } KisAcyclicSignalConnector *KisAcyclicSignalConnector::createCoordinatedConnector() { KisAcyclicSignalConnector *conn = new KisAcyclicSignalConnector(this); conn->m_parentConnector = this; m_coordinatedConnectors.append(conn); return conn; } void KisAcyclicSignalConnector::forwardSlotDouble(double value) { if (m_signalsBlocked) return; lock(); emit forwardSignalDouble(value); unlock(); } void KisAcyclicSignalConnector::backwardSlotDouble(double value) { if (m_signalsBlocked) return; lock(); emit backwardSignalDouble(value); unlock(); } void KisAcyclicSignalConnector::forwardSlotInt(int value) { if (m_signalsBlocked) return; lock(); emit forwardSignalInt(value); unlock(); } void KisAcyclicSignalConnector::backwardSlotInt(int value) { if (m_signalsBlocked) return; lock(); emit backwardSignalInt(value); unlock(); } void KisAcyclicSignalConnector::forwardSlotBool(bool value) { if (m_signalsBlocked) return; lock(); emit forwardSignalBool(value); unlock(); } void KisAcyclicSignalConnector::backwardSlotBool(bool value) { if (m_signalsBlocked) return; lock(); emit backwardSignalBool(value); unlock(); } void KisAcyclicSignalConnector::forwardSlotVoid() { if (m_signalsBlocked) return; lock(); emit forwardSignalVoid(); unlock(); } void KisAcyclicSignalConnector::backwardSlotVoid() { if (m_signalsBlocked) return; lock(); emit backwardSignalVoid(); unlock(); } void KisAcyclicSignalConnector::forwardSlotVariant(const QVariant &value) { if (m_signalsBlocked) return; lock(); emit forwardSignalVariant(value); unlock(); } void KisAcyclicSignalConnector::backwardSlotVariant(const QVariant &value) { if (m_signalsBlocked) return; lock(); emit backwardSignalVariant(value); unlock(); } void KisAcyclicSignalConnector::forwardSlotResourcePair(int key, const QVariant &resource) { if (m_signalsBlocked) return; lock(); emit forwardSignalResourcePair(key, resource); unlock(); } void KisAcyclicSignalConnector::backwardSlotResourcePair(int key, const QVariant &resource) { if (m_signalsBlocked) return; lock(); emit backwardSignalResourcePair(key, resource); unlock(); } void KisAcyclicSignalConnector::forwardSlotKoColor(const KoColor &value) { if (m_signalsBlocked) return; lock(); emit forwardSignalKoColor(value); unlock(); } void KisAcyclicSignalConnector::backwardSlotKoColor(const KoColor &value) { if (m_signalsBlocked) return; lock(); emit backwardSignalKoColor(value); unlock(); } diff --git a/libs/global/kis_acyclic_signal_connector.h b/libs/global/kis_acyclic_signal_connector.h index 3b32d2194e..400f0b7ea0 100644 --- a/libs/global/kis_acyclic_signal_connector.h +++ b/libs/global/kis_acyclic_signal_connector.h @@ -1,202 +1,208 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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) any later version. * * 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. */ #ifndef __KIS_ACYCLIC_SIGNAL_CONNECTOR_H #define __KIS_ACYCLIC_SIGNAL_CONNECTOR_H #include #include "kritaglobal_export.h" #include class KisAcyclicSignalConnector; class KoColor; #include #include /** * A special class for connecting UI elements to manager classes. * It allows to avoid direct calling blockSignals() for the sender UI * element all the time. This is the most important when the measured * value can be changed not only by the user through the UI, but also * by the manager according to some internal rules. * * Example: * * Suppose we have the following connections: * * 1) QDoubleSpinBox::valueChanged(double) -> Manager::slotSetValue(double) * 2) Manager::valueChanged(double) -> QDoubleSpinBox::setValue(double) * * Now if the manager decides to change/correct the value, the spinbox * will go into an infinite loop. * * See an example in KisToolCropConfigWidget. * * NOTE (coordinated connectors): * * Please make sure that you don't convert more than one forward and one backward * connection to the connector! If you do so, they will become connected to the * same forwarding slot and, therefore, both output signals will be emitted on * every incoming signal. * * To connect multiple connections that block recursive calls, please use * "coordinated connectors". Each such connector will have two more connection * slots that you can reuse. * */ class KRITAGLOBAL_EXPORT KisAcyclicSignalConnector : public QObject { Q_OBJECT public: typedef std::unique_lock Blocker; public: KisAcyclicSignalConnector(QObject *parent = 0); ~KisAcyclicSignalConnector(); void connectForwardDouble(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectBackwardDouble(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectForwardInt(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectBackwardInt(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectForwardBool(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectBackwardBool(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectForwardVoid(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectBackwardVoid(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectForwardVariant(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectBackwardVariant(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectForwardResourcePair(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectBackwardResourcePair(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectForwardKoColor(QObject *sender, const char *signal, QObject *receiver, const char *method); void connectBackwardKoColor(QObject *sender, const char *signal, QObject *receiver, const char *method); /** * Lock the connector and all its coordinated child connectors */ void lock(); /** * Unlock the connector and all its coordinated child connectors */ void unlock(); + /** + * \return true if the connector is locked by some signal or manually. + * Used for debugging purposes mostly. + */ + bool isLocked() const; + /** * @brief create a coordinated connector that can be used for extending * the number of self-locking connection. * * The coordinated connector can be used to extend the number of self-locking * connections. Each coordinated connector adds two more connection slots (forward * and backward). Lock of any connector in a coordinated group will lock the whole * group. * * The created connector is owned by *this, don't delete it! */ KisAcyclicSignalConnector *createCoordinatedConnector(); private: /** * Lock this connector only. */ void coordinatedLock(); /** * Unlock this connector only. */ void coordinatedUnlock(); private Q_SLOTS: void forwardSlotDouble(double value); void backwardSlotDouble(double value); void forwardSlotInt(int value); void backwardSlotInt(int value); void forwardSlotBool(bool value); void backwardSlotBool(bool value); void forwardSlotVoid(); void backwardSlotVoid(); void forwardSlotVariant(const QVariant &value); void backwardSlotVariant(const QVariant &value); void forwardSlotResourcePair(int key, const QVariant &resource); void backwardSlotResourcePair(int key, const QVariant &resource); void forwardSlotKoColor(const KoColor &value); void backwardSlotKoColor(const KoColor &value); Q_SIGNALS: void forwardSignalDouble(double value); void backwardSignalDouble(double value); void forwardSignalInt(int value); void backwardSignalInt(int value); void forwardSignalBool(bool value); void backwardSignalBool(bool value); void forwardSignalVoid(); void backwardSignalVoid(); void forwardSignalVariant(const QVariant &value); void backwardSignalVariant(const QVariant &value); void forwardSignalResourcePair(int key, const QVariant &value); void backwardSignalResourcePair(int key, const QVariant &value); void forwardSignalKoColor(const KoColor &value); void backwardSignalKoColor(const KoColor &value); private: int m_signalsBlocked; QVector> m_coordinatedConnectors; QPointer m_parentConnector; }; #endif /* __KIS_ACYCLIC_SIGNAL_CONNECTOR_H */