File indexing completed on 2024-05-12 15:56:55

0001 /*
0002  *  SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_ACYCLIC_SIGNAL_CONNECTOR_H
0008 #define __KIS_ACYCLIC_SIGNAL_CONNECTOR_H
0009 
0010 #include <QObject>
0011 #include "kritaglobal_export.h"
0012 #include <mutex>
0013 
0014 class KisAcyclicSignalConnector;
0015 class KoColor;
0016 
0017 #include <QVector>
0018 #include <QPointer>
0019 
0020 /**
0021  * A special class for connecting UI elements to manager classes.
0022  * It allows to avoid direct calling blockSignals() for the sender UI
0023  * element all the time. This is the most important when the measured
0024  * value can be changed not only by the user through the UI, but also
0025  * by the manager according to some internal rules.
0026  *
0027  * Example:
0028  *
0029  * Suppose we have the following connections:
0030  *
0031  * 1) QDoubleSpinBox::valueChanged(double) -> Manager::slotSetValue(double)
0032  * 2) Manager::valueChanged(double) -> QDoubleSpinBox::setValue(double)
0033  *
0034  * Now if the manager decides to change/correct the value, the spinbox
0035  * will go into an infinite loop.
0036  *
0037  * See an example in KisToolCropConfigWidget.
0038  *
0039  * NOTE (coordinated connectors):
0040  *
0041  * Please make sure that you don't convert more than one forward and one backward
0042  * connection to the connector! If you do so, they will become connected to the
0043  * same forwarding slot and, therefore, both output signals will be emitted on
0044  * every incoming signal.
0045  *
0046  * To connect multiple connections that block recursive calls, please use
0047  * "coordinated connectors". Each such connector will have two more connection
0048  * slots that you can reuse.
0049  *
0050  */
0051 
0052 class KRITAGLOBAL_EXPORT KisAcyclicSignalConnector : public QObject
0053 {
0054     Q_OBJECT
0055 public:
0056     typedef std::unique_lock<KisAcyclicSignalConnector> Blocker;
0057 
0058 public:
0059 
0060     KisAcyclicSignalConnector(QObject *parent = 0);
0061     ~KisAcyclicSignalConnector();
0062 
0063     void connectForwardDouble(QObject *sender, const char *signal,
0064                               QObject *receiver, const char *method);
0065 
0066     void connectBackwardDouble(QObject *sender, const char *signal,
0067                                QObject *receiver, const char *method);
0068 
0069     void connectForwardInt(QObject *sender, const char *signal,
0070                            QObject *receiver, const char *method);
0071 
0072     void connectBackwardInt(QObject *sender, const char *signal,
0073                             QObject *receiver, const char *method);
0074 
0075     void connectForwardBool(QObject *sender, const char *signal,
0076                             QObject *receiver, const char *method);
0077 
0078     void connectBackwardBool(QObject *sender, const char *signal,
0079                              QObject *receiver, const char *method);
0080 
0081     void connectForwardVoid(QObject *sender, const char *signal,
0082                             QObject *receiver, const char *method);
0083 
0084     void connectBackwardVoid(QObject *sender, const char *signal,
0085                              QObject *receiver, const char *method);
0086 
0087     void connectForwardVariant(QObject *sender, const char *signal,
0088                                QObject *receiver, const char *method);
0089 
0090     void connectBackwardVariant(QObject *sender, const char *signal,
0091                                 QObject *receiver, const char *method);
0092 
0093     void connectForwardResourcePair(QObject *sender, const char *signal,
0094                                      QObject *receiver, const char *method);
0095 
0096     void connectBackwardResourcePair(QObject *sender, const char *signal,
0097                                      QObject *receiver, const char *method);
0098 
0099     void connectForwardKoColor(QObject *sender, const char *signal,
0100                                QObject *receiver, const char *method);
0101 
0102     void connectBackwardKoColor(QObject *sender, const char *signal,
0103                                 QObject *receiver, const char *method);
0104 
0105     /**
0106      * Lock the connector and all its coordinated child connectors
0107      */
0108     void lock();
0109 
0110     /**
0111      * Unlock the connector and all its coordinated child connectors
0112      */
0113     void unlock();
0114 
0115     /**
0116      * \return true if the connector is locked by some signal or manually.
0117      * Used for debugging purposes mostly.
0118      */
0119     bool isLocked() const;
0120 
0121     /**
0122      * @brief create a coordinated connector that can be used for extending
0123      *        the number of self-locking connection.
0124      *
0125      * The coordinated connector can be used to extend the number of self-locking
0126      * connections. Each coordinated connector adds two more connection slots (forward
0127      * and backward).  Lock of any connector in a coordinated group will lock the whole
0128      * group.
0129      *
0130      * The created connector is owned by *this, don't delete it!
0131      */
0132     KisAcyclicSignalConnector *createCoordinatedConnector();
0133 
0134 private:
0135 
0136     /**
0137      * Lock this connector only.
0138      */
0139     void coordinatedLock();
0140 
0141     /**
0142      * Unlock this connector only.
0143      */
0144     void coordinatedUnlock();
0145 
0146 private Q_SLOTS:
0147     void forwardSlotDouble(double value);
0148     void backwardSlotDouble(double value);
0149 
0150     void forwardSlotInt(int value);
0151     void backwardSlotInt(int value);
0152 
0153     void forwardSlotBool(bool value);
0154     void backwardSlotBool(bool value);
0155 
0156     void forwardSlotVoid();
0157     void backwardSlotVoid();
0158 
0159     void forwardSlotVariant(const QVariant &value);
0160     void backwardSlotVariant(const QVariant &value);
0161 
0162     void forwardSlotResourcePair(int key, const QVariant &resource);
0163     void backwardSlotResourcePair(int key, const QVariant &resource);
0164 
0165     void forwardSlotKoColor(const KoColor &value);
0166     void backwardSlotKoColor(const KoColor &value);
0167 
0168 Q_SIGNALS:
0169     void forwardSignalDouble(double value);
0170     void backwardSignalDouble(double value);
0171 
0172     void forwardSignalInt(int value);
0173     void backwardSignalInt(int value);
0174 
0175     void forwardSignalBool(bool value);
0176     void backwardSignalBool(bool value);
0177 
0178     void forwardSignalVoid();
0179     void backwardSignalVoid();
0180 
0181     void forwardSignalVariant(const QVariant &value);
0182     void backwardSignalVariant(const QVariant &value);
0183 
0184     void forwardSignalResourcePair(int key, const QVariant &value);
0185     void backwardSignalResourcePair(int key, const QVariant &value);
0186 
0187     void forwardSignalKoColor(const KoColor &value);
0188     void backwardSignalKoColor(const KoColor &value);
0189 
0190 private:
0191     int m_signalsBlocked;
0192     QVector<QPointer<KisAcyclicSignalConnector>> m_coordinatedConnectors;
0193     QPointer<KisAcyclicSignalConnector> m_parentConnector;
0194 };
0195 
0196 #endif /* __KIS_ACYCLIC_SIGNAL_CONNECTOR_H */