323 lines
8.5 KiB
C++
323 lines
8.5 KiB
C++
#include "QPropertyHandle.h"
|
|
#include <QRegularExpression>
|
|
#include "PropertyHandleImpl/QPropertyHandleImpl_Sequential.h"
|
|
#include "PropertyHandleImpl/QPropertyHandleImpl_Associative.h"
|
|
#include "PropertyHandleImpl/QPropertyHandleImpl_Enum.h"
|
|
#include "PropertyHandleImpl/QPropertyHandleImpl_Object.h"
|
|
#include "PropertyHandleImpl/QPropertyHandleImpl_RawType.h"
|
|
|
|
QPropertyHandle::QPropertyHandle(QObject* inParent, QMetaType inType, QString inPropertyPath, Getter inGetter, Setter inSetter)
|
|
: mType(inType)
|
|
, mPropertyPath(inPropertyPath)
|
|
, mGetter(inGetter)
|
|
, mSetter(inSetter)
|
|
{
|
|
setParent(inParent);
|
|
setObjectName(inPropertyPath.split(".").back());
|
|
resloveMetaData();
|
|
mInitialValue = inGetter();
|
|
mPropertyType = parserType(inType);
|
|
switch (mPropertyType)
|
|
{
|
|
default:
|
|
break;
|
|
case PropertyType::RawType:
|
|
mImpl.reset(new QPropertyHandleImpl_RawType(this));
|
|
break;
|
|
case PropertyType::Enum:
|
|
mImpl.reset(new QPropertyHandleImpl_Enum(this));
|
|
break;
|
|
case PropertyType::Sequential:
|
|
mImpl.reset(new QPropertyHandleImpl_Sequential(this));
|
|
break;
|
|
case PropertyType::Associative:
|
|
mImpl.reset(new QPropertyHandleImpl_Associative(this));
|
|
break;
|
|
case PropertyType::Object:
|
|
mImpl.reset(new QPropertyHandleImpl_Object(this));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void QPropertyHandle::resloveMetaData()
|
|
{
|
|
auto metaObj = parent()->metaObject();
|
|
auto firstField = getPropertyPath().split(".").first();
|
|
for (int i = 0; i < metaObj->classInfoCount(); i++) {
|
|
auto metaClassInfo = metaObj->classInfo(i);
|
|
if (metaClassInfo.name() == firstField) {
|
|
QStringList fields = QString(metaClassInfo.value()).split(",", Qt::SplitBehaviorFlags::SkipEmptyParts);
|
|
for (auto field : fields) {
|
|
QStringList pair = field.split("=");
|
|
QString key, value;
|
|
if (pair.size() > 0) {
|
|
key = pair.first().trimmed();
|
|
}
|
|
if (pair.size() > 1) {
|
|
value = pair[1].trimmed();
|
|
}
|
|
mMetaData[key] = value;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
QPropertyHandle* QPropertyHandle::Find(const QObject* inParent, const QString& inPropertyPath)
|
|
{
|
|
for (QObject* child : inParent->children()) {
|
|
QPropertyHandle* handler = qobject_cast<QPropertyHandle*>(child);
|
|
if (handler && handler->getPropertyPath() == inPropertyPath) {
|
|
return handler;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
QPropertyHandle* QPropertyHandle::FindOrCreate(QObject* inParent, QMetaType inType, QString inPropertyPath, Getter inGetter, Setter inSetter)
|
|
{
|
|
QPropertyHandle* handle = Find(inParent, inPropertyPath);
|
|
if (handle)
|
|
return handle;
|
|
return new QPropertyHandle(
|
|
inParent,
|
|
inType,
|
|
inPropertyPath,
|
|
inGetter,
|
|
inSetter
|
|
);
|
|
}
|
|
|
|
QPropertyHandle* QPropertyHandle::FindOrCreate(QObject* inObject)
|
|
{
|
|
QPropertyHandle* handle = Find(inObject, "");
|
|
if (handle)
|
|
return handle;
|
|
return new QPropertyHandle(
|
|
inObject,
|
|
inObject->metaObject()->metaType(),
|
|
"",
|
|
[inObject]() {return QVariant::fromValue(inObject); },
|
|
[inObject](QVariant var) {}
|
|
);
|
|
}
|
|
|
|
QPropertyHandle* QPropertyHandle::Create(QObject* inParent, QMetaType inType, QString inPropertyPath, Getter inGetter, Setter inSetter)
|
|
{
|
|
return new QPropertyHandle(inParent, inType, inPropertyPath, inGetter, inSetter);
|
|
}
|
|
|
|
void QPropertyHandle::Cleanup(QObject* inParent)
|
|
{
|
|
for (QObject* child : inParent->children()) {
|
|
QPropertyHandle* handler = qobject_cast<QPropertyHandle*>(child);
|
|
if (handler) {
|
|
handler->deleteLater();
|
|
}
|
|
}
|
|
}
|
|
|
|
QMetaType QPropertyHandle::getType()
|
|
{
|
|
return mType;
|
|
}
|
|
|
|
QPropertyHandle::PropertyType QPropertyHandle::getPropertyType() const
|
|
{
|
|
return mPropertyType;
|
|
}
|
|
|
|
QString QPropertyHandle::getName()
|
|
{
|
|
return objectName();
|
|
}
|
|
|
|
QString QPropertyHandle::getPropertyPath()
|
|
{
|
|
return mPropertyPath;
|
|
}
|
|
|
|
QString QPropertyHandle::createSubPath(const QString& inSubName)
|
|
{
|
|
return getPropertyPath() + "." + inSubName;
|
|
}
|
|
|
|
void QPropertyHandle::invalidateStructure()
|
|
{
|
|
Q_EMIT asStructureChanged();
|
|
}
|
|
|
|
QVariant QPropertyHandle::getVar()
|
|
{
|
|
return mGetter();
|
|
}
|
|
|
|
void QPropertyHandle::setVar(QVariant var)
|
|
{
|
|
QVariant lastVar = mGetter();
|
|
if (lastVar != var) {
|
|
mSetter(var);
|
|
Q_EMIT asVarChanged(var);
|
|
QVariant currVar = mGetter();
|
|
if (currVar != var) {
|
|
Q_EMIT asRequestRollback(currVar);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool QPropertyHandle::hasMetaData(const QString& inName) const
|
|
{
|
|
return mMetaData.contains(inName);
|
|
}
|
|
|
|
QVariant QPropertyHandle::getMetaData(const QString& inName) const
|
|
{
|
|
return mMetaData.value(inName);
|
|
}
|
|
|
|
const QVariantHash& QPropertyHandle::getMetaDataMap() const
|
|
{
|
|
return mMetaData;
|
|
}
|
|
|
|
QPropertyHandle* QPropertyHandle::findChild(QString inPropertyName)
|
|
{
|
|
return Find(this->parent(), this->createSubPath(inPropertyName));
|
|
}
|
|
|
|
QPropertyHandle* QPropertyHandle::findOrCreateChild(QMetaType inType, QString inPropertyName, Getter inGetter, Setter inSetter)
|
|
{
|
|
QVariant var = inGetter();
|
|
QObject* object = var.value<QObject*>();
|
|
QPropertyHandle* childHandle = nullptr;
|
|
if (object) {
|
|
childHandle = QPropertyHandle::FindOrCreate(
|
|
object
|
|
);
|
|
childHandle->setObjectName(inPropertyName);
|
|
}
|
|
else {
|
|
childHandle = QPropertyHandle::FindOrCreate(
|
|
this->parent(),
|
|
inType,
|
|
this->createSubPath(inPropertyName),
|
|
inGetter,
|
|
inSetter
|
|
);
|
|
}
|
|
|
|
childHandle->disconnect(this);
|
|
connect(this, &QPropertyHandle::asVarChanged, childHandle, [childHandle](QVariant) {
|
|
QVariant var = childHandle->getVar();
|
|
Q_EMIT childHandle->asRequestRollback(var);
|
|
});
|
|
connect(this, &QPropertyHandle::asRequestRollback, childHandle, [childHandle](QVariant) {
|
|
QVariant var = childHandle->getVar();
|
|
Q_EMIT childHandle->asRequestRollback(var);
|
|
});
|
|
return childHandle;
|
|
}
|
|
|
|
QQuickItem* QPropertyHandle::setupNameEditor(QQuickItem* inParent)
|
|
{
|
|
return mImpl->createNameEditor(inParent);
|
|
}
|
|
|
|
QQuickItem* QPropertyHandle::steupValueEditor(QQuickItem* inParent)
|
|
{
|
|
return mImpl->createValueEditor(inParent);
|
|
}
|
|
|
|
IPropertyHandleImpl::Type QPropertyHandle::type()
|
|
{
|
|
return mImpl->type();
|
|
}
|
|
|
|
QPropertyHandleImpl_Enum* QPropertyHandle::asEnum()
|
|
{
|
|
return static_cast<QPropertyHandleImpl_Enum*>(mImpl.get());
|
|
}
|
|
|
|
QPropertyHandleImpl_Object* QPropertyHandle::asObject()
|
|
{
|
|
return static_cast<QPropertyHandleImpl_Object*>(mImpl.get());
|
|
}
|
|
|
|
QPropertyHandleImpl_Associative* QPropertyHandle::asAssociative()
|
|
{
|
|
return static_cast<QPropertyHandleImpl_Associative*>(mImpl.get());
|
|
}
|
|
|
|
QPropertyHandleImpl_Sequential* QPropertyHandle::asSequential()
|
|
{
|
|
return static_cast<QPropertyHandleImpl_Sequential*>(mImpl.get());
|
|
}
|
|
|
|
QPropertyHandle::PropertyType QPropertyHandle::parserType(QMetaType inType)
|
|
{
|
|
if (QMetaType::canConvert(inType, QMetaType::fromType<QVariantList>())
|
|
&& !QMetaType::canConvert(inType, QMetaType::fromType<QString>())
|
|
) {
|
|
return Sequential;
|
|
}
|
|
else if (QMetaType::canConvert(inType, QMetaType::fromType<QVariantMap>())) {
|
|
return Associative;
|
|
}
|
|
else if (inType.flags() & QMetaType::IsEnumeration) {
|
|
return Enum;
|
|
}
|
|
else {
|
|
QRegularExpression reg("QSharedPointer\\<(.+)\\>");
|
|
QRegularExpressionMatch match = reg.match(inType.name(), 0, QRegularExpression::MatchType::PartialPreferCompleteMatch, QRegularExpression::AnchorAtOffsetMatchOption);
|
|
QStringList matchTexts = match.capturedTexts();
|
|
QMetaType innerMetaType;
|
|
if (!matchTexts.isEmpty()) {
|
|
QString metaTypeName = matchTexts.back();
|
|
innerMetaType = QMetaType::fromName(metaTypeName.toLocal8Bit());
|
|
}
|
|
if (innerMetaType.metaObject() || inType.metaObject()) {
|
|
return Object;
|
|
}
|
|
else {
|
|
return RawType;
|
|
}
|
|
}
|
|
}
|
|
|
|
QVariant QPropertyHandle::createNewVariant(QMetaType inOutputType)
|
|
{
|
|
QRegularExpression reg("QSharedPointer\\<(.+)\\>");
|
|
QRegularExpressionMatch match = reg.match(inOutputType.name());
|
|
QStringList matchTexts = match.capturedTexts();
|
|
if (!matchTexts.isEmpty()) {
|
|
QMetaType innerMetaType = QMetaType::fromName((matchTexts.back()).toLocal8Bit());
|
|
if (innerMetaType.isValid()) {
|
|
void* ptr = innerMetaType.create();
|
|
QVariant sharedPtr(inOutputType);
|
|
memcpy(sharedPtr.data(), &ptr, sizeof(ptr));
|
|
QtSharedPointer::ExternalRefCountData* data = ExternalRefCountWithMetaType::create(innerMetaType, ptr);
|
|
memcpy((char*)sharedPtr.data() + sizeof(ptr), &data, sizeof(data));
|
|
return sharedPtr;
|
|
}
|
|
}
|
|
else if (inOutputType.flags().testFlag(QMetaType::IsPointer)) {
|
|
const QMetaObject* metaObject = inOutputType.metaObject();
|
|
if (metaObject && metaObject->inherits(&QObject::staticMetaObject)) {
|
|
QObject* obj = metaObject->newInstance();
|
|
if (obj)
|
|
return QVariant::fromValue(obj);
|
|
}
|
|
QMetaType innerMetaType = QMetaType::fromName(QString(inOutputType.name()).remove("*").toLocal8Bit());
|
|
if (innerMetaType.isValid()) {
|
|
void* ptr = innerMetaType.create();
|
|
QVariant var(inOutputType, ptr);
|
|
memcpy(var.data(), &ptr, sizeof(ptr));
|
|
return var;
|
|
}
|
|
else {
|
|
return QVariant();
|
|
}
|
|
}
|
|
return QVariant(inOutputType);
|
|
}
|