File indexing completed on 2024-05-19 04:29:31

0001 /*
0002  *  SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "KisWidgetConnectionUtils.h"
0008 
0009 #include <QMetaObject>
0010 #include <QMetaProperty>
0011 #include <QAbstractButton>
0012 #include <QAction>
0013 #include <QComboBox>
0014 #include <QButtonGroup>
0015 #include <QSpinBox>
0016 #include <QDoubleSpinBox>
0017 #include <QLineEdit>
0018 #include "kis_debug.h"
0019 #include "kis_spacing_selection_widget.h"
0020 #include "kis_multipliers_double_slider_spinbox.h"
0021 #include "KisAngleSelector.h"
0022 #include "kis_file_name_requester.h"
0023 
0024 class ConnectButtonStateHelper : public QObject
0025 {
0026     Q_OBJECT
0027 public:
0028 
0029     ConnectButtonStateHelper(QAbstractButton *parent)
0030         : QObject(parent),
0031           m_button(parent)
0032     {
0033     }
0034 public Q_SLOTS:
0035     void updateState(const CheckBoxState &state) {
0036         QSignalBlocker b(m_button);
0037         m_button->setEnabled(state.enabled);
0038         m_button->setChecked(state.value);
0039 
0040         // TODO: verify if the two properties are equal or the control is disabled
0041     }
0042 
0043 private:
0044     QAbstractButton *m_button;
0045 };
0046 
0047 class ConnectComboBoxStateHelper : public QObject
0048 {
0049     Q_OBJECT
0050 public:
0051 
0052     ConnectComboBoxStateHelper(QComboBox *parent)
0053         : QObject(parent),
0054           m_comboBox(parent)
0055     {
0056     }
0057 public Q_SLOTS:
0058     void updateState(const ComboBoxState &state) {
0059         QSignalBlocker b(m_comboBox);
0060 
0061         while (m_comboBox->count() > 0) {
0062             m_comboBox->removeItem(0);
0063         }
0064 
0065         m_comboBox->addItems(state.items);
0066         m_comboBox->setCurrentIndex(state.currentIndex);
0067         m_comboBox->setEnabled(state.enabled);
0068 
0069         // TODO: verify if the two properties are equal or the control is disabled
0070     }
0071 
0072 private:
0073     QComboBox *m_comboBox;
0074 };
0075 
0076 
0077 namespace KisWidgetConnectionUtils {
0078 
0079 template<typename Button>
0080 void connectButtonLikeControl(Button *button, QObject *source, const char *property)
0081 {
0082     const QMetaObject* meta = source->metaObject();
0083     QMetaProperty prop = meta->property(meta->indexOfProperty(property));
0084 
0085     KIS_SAFE_ASSERT_RECOVER_RETURN(prop.hasNotifySignal());
0086 
0087     QMetaMethod signal = prop.notifySignal();
0088 
0089     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0090     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("bool"));
0091 
0092     const QMetaObject* dstMeta = button->metaObject();
0093 
0094     QMetaMethod updateSlot = dstMeta->method(
0095         dstMeta->indexOfSlot("setChecked(bool)"));
0096     QObject::connect(source, signal, button, updateSlot);
0097 
0098     button->setChecked(prop.read(source).toBool());
0099 
0100     if (prop.isWritable()) {
0101         QObject::connect(button, &Button::toggled,
0102                          source, [prop, source] (bool value) { prop.write(source, value); });
0103     }
0104 }
0105 
0106 void connectControl(QAbstractButton *button, QObject *source, const char *property)
0107 {
0108     connectButtonLikeControl(button, source, property);
0109 }
0110 
0111 void connectControl(QAction *button, QObject *source, const char *property)
0112 {
0113     connectButtonLikeControl(button, source, property);
0114 }
0115 
0116 void connectControl(QSpinBox *spinBox, QObject *source, const char *property)
0117 {
0118     const QMetaObject* meta = source->metaObject();
0119     QMetaProperty prop = meta->property(meta->indexOfProperty(property));
0120 
0121     KIS_SAFE_ASSERT_RECOVER_RETURN(prop.hasNotifySignal());
0122 
0123     QMetaMethod signal = prop.notifySignal();
0124 
0125     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0126     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("int"));
0127 
0128     const QMetaObject* dstMeta = spinBox->metaObject();
0129 
0130     QMetaMethod updateSlot = dstMeta->method(
0131                 dstMeta->indexOfSlot("setValue(int)"));
0132     QObject::connect(source, signal, spinBox, updateSlot);
0133 
0134     spinBox->setValue(prop.read(source).toInt());
0135 
0136     if (prop.isWritable()) {
0137         QObject::connect(spinBox, qOverload<int>(&QSpinBox::valueChanged),
0138                          source, [prop, source] (int value) { prop.write(source, value); });
0139     }
0140 }
0141 
0142 void connectControl(QDoubleSpinBox *spinBox, QObject *source, const char *property)
0143 {
0144     const QMetaObject* meta = source->metaObject();
0145     QMetaProperty prop = meta->property(meta->indexOfProperty(property));
0146 
0147     KIS_SAFE_ASSERT_RECOVER_RETURN(prop.hasNotifySignal());
0148 
0149     QMetaMethod signal = prop.notifySignal();
0150 
0151     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0152     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("qreal"));
0153 
0154     const QMetaObject* dstMeta = spinBox->metaObject();
0155 
0156     QMetaMethod updateSlot = dstMeta->method(
0157                 dstMeta->indexOfSlot("setValue(qreal)"));
0158     QObject::connect(source, signal, spinBox, updateSlot);
0159 
0160     spinBox->setValue(prop.read(source).toReal());
0161 
0162     if (prop.isWritable()) {
0163         QObject::connect(spinBox, qOverload<qreal>(&QDoubleSpinBox::valueChanged),
0164                          source, [prop, source] (qreal value) { prop.write(source, value); });
0165     }
0166 }
0167 
0168 class ConnectIntSpinBoxStateHelper : public QObject
0169 {
0170     Q_OBJECT
0171 public:
0172 
0173     ConnectIntSpinBoxStateHelper(QSpinBox *parent)
0174         : QObject(parent),
0175         m_spinBox(parent)
0176     {
0177     }
0178 public Q_SLOTS:
0179     void setState(IntSpinBoxState state) {
0180         QSignalBlocker b(m_spinBox);
0181 
0182         m_spinBox->setEnabled(state.enabled);
0183         m_spinBox->setRange(state.min, state.max);
0184         m_spinBox->setValue(state.value);
0185     }
0186 
0187 private:
0188     QSpinBox *m_spinBox;
0189 };
0190 
0191 
0192 void connectControlState(QSpinBox *spinBox, QObject *source, const char *readStateProperty, const char *writeProperty)
0193 {
0194     const QMetaObject* meta = source->metaObject();
0195     QMetaProperty readStateProp = meta->property(meta->indexOfProperty(readStateProperty));
0196 
0197     KIS_SAFE_ASSERT_RECOVER_RETURN(readStateProp.hasNotifySignal());
0198 
0199     QMetaMethod signal = readStateProp.notifySignal();
0200 
0201     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0202     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("IntSpinBoxState"));
0203 
0204     ConnectIntSpinBoxStateHelper *helper = new ConnectIntSpinBoxStateHelper(spinBox);
0205 
0206     const QMetaObject* dstMeta = helper->metaObject();
0207 
0208     QMetaMethod updateSlot = dstMeta->method(
0209         dstMeta->indexOfSlot("setState(IntSpinBoxState)"));
0210     QObject::connect(source, signal, helper, updateSlot);
0211 
0212     helper->setState(readStateProp.read(source).value<IntSpinBoxState>());
0213 
0214     QMetaProperty writeProp = meta->property(meta->indexOfProperty(writeProperty));
0215     if (writeProp.isWritable()) {
0216         QObject::connect(spinBox, qOverload<int>(&QSpinBox::valueChanged),
0217                          source, [writeProp, source] (int value) { writeProp.write(source, value); });
0218     }
0219 }
0220 
0221 class ConnectDoubleSpinBoxStateHelper : public QObject
0222 {
0223     Q_OBJECT
0224 public:
0225 
0226     ConnectDoubleSpinBoxStateHelper(QDoubleSpinBox *parent)
0227         : QObject(parent),
0228         m_spinBox(parent)
0229     {
0230     }
0231 public Q_SLOTS:
0232     void setState(DoubleSpinBoxState state) {
0233         QSignalBlocker b(m_spinBox);
0234 
0235         m_spinBox->setEnabled(state.enabled);
0236         m_spinBox->setRange(state.min, state.max);
0237         m_spinBox->setValue(state.value);
0238     }
0239 
0240 private:
0241     QDoubleSpinBox *m_spinBox;
0242 };
0243 
0244 
0245 void connectControlState(QDoubleSpinBox *spinBox, QObject *source, const char *readStateProperty, const char *writeProperty)
0246 {
0247     const QMetaObject* meta = source->metaObject();
0248     QMetaProperty readStateProp = meta->property(meta->indexOfProperty(readStateProperty));
0249 
0250     KIS_SAFE_ASSERT_RECOVER_RETURN(readStateProp.hasNotifySignal());
0251 
0252     QMetaMethod signal = readStateProp.notifySignal();
0253 
0254     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0255     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("DoubleSpinBoxState"));
0256 
0257     ConnectDoubleSpinBoxStateHelper *helper = new ConnectDoubleSpinBoxStateHelper(spinBox);
0258 
0259     const QMetaObject* dstMeta = helper->metaObject();
0260 
0261     QMetaMethod updateSlot = dstMeta->method(
0262         dstMeta->indexOfSlot("setState(DoubleSpinBoxState)"));
0263     QObject::connect(source, signal, helper, updateSlot);
0264 
0265     helper->setState(readStateProp.read(source).value<DoubleSpinBoxState>());
0266 
0267     QMetaProperty writeProp = meta->property(meta->indexOfProperty(writeProperty));
0268     if (writeProp.isWritable()) {
0269         QObject::connect(spinBox, qOverload<qreal>(&QDoubleSpinBox::valueChanged),
0270                          source, [writeProp, source] (qreal value) { writeProp.write(source, value); });
0271     }
0272 }
0273 
0274 
0275 void connectControl(KisMultipliersDoubleSliderSpinBox *spinBox, QObject *source, const char *property)
0276 {
0277     const QMetaObject* meta = source->metaObject();
0278     QMetaProperty prop = meta->property(meta->indexOfProperty(property));
0279 
0280     KIS_SAFE_ASSERT_RECOVER_RETURN(prop.hasNotifySignal());
0281 
0282     QMetaMethod signal = prop.notifySignal();
0283 
0284     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0285     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("qreal"));
0286 
0287     const QMetaObject* dstMeta = spinBox->metaObject();
0288 
0289     QMetaMethod updateSlot = dstMeta->method(
0290                 dstMeta->indexOfSlot("setValue(qreal)"));
0291     QObject::connect(source, signal, spinBox, updateSlot);
0292 
0293     spinBox->setValue(prop.read(source).toReal());
0294 
0295     if (prop.isWritable()) {
0296         QObject::connect(spinBox, qOverload<qreal>(&KisMultipliersDoubleSliderSpinBox::valueChanged),
0297                          source, [prop, source] (qreal value) { prop.write(source, value); });
0298     }
0299 }
0300 
0301 
0302 class ConnectButtonGroupHelper : public QObject
0303 {
0304     Q_OBJECT
0305 public:
0306 
0307     ConnectButtonGroupHelper(QButtonGroup *parent)
0308         : QObject(parent),
0309           m_buttonGroup(parent)
0310     {
0311         QObject::connect(m_buttonGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &ConnectButtonGroupHelper::slotButtonClicked);
0312     }
0313 public Q_SLOTS:
0314     void updateState(int value) {
0315         QAbstractButton *btn = m_buttonGroup->button(value);
0316         KIS_SAFE_ASSERT_RECOVER_RETURN(btn);
0317         btn->setChecked(true);
0318     }
0319 
0320     void updateState(ButtonGroupState state) {
0321         QAbstractButton *btn = m_buttonGroup->button(state.value);
0322         KIS_SAFE_ASSERT_RECOVER_RETURN(btn);
0323         btn->setChecked(true);
0324 
0325         Q_FOREACH (QAbstractButton *btn, m_buttonGroup->buttons()) {
0326             btn->setEnabled(state.enabled);
0327         }
0328     }
0329 
0330     void slotButtonClicked(QAbstractButton *btn) {
0331         int id = m_buttonGroup->id(btn);
0332         KIS_SAFE_ASSERT_RECOVER_RETURN(id >= 0);
0333 
0334         Q_EMIT idClicked(id);
0335     }
0336 
0337 Q_SIGNALS:
0338     // this signal was added only in Qt 5.15
0339     void idClicked(int id);
0340 
0341 private:
0342     QButtonGroup *m_buttonGroup;
0343 };
0344 
0345 void connectControl(QButtonGroup *group, QObject *source, const char *property)
0346 {
0347     const QMetaObject* meta = source->metaObject();
0348     QMetaProperty prop = meta->property(meta->indexOfProperty(property));
0349 
0350     KIS_SAFE_ASSERT_RECOVER_RETURN(prop.hasNotifySignal());
0351 
0352     QMetaMethod signal = prop.notifySignal();
0353 
0354     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0355     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("int"));
0356 
0357 
0358     ConnectButtonGroupHelper *helper = new ConnectButtonGroupHelper(group);
0359 
0360     const QMetaObject* dstMeta = helper->metaObject();
0361 
0362     QMetaMethod updateSlot = dstMeta->method(
0363                 dstMeta->indexOfSlot("updateState(int)"));
0364     QObject::connect(source, signal, helper, updateSlot);
0365 
0366     helper->updateState(prop.read(source).toInt());
0367 
0368     if (prop.isWritable()) {
0369         QObject::connect(helper, &ConnectButtonGroupHelper::idClicked,
0370                          source, [prop, source] (int value) { prop.write(source, value); });
0371     }
0372 }
0373 
0374 void connectControlState(QButtonGroup *group, QObject *source, const char *readStateProperty, const char *writeProperty)
0375 {
0376     const QMetaObject* meta = source->metaObject();
0377     QMetaProperty readStateProp = meta->property(meta->indexOfProperty(readStateProperty));
0378 
0379     KIS_SAFE_ASSERT_RECOVER_RETURN(readStateProp.hasNotifySignal());
0380 
0381     QMetaMethod signal = readStateProp.notifySignal();
0382 
0383     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0384     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("ButtonGroupState"));
0385 
0386     ConnectButtonGroupHelper *helper = new ConnectButtonGroupHelper(group);
0387 
0388     const QMetaObject* dstMeta = helper->metaObject();
0389 
0390     QMetaMethod updateSlot = dstMeta->method(
0391                 dstMeta->indexOfSlot("updateState(ButtonGroupState)"));
0392     QObject::connect(source, signal, helper, updateSlot);
0393 
0394     helper->updateState(readStateProp.read(source).value<ButtonGroupState>());
0395 
0396     QMetaProperty writeProp = meta->property(meta->indexOfProperty(writeProperty));
0397     if (writeProp.isWritable()) {
0398         QObject::connect(helper, &ConnectButtonGroupHelper::idClicked,
0399                          source, [writeProp, source] (int value) { writeProp.write(source, value); });
0400     }
0401 }
0402 
0403 void connectControlState(QAbstractButton *button, QObject *source, const char *readStatePropertyName, const char *writePropertyName)
0404 {
0405     const QMetaObject* meta = source->metaObject();
0406     QMetaProperty readStateProp = meta->property(meta->indexOfProperty(readStatePropertyName));
0407 
0408     KIS_SAFE_ASSERT_RECOVER_RETURN(readStateProp.hasNotifySignal());
0409 
0410     QMetaMethod signal = readStateProp.notifySignal();
0411 
0412     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0413     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("CheckBoxState"));
0414 
0415     ConnectButtonStateHelper *helper = new ConnectButtonStateHelper(button);
0416 
0417     const QMetaObject* dstMeta = helper->metaObject();
0418 
0419     QMetaMethod updateSlot = dstMeta->method(
0420                 dstMeta->indexOfSlot("updateState(CheckBoxState)"));
0421     QObject::connect(source, signal, helper, updateSlot);
0422 
0423     helper->updateState(readStateProp.read(source).value<CheckBoxState>());
0424 
0425     QMetaProperty writeProp = meta->property(meta->indexOfProperty(writePropertyName));
0426     if (writeProp.isWritable()) {
0427         button->connect(button, &QAbstractButton::toggled,
0428                         source, [writeProp, source] (bool value) { writeProp.write(source, value); });
0429     }
0430 }
0431 
0432 
0433 void connectControlState(QComboBox *button, QObject *source, const char *readStatePropertyName, const char *writePropertyName)
0434 {
0435     const QMetaObject* meta = source->metaObject();
0436     QMetaProperty readStateProp = meta->property(meta->indexOfProperty(readStatePropertyName));
0437 
0438     KIS_SAFE_ASSERT_RECOVER_RETURN(readStateProp.hasNotifySignal());
0439 
0440     QMetaMethod signal = readStateProp.notifySignal();
0441 
0442     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0443     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("ComboBoxState"));
0444 
0445     ConnectComboBoxStateHelper *helper = new ConnectComboBoxStateHelper(button);
0446 
0447     const QMetaObject* dstMeta = helper->metaObject();
0448 
0449     QMetaMethod updateSlot = dstMeta->method(
0450                 dstMeta->indexOfSlot("updateState(ComboBoxState)"));
0451     QObject::connect(source, signal, helper, updateSlot);
0452 
0453     helper->updateState(readStateProp.read(source).value<ComboBoxState>());
0454 
0455     QMetaProperty writeProp = meta->property(meta->indexOfProperty(writePropertyName));
0456     if (writeProp.isWritable()) {
0457         QObject::connect(button, qOverload<int>(&QComboBox::currentIndexChanged),
0458                          source, [writeProp, source] (int value) { writeProp.write(source, value); });
0459     }
0460 }
0461 
0462 void connectControl(QComboBox *button, QObject *source, const char *property)
0463 {
0464     const QMetaObject* meta = source->metaObject();
0465     QMetaProperty stateProp = meta->property(meta->indexOfProperty(property));
0466 
0467     KIS_SAFE_ASSERT_RECOVER_RETURN(stateProp.hasNotifySignal());
0468 
0469     QMetaMethod signal = stateProp.notifySignal();
0470 
0471     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0472     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("int"));
0473 
0474     const QMetaObject* dstMeta = button->metaObject();
0475 
0476     QMetaMethod updateSlot = dstMeta->method(
0477                 dstMeta->indexOfSlot("setCurrentIndex(int)"));
0478     QObject::connect(source, signal, button, updateSlot);
0479 
0480     button->setCurrentIndex(stateProp.read(source).value<int>());
0481 
0482     if (stateProp.isWritable()) {
0483         QObject::connect(button, qOverload<int>(&QComboBox::currentIndexChanged),
0484                          source, [stateProp, source] (int value) { stateProp.write(source, value); });
0485     }
0486 }
0487 
0488 class ConnectSpacingWidgetHelper : public QObject
0489 {
0490     Q_OBJECT
0491 public:
0492 
0493     ConnectSpacingWidgetHelper(KisSpacingSelectionWidget *parent)
0494         : QObject(parent),
0495           m_spacingWidget(parent)
0496     {
0497         connect(parent, &KisSpacingSelectionWidget::sigSpacingChanged,
0498                 this, &ConnectSpacingWidgetHelper::slotWidgetChanged);
0499     }
0500 public Q_SLOTS:
0501     void slotWidgetChanged() {
0502         Q_EMIT sigWidgetChanged({m_spacingWidget->spacing(), m_spacingWidget->autoSpacingActive(), m_spacingWidget->autoSpacingCoeff()});
0503     }
0504 
0505     void slotPropertyChanged(SpacingState state) {
0506         m_spacingWidget->setSpacing(state.useAutoSpacing, state.useAutoSpacing ? state.autoSpacingCoeff : state.spacing);
0507     }
0508 
0509 Q_SIGNALS:
0510     // this signal was added only in Qt 5.15
0511     void sigWidgetChanged(SpacingState state);
0512 
0513 private:
0514     KisSpacingSelectionWidget *m_spacingWidget;
0515 };
0516 
0517 void connectControl(KisSpacingSelectionWidget *widget, QObject *source, const char *property)
0518 {
0519     const QMetaObject* meta = source->metaObject();
0520     QMetaProperty stateProp = meta->property(meta->indexOfProperty(property));
0521 
0522     KIS_SAFE_ASSERT_RECOVER_RETURN(stateProp.hasNotifySignal());
0523 
0524     QMetaMethod signal = stateProp.notifySignal();
0525 
0526     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0527     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("SpacingState"));
0528 
0529     ConnectSpacingWidgetHelper *helper = new ConnectSpacingWidgetHelper(widget);
0530 
0531     const QMetaObject* dstMeta = helper->metaObject();
0532 
0533     QMetaMethod updateSlot = dstMeta->method(
0534                 dstMeta->indexOfSlot("slotPropertyChanged(SpacingState)"));
0535     QObject::connect(source, signal, helper, updateSlot);
0536 
0537     helper->slotPropertyChanged(stateProp.read(source).value<SpacingState>());
0538 
0539     if (stateProp.isWritable()) {
0540         QObject::connect(helper, &ConnectSpacingWidgetHelper::sigWidgetChanged,
0541                          source, [stateProp, source] (SpacingState value) { stateProp.write(source, QVariant::fromValue(value)); });
0542     }
0543 }
0544 
0545 void connectControl(KisAngleSelector *widget, QObject *source, const char *property)
0546 {
0547     const QMetaObject* meta = source->metaObject();
0548     QMetaProperty prop = meta->property(meta->indexOfProperty(property));
0549 
0550     KIS_SAFE_ASSERT_RECOVER_RETURN(prop.hasNotifySignal());
0551 
0552     QMetaMethod signal = prop.notifySignal();
0553 
0554     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0555     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("qreal"));
0556 
0557     const QMetaObject* dstMeta = widget->metaObject();
0558 
0559     QMetaMethod updateSlot = dstMeta->method(
0560                 dstMeta->indexOfSlot("setAngle(qreal)"));
0561     QObject::connect(source, signal, widget, updateSlot);
0562 
0563     widget->setAngle(prop.read(source).toReal());
0564 
0565     if (prop.isWritable()) {
0566         QObject::connect(widget, &KisAngleSelector::angleChanged,
0567                          source, [prop, source] (qreal value) { prop.write(source, value); });
0568     }
0569 }
0570 
0571 void connectControl(QLineEdit *widget, QObject *source, const char *property)
0572 {
0573     const QMetaObject* meta = source->metaObject();
0574     QMetaProperty prop = meta->property(meta->indexOfProperty(property));
0575 
0576     KIS_SAFE_ASSERT_RECOVER_RETURN(prop.hasNotifySignal());
0577 
0578     QMetaMethod signal = prop.notifySignal();
0579 
0580     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0581     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("QString"));
0582 
0583     const QMetaObject* dstMeta = widget->metaObject();
0584 
0585     QMetaMethod updateSlot = dstMeta->method(
0586                 dstMeta->indexOfSlot("setText(QString)"));
0587     QObject::connect(source, signal, widget, updateSlot);
0588 
0589     widget->setText(prop.read(source).toString());
0590 
0591     if (prop.isWritable()) {
0592         QObject::connect(widget, &QLineEdit::textChanged,
0593                          source, [prop, source] (const QString &value) { prop.write(source, value); });
0594     }
0595 }
0596 
0597 void connectControl(KisFileNameRequester *widget, QObject *source, const char *property)
0598 {
0599     const QMetaObject* meta = source->metaObject();
0600     QMetaProperty prop = meta->property(meta->indexOfProperty(property));
0601 
0602     KIS_SAFE_ASSERT_RECOVER_RETURN(prop.hasNotifySignal());
0603 
0604     QMetaMethod signal = prop.notifySignal();
0605 
0606     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterCount() >= 1);
0607     KIS_SAFE_ASSERT_RECOVER_RETURN(signal.parameterType(0) == QMetaType::type("QString"));
0608     
0609     const QMetaObject* dstMeta = widget->metaObject();
0610 
0611     QMetaMethod updateSlot = dstMeta->method(
0612                 dstMeta->indexOfSlot("setFileName(QString)"));
0613     QObject::connect(source, signal, widget, updateSlot);
0614     
0615     widget->setFileName(prop.read(source).toString());
0616 
0617     if (prop.isWritable()) {
0618         QObject::connect(widget, &KisFileNameRequester::textChanged,
0619                          source, [prop, source] (const QString &value) {
0620                              prop.write(source, value); });
0621     }
0622 }
0623 
0624 void connectWidgetVisibleToProperty(QWidget* widget, QObject* source, const char* property)
0625 {
0626     const QMetaObject* meta = source->metaObject();
0627     QMetaProperty prop = meta->property(meta->indexOfProperty(property));
0628     QMetaMethod signal = prop.notifySignal();
0629     
0630     const QMetaObject* dstMeta = widget->metaObject();
0631     
0632     QMetaMethod updateSlot = dstMeta->method(
0633         dstMeta->indexOfSlot("setVisible(bool)"));
0634     
0635     QObject::connect(source, signal, widget, updateSlot);
0636     widget->setVisible(prop.read(source).toBool());
0637 }
0638 
0639 }
0640 
0641 #include <KisWidgetConnectionUtils.moc>