/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of a Qt Solutions component.
**
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
**     the names of its contributors may be used to endorse or promote
**     products derived from this software without specific prior written
**     permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
****************************************************************************/

// Qt4 -> Qt5
#define Q_TYPENAME typename

#include "qteditorfactory.h"
#include "qtpropertybrowserutils_p.h"
#include <QSpinBox>
#include <QScrollBar>
#include <QComboBox>
#include <QAbstractItemView>
#include <QLineEdit>
#include <QDateTimeEdit>
#include <QHBoxLayout>
#include <QMenu>
#include <QKeyEvent>
#include <QRegularExpressionValidator>
#include <QApplication>
#include <QLabel>
#include <QToolButton>
#include <QColorDialog>
#include <QFontDialog>
#include <QSpacerItem>
#include <QStyleOption>
#include <QPainter>
#include <QMap>
#include <QRegularExpression>

#if defined(Q_CC_MSVC)
#    pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */
#endif

#if QT_VERSION >= 0x040400
QT_BEGIN_NAMESPACE
#endif

// Set a hard coded left margin to account for the indentation
// of the tree view icon when switching to an editor

static inline void setupTreeViewEditorMargin(QLayout* lt) {
    enum { DecorationMargin = 4 };
    if (QApplication::layoutDirection() == Qt::LeftToRight) {
        lt->setContentsMargins(DecorationMargin, 0, 0, 0);
    }
    else {
        lt->setContentsMargins(0, 0, DecorationMargin, 0);
    }
}

// ---------- EditorFactoryPrivate :
// Base class for editor factory private classes. Manages mapping of properties to editors and vice versa.

template <class Editor>
class EditorFactoryPrivate {
public:

    typedef QList<Editor*> EditorList;
    typedef QMap<QtProperty*, EditorList> PropertyToEditorListMap;
    typedef QMap<Editor*, QtProperty*> EditorToPropertyMap;

    Editor* createEditor(QtProperty* property, QWidget* parent);
    void initializeEditor(QtProperty* property, Editor* e);
    void slotEditorDestroyed(QObject* object);

    PropertyToEditorListMap  m_createdEditors;
    EditorToPropertyMap m_editorToProperty;
};

template <class Editor>
Editor* EditorFactoryPrivate<Editor>::createEditor(QtProperty* property, QWidget* parent) {
    auto* editor = new Editor(parent);
    initializeEditor(property, editor);
    return editor;
}

template <class Editor>
void EditorFactoryPrivate<Editor>::initializeEditor(QtProperty* property, Editor* editor) {
    Q_TYPENAME PropertyToEditorListMap::iterator it = m_createdEditors.find(property);
    if (it == m_createdEditors.end()) {
        it = m_createdEditors.insert(property, EditorList());
    }
    it.value().append(editor);
    m_editorToProperty.insert(editor, property);
}

template <class Editor>
void EditorFactoryPrivate<Editor>::slotEditorDestroyed(QObject* object) {
    const Q_TYPENAME EditorToPropertyMap::iterator ecend = m_editorToProperty.end();
    for (Q_TYPENAME EditorToPropertyMap::iterator itEditor = m_editorToProperty.begin(); itEditor !=  ecend; ++itEditor) {
        if (itEditor.key() == object) {
            Editor* editor = itEditor.key();
            QtProperty* property = itEditor.value();
            const Q_TYPENAME PropertyToEditorListMap::iterator pit = m_createdEditors.find(property);
            if (pit != m_createdEditors.end()) {
                pit.value().removeAll(editor);
                if (pit.value().empty()) {
                    m_createdEditors.erase(pit);
                }
            }
            m_editorToProperty.erase(itEditor);
            return;
        }
    }
}

// ------------ QtSpinBoxFactory

class QtSpinBoxFactoryPrivate : public EditorFactoryPrivate<QSpinBox> {
    QtSpinBoxFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtSpinBoxFactory)
public:

    void slotPropertyChanged(QtProperty* property, int value);
    void slotRangeChanged(QtProperty* property, int min, int max);
    void slotSingleStepChanged(QtProperty* property, int step);
    void slotSetValue(int value);
};

void QtSpinBoxFactoryPrivate::slotPropertyChanged(QtProperty* property, int value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }
    QListIterator<QSpinBox*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QSpinBox* editor = itEditor.next();
        if (editor->value() != value) {
            editor->blockSignals(true);
            editor->setValue(value);
            editor->blockSignals(false);
        }
    }
}

void QtSpinBoxFactoryPrivate::slotRangeChanged(QtProperty* property, int min, int max) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtIntPropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QListIterator<QSpinBox*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QSpinBox* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setRange(min, max);
        editor->setValue(manager->value(property));
        editor->blockSignals(false);
    }
}

void QtSpinBoxFactoryPrivate::slotSingleStepChanged(QtProperty* property, int step) {
    if (!m_createdEditors.contains(property)) {
        return;
    }
    QListIterator<QSpinBox*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QSpinBox* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setSingleStep(step);
        editor->blockSignals(false);
    }
}

void QtSpinBoxFactoryPrivate::slotSetValue(int value) {
    QObject* object = q_ptr->sender();
    const QMap<QSpinBox*, QtProperty*>::ConstIterator  ecend = m_editorToProperty.constEnd();
    for (QMap<QSpinBox*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor !=  ecend; ++itEditor) {
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtIntPropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
    }
}

/*!
    \class QtSpinBoxFactory

    \brief The QtSpinBoxFactory class provides QSpinBox widgets for
    properties created by QtIntPropertyManager objects.

    \sa QtAbstractEditorFactory, QtIntPropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtSpinBoxFactory::QtSpinBoxFactory(QObject* parent)
    : QtAbstractEditorFactory<QtIntPropertyManager>(parent) {
    d_ptr = new QtSpinBoxFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtSpinBoxFactory::~QtSpinBoxFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtSpinBoxFactory::connectPropertyManager(QtIntPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, int)),
            this, SLOT(slotPropertyChanged(QtProperty*, int)));
    connect(manager, SIGNAL(rangeChanged(QtProperty*, int, int)),
            this, SLOT(slotRangeChanged(QtProperty*, int, int)));
    connect(manager, SIGNAL(singleStepChanged(QtProperty*, int)),
            this, SLOT(slotSingleStepChanged(QtProperty*, int)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtSpinBoxFactory::createEditor(QtIntPropertyManager* manager, QtProperty* property,
                                        QWidget* parent) {
    QSpinBox* editor = d_ptr->createEditor(property, parent);
    editor->setSingleStep(manager->singleStep(property));
    editor->setRange(manager->minimum(property), manager->maximum(property));
    editor->setValue(manager->value(property));
    editor->setKeyboardTracking(false);

    connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtSpinBoxFactory::disconnectPropertyManager(QtIntPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, int)),
               this, SLOT(slotPropertyChanged(QtProperty*, int)));
    disconnect(manager, SIGNAL(rangeChanged(QtProperty*, int, int)),
               this, SLOT(slotRangeChanged(QtProperty*, int, int)));
    disconnect(manager, SIGNAL(singleStepChanged(QtProperty*, int)),
               this, SLOT(slotSingleStepChanged(QtProperty*, int)));
}

// QtSliderFactory

class QtSliderFactoryPrivate : public EditorFactoryPrivate<QSlider> {
    QtSliderFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtSliderFactory)
public:
    void slotPropertyChanged(QtProperty* property, int value);
    void slotRangeChanged(QtProperty* property, int min, int max);
    void slotSingleStepChanged(QtProperty* property, int step);
    void slotSetValue(int value);
};

void QtSliderFactoryPrivate::slotPropertyChanged(QtProperty* property, int value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }
    QListIterator<QSlider*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QSlider* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setValue(value);
        editor->blockSignals(false);
    }
}

void QtSliderFactoryPrivate::slotRangeChanged(QtProperty* property, int min, int max) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtIntPropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QListIterator<QSlider*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QSlider* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setRange(min, max);
        editor->setValue(manager->value(property));
        editor->blockSignals(false);
    }
}

void QtSliderFactoryPrivate::slotSingleStepChanged(QtProperty* property, int step) {
    if (!m_createdEditors.contains(property)) {
        return;
    }
    QListIterator<QSlider*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QSlider* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setSingleStep(step);
        editor->blockSignals(false);
    }
}

void QtSliderFactoryPrivate::slotSetValue(int value) {
    QObject* object = q_ptr->sender();
    const QMap<QSlider*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
    for (QMap<QSlider*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) {
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtIntPropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
    }
}

/*!
    \class QtSliderFactory

    \brief The QtSliderFactory class provides QSlider widgets for
    properties created by QtIntPropertyManager objects.

    \sa QtAbstractEditorFactory, QtIntPropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtSliderFactory::QtSliderFactory(QObject* parent)
    : QtAbstractEditorFactory<QtIntPropertyManager>(parent) {
    d_ptr = new QtSliderFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtSliderFactory::~QtSliderFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtSliderFactory::connectPropertyManager(QtIntPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, int)),
            this, SLOT(slotPropertyChanged(QtProperty*, int)));
    connect(manager, SIGNAL(rangeChanged(QtProperty*, int, int)),
            this, SLOT(slotRangeChanged(QtProperty*, int, int)));
    connect(manager, SIGNAL(singleStepChanged(QtProperty*, int)),
            this, SLOT(slotSingleStepChanged(QtProperty*, int)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtSliderFactory::createEditor(QtIntPropertyManager* manager, QtProperty* property,
                                       QWidget* parent) {
    auto* editor = new QSlider(Qt::Horizontal, parent);
    d_ptr->initializeEditor(property, editor);
    editor->setSingleStep(manager->singleStep(property));
    editor->setRange(manager->minimum(property), manager->maximum(property));
    editor->setValue(manager->value(property));

    connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtSliderFactory::disconnectPropertyManager(QtIntPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, int)),
               this, SLOT(slotPropertyChanged(QtProperty*, int)));
    disconnect(manager, SIGNAL(rangeChanged(QtProperty*, int, int)),
               this, SLOT(slotRangeChanged(QtProperty*, int, int)));
    disconnect(manager, SIGNAL(singleStepChanged(QtProperty*, int)),
               this, SLOT(slotSingleStepChanged(QtProperty*, int)));
}

// QtSliderFactory

class QtScrollBarFactoryPrivate : public  EditorFactoryPrivate<QScrollBar> {
    QtScrollBarFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtScrollBarFactory)
public:
    void slotPropertyChanged(QtProperty* property, int value);
    void slotRangeChanged(QtProperty* property, int min, int max);
    void slotSingleStepChanged(QtProperty* property, int step);
    void slotSetValue(int value);
};

void QtScrollBarFactoryPrivate::slotPropertyChanged(QtProperty* property, int value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QListIterator<QScrollBar*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QScrollBar* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setValue(value);
        editor->blockSignals(false);
    }
}

void QtScrollBarFactoryPrivate::slotRangeChanged(QtProperty* property, int min, int max) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtIntPropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QListIterator<QScrollBar*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QScrollBar* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setRange(min, max);
        editor->setValue(manager->value(property));
        editor->blockSignals(false);
    }
}

void QtScrollBarFactoryPrivate::slotSingleStepChanged(QtProperty* property, int step) {
    if (!m_createdEditors.contains(property)) {
        return;
    }
    QListIterator<QScrollBar*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QScrollBar* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setSingleStep(step);
        editor->blockSignals(false);
    }
}

void QtScrollBarFactoryPrivate::slotSetValue(int value) {
    QObject* object = q_ptr->sender();
    const QMap<QScrollBar*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
    for (QMap<QScrollBar*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtIntPropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtScrollBarFactory

    \brief The QtScrollBarFactory class provides QScrollBar widgets for
    properties created by QtIntPropertyManager objects.

    \sa QtAbstractEditorFactory, QtIntPropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtScrollBarFactory::QtScrollBarFactory(QObject* parent)
    : QtAbstractEditorFactory<QtIntPropertyManager>(parent) {
    d_ptr = new QtScrollBarFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtScrollBarFactory::~QtScrollBarFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtScrollBarFactory::connectPropertyManager(QtIntPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, int)),
            this, SLOT(slotPropertyChanged(QtProperty*, int)));
    connect(manager, SIGNAL(rangeChanged(QtProperty*, int, int)),
            this, SLOT(slotRangeChanged(QtProperty*, int, int)));
    connect(manager, SIGNAL(singleStepChanged(QtProperty*, int)),
            this, SLOT(slotSingleStepChanged(QtProperty*, int)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtScrollBarFactory::createEditor(QtIntPropertyManager* manager, QtProperty* property,
        QWidget* parent) {
    auto* editor = new QScrollBar(Qt::Horizontal, parent);
    d_ptr->initializeEditor(property, editor);
    editor->setSingleStep(manager->singleStep(property));
    editor->setRange(manager->minimum(property), manager->maximum(property));
    editor->setValue(manager->value(property));
    connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtScrollBarFactory::disconnectPropertyManager(QtIntPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, int)),
               this, SLOT(slotPropertyChanged(QtProperty*, int)));
    disconnect(manager, SIGNAL(rangeChanged(QtProperty*, int, int)),
               this, SLOT(slotRangeChanged(QtProperty*, int, int)));
    disconnect(manager, SIGNAL(singleStepChanged(QtProperty*, int)),
               this, SLOT(slotSingleStepChanged(QtProperty*, int)));
}

// QtCheckBoxFactory

class QtCheckBoxFactoryPrivate : public EditorFactoryPrivate<QtBoolEdit> {
    QtCheckBoxFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtCheckBoxFactory)
public:
    void slotPropertyChanged(QtProperty* property, bool value);
    void slotSetValue(bool value);
};

void QtCheckBoxFactoryPrivate::slotPropertyChanged(QtProperty* property, bool value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QListIterator<QtBoolEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QtBoolEdit* editor = itEditor.next();
        editor->blockCheckBoxSignals(true);
        editor->setChecked(value);
        editor->blockCheckBoxSignals(false);
    }
}

void QtCheckBoxFactoryPrivate::slotSetValue(bool value) {
    QObject* object = q_ptr->sender();

    const QMap<QtBoolEdit*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
    for (QMap<QtBoolEdit*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend;  ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtBoolPropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtCheckBoxFactory

    \brief The QtCheckBoxFactory class provides QCheckBox widgets for
    properties created by QtBoolPropertyManager objects.

    \sa QtAbstractEditorFactory, QtBoolPropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtCheckBoxFactory::QtCheckBoxFactory(QObject* parent)
    : QtAbstractEditorFactory<QtBoolPropertyManager>(parent) {
    d_ptr = new QtCheckBoxFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtCheckBoxFactory::~QtCheckBoxFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtCheckBoxFactory::connectPropertyManager(QtBoolPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, bool)),
            this, SLOT(slotPropertyChanged(QtProperty*, bool)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtCheckBoxFactory::createEditor(QtBoolPropertyManager* manager, QtProperty* property,
        QWidget* parent) {
    QtBoolEdit* editor = d_ptr->createEditor(property, parent);
    editor->setChecked(manager->value(property));

    connect(editor, SIGNAL(toggled(bool)), this, SLOT(slotSetValue(bool)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtCheckBoxFactory::disconnectPropertyManager(QtBoolPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, bool)),
               this, SLOT(slotPropertyChanged(QtProperty*, bool)));
}

// QtDoubleSpinBoxFactory

class QtDoubleSpinBoxFactoryPrivate : public EditorFactoryPrivate<QDoubleSpinBox> {
    QtDoubleSpinBoxFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtDoubleSpinBoxFactory)
public:

    void slotPropertyChanged(QtProperty* property, double value);
    void slotRangeChanged(QtProperty* property, double min, double max);
    void slotSingleStepChanged(QtProperty* property, double step);
    void slotDecimalsChanged(QtProperty* property, int prec);
    void slotSetValue(double value);
};

void QtDoubleSpinBoxFactoryPrivate::slotPropertyChanged(QtProperty* property, double value) {
    QList<QDoubleSpinBox*> editors = m_createdEditors[property];
    QListIterator<QDoubleSpinBox*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QDoubleSpinBox* editor = itEditor.next();
        if (editor->value() != value) {
            editor->blockSignals(true);
            editor->setValue(value);
            editor->blockSignals(false);
        }
    }
}

void QtDoubleSpinBoxFactoryPrivate::slotRangeChanged(QtProperty* property,
        double min, double max) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtDoublePropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QList<QDoubleSpinBox*> editors = m_createdEditors[property];
    QListIterator<QDoubleSpinBox*> itEditor(editors);
    while (itEditor.hasNext()) {
        QDoubleSpinBox* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setRange(min, max);
        editor->setValue(manager->value(property));
        editor->blockSignals(false);
    }
}

void QtDoubleSpinBoxFactoryPrivate::slotSingleStepChanged(QtProperty* property, double step) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtDoublePropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QList<QDoubleSpinBox*> editors = m_createdEditors[property];
    QListIterator<QDoubleSpinBox*> itEditor(editors);
    while (itEditor.hasNext()) {
        QDoubleSpinBox* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setSingleStep(step);
        editor->blockSignals(false);
    }
}

void QtDoubleSpinBoxFactoryPrivate::slotDecimalsChanged(QtProperty* property, int prec) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtDoublePropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QList<QDoubleSpinBox*> editors = m_createdEditors[property];
    QListIterator<QDoubleSpinBox*> itEditor(editors);
    while (itEditor.hasNext()) {
        QDoubleSpinBox* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setDecimals(prec);
        editor->setValue(manager->value(property));
        editor->blockSignals(false);
    }
}

void QtDoubleSpinBoxFactoryPrivate::slotSetValue(double value) {
    QObject* object = q_ptr->sender();
    const QMap<QDoubleSpinBox*, QtProperty*>::ConstIterator itcend = m_editorToProperty.constEnd();
    for (QMap<QDoubleSpinBox*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != itcend; ++itEditor) {
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtDoublePropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
    }
}

/*! \class QtDoubleSpinBoxFactory

    \brief The QtDoubleSpinBoxFactory class provides QDoubleSpinBox
    widgets for properties created by QtDoublePropertyManager objects.

    \sa QtAbstractEditorFactory, QtDoublePropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtDoubleSpinBoxFactory::QtDoubleSpinBoxFactory(QObject* parent)
    : QtAbstractEditorFactory<QtDoublePropertyManager>(parent) {
    d_ptr = new QtDoubleSpinBoxFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtDoubleSpinBoxFactory::~QtDoubleSpinBoxFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtDoubleSpinBoxFactory::connectPropertyManager(QtDoublePropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, double)),
            this, SLOT(slotPropertyChanged(QtProperty*, double)));
    connect(manager, SIGNAL(rangeChanged(QtProperty*, double, double)),
            this, SLOT(slotRangeChanged(QtProperty*, double, double)));
    connect(manager, SIGNAL(singleStepChanged(QtProperty*, double)),
            this, SLOT(slotSingleStepChanged(QtProperty*, double)));
    connect(manager, SIGNAL(decimalsChanged(QtProperty*, int)),
            this, SLOT(slotDecimalsChanged(QtProperty*, int)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtDoubleSpinBoxFactory::createEditor(QtDoublePropertyManager* manager,
        QtProperty* property, QWidget* parent) {
    QDoubleSpinBox* editor = d_ptr->createEditor(property, parent);
    editor->setSingleStep(manager->singleStep(property));
    editor->setDecimals(manager->decimals(property));
    editor->setRange(manager->minimum(property), manager->maximum(property));
    editor->setValue(manager->value(property));
    editor->setKeyboardTracking(false);

    connect(editor, SIGNAL(valueChanged(double)), this, SLOT(slotSetValue(double)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtDoubleSpinBoxFactory::disconnectPropertyManager(QtDoublePropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, double)),
               this, SLOT(slotPropertyChanged(QtProperty*, double)));
    disconnect(manager, SIGNAL(rangeChanged(QtProperty*, double, double)),
               this, SLOT(slotRangeChanged(QtProperty*, double, double)));
    disconnect(manager, SIGNAL(singleStepChanged(QtProperty*, double)),
               this, SLOT(slotSingleStepChanged(QtProperty*, double)));
    disconnect(manager, SIGNAL(decimalsChanged(QtProperty*, int)),
               this, SLOT(slotDecimalsChanged(QtProperty*, int)));
}

// QtLineEditFactory

class QtLineEditFactoryPrivate : public EditorFactoryPrivate<QLineEdit> {
    QtLineEditFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtLineEditFactory)
public:

    void slotPropertyChanged(QtProperty* property, const QString& value);
    void slotRegExpChanged(QtProperty* property, const QRegularExpression& regExp);
    void slotSetValue(const QString& value);
    void slotEchoModeChanged(QtProperty*, int);
};

void QtLineEditFactoryPrivate::slotPropertyChanged(QtProperty* property,
        const QString& value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QListIterator<QLineEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QLineEdit* editor = itEditor.next();
        if (editor->text() != value) {
            editor->setText(value);
        }
    }
}

void QtLineEditFactoryPrivate::slotRegExpChanged(QtProperty* property,
        const QRegularExpression& regExp) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtStringPropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QListIterator<QLineEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QLineEdit* editor = itEditor.next();
        editor->blockSignals(true);
        const QValidator* oldValidator = editor->validator();
        QValidator* newValidator = nullptr;
        if (regExp.isValid()) {
            newValidator = new QRegularExpressionValidator(regExp, editor);
        }
        editor->setValidator(newValidator);
        if (oldValidator) {
            delete oldValidator;
        }
        editor->blockSignals(false);
    }
}

void QtLineEditFactoryPrivate::slotEchoModeChanged(QtProperty* property, int echoMode) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtStringPropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QListIterator<QLineEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QLineEdit* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setEchoMode((EchoMode)echoMode);
        editor->blockSignals(false);
    }


}

void QtLineEditFactoryPrivate::slotSetValue(const QString& value) {
    QObject* object = q_ptr->sender();
    const QMap<QLineEdit*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
    for (QMap<QLineEdit*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtStringPropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtLineEditFactory

    \brief The QtLineEditFactory class provides QLineEdit widgets for
    properties created by QtStringPropertyManager objects.

    \sa QtAbstractEditorFactory, QtStringPropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtLineEditFactory::QtLineEditFactory(QObject* parent)
    : QtAbstractEditorFactory<QtStringPropertyManager>(parent) {
    d_ptr = new QtLineEditFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtLineEditFactory::~QtLineEditFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtLineEditFactory::connectPropertyManager(QtStringPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, const QString&)),
            this, SLOT(slotPropertyChanged(QtProperty*, const QString&)));
    connect(manager, SIGNAL(regExpChanged(QtProperty*, QRegularExpression)),
            this, SLOT(slotRegExpChanged(QtProperty*, QRegularExpression)));
    connect(manager, SIGNAL(echoModeChanged(QtProperty*, int)),
            this, SLOT(slotEchoModeChanged(QtProperty*, int)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtLineEditFactory::createEditor(QtStringPropertyManager* manager,
        QtProperty* property, QWidget* parent) {

    QLineEdit* editor = d_ptr->createEditor(property, parent);
    editor->setEchoMode((EchoMode)manager->echoMode(property));
    QRegularExpression regExp = manager->regExp(property);
    if (regExp.isValid() && !regExp.pattern().isEmpty()) {
        QValidator* validator = new QRegularExpressionValidator(regExp, editor);
        editor->setValidator(validator);
    }
    editor->setText(manager->value(property));

    connect(editor, SIGNAL(textEdited(const QString&)),
            this, SLOT(slotSetValue(const QString&)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtLineEditFactory::disconnectPropertyManager(QtStringPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, const QString&)),
               this, SLOT(slotPropertyChanged(QtProperty*, const QString&)));
    disconnect(manager, SIGNAL(regExpChanged(QtProperty*, QRegularExpression)),
               this, SLOT(slotRegExpChanged(QtProperty*, QRegularExpression)));
    disconnect(manager, SIGNAL(echoModeChanged(QtProperty*, int)),
               this, SLOT(slotEchoModeChanged(QtProperty*, int)));
}

// QtDateEditFactory

class QtDateEditFactoryPrivate : public EditorFactoryPrivate<QDateEdit> {
    QtDateEditFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtDateEditFactory)
public:

    void slotPropertyChanged(QtProperty* property, const QDate& value);
    void slotRangeChanged(QtProperty* property, const QDate& min, const QDate& max);
    void slotSetValue(const QDate& value);
};

void QtDateEditFactoryPrivate::slotPropertyChanged(QtProperty* property, const QDate& value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }
    QListIterator<QDateEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QDateEdit* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setDate(value);
        editor->blockSignals(false);
    }
}

void QtDateEditFactoryPrivate::slotRangeChanged(QtProperty* property,
        const QDate& min, const QDate& max) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtDatePropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QListIterator<QDateEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QDateEdit* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setDateRange(min, max);
        editor->setDate(manager->value(property));
        editor->blockSignals(false);
    }
}

void QtDateEditFactoryPrivate::slotSetValue(const QDate& value) {
    QObject* object = q_ptr->sender();
    const QMap<QDateEdit*, QtProperty*>::ConstIterator  ecend = m_editorToProperty.constEnd();
    for (QMap<QDateEdit*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtDatePropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtDateEditFactory

    \brief The QtDateEditFactory class provides QDateEdit widgets for
    properties created by QtDatePropertyManager objects.

    \sa QtAbstractEditorFactory, QtDatePropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtDateEditFactory::QtDateEditFactory(QObject* parent)
    : QtAbstractEditorFactory<QtDatePropertyManager>(parent) {
    d_ptr = new QtDateEditFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtDateEditFactory::~QtDateEditFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtDateEditFactory::connectPropertyManager(QtDatePropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, const QDate&)),
            this, SLOT(slotPropertyChanged(QtProperty*, const QDate&)));
    connect(manager, SIGNAL(rangeChanged(QtProperty*, const QDate&, const QDate&)),
            this, SLOT(slotRangeChanged(QtProperty*, const QDate&, const QDate&)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtDateEditFactory::createEditor(QtDatePropertyManager* manager, QtProperty* property,
        QWidget* parent) {
    QDateEdit* editor = d_ptr->createEditor(property, parent);
    editor->setCalendarPopup(true);
    editor->setDateRange(manager->minimum(property), manager->maximum(property));
    editor->setDate(manager->value(property));

    connect(editor, SIGNAL(dateChanged(const QDate&)),
            this, SLOT(slotSetValue(const QDate&)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtDateEditFactory::disconnectPropertyManager(QtDatePropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, const QDate&)),
               this, SLOT(slotPropertyChanged(QtProperty*, const QDate&)));
    disconnect(manager, SIGNAL(rangeChanged(QtProperty*, const QDate&, const QDate&)),
               this, SLOT(slotRangeChanged(QtProperty*, const QDate&, const QDate&)));
}

// QtTimeEditFactory

class QtTimeEditFactoryPrivate : public EditorFactoryPrivate<QTimeEdit> {
    QtTimeEditFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtTimeEditFactory)
public:

    void slotPropertyChanged(QtProperty* property, const QTime& value);
    void slotSetValue(const QTime& value);
};

void QtTimeEditFactoryPrivate::slotPropertyChanged(QtProperty* property, const QTime& value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }
    QListIterator<QTimeEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QTimeEdit* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setTime(value);
        editor->blockSignals(false);
    }
}

void QtTimeEditFactoryPrivate::slotSetValue(const QTime& value) {
    QObject* object = q_ptr->sender();
    const  QMap<QTimeEdit*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
    for (QMap<QTimeEdit*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtTimePropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtTimeEditFactory

    \brief The QtTimeEditFactory class provides QTimeEdit widgets for
    properties created by QtTimePropertyManager objects.

    \sa QtAbstractEditorFactory, QtTimePropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtTimeEditFactory::QtTimeEditFactory(QObject* parent)
    : QtAbstractEditorFactory<QtTimePropertyManager>(parent) {
    d_ptr = new QtTimeEditFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtTimeEditFactory::~QtTimeEditFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtTimeEditFactory::connectPropertyManager(QtTimePropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, const QTime&)),
            this, SLOT(slotPropertyChanged(QtProperty*, const QTime&)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtTimeEditFactory::createEditor(QtTimePropertyManager* manager, QtProperty* property,
        QWidget* parent) {
    QTimeEdit* editor = d_ptr->createEditor(property, parent);
    editor->setTime(manager->value(property));

    connect(editor, SIGNAL(timeChanged(const QTime&)),
            this, SLOT(slotSetValue(const QTime&)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtTimeEditFactory::disconnectPropertyManager(QtTimePropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, const QTime&)),
               this, SLOT(slotPropertyChanged(QtProperty*, const QTime&)));
}

// QtDateTimeEditFactory

class QtDateTimeEditFactoryPrivate : public EditorFactoryPrivate<QDateTimeEdit> {
    QtDateTimeEditFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtDateTimeEditFactory)
public:

    void slotPropertyChanged(QtProperty* property, const QDateTime& value);
    void slotSetValue(const QDateTime& value);

};

void QtDateTimeEditFactoryPrivate::slotPropertyChanged(QtProperty* property,
        const QDateTime& value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QListIterator<QDateTimeEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QDateTimeEdit* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setDateTime(value);
        editor->blockSignals(false);
    }
}

void QtDateTimeEditFactoryPrivate::slotSetValue(const QDateTime& value) {
    QObject* object = q_ptr->sender();
    const  QMap<QDateTimeEdit*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
    for (QMap<QDateTimeEdit*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend;  ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtDateTimePropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtDateTimeEditFactory

    \brief The QtDateTimeEditFactory class provides QDateTimeEdit
    widgets for properties created by QtDateTimePropertyManager objects.

    \sa QtAbstractEditorFactory, QtDateTimePropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtDateTimeEditFactory::QtDateTimeEditFactory(QObject* parent)
    : QtAbstractEditorFactory<QtDateTimePropertyManager>(parent) {
    d_ptr = new QtDateTimeEditFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtDateTimeEditFactory::~QtDateTimeEditFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtDateTimeEditFactory::connectPropertyManager(QtDateTimePropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, const QDateTime&)),
            this, SLOT(slotPropertyChanged(QtProperty*, const QDateTime&)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtDateTimeEditFactory::createEditor(QtDateTimePropertyManager* manager,
        QtProperty* property, QWidget* parent) {
    QDateTimeEdit* editor =  d_ptr->createEditor(property, parent);
    editor->setDateTime(manager->value(property));

    connect(editor, SIGNAL(dateTimeChanged(const QDateTime&)),
            this, SLOT(slotSetValue(const QDateTime&)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtDateTimeEditFactory::disconnectPropertyManager(QtDateTimePropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, const QDateTime&)),
               this, SLOT(slotPropertyChanged(QtProperty*, const QDateTime&)));
}

// QtKeySequenceEditorFactory

class QtKeySequenceEditorFactoryPrivate : public EditorFactoryPrivate<QtKeySequenceEdit> {
    QtKeySequenceEditorFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtKeySequenceEditorFactory)
public:

    void slotPropertyChanged(QtProperty* property, const QKeySequence& value);
    void slotSetValue(const QKeySequence& value);
};

void QtKeySequenceEditorFactoryPrivate::slotPropertyChanged(QtProperty* property,
        const QKeySequence& value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QListIterator<QtKeySequenceEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QtKeySequenceEdit* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setKeySequence(value);
        editor->blockSignals(false);
    }
}

void QtKeySequenceEditorFactoryPrivate::slotSetValue(const QKeySequence& value) {
    QObject* object = q_ptr->sender();
    const  QMap<QtKeySequenceEdit*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
    for (QMap<QtKeySequenceEdit*, QtProperty*>::ConstIterator itEditor =  m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtKeySequencePropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtKeySequenceEditorFactory

    \brief The QtKeySequenceEditorFactory class provides editor
    widgets for properties created by QtKeySequencePropertyManager objects.

    \sa QtAbstractEditorFactory
*/

/*!
    Creates a factory with the given \a parent.
*/
QtKeySequenceEditorFactory::QtKeySequenceEditorFactory(QObject* parent)
    : QtAbstractEditorFactory<QtKeySequencePropertyManager>(parent) {
    d_ptr = new QtKeySequenceEditorFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtKeySequenceEditorFactory::~QtKeySequenceEditorFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtKeySequenceEditorFactory::connectPropertyManager(QtKeySequencePropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, const QKeySequence&)),
            this, SLOT(slotPropertyChanged(QtProperty*, const QKeySequence&)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtKeySequenceEditorFactory::createEditor(QtKeySequencePropertyManager* manager,
        QtProperty* property, QWidget* parent) {
    QtKeySequenceEdit* editor = d_ptr->createEditor(property, parent);
    editor->setKeySequence(manager->value(property));

    connect(editor, SIGNAL(keySequenceChanged(const QKeySequence&)),
            this, SLOT(slotSetValue(const QKeySequence&)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtKeySequenceEditorFactory::disconnectPropertyManager(QtKeySequencePropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, const QKeySequence&)),
               this, SLOT(slotPropertyChanged(QtProperty*, const QKeySequence&)));
}

// QtCharEdit

class QtCharEdit : public QWidget {
    Q_OBJECT
public:
    QtCharEdit(QWidget* parent = nullptr);

    QChar value() const;
    bool eventFilter(QObject* o, QEvent* e) override;
public Q_SLOTS:
    void setValue(const QChar& value);
Q_SIGNALS:
    void valueChanged(const QChar& value);
protected:
    void focusInEvent(QFocusEvent* e) override;
    void focusOutEvent(QFocusEvent* e) override;
    void keyPressEvent(QKeyEvent* e) override;
    void keyReleaseEvent(QKeyEvent* e) override;
    void paintEvent(QPaintEvent*) override;
    bool event(QEvent* e) override;
private slots:
    void slotClearChar();
private:
    void handleKeyEvent(QKeyEvent* e);

    QChar m_value;
    QLineEdit* m_lineEdit;
};

QtCharEdit::QtCharEdit(QWidget* parent)
    : QWidget(parent),  m_lineEdit(new QLineEdit(this)) {
    auto* layout = new QHBoxLayout(this);
    layout->addWidget(m_lineEdit);
    layout->setContentsMargins(QMargins());
    m_lineEdit->installEventFilter(this);
    m_lineEdit->setReadOnly(true);
    m_lineEdit->setFocusProxy(this);
    setFocusPolicy(m_lineEdit->focusPolicy());
    setAttribute(Qt::WA_InputMethodEnabled);
}

bool QtCharEdit::eventFilter(QObject* o, QEvent* e) {
    if (o == m_lineEdit && e->type() == QEvent::ContextMenu) {
        auto* c = static_cast<QContextMenuEvent*>(e);
        QMenu* menu = m_lineEdit->createStandardContextMenu();
        const auto actions = menu->actions();
        QListIterator<QAction*> itAction(actions);
        while (itAction.hasNext()) {
            QAction* action = itAction.next();
            action->setShortcut(QKeySequence());
            QString actionString = action->text();
            const int pos = actionString.lastIndexOf(QLatin1Char('\t'));
            if (pos > 0) {
                actionString = actionString.remove(pos, actionString.length() - pos);
            }
            action->setText(actionString);
        }
        QAction* actionBefore = nullptr;
        if (actions.count() > 0) {
            actionBefore = actions[0];
        }
        QAction* clearAction = new QAction(tr("Clear Char"), menu);
        menu->insertAction(actionBefore, clearAction);
        menu->insertSeparator(actionBefore);
        clearAction->setEnabled(!m_value.isNull());
        connect(clearAction, SIGNAL(triggered()), this, SLOT(slotClearChar()));
        menu->exec(c->globalPos());
        delete menu;
        e->accept();
        return true;
    }

    return QWidget::eventFilter(o, e);
}

void QtCharEdit::slotClearChar() {
    if (m_value.isNull()) {
        return;
    }
    setValue(QChar());
    emit valueChanged(m_value);
}

void QtCharEdit::handleKeyEvent(QKeyEvent* e) {
    const int key = e->key();
    switch (key) {
        case Qt::Key_Control:
        case Qt::Key_Shift:
        case Qt::Key_Meta:
        case Qt::Key_Alt:
        case Qt::Key_Super_L:
        case Qt::Key_Return:
            return;
        default:
            break;
    }

    const QString text = e->text();
    if (text.count() != 1) {
        return;
    }

    const QChar c = text.at(0);
    if (!c.isPrint()) {
        return;
    }

    if (m_value == c) {
        return;
    }

    m_value = c;
    const QString str = m_value.isNull() ? QString() : QString(m_value);
    m_lineEdit->setText(str);
    e->accept();
    emit valueChanged(m_value);
}

void QtCharEdit::setValue(const QChar& value) {
    if (value == m_value) {
        return;
    }

    m_value = value;
    QString str = value.isNull() ? QString() : QString(value);
    m_lineEdit->setText(str);
}

QChar QtCharEdit::value() const {
    return m_value;
}

void QtCharEdit::focusInEvent(QFocusEvent* e) {
    m_lineEdit->event(e);
    m_lineEdit->selectAll();
    QWidget::focusInEvent(e);
}

void QtCharEdit::focusOutEvent(QFocusEvent* e) {
    m_lineEdit->event(e);
    QWidget::focusOutEvent(e);
}

void QtCharEdit::keyPressEvent(QKeyEvent* e) {
    handleKeyEvent(e);
    e->accept();
}

void QtCharEdit::keyReleaseEvent(QKeyEvent* e) {
    m_lineEdit->event(e);
}

void QtCharEdit::paintEvent(QPaintEvent*) {
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

bool QtCharEdit::event(QEvent* e) {
    switch (e->type()) {
        case QEvent::Shortcut:
        case QEvent::ShortcutOverride:
        case QEvent::KeyRelease:
            e->accept();
            return true;
        default:
            break;
    }
    return QWidget::event(e);
}

// QtCharEditorFactory

class QtCharEditorFactoryPrivate : public EditorFactoryPrivate<QtCharEdit> {
    QtCharEditorFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtCharEditorFactory)
public:

    void slotPropertyChanged(QtProperty* property, const QChar& value);
    void slotSetValue(const QChar& value);

};

void QtCharEditorFactoryPrivate::slotPropertyChanged(QtProperty* property,
        const QChar& value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QListIterator<QtCharEdit*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QtCharEdit* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setValue(value);
        editor->blockSignals(false);
    }
}

void QtCharEditorFactoryPrivate::slotSetValue(const QChar& value) {
    QObject* object = q_ptr->sender();
    const QMap<QtCharEdit*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
    for (QMap<QtCharEdit*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend;  ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtCharPropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtCharEditorFactory

    \brief The QtCharEditorFactory class provides editor
    widgets for properties created by QtCharPropertyManager objects.

    \sa QtAbstractEditorFactory
*/

/*!
    Creates a factory with the given \a parent.
*/
QtCharEditorFactory::QtCharEditorFactory(QObject* parent)
    : QtAbstractEditorFactory<QtCharPropertyManager>(parent) {
    d_ptr = new QtCharEditorFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtCharEditorFactory::~QtCharEditorFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtCharEditorFactory::connectPropertyManager(QtCharPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, const QChar&)),
            this, SLOT(slotPropertyChanged(QtProperty*, const QChar&)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtCharEditorFactory::createEditor(QtCharPropertyManager* manager,
        QtProperty* property, QWidget* parent) {
    QtCharEdit* editor = d_ptr->createEditor(property, parent);
    editor->setValue(manager->value(property));

    connect(editor, SIGNAL(valueChanged(const QChar&)),
            this, SLOT(slotSetValue(const QChar&)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtCharEditorFactory::disconnectPropertyManager(QtCharPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, const QChar&)),
               this, SLOT(slotPropertyChanged(QtProperty*, const QChar&)));
}

// QtEnumEditorFactory

class QtEnumEditorFactoryPrivate : public EditorFactoryPrivate<QComboBox> {
    QtEnumEditorFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtEnumEditorFactory)
public:

    void slotPropertyChanged(QtProperty* property, int value);
    void slotEnumNamesChanged(QtProperty* property, const QStringList&);
    void slotEnumIconsChanged(QtProperty* property, const QMap<int, QIcon>&);
    void slotSetValue(int value);
};

void QtEnumEditorFactoryPrivate::slotPropertyChanged(QtProperty* property, int value) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QListIterator<QComboBox*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QComboBox* editor = itEditor.next();
        editor->blockSignals(true);
        editor->setCurrentIndex(value);
        editor->blockSignals(false);
    }
}

void QtEnumEditorFactoryPrivate::slotEnumNamesChanged(QtProperty* property,
        const QStringList& enumNames) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtEnumPropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    QMap<int, QIcon> enumIcons = manager->enumIcons(property);

    QListIterator<QComboBox*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QComboBox* editor = itEditor.next();
        editor->blockSignals(true);
        editor->clear();
        editor->addItems(enumNames);
        const int nameCount = enumNames.count();
        for (int i = 0; i < nameCount; i++) {
            editor->setItemIcon(i, enumIcons.value(i));
        }
        editor->setCurrentIndex(manager->value(property));
        editor->blockSignals(false);
    }
}

void QtEnumEditorFactoryPrivate::slotEnumIconsChanged(QtProperty* property,
        const QMap<int, QIcon>& enumIcons) {
    if (!m_createdEditors.contains(property)) {
        return;
    }

    QtEnumPropertyManager* manager = q_ptr->propertyManager(property);
    if (!manager) {
        return;
    }

    const QStringList enumNames = manager->enumNames(property);
    QListIterator<QComboBox*> itEditor(m_createdEditors[property]);
    while (itEditor.hasNext()) {
        QComboBox* editor = itEditor.next();
        editor->blockSignals(true);
        const int nameCount = enumNames.count();
        for (int i = 0; i < nameCount; i++) {
            editor->setItemIcon(i, enumIcons.value(i));
        }
        editor->setCurrentIndex(manager->value(property));
        editor->blockSignals(false);
    }
}

void QtEnumEditorFactoryPrivate::slotSetValue(int value) {
    QObject* object = q_ptr->sender();
    const  QMap<QComboBox*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
    for (QMap<QComboBox*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtEnumPropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtEnumEditorFactory

    \brief The QtEnumEditorFactory class provides QComboBox widgets for
    properties created by QtEnumPropertyManager objects.

    \sa QtAbstractEditorFactory, QtEnumPropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtEnumEditorFactory::QtEnumEditorFactory(QObject* parent)
    : QtAbstractEditorFactory<QtEnumPropertyManager>(parent) {
    d_ptr = new QtEnumEditorFactoryPrivate();
    d_ptr->q_ptr = this;

}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtEnumEditorFactory::~QtEnumEditorFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtEnumEditorFactory::connectPropertyManager(QtEnumPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, int)),
            this, SLOT(slotPropertyChanged(QtProperty*, int)));
    connect(manager, SIGNAL(enumNamesChanged(QtProperty*, const QStringList&)),
            this, SLOT(slotEnumNamesChanged(QtProperty*, const QStringList&)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtEnumEditorFactory::createEditor(QtEnumPropertyManager* manager, QtProperty* property,
        QWidget* parent) {
    QComboBox* editor = d_ptr->createEditor(property, parent);
    editor->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
    editor->setMinimumContentsLength(1);
    editor->view()->setTextElideMode(Qt::ElideRight);
    QStringList enumNames = manager->enumNames(property);
    editor->addItems(enumNames);
    QMap<int, QIcon> enumIcons = manager->enumIcons(property);
    const int enumNamesCount = enumNames.count();
    for (int i = 0; i < enumNamesCount; i++) {
        editor->setItemIcon(i, enumIcons.value(i));
    }
    editor->setCurrentIndex(manager->value(property));

    connect(editor, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetValue(int)));
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtEnumEditorFactory::disconnectPropertyManager(QtEnumPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, int)),
               this, SLOT(slotPropertyChanged(QtProperty*, int)));
    disconnect(manager, SIGNAL(enumNamesChanged(QtProperty*, const QStringList&)),
               this, SLOT(slotEnumNamesChanged(QtProperty*, const QStringList&)));
}

// QtCursorEditorFactory

Q_GLOBAL_STATIC(QtCursorDatabase, cursorDatabase)

class QtCursorEditorFactoryPrivate {
    QtCursorEditorFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtCursorEditorFactory)
public:
    QtCursorEditorFactoryPrivate();

    void slotPropertyChanged(QtProperty* property, const QCursor& cursor);
    void slotEnumChanged(QtProperty* property, int value);
    void slotEditorDestroyed(QObject* object);

    QtEnumEditorFactory* m_enumEditorFactory;
    QtEnumPropertyManager* m_enumPropertyManager;

    QMap<QtProperty*, QtProperty*> m_propertyToEnum;
    QMap<QtProperty*, QtProperty*> m_enumToProperty;
    QMap<QtProperty*, QList<QWidget*> > m_enumToEditors;
    QMap<QWidget*, QtProperty*> m_editorToEnum;
    bool m_updatingEnum{false};
};

QtCursorEditorFactoryPrivate::QtCursorEditorFactoryPrivate() {

}

void QtCursorEditorFactoryPrivate::slotPropertyChanged(QtProperty* property, const QCursor& cursor) {
    // update enum property
    QtProperty* enumProp = m_propertyToEnum.value(property);
    if (!enumProp) {
        return;
    }

    m_updatingEnum = true;
    m_enumPropertyManager->setValue(enumProp, cursorDatabase()->cursorToValue(cursor));
    m_updatingEnum = false;
}

void QtCursorEditorFactoryPrivate::slotEnumChanged(QtProperty* property, int value) {
    if (m_updatingEnum) {
        return;
    }
    // update cursor property
    QtProperty* prop = m_enumToProperty.value(property);
    if (!prop) {
        return;
    }
    QtCursorPropertyManager* cursorManager = q_ptr->propertyManager(prop);
    if (!cursorManager) {
        return;
    }
#ifndef QT_NO_CURSOR
    cursorManager->setValue(prop, QCursor(cursorDatabase()->valueToCursor(value)));
#endif
}

void QtCursorEditorFactoryPrivate::slotEditorDestroyed(QObject* object) {
    // remove from m_editorToEnum map;
    // remove from m_enumToEditors map;
    // if m_enumToEditors doesn't contains more editors delete enum property;
    const  QMap<QWidget*, QtProperty*>::ConstIterator ecend = m_editorToEnum.constEnd();
    for (QMap<QWidget*, QtProperty*>::ConstIterator itEditor = m_editorToEnum.constBegin(); itEditor != ecend; ++itEditor)
        if (itEditor.key() == object) {
            QWidget* editor = itEditor.key();
            QtProperty* enumProp = itEditor.value();
            m_editorToEnum.remove(editor);
            m_enumToEditors[enumProp].removeAll(editor);
            if (m_enumToEditors[enumProp].isEmpty()) {
                m_enumToEditors.remove(enumProp);
                QtProperty* property = m_enumToProperty.value(enumProp);
                m_enumToProperty.remove(enumProp);
                m_propertyToEnum.remove(property);
                delete enumProp;
            }
            return;
        }
}

/*!
    \class QtCursorEditorFactory

    \brief The QtCursorEditorFactory class provides QComboBox widgets for
    properties created by QtCursorPropertyManager objects.

    \sa QtAbstractEditorFactory, QtCursorPropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtCursorEditorFactory::QtCursorEditorFactory(QObject* parent)
    : QtAbstractEditorFactory<QtCursorPropertyManager>(parent) {
    d_ptr = new QtCursorEditorFactoryPrivate();
    d_ptr->q_ptr = this;

    d_ptr->m_enumEditorFactory = new QtEnumEditorFactory(this);
    d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this);
    connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty*, int)),
            this, SLOT(slotEnumChanged(QtProperty*, int)));
    d_ptr->m_enumEditorFactory->addPropertyManager(d_ptr->m_enumPropertyManager);
}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtCursorEditorFactory::~QtCursorEditorFactory() {
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtCursorEditorFactory::connectPropertyManager(QtCursorPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, const QCursor&)),
            this, SLOT(slotPropertyChanged(QtProperty*, const QCursor&)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtCursorEditorFactory::createEditor(QtCursorPropertyManager* manager, QtProperty* property,
        QWidget* parent) {
    QtProperty* enumProp = nullptr;
    if (d_ptr->m_propertyToEnum.contains(property)) {
        enumProp = d_ptr->m_propertyToEnum[property];
    }
    else {
        enumProp = d_ptr->m_enumPropertyManager->addProperty(property->propertyName());
        d_ptr->m_enumPropertyManager->setEnumNames(enumProp, cursorDatabase()->cursorShapeNames());
        d_ptr->m_enumPropertyManager->setEnumIcons(enumProp, cursorDatabase()->cursorShapeIcons());
#ifndef QT_NO_CURSOR
        d_ptr->m_enumPropertyManager->setValue(enumProp, cursorDatabase()->cursorToValue(manager->value(property)));
#endif
        d_ptr->m_propertyToEnum[property] = enumProp;
        d_ptr->m_enumToProperty[enumProp] = property;
    }
    QtAbstractEditorFactoryBase* af = d_ptr->m_enumEditorFactory;
    QWidget* editor = af->createEditor(enumProp, parent);
    d_ptr->m_enumToEditors[enumProp].append(editor);
    d_ptr->m_editorToEnum[editor] = enumProp;
    connect(editor, SIGNAL(destroyed(QObject*)),
            this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtCursorEditorFactory::disconnectPropertyManager(QtCursorPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, const QCursor&)),
               this, SLOT(slotPropertyChanged(QtProperty*, const QCursor&)));
}

// QtColorEditWidget

class QtColorEditWidget : public QWidget {
    Q_OBJECT

public:
    QtColorEditWidget(QWidget* parent);

    bool eventFilter(QObject* obj, QEvent* ev) override;

public Q_SLOTS:
    void setValue(const QColor& value);

Q_SIGNALS:
    void valueChanged(const QColor& value);

protected:
    void paintEvent(QPaintEvent*) override;

private Q_SLOTS:
    void buttonClicked();

private:
    QColor m_color;
    QLabel* m_pixmapLabel;
    QLabel* m_label;
    QToolButton* m_button;
};

QtColorEditWidget::QtColorEditWidget(QWidget* parent) :
    QWidget(parent),
    m_pixmapLabel(new QLabel),
    m_label(new QLabel),
    m_button(new QToolButton) {
    auto* lt = new QHBoxLayout(this);
    setupTreeViewEditorMargin(lt);
    lt->setSpacing(0);
    lt->addWidget(m_pixmapLabel);
    lt->addWidget(m_label);
    lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));

    m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
    m_button->setFixedWidth(20);
    setFocusProxy(m_button);
    setFocusPolicy(m_button->focusPolicy());
    m_button->setText(tr("..."));
    m_button->installEventFilter(this);
    connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked()));
    lt->addWidget(m_button);
    m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::brushValuePixmap(QBrush(m_color)));
    m_label->setText(QtPropertyBrowserUtils::colorValueText(m_color));
}

void QtColorEditWidget::setValue(const QColor& c) {
    if (m_color != c) {
        m_color = c;
        m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::brushValuePixmap(QBrush(c)));
        m_label->setText(QtPropertyBrowserUtils::colorValueText(c));
    }
}

void QtColorEditWidget::buttonClicked() {
    QRgb oldRgba = m_color.rgba();
    QColor newRgba = QColorDialog::getColor(oldRgba, this, "Choose New Color",  QColorDialog::ShowAlphaChannel);
    if (newRgba.isValid() && newRgba.rgba() != oldRgba) {
        setValue(QColor::fromRgba(newRgba.rgba()));
        emit valueChanged(m_color);
    }
}

bool QtColorEditWidget::eventFilter(QObject* obj, QEvent* ev) {
    if (obj == m_button) {
        switch (ev->type()) {
            case QEvent::KeyPress:
            case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate
                switch (static_cast<const QKeyEvent*>(ev)->key()) {
                    case Qt::Key_Escape:
                    case Qt::Key_Enter:
                    case Qt::Key_Return:
                        ev->ignore();
                        return true;
                    default:
                        break;
                }
            }
            break;
            default:
                break;
        }
    }
    return QWidget::eventFilter(obj, ev);
}

void QtColorEditWidget::paintEvent(QPaintEvent*) {
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

// QtColorEditorFactoryPrivate

class QtColorEditorFactoryPrivate : public EditorFactoryPrivate<QtColorEditWidget> {
    QtColorEditorFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtColorEditorFactory)
public:

    void slotPropertyChanged(QtProperty* property, const QColor& value);
    void slotSetValue(const QColor& value);
};

void QtColorEditorFactoryPrivate::slotPropertyChanged(QtProperty* property,
        const QColor& value) {
    const PropertyToEditorListMap::iterator it = m_createdEditors.find(property);
    if (it == m_createdEditors.end()) {
        return;
    }
    QListIterator<QtColorEditWidget*> itEditor(it.value());

    while (itEditor.hasNext()) {
        itEditor.next()->setValue(value);
    }
}

void QtColorEditorFactoryPrivate::slotSetValue(const QColor& value) {
    QObject* object = q_ptr->sender();
    const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd();
    for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtColorPropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtColorEditorFactory

    \brief The QtColorEditorFactory class provides color editing  for
    properties created by QtColorPropertyManager objects.

    \sa QtAbstractEditorFactory, QtColorPropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtColorEditorFactory::QtColorEditorFactory(QObject* parent) :
    QtAbstractEditorFactory<QtColorPropertyManager>(parent),
    d_ptr(new QtColorEditorFactoryPrivate()) {
    d_ptr->q_ptr = this;
}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtColorEditorFactory::~QtColorEditorFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtColorEditorFactory::connectPropertyManager(QtColorPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, QColor)),
            this, SLOT(slotPropertyChanged(QtProperty*, QColor)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtColorEditorFactory::createEditor(QtColorPropertyManager* manager,
        QtProperty* property, QWidget* parent) {
    QtColorEditWidget* editor = d_ptr->createEditor(property, parent);
    editor->setValue(manager->value(property));
    connect(editor, SIGNAL(valueChanged(QColor)), this, SLOT(slotSetValue(QColor)));
    connect(editor, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtColorEditorFactory::disconnectPropertyManager(QtColorPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, QColor)), this, SLOT(slotPropertyChanged(QtProperty*, QColor)));
}

// QtFontEditWidget

class QtFontEditWidget : public QWidget {
    Q_OBJECT

public:
    QtFontEditWidget(QWidget* parent);

    bool eventFilter(QObject* obj, QEvent* ev) override;

public Q_SLOTS:
    void setValue(const QFont& value);

Q_SIGNALS:
    void valueChanged(const QFont& value);

protected:
    void paintEvent(QPaintEvent*) override;

private Q_SLOTS:
    void buttonClicked();

private:
    QFont m_font;
    QLabel* m_pixmapLabel;
    QLabel* m_label;
    QToolButton* m_button;
};

QtFontEditWidget::QtFontEditWidget(QWidget* parent) :
    QWidget(parent),
    m_pixmapLabel(new QLabel),
    m_label(new QLabel),
    m_button(new QToolButton) {
    auto* lt = new QHBoxLayout(this);
    setupTreeViewEditorMargin(lt);
    lt->setSpacing(0);
    lt->addWidget(m_pixmapLabel);
    lt->addWidget(m_label);
    lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));

    m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
    m_button->setFixedWidth(20);
    setFocusProxy(m_button);
    setFocusPolicy(m_button->focusPolicy());
    m_button->setText(tr("..."));
    m_button->installEventFilter(this);
    connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked()));
    lt->addWidget(m_button);
    m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::fontValuePixmap(m_font));
    m_label->setText(QtPropertyBrowserUtils::fontValueText(m_font));
}

void QtFontEditWidget::setValue(const QFont& f) {
    if (m_font != f) {
        m_font = f;
        m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::fontValuePixmap(f));
        m_label->setText(QtPropertyBrowserUtils::fontValueText(f));
    }
}

void QtFontEditWidget::buttonClicked() {
    bool ok = false;
    QFont newFont = QFontDialog::getFont(&ok, m_font, this, tr("Select Font"));
    if (ok && newFont != m_font) {
        QFont f = m_font;
        // prevent mask for unchanged attributes, don't change other attributes (like kerning, etc...)
        if (m_font.family() != newFont.family()) {
            f.setFamily(newFont.family());
        }
        if (m_font.pointSize() != newFont.pointSize()) {
            f.setPointSize(newFont.pointSize());
        }
        if (m_font.bold() != newFont.bold()) {
            f.setBold(newFont.bold());
        }
        if (m_font.italic() != newFont.italic()) {
            f.setItalic(newFont.italic());
        }
        if (m_font.underline() != newFont.underline()) {
            f.setUnderline(newFont.underline());
        }
        if (m_font.strikeOut() != newFont.strikeOut()) {
            f.setStrikeOut(newFont.strikeOut());
        }
        setValue(f);
        emit valueChanged(m_font);
    }
}

bool QtFontEditWidget::eventFilter(QObject* obj, QEvent* ev) {
    if (obj == m_button) {
        switch (ev->type()) {
            case QEvent::KeyPress:
            case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate
                switch (static_cast<const QKeyEvent*>(ev)->key()) {
                    case Qt::Key_Escape:
                    case Qt::Key_Enter:
                    case Qt::Key_Return:
                        ev->ignore();
                        return true;
                    default:
                        break;
                }
            }
            break;
            default:
                break;
        }
    }
    return QWidget::eventFilter(obj, ev);
}

void QtFontEditWidget::paintEvent(QPaintEvent*) {
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

// QtFontEditorFactoryPrivate

class QtFontEditorFactoryPrivate : public EditorFactoryPrivate<QtFontEditWidget> {
    QtFontEditorFactory* q_ptr;
    Q_DECLARE_PUBLIC(QtFontEditorFactory)
public:

    void slotPropertyChanged(QtProperty* property, const QFont& value);
    void slotSetValue(const QFont& value);
};

void QtFontEditorFactoryPrivate::slotPropertyChanged(QtProperty* property,
        const QFont& value) {
    const PropertyToEditorListMap::iterator it = m_createdEditors.find(property);
    if (it == m_createdEditors.end()) {
        return;
    }
    QListIterator<QtFontEditWidget*> itEditor(it.value());

    while (itEditor.hasNext()) {
        itEditor.next()->setValue(value);
    }
}

void QtFontEditorFactoryPrivate::slotSetValue(const QFont& value) {
    QObject* object = q_ptr->sender();
    const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd();
    for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
        if (itEditor.key() == object) {
            QtProperty* property = itEditor.value();
            QtFontPropertyManager* manager = q_ptr->propertyManager(property);
            if (!manager) {
                return;
            }
            manager->setValue(property, value);
            return;
        }
}

/*!
    \class QtFontEditorFactory

    \brief The QtFontEditorFactory class provides font editing for
    properties created by QtFontPropertyManager objects.

    \sa QtAbstractEditorFactory, QtFontPropertyManager
*/

/*!
    Creates a factory with the given \a parent.
*/
QtFontEditorFactory::QtFontEditorFactory(QObject* parent) :
    QtAbstractEditorFactory<QtFontPropertyManager>(parent),
    d_ptr(new QtFontEditorFactoryPrivate()) {
    d_ptr->q_ptr = this;
}

/*!
    Destroys this factory, and all the widgets it has created.
*/
QtFontEditorFactory::~QtFontEditorFactory() {
    qDeleteAll(d_ptr->m_editorToProperty.keys());
    delete d_ptr;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtFontEditorFactory::connectPropertyManager(QtFontPropertyManager* manager) {
    connect(manager, SIGNAL(valueChanged(QtProperty*, QFont)),
            this, SLOT(slotPropertyChanged(QtProperty*, QFont)));
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
QWidget* QtFontEditorFactory::createEditor(QtFontPropertyManager* manager,
        QtProperty* property, QWidget* parent) {
    QtFontEditWidget* editor = d_ptr->createEditor(property, parent);
    editor->setValue(manager->value(property));
    connect(editor, SIGNAL(valueChanged(QFont)), this, SLOT(slotSetValue(QFont)));
    connect(editor, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*)));
    return editor;
}

/*!
    \internal

    Reimplemented from the QtAbstractEditorFactory class.
*/
void QtFontEditorFactory::disconnectPropertyManager(QtFontPropertyManager* manager) {
    disconnect(manager, SIGNAL(valueChanged(QtProperty*, QFont)), this, SLOT(slotPropertyChanged(QtProperty*, QFont)));
}

#if QT_VERSION >= 0x040400
QT_END_NAMESPACE
#endif

#include "moc_qteditorfactory.cpp"
#include "qteditorfactory.moc"
