aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util/qquickbind.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/util/qquickbind.cpp')
-rw-r--r--src/quick/util/qquickbind.cpp309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/quick/util/qquickbind.cpp b/src/quick/util/qquickbind.cpp
new file mode 100644
index 0000000000..a3fba06359
--- /dev/null
+++ b/src/quick/util/qquickbind.cpp
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbind_p.h"
+
+#include <private/qqmlnullablevalue_p_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlguard_p.h>
+
+#include <qqmlengine.h>
+#include <qqmlcontext.h>
+#include <qqmlproperty.h>
+#include <qqmlinfo.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickBindPrivate : public QObjectPrivate
+{
+public:
+ QQuickBindPrivate() : componentComplete(true), obj(0), prevBind(0) {}
+ ~QQuickBindPrivate() { if (prevBind) prevBind->destroy(); }
+
+ QQmlNullableValue<bool> when;
+ bool componentComplete;
+ QQmlGuard<QObject> obj;
+ QString propName;
+ QQmlNullableValue<QVariant> value;
+ QQmlProperty prop;
+ QQmlAbstractBinding *prevBind;
+};
+
+
+/*!
+ \qmlclass Binding QQuickBind
+ \inqmlmodule QtQuick 2
+ \ingroup qml-working-with-data
+ \brief The Binding element allows arbitrary property bindings to be created.
+
+ \section1 Binding to an inaccessible property
+
+ Sometimes it is necessary to bind to a property of an object that wasn't
+ directly instantiated by QML - generally a property of a class exported
+ to QML by C++. In these cases, regular property binding doesn't work. Binding
+ allows you to bind any value to any property.
+
+ For example, imagine a C++ application that maps an "app.enteredText"
+ property into QML. You could use Binding to update the enteredText property
+ like this.
+ \code
+ TextEdit { id: myTextField; text: "Please type here..." }
+ Binding { target: app; property: "enteredText"; value: myTextField.text }
+ \endcode
+ Whenever the text in the TextEdit is updated, the C++ property will be
+ updated also.
+
+ \section1 "Single-branch" conditional binding
+
+ In some circumstances you may want to control the value of a property
+ only when a certain condition is true (and relinquish control in all
+ other cirumstances). This often isn't possible to accomplish with a direct
+ binding, as you need to supply values for all possible branches.
+
+ \qml
+ // warning: "Unable to assign [undefined] to double value"
+ value: if (mouse.pressed) mouse.mouseX
+ \endqml
+
+ The above example will produce a warning whenever we release the mouse, as the value
+ of the binding is undefined when the mouse isn't pressed. We can use the Binding
+ element to rewrite the above code and avoid the warning.
+
+ \qml
+ Binding on value {
+ when: mouse.pressed
+ value: mouse.mouseX
+ }
+ \endqml
+
+ The Binding element will also restore any previously set direct bindings on
+ the property. In that sense, it functions much like a simplified State.
+
+ \qml
+ // this is equivilant to the above Binding
+ State {
+ name: "pressed"
+ when: mouse.pressed
+ PropertyChanges {
+ target: obj
+ value: mouse.mouseX
+ }
+ }
+ \endqml
+
+ If the binding target or binding property is changed, the bound value is
+ immediately pushed onto the new target.
+
+ \sa QtQml
+*/
+QQuickBind::QQuickBind(QObject *parent)
+ : QObject(*(new QQuickBindPrivate), parent)
+{
+}
+
+QQuickBind::~QQuickBind()
+{
+}
+
+/*!
+ \qmlproperty bool QtQuick2::Binding::when
+
+ This property holds when the binding is active.
+ This should be set to an expression that evaluates to true when you want the binding to be active.
+
+ \code
+ Binding {
+ target: contactName; property: 'text'
+ value: name; when: list.ListView.isCurrentItem
+ }
+ \endcode
+
+ When the binding becomes inactive again, any direct bindings that were previously
+ set on the property will be restored.
+*/
+bool QQuickBind::when() const
+{
+ Q_D(const QQuickBind);
+ return d->when;
+}
+
+void QQuickBind::setWhen(bool v)
+{
+ Q_D(QQuickBind);
+ if (!d->when.isNull && d->when == v)
+ return;
+
+ d->when = v;
+ eval();
+}
+
+/*!
+ \qmlproperty Object QtQuick2::Binding::target
+
+ The object to be updated.
+*/
+QObject *QQuickBind::object()
+{
+ Q_D(const QQuickBind);
+ return d->obj;
+}
+
+void QQuickBind::setObject(QObject *obj)
+{
+ Q_D(QQuickBind);
+ if (d->obj && d->when.isValid() && d->when) {
+ /* if we switch the object at runtime, we need to restore the
+ previous binding on the old object before continuing */
+ d->when = false;
+ eval();
+ d->when = true;
+ }
+ d->obj = obj;
+ if (d->componentComplete)
+ d->prop = QQmlProperty(d->obj, d->propName);
+ eval();
+}
+
+/*!
+ \qmlproperty string QtQuick2::Binding::property
+
+ The property to be updated.
+*/
+QString QQuickBind::property() const
+{
+ Q_D(const QQuickBind);
+ return d->propName;
+}
+
+void QQuickBind::setProperty(const QString &p)
+{
+ Q_D(QQuickBind);
+ if (!d->propName.isEmpty() && d->when.isValid() && d->when) {
+ /* if we switch the property name at runtime, we need to restore the
+ previous binding on the old object before continuing */
+ d->when = false;
+ eval();
+ d->when = true;
+ }
+ d->propName = p;
+ if (d->componentComplete)
+ d->prop = QQmlProperty(d->obj, d->propName);
+ eval();
+}
+
+/*!
+ \qmlproperty any QtQuick2::Binding::value
+
+ The value to be set on the target object and property. This can be a
+ constant (which isn't very useful), or a bound expression.
+*/
+QVariant QQuickBind::value() const
+{
+ Q_D(const QQuickBind);
+ return d->value.value;
+}
+
+void QQuickBind::setValue(const QVariant &v)
+{
+ Q_D(QQuickBind);
+ d->value = v;
+ eval();
+}
+
+void QQuickBind::setTarget(const QQmlProperty &p)
+{
+ Q_D(QQuickBind);
+ d->prop = p;
+}
+
+void QQuickBind::classBegin()
+{
+ Q_D(QQuickBind);
+ d->componentComplete = false;
+}
+
+void QQuickBind::componentComplete()
+{
+ Q_D(QQuickBind);
+ d->componentComplete = true;
+ if (!d->prop.isValid())
+ d->prop = QQmlProperty(d->obj, d->propName);
+ eval();
+}
+
+void QQuickBind::eval()
+{
+ Q_D(QQuickBind);
+ if (!d->prop.isValid() || d->value.isNull || !d->componentComplete)
+ return;
+
+ if (d->when.isValid()) {
+ if (!d->when) {
+ //restore any previous binding
+ if (d->prevBind) {
+ QQmlAbstractBinding *tmp = d->prevBind;
+ d->prevBind = 0;
+ tmp = QQmlPropertyPrivate::setBinding(d->prop, tmp);
+ if (tmp) //should this ever be true?
+ tmp->destroy();
+ }
+ return;
+ }
+
+ //save any set binding for restoration
+ QQmlAbstractBinding *tmp;
+ tmp = QQmlPropertyPrivate::setBinding(d->prop, 0);
+ if (tmp && d->prevBind)
+ d->prevBind->destroy();
+ else if (!d->prevBind)
+ d->prevBind = tmp;
+ }
+
+ d->prop.write(d->value.value);
+}
+
+QT_END_NAMESPACE