7#include <private/qobject_p.h>
8#include <private/qqmlcontextdata_p.h>
9#include <private/qqmlproperty_p.h>
10#include <private/qqmlvaluetype_p.h>
11#include <private/qv4scopedvalue_p.h>
13#include <QtQml/qqmlinfo.h>
14#include <QtCore/qcompare.h>
22 QObject *object,
const QQmlPropertyData *core,
23 const QQmlPropertyData *valueTypeData =
nullptr)
29 bool isValid()
const {
return m_object !=
nullptr && m_core !=
nullptr; }
32 void write(QVariant &&value)
const;
43 const QString coreName = m_core->name(m_object);
45 const QQmlPropertyData *vt = valueTypeData();
49 const QMetaObject *vtMetaObject = QQmlMetaType::metaObjectForValueType(m_core->propType());
50 Q_ASSERT(vtMetaObject);
51 const char *vtName = vtMetaObject->property(vt->coreIndex()).name();
52 return coreName + QLatin1Char(
'.') + QString::fromUtf8(vtName);
62 m_valueTypeData =
nullptr;
68 QPointer<QObject> m_object;
69 const QQmlPropertyData *m_core =
nullptr;
70 const QQmlPropertyData *m_valueTypeData =
nullptr;
75 return a.m_core == b.m_core && a.m_valueTypeData == b.m_valueTypeData
76 && a.m_object == b.m_object;
109 QObject::disconnect(m_connection);
113 void write(QVariant value)
const { m_property.write(std::move(value)); }
116 return m_property.coerce(source, q);
120 static void impl(
int which, QtPrivate::QSlotObjectBase *self, QObject *r,
void **a,
bool *ret);
123 impl(QtPrivate::QSlotObjectBase::Call,
this, receiver,
nullptr,
nullptr);
130 QMetaObject::Connection createConnection(QQmlSynchronizer *receiver)
133 QObject *object = m_property.object();
135 const int notifyIndex = m_property.notifyIndex();
136 Q_ASSERT(notifyIndex != -1);
138 return QObjectPrivate::connectImpl(
139 object, notifyIndex, receiver,
nullptr,
this, Qt::AutoConnection,
nullptr,
140 object->metaObject());
145 QMetaObject::Connection m_connection;
154 , m_synchronizer(receiver)
158 void write(QVariant value)
const { m_property.write(std::move(value)); }
161 return m_property.coerce(source, q);
170 const QQmlPropertyData *core = m_property.core();
171 Q_ASSERT(core && core->isValid());
172 QObject *object = m_property.object();
175 QUntypedBindable bindable;
176 void *argv[1] { &bindable };
177 core->doMetacall<QMetaObject::BindableProperty>(object, core->coreIndex(), argv);
178 Q_ASSERT(bindable.isValid());
180 return bindable.onValueChanged(*
this);
198 QPropertyChangeHandler<QQmlSynchronizerHandler> changeHandler;
203 Q_DECLARE_PUBLIC(QQmlSynchronizer)
255 const QString &property,
OwnedTarget *objectProperty, QQmlSynchronizer *q);
265
266
267
268
269
270
271
272
273
274
275
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
419QQmlSynchronizer::QQmlSynchronizer(QObject *parent)
420 : QObject(*(
new QQmlSynchronizerPrivate), parent)
424void QQmlSynchronizer::setTarget(
const QQmlProperty &target)
426 Q_D(QQmlSynchronizer);
429 Q_ASSERT(!d->isComponentFinalized);
431 QQmlPropertyPrivate *p = QQmlPropertyPrivate::get(target);
432 d->target.object = p->object;
433 d->target.core = std::make_unique<QQmlPropertyData>(p->core);
434 d->target.auxiliary = p->valueTypeData.isValid()
435 ? std::make_unique<QQmlPropertyData>(p->valueTypeData)
439void QQmlSynchronizer::componentFinalized()
441 Q_D(QQmlSynchronizer);
443 d->isComponentFinalized =
true;
448
449
450
451
452
453
454QObject *QQmlSynchronizer::sourceObject()
const
456 Q_D(
const QQmlSynchronizer);
457 return d->sourceObjectProperty.object;
460void QQmlSynchronizer::setSourceObject(QObject *object)
462 Q_D(QQmlSynchronizer);
463 if (object == d->sourceObjectProperty.object)
466 if (d->isComponentFinalized)
467 d->disconnectObjectProperty(d->sourceProperty, &d->sourceObjectProperty);
469 d->sourceObjectProperty.object = object;
470 emit sourceObjectChanged();
472 if (d->isComponentFinalized)
473 d->connectObjectProperty(d->sourceProperty, &d->sourceObjectProperty,
this);
477
478
479
480
481
482
483QString QQmlSynchronizer::sourceProperty()
const
485 Q_D(
const QQmlSynchronizer);
486 return d->sourceProperty;
489void QQmlSynchronizer::setSourceProperty(
const QString &property)
491 Q_D(QQmlSynchronizer);
492 if (property == d->sourceProperty)
495 if (d->isComponentFinalized)
496 d->disconnectObjectProperty(d->sourceProperty, &d->sourceObjectProperty);
498 d->sourceProperty = property;
499 emit sourcePropertyChanged();
501 if (d->isComponentFinalized)
502 d->connectObjectProperty(d->sourceProperty, &d->sourceObjectProperty,
this);
506
507
508
509
510
511
512QObject *QQmlSynchronizer::targetObject()
const
514 Q_D(
const QQmlSynchronizer);
515 return d->targetObjectProperty.object;
518void QQmlSynchronizer::setTargetObject(QObject *object)
520 Q_D(QQmlSynchronizer);
521 if (object == d->targetObjectProperty.object)
524 if (d->isComponentFinalized)
525 d->disconnectObjectProperty(d->targetProperty, &d->targetObjectProperty);
527 d->targetObjectProperty.object = object;
528 emit targetObjectChanged();
530 if (d->isComponentFinalized)
531 d->connectObjectProperty(d->targetProperty, &d->targetObjectProperty,
this);
535
536
537
538
539
540
541QString QQmlSynchronizer::targetProperty()
const
543 Q_D(
const QQmlSynchronizer);
544 return d->targetProperty;
547void QQmlSynchronizer::setTargetProperty(
const QString &property)
549 Q_D(QQmlSynchronizer);
550 if (property == d->targetProperty)
553 if (d->isComponentFinalized)
554 d->disconnectObjectProperty(d->targetProperty, &d->targetObjectProperty);
556 d->targetProperty = property;
557 emit targetPropertyChanged();
559 if (d->isComponentFinalized)
560 d->connectObjectProperty(d->targetProperty, &d->targetObjectProperty,
this);
564
565
566
567
568
569
570
573
574
575
576
577
581 QQmlSynchronizer *q,
const QQmlSynchronizerProperty &property)
583 if (property.core()->notifiesViaBindable()) {
584 changeHandlers.push_back(QQmlSynchronizerChangeHandler(
this, property));
585 }
else if (
const int notifyIndex = property.notifyIndex(); notifyIndex != -1) {
586 slotObjects.push_back(QQmlRefPointer(
587 new QQmlSynchronizerSlotObject(q, property),
588 QQmlRefPointer<QQmlSynchronizerSlotObject>::AddRef));
593 const QString &property,
OwnedTarget *objectProperty)
595 QObject *object = objectProperty->object;
596 if (!object || property.isEmpty())
599 QQmlPropertyData localCore;
600 const QQmlPropertyData *coreData = objectProperty->core
601 ? objectProperty->core.get()
602 : QQmlPropertyCache::property(object, property, {}, &localCore);
603 if (!coreData || coreData->isFunction())
607 const auto slot = std::find_if(slotObjects.begin(), slotObjects.end(), [&](
const auto &slot) {
608 return slot->contains(synchronizerProperty);
611 if (slot == slotObjects.end()) {
613 = std::find_if(changeHandlers.begin(), changeHandlers.end(), [&](
const auto &handler) {
614 return handler.contains(synchronizerProperty);
617 Q_ASSERT(handler != changeHandlers.end());
618 changeHandlers.erase(handler);
620 slotObjects.erase(slot);
623 objectProperty->core.reset();
624 objectProperty->auxiliary.reset();
628 const QString &property,
OwnedTarget *objectProperty, QQmlSynchronizer *q)
630 QObject *object = objectProperty->object;
631 if (!object || property.isEmpty())
634 QQmlPropertyData localCore;
635 const QQmlPropertyData *coreData = QQmlPropertyCache::property(object, property, {}, &localCore);
637 qmlWarning(q) <<
"Target object has no property called " << property;
641 if (coreData->isFunction()) {
642 qmlWarning(q) <<
"Member " << property <<
" of target object is a function";
646 if (coreData == &localCore) {
647 objectProperty->core = std::make_unique<QQmlPropertyData>(std::move(localCore));
648 coreData = objectProperty->core.get();
652 createConnection(q, synchronizerProperty);
653 return synchronizerProperty;
658 QObject *object = target.object;
660 return QQmlSynchronizerProperty();
662 const QQmlPropertyData *core = target.core.get();
663 Q_ASSERT(core->isValid());
665 if (
const QQmlPropertyData *valueTypeData = target.auxiliary.get()) {
666 const QQmlSynchronizerProperty property(object, core, valueTypeData);
667 createConnection(q, property);
671 const QQmlSynchronizerProperty property(object, core);
672 createConnection(q, property);
678 changeHandlers.clear();
681 QQmlSynchronizerProperty initializationSource = connectTarget(q);
682 if (QQmlSynchronizerProperty source = connectObjectProperty(
683 sourceProperty, &sourceObjectProperty, q); source.isValid()) {
684 initializationSource = source;
686 connectObjectProperty(targetProperty, &targetObjectProperty, q);
688 const QQmlPropertyCache::ConstPtr propertyCache = QQmlData::ensurePropertyCache(q);
689 Q_ASSERT(propertyCache);
691 const int propertyCount = propertyCache->propertyCount();
692 const int propertyOffset = QQmlSynchronizer::staticMetaObject.propertyCount();
694 bool foundSource =
false;
695 for (
int i = propertyOffset; i < propertyCount; ++i) {
696 const QQmlPropertyData *property = propertyCache->property(i);
697 if (!property->isAlias())
700 const QQmlSynchronizerProperty synchronizerProperty(q, property);
701 createConnection(q, synchronizerProperty);
703 if (!foundSource && property->name(q) == QLatin1String(
"source")) {
704 initializationSource = synchronizerProperty;
710 if (initializationSource.isValid())
711 synchronize(initializationSource);
716 const QVariant value = property.read();
721 currentState->results[property] = (value == currentState->value) ? Accepted : Bounced;
725 Q_Q(QQmlSynchronizer);
728 state.results[property] = Origin;
729 const auto guard = QScopedValueRollback(
currentState, &state);
731 for (
const auto &slotObject : slotObjects) {
732 if (slotObject->contains(property))
734 state.results[slotObject->property()] = Ignored;
735 state.value = slotObject->coerce(value, q);
736 slotObject->write(state.value);
739 for (
const QQmlSynchronizerChangeHandler &changeHandler : changeHandlers) {
740 if (changeHandler.contains(property))
742 state.results[changeHandler.property()] = Ignored;
743 state.value = changeHandler.coerce(value, q);
744 changeHandler.write(state.value);
748 for (
auto it = state.results.constBegin(), end = state.results.constEnd(); it != end; ++it) {
755 emit q->valueBounced(key.object(), key.name());
760 emit q->valueIgnored(key.object(), key.name());
768 int which, QSlotObjectBase *self, QObject *r,
void **a,
bool *ret)
775 delete synchronizerSlotObject;
778 QQmlSynchronizer *q =
static_cast<QQmlSynchronizer *>(r);
779 QQmlSynchronizerPrivate::get(q)->synchronize(synchronizerSlotObject->m_property);
793 const QMetaType metaType = property->propType();
794 if (metaType == QMetaType::fromType<QVariant>()) {
796 property->readProperty(object, &content);
800 QVariant content(metaType);
801 property->readProperty(object, content.data());
810 QVariant coreContent = doReadProperty(m_object.data(), m_core);
812 if (!m_valueTypeData)
815 if (QQmlGadgetPtrWrapper *wrapper
816 = QQmlGadgetPtrWrapper::instance(qmlEngine(m_object), coreContent.metaType())) {
817 return doReadProperty(wrapper, m_valueTypeData);
820 QQmlGadgetPtrWrapper wrapper(QQmlMetaType::valueType(coreContent.metaType()));
821 return doReadProperty(&wrapper, m_valueTypeData);
826 Q_ASSERT(value.metaType() == metaType());
831 if (!m_valueTypeData) {
832 m_core->writeProperty(m_object, value.data(), QQmlPropertyData::DontRemoveBinding);
836 QVariant coreContent = doReadProperty(m_object, m_core);
838 if (QQmlGadgetPtrWrapper *wrapper
839 = QQmlGadgetPtrWrapper::instance(qmlEngine(m_object), coreContent.metaType())) {
840 m_valueTypeData->writeProperty(wrapper, value.data(), QQmlPropertyData::DontRemoveBinding);
841 m_core->writeProperty(m_object, coreContent.data(), QQmlPropertyData::DontRemoveBinding);
845 QQmlGadgetPtrWrapper wrapper(QQmlMetaType::valueType(coreContent.metaType()));
846 m_valueTypeData->writeProperty(&wrapper, value.data(), QQmlPropertyData::DontRemoveBinding);
847 m_core->writeProperty(m_object, coreContent.data(), QQmlPropertyData::DontRemoveBinding);
854 const QMetaType targetMetaType = m_valueTypeData
855 ? m_valueTypeData->propType()
856 : m_core->propType();
857 const QMetaType sourceMetaType = source.metaType();
858 if (targetMetaType == sourceMetaType)
861 QVariant target(targetMetaType);
863 QQmlData *ddata = QQmlData::get(q);
864 if (ddata && !ddata->jsWrapper.isNullOrUndefined()) {
865 QV4::Scope scope(ddata->jsWrapper.engine());
866 QV4::ScopedValue scoped(scope, scope.engine->fromData(sourceMetaType, source.constData()));
867 if (QV4::ExecutionEngine::metaTypeFromJS(scoped, targetMetaType, target.data()))
871 if (QMetaType::convert(sourceMetaType, source.constData(), targetMetaType, target.data()))
874 qmlWarning(q) <<
"Cannot convert from " << sourceMetaType.name() <<
" to " << targetMetaType.name();
QQmlSynchronizerChangeHandler(QQmlSynchronizerPrivate *receiver, const QQmlSynchronizerProperty &property)
QPropertyChangeHandler< QQmlSynchronizerHandler > createChangeHandler()
bool contains(const QQmlSynchronizerProperty &p) const
void write(QVariant value) const
QVariant coerce(const QVariant &source, QQmlSynchronizer *q) const
QQmlSynchronizerHandler(QQmlSynchronizerPrivate *receiver, const QQmlSynchronizerProperty &property)
QQmlSynchronizerProperty property() const
OwnedTarget sourceObjectProperty
QQmlSynchronizerProperty connectObjectProperty(const QString &property, OwnedTarget *objectProperty, QQmlSynchronizer *q)
void initialize(QQmlSynchronizer *q)
void synchronize(const QQmlSynchronizerProperty &property)
std::vector< QQmlSynchronizerChangeHandler > changeHandlers
QQmlSynchronizerProperty connectTarget(QQmlSynchronizer *q)
bool isComponentFinalized
OwnedTarget targetObjectProperty
static QQmlSynchronizerPrivate * get(QQmlSynchronizer *q)
std::vector< QQmlRefPointer< QQmlSynchronizerSlotObject > > slotObjects
void disconnectObjectProperty(const QString &property, OwnedTarget *objectProperty)
void createConnection(QQmlSynchronizer *q, const QQmlSynchronizerProperty &property)
\qmlsignal Qt.labs.synchronizer::Synchronizer::valueBounced(QtObject object, string property)
void write(QVariant value) const
QQmlSynchronizerProperty property() const
~QQmlSynchronizerSlotObject()
QVariant coerce(const QVariant &source, QQmlSynchronizer *q) const
bool contains(const QQmlSynchronizerProperty &p) const
static void impl(int which, QtPrivate::QSlotObjectBase *self, QObject *r, void **a, bool *ret)
QQmlSynchronizerSlotObject(QQmlSynchronizer *receiver, const QQmlSynchronizerProperty &property)
void operator()(QQmlSynchronizer *receiver)
Combined button and popup list for selecting options.
static QVariant doReadProperty(QObject *object, const QQmlPropertyData *property)
std::unique_ptr< const QQmlPropertyData > core
std::unique_ptr< const QQmlPropertyData > auxiliary
QPointer< QObject > object
QHash< QQmlSynchronizerProperty, Result > results
const QQmlPropertyData * valueTypeData() const
QQmlSynchronizerProperty()=default
QVariant coerce(const QVariant &source, QQmlSynchronizer *q) const
friend bool comparesEqual(const QQmlSynchronizerProperty &a, const QQmlSynchronizerProperty &b) noexcept
QQmlSynchronizerProperty(QObject *object, const QQmlPropertyData *core, const QQmlPropertyData *valueTypeData=nullptr)
void write(QVariant &&value) const
const QQmlPropertyData * core() const