219 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit,
220 const QV4::CompiledData::Binding *binding)
222 switch (binding->type()) {
223 case QV4::CompiledData::Binding::Type_Object:
224 error(compilationUnit->objectAt(binding->value.objectIndex),
225 QQuickPropertyChanges::tr(
226 "PropertyChanges does not support creating state-specific objects."));
228 case QV4::CompiledData::Binding::Type_GroupProperty:
229 case QV4::CompiledData::Binding::Type_AttachedProperty: {
230 const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex);
231 const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
232 for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
233 verifyList(compilationUnit, subBinding);
256 Q_Q(QQuickPropertyChanges);
258 QString propertyName = propertyPrefix + compilationUnit->stringAt(binding->propertyNameIndex);
260 switch (binding->type()) {
261 case QV4::CompiledData::Binding::Type_GroupProperty:
262 case QV4::CompiledData::Binding::Type_AttachedProperty: {
263 QString pre = propertyName + QLatin1Char(
'.');
264 const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex);
265 const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
266 for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
267 decodeBinding(pre, compilationUnit, subBinding);
275 if (binding->isSignalHandler() || QQmlSignalNames::isHandlerName(propertyName)) {
277 if (prop.isSignalProperty()) {
279 handler->property = prop;
280 handler->expression.adopt(
281 new QQmlBoundSignalExpression(
282 prop.object(), QQmlPropertyPrivate::get(prop)->signalIndex(),
283 QQmlContextData::get(qmlContext(q)), prop.object(),
284 compilationUnit->runtimeFunctions.at(binding->value.compiledScriptIndex)));
285 signalReplacements << handler;
290 if (binding->type() == QV4::CompiledData::Binding::Type_Script
291 || binding->isTranslationBinding()) {
296 QQmlData *ddata = QQmlData::get(q);
297 if (ddata && ddata->outerContext && !ddata->outerContext->url().isEmpty()) {
298 url = ddata->outerContext->url();
299 line = ddata->lineNumber;
300 column = ddata->columnNumber;
304 QQmlBinding::Identifier id = QQmlBinding::Invalid;
306 if (!binding->isTranslationBinding()) {
307 expression = compilationUnit->bindingValueAsString(binding);
308 id = binding->value.compiledScriptIndex;
310 expressions << ExpressionChange(propertyName, binding, id, expression, url, line, column);
315 switch (binding->type()) {
316 case QV4::CompiledData::Binding::Type_Script:
317 case QV4::CompiledData::Binding::Type_Translation:
318 case QV4::CompiledData::Binding::Type_TranslationById:
320 case QV4::CompiledData::Binding::Type_String:
321 var = compilationUnit->bindingValueAsString(binding);
323 case QV4::CompiledData::Binding::Type_Number:
324 var = compilationUnit->bindingValueAsNumber(binding);
326 case QV4::CompiledData::Binding::Type_Boolean:
327 var = binding->valueAsBoolean();
329 case QV4::CompiledData::Binding::Type_Null:
330 var = QVariant::fromValue(
nullptr);
336 properties << std::make_pair(propertyName, var);
416 Q_Q(QQuickPropertyChanges);
417 QQmlData *ddata = QQmlData::get(q);
419 object, property, ddata ? ddata->outerContext : QQmlRefPointer<QQmlContextData>(),
420 QQmlPropertyPrivate::InitFlag::AllowId | QQmlPropertyPrivate::InitFlag::AllowSignal);
421 if (!prop.isValid()) {
422 qmlWarning(q) << QQuickPropertyChanges::tr(
"Cannot assign to non-existent property \"%1\"").arg(property);
423 return QQmlProperty();
424 }
else if (!(prop.type() & QQmlProperty::SignalProperty) && !prop.isWritable()) {
425 qmlWarning(q) << QQuickPropertyChanges::tr(
"Cannot assign to read-only property \"%1\"").arg(property);
426 return QQmlProperty();
431QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
433 Q_D(QQuickPropertyChanges);
439 for (
int ii = 0; ii < d->properties.size(); ++ii) {
440 QQmlProperty prop = d->property(d->properties.at(ii).first);
442 QQuickStateAction a(d->object, prop, d->properties.at(ii).first,
443 d->properties.at(ii).second);
445 if (a.property.isValid()) {
446 a.restore = restoreEntryValues();
451 for (
int ii = 0; ii < d->signalReplacements.size(); ++ii) {
452 QQuickReplaceSignalHandler *handler = d->signalReplacements.at(ii);
454 if (handler->property.isValid()) {
461 for (
int ii = 0; ii < d->expressions.size(); ++ii) {
463 QQuickPropertyChangesPrivate::ExpressionChange e = d->expressions.at(ii);
464 const QString &property = e.name;
465 QQmlProperty prop = d->property(property);
467 if (prop.isValid()) {
469 a.restore = restoreEntryValues();
471 a.fromValue = a.property.read();
472 a.specifiedObject = d->object;
473 a.specifiedProperty = property;
475 QQmlRefPointer<QQmlContextData> context = QQmlContextData::get(qmlContext(
this));
476 QV4::Scope scope(qmlEngine(
this)->handle());
477 QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, QV4::QmlContext::create(scope.engine->rootContext(), context, object()));
484 std::unique_ptr<QQmlBinding> newBinding =
nullptr;
485 if (e.binding && e.binding->isTranslationBinding()) {
486 newBinding.reset(QQmlBinding::createTranslationBinding(d->compilationUnit, e.binding, object(), context));
487 }
else if (e.id != QQmlBinding::Invalid) {
488 newBinding.reset(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, d->compilationUnit->runtimeFunctions.at(e.id), object(), context, qmlCtxt));
490 newBinding.reset(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, e.expression, object(), context, e.url.toString(), e.line));
492 a.toValue = newBinding->evaluate();
494 QQmlAnyBinding newBinding =
nullptr;
495 if (e.binding && e.binding->isTranslationBinding()) {
496 newBinding = QQmlAnyBinding::createTranslationBinding(prop, d->compilationUnit, e.binding, object(), context);
497 }
else if (e.id != QQmlBinding::Invalid) {
498 newBinding = QQmlAnyBinding::createFromFunction(prop,
499 d->compilationUnit->runtimeFunctions.at(e.id),
500 object(), context, qmlCtxt);
502 newBinding = QQmlAnyBinding::createFromCodeString(prop, e.expression, object(), context, e.url.toString(), e.line);
505 a.toBinding = newBinding;
506 a.deletableToBinding =
true;
584void QQuickPropertyChanges::changeValue(
const QString &name,
const QVariant &value)
586 Q_D(QQuickPropertyChanges);
587 typedef std::pair<QString, QVariant> PropertyEntry;
589 for (
auto it = d->expressions.begin(), end = d->expressions.end(); it != end; ++it) {
590 if (it->name == name) {
591 d->expressions.erase(it);
592 if (state() && state()->isStateActive()) {
593 QQmlPropertyPrivate::removeBinding(d->property(name));
594 d->property(name).write(value);
597 d->properties.append(PropertyEntry(name, value));
602 for (
auto it = d->properties.begin(), end = d->properties.end(); it != end; ++it) {
603 if (it->first == name) {
605 if (state() && state()->isStateActive())
606 d->property(name).write(value);
611 QQuickStateAction action;
612 action.restore = restoreEntryValues();
613 action.property = d->property(name);
614 action.fromValue = action.property.read();
615 action.specifiedObject = object();
616 action.specifiedProperty = name;
617 action.toValue = value;
619 d->properties.append(PropertyEntry(name, value));
620 if (state() && state()->isStateActive()) {
621 state()->addEntryToRevertList(action);
622 QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(action.property);
624 oldBinding->setEnabled(
false, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
625 d->property(name).write(value);
629void QQuickPropertyChanges::changeExpression(
const QString &name,
const QString &expression)
631 Q_D(QQuickPropertyChanges);
632 typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry;
634 bool hadValue =
false;
636 for (
auto it = d->properties.begin(), end = d->properties.end(); it != end; ++it) {
637 if (it->first == name) {
638 d->properties.erase(it);
644 for (
auto it = d->expressions.begin(), end = d->expressions.end(); it != end; ++it) {
645 if (it->name == name) {
646 it->expression = expression;
647 if (state() && state()->isStateActive()) {
648 auto prop = d->property(name);
649 auto context = QQmlContextData::get(qmlContext(
this));
652 QQmlAnyBinding::createFromCodeString(prop, expression, object(), context, url, lineNumber).installOn(prop);
659 d->expressions.append(ExpressionEntry(name,
nullptr, QQmlBinding::Invalid, expression, QUrl(), -1, -1));
662 const quint16 lineNumber = 0;
663 if (state() && state()->isStateActive()) {
665 auto prop = d->property(name);
666 QQmlAnyBinding oldBinding = QQmlAnyBinding::takeFrom(prop);
668 state()->changeBindingInRevertList(object(), name, oldBinding);
670 QQmlAnyBinding::createFromCodeString(prop, expression, object(), QQmlContextData::get(qmlContext(
this)), url, lineNumber).installOn(prop);
672 QQuickStateAction action;
673 action.restore = restoreEntryValues();
674 action.property = d->property(name);
675 action.fromValue = action.property.read();
676 action.specifiedObject = object();
677 action.specifiedProperty = name;
679 QQmlAnyBinding newBinding;
681 newBinding = QQmlBinding::create(
682 &QQmlPropertyPrivate::get(action.property)->core, expression,
683 object(), QQmlContextData::get(qmlContext(
this)));
685 const auto prop = action.property;
686 const auto context = QQmlContextData::get(qmlContext(
this));
687 newBinding = QQmlAnyBinding::createFromCodeString(prop, expression, object(), context, url, lineNumber);
693 action.toValue =
static_cast<QQmlBinding *>(newBinding.asAbstractBinding())->evaluate();
696 QQmlAnyBinding::removeBindingFrom(action.property);
697 newBinding.installOn(action.property);
698 action.toBinding = newBinding;
699 action.deletableToBinding =
true;
700 state()->addEntryToRevertList(action);
728void QQuickPropertyChanges::removeProperty(
const QString &name)
730 Q_D(QQuickPropertyChanges);
732 for (
auto it = d->expressions.begin(), end = d->expressions.end(); it != end; ++it) {
733 if (it->name == name) {
734 d->expressions.erase(it);
735 state()->removeEntryFromRevertList(object(), name);
740 for (
auto it = d->properties.begin(), end = d->properties.end(); it != end; ++it) {
741 if (it->first == name) {
742 d->properties.erase(it);
743 state()->removeEntryFromRevertList(object(), name);