commit 715000af0eb6a9092dba8c0923031b7e6f0e0b60
Author: Aaron Kennedy <aaron.kennedy@nokia.com>
Date:   Tue Nov 15 15:05:02 2011 +0000

    Allow alias signals to be used prior to the object being created
    
    Task-number: QTBUG-21580
    Change-Id: I09fa2aa6a2c265d8e4a38196c368690df0acfa25

diff --git a/src/declarative/qml/ftw/ftw.pri b/src/declarative/qml/ftw/ftw.pri
index 9d114e2..9df0af8 100644
--- a/src/declarative/qml/ftw/ftw.pri
+++ b/src/declarative/qml/ftw/ftw.pri
@@ -13,6 +13,7 @@ HEADERS +=  \
     $$PWD/qrecursionwatcher_p.h \
     $$PWD/qdeletewatcher_p.h \
     $$PWD/qrecyclepool_p.h \
+    $$PWD/qflagpointer_p.h \
 
 SOURCES += \
     $$PWD/qintrusivelist.cpp \
diff --git a/src/declarative/qml/ftw/qflagpointer_p.h b/src/declarative/qml/ftw/qflagpointer_p.h
new file mode 100644
index 0000000..20f829b
--- /dev/null
+++ b/src/declarative/qml/ftw/qflagpointer_p.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative 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$
+**
+****************************************************************************/
+
+#ifndef QFLAGPOINTER_P_H
+#define QFLAGPOINTER_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+class QFlagPointer {
+public:
+    inline QFlagPointer();
+    inline QFlagPointer(T *);
+    inline QFlagPointer(const QFlagPointer<T> &o);
+
+    inline bool isNull() const;
+
+    inline bool flag() const;
+    inline void setFlag();
+    inline void clearFlag();
+
+    inline bool flag2() const;
+    inline void setFlag2();
+    inline void clearFlag2();
+
+    inline QFlagPointer<T> &operator=(const QFlagPointer &o);
+    inline QFlagPointer<T> &operator=(T *);
+
+    inline T *operator->() const;
+    inline T *operator*() const;
+
+private:
+    intptr_t ptr_value;
+
+    static const intptr_t FlagBit = 0x1;
+    static const intptr_t Flag2Bit = 0x2;
+    static const intptr_t FlagsMask = FlagBit | Flag2Bit;
+};
+
+template<typename T>
+QFlagPointer<T>::QFlagPointer()
+: ptr_value(0)
+{
+}
+
+template<typename T>
+QFlagPointer<T>::QFlagPointer(T *v)
+: ptr_value(intptr_t(v))
+{
+    Q_ASSERT((ptr_value & FlagsMask) == 0);
+}
+
+template<typename T>
+QFlagPointer<T>::QFlagPointer(const QFlagPointer<T> &o)
+: ptr_value(o.ptr_value)
+{
+}
+
+template<typename T>
+bool QFlagPointer<T>::isNull() const
+{
+    return 0 == (ptr_value & (~FlagsMask));
+}
+
+template<typename T>
+bool QFlagPointer<T>::flag() const
+{
+    return ptr_value & FlagBit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlag()
+{
+    ptr_value |= FlagBit;
+}
+
+template<typename T>
+void QFlagPointer<T>::clearFlag()
+{
+    ptr_value &= ~FlagBit;
+}
+
+template<typename T>
+bool QFlagPointer<T>::flag2() const
+{
+    return ptr_value & Flag2Bit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlag2()
+{
+    ptr_value|= Flag2Bit;
+}
+
+template<typename T>
+void QFlagPointer<T>::clearFlag2()
+{
+    ptr_value &= ~Flag2Bit;
+}
+
+template<typename T>
+QFlagPointer<T> &QFlagPointer<T>::operator=(const QFlagPointer &o)
+{
+    ptr_value = o.ptr_value;
+    return *this;
+}
+
+template<typename T>
+QFlagPointer<T> &QFlagPointer<T>::operator=(T *o)
+{
+    Q_ASSERT((intptr_t(o) & FlagsMask) == 0);
+
+    ptr_value = intptr_t(o) | (ptr_value & FlagsMask);
+    return *this;
+}
+
+template<typename T>
+T *QFlagPointer<T>::operator->() const
+{
+    return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T>
+T *QFlagPointer<T>::operator*() const
+{
+    return (T *)(ptr_value & ~FlagsMask);
+}
+
+QT_END_NAMESPACE
+
+#endif // QFLAGPOINTER_P_H
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index fb6473c..92aa7bf 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -67,10 +67,12 @@
 #include <QtCore/qset.h>
 
 #include <private/qobject_p.h>
-#include "qdeclarativeguard_p.h"
+#include <private/qflagpointer_p.h>
+#include <private/qdeclarativeguard_p.h>
 
 #include <private/qv8_p.h>
 
+
 QT_BEGIN_NAMESPACE
 
 class QV8Bindings;
@@ -184,13 +186,13 @@ public:
     // id guards
     struct ContextGuard : public QDeclarativeGuard<QObject>
     {
-        ContextGuard() : context(0) {}
-        inline ContextGuard &operator=(QObject *obj)
-        { QDeclarativeGuard<QObject>::operator=(obj); return *this; }
-        virtual void objectDestroyed(QObject *) { 
-            if (context->contextObject && !QObjectPrivate::get(context->contextObject)->wasDeleted) bindings.notify(); 
-        }
-        QDeclarativeContextData *context;
+        inline ContextGuard();
+        inline ContextGuard &operator=(QObject *obj);
+        inline void objectDestroyed(QObject *);
+
+        inline bool wasSet() const;
+
+        QFlagPointer<QDeclarativeContextData> context;
         QDeclarativeNotifier bindings;
     };
     ContextGuard *idValues;
@@ -302,6 +304,30 @@ QDeclarativeGuardedContextData::operator=(QDeclarativeContextData *d)
     return *this;
 }
 
+QDeclarativeContextData::ContextGuard::ContextGuard()
+: context(0)
+{
+}
+
+QDeclarativeContextData::ContextGuard &QDeclarativeContextData::ContextGuard::operator=(QObject *obj)
+{
+    QDeclarativeGuard<QObject>::operator=(obj);
+    context.setFlag();
+    bindings.notify(); // For alias connections
+    return *this;
+}
+
+void QDeclarativeContextData::ContextGuard::objectDestroyed(QObject *)
+{
+    if (context->contextObject && !QObjectPrivate::get(context->contextObject)->wasDeleted)
+        bindings.notify();
+}
+
+bool QDeclarativeContextData::ContextGuard::wasSet() const
+{
+    return context.flag();
+}
+
 QT_END_NAMESPACE
 
 #endif // QDECLARATIVECONTEXT_P_H
diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp
index 9cdec02..f768d8c 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject.cpp
+++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp
@@ -94,6 +94,17 @@ private:
     inline void cleanup();
 };
 
+class QDeclarativeVMEMetaObjectEndpoint : public QDeclarativeNotifierEndpoint
+{
+public:
+    QDeclarativeVMEMetaObjectEndpoint();
+    static void vmecallback(QDeclarativeNotifierEndpoint *);
+    void tryConnect();
+
+    QFlagPointer<QDeclarativeVMEMetaObject> metaObject;
+};
+
+
 QDeclarativeVMEVariant::QDeclarativeVMEVariant()
 : type(QVariant::Invalid)
 {
@@ -378,13 +389,50 @@ void QDeclarativeVMEVariant::setValue(const QJSValue &v)
     }
 }
 
+QDeclarativeVMEMetaObjectEndpoint::QDeclarativeVMEMetaObjectEndpoint()
+{
+    callback = &vmecallback;
+}
+
+void QDeclarativeVMEMetaObjectEndpoint::vmecallback(QDeclarativeNotifierEndpoint *e)
+{
+    QDeclarativeVMEMetaObjectEndpoint *vmee = static_cast<QDeclarativeVMEMetaObjectEndpoint*>(e);
+    vmee->tryConnect();
+}
+
+void QDeclarativeVMEMetaObjectEndpoint::tryConnect()
+{
+    if (metaObject.flag())
+        return;
+
+    int aliasId = this - metaObject->aliasEndpoints;
+
+    QDeclarativeVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId;
+    if (!d->isObjectAlias()) {
+        QDeclarativeContextData *ctxt = metaObject->ctxt;
+        QObject *target = ctxt->idValues[d->contextIdx].data();
+        if (!target)
+            return;
+
+        QMetaProperty prop = target->metaObject()->property(d->propertyIndex());
+        if (prop.hasNotifySignal()) {
+            int sigIdx = metaObject->methodOffset + aliasId + metaObject->metaData->propertyCount;
+            QDeclarativePropertyPrivate::connect(target, prop.notifySignalIndex(),
+                                                 metaObject->object, sigIdx);
+        }
+    }
+
+    metaObject.setFlag();
+}
+
 QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj,
                                                      const QMetaObject *other, 
                                                      const QDeclarativeVMEMetaData *meta,
                                                      QDeclarativeCompiledData *cdata)
 : QV8GCCallback::Node(GcPrologueCallback), object(obj), compiledData(cdata),
   ctxt(QDeclarativeData::get(obj, true)->outerContext), metaData(meta), data(0),
-  firstVarPropertyIndex(-1), varPropertiesInitialized(false), v8methods(0), parent(0)
+  aliasEndpoints(0), firstVarPropertyIndex(-1), varPropertiesInitialized(false),
+  v8methods(0), parent(0)
 {
     compiledData->addref();
 
@@ -423,6 +471,7 @@ QDeclarativeVMEMetaObject::~QDeclarativeVMEMetaObject()
     compiledData->release();
     delete parent;
     delete [] data;
+    delete [] aliasEndpoints;
 
     for (int ii = 0; v8methods && ii < metaData->methodCount; ++ii) {
         qPersistentDispose(v8methods[ii]);
@@ -974,25 +1023,20 @@ bool QDeclarativeVMEMetaObject::aliasTarget(int index, QObject **target, int *co
 void QDeclarativeVMEMetaObject::connectAlias(int aliasId)
 {
     if (!aConnected.testBit(aliasId)) {
-        aConnected.setBit(aliasId);
 
-        QDeclarativeContext *context = ctxt->asQDeclarativeContext();
-        QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context);
+        if (!aliasEndpoints)
+            aliasEndpoints = new QDeclarativeVMEMetaObjectEndpoint[metaData->aliasCount];
+
+        aConnected.setBit(aliasId);
 
         QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + aliasId;
 
-        QObject *target = ctxtPriv->data->idValues[d->contextIdx].data();
-        if (!target) 
-            return;
+        QDeclarativeVMEMetaObjectEndpoint *endpoint = aliasEndpoints + aliasId;
+        endpoint->metaObject = this;
 
-        int sigIdx = methodOffset + aliasId + metaData->propertyCount;
-        QMetaObject::connect(context, d->contextIdx + ctxtPriv->notifyIndex, object, sigIdx);
+        endpoint->connect(&ctxt->idValues[d->contextIdx].bindings);
 
-        if (!d->isObjectAlias()) {
-            QMetaProperty prop = target->metaObject()->property(d->propertyIndex());
-            if (prop.hasNotifySignal())
-                QDeclarativePropertyPrivate::connect(target, prop.notifySignalIndex(), object, sigIdx);
-        }
+        endpoint->tryConnect();
     }
 }
 
diff --git a/src/declarative/qml/qdeclarativevmemetaobject_p.h b/src/declarative/qml/qdeclarativevmemetaobject_p.h
index 6076dcf..de0ac9e 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject_p.h
+++ b/src/declarative/qml/qdeclarativevmemetaobject_p.h
@@ -139,6 +139,7 @@ struct QDeclarativeVMEMetaData
 class QV8QObjectWrapper;
 class QDeclarativeVMEVariant;
 class QDeclarativeRefCount;
+class QDeclarativeVMEMetaObjectEndpoint;
 class Q_AUTOTEST_EXPORT QDeclarativeVMEMetaObject : public QAbstractDynamicMetaObject,
                                                     public QV8GCCallback::Node
 {
@@ -161,6 +162,8 @@ protected:
     virtual int metaCall(QMetaObject::Call _c, int _id, void **_a);
 
 private:
+    friend class QDeclarativeVMEMetaObjectEndpoint;
+
     QObject *object;
     QDeclarativeCompiledData *compiledData;
     QDeclarativeGuardedContextData ctxt;
@@ -170,6 +173,7 @@ private:
     int methodOffset;
 
     QDeclarativeVMEVariant *data;
+    QDeclarativeVMEMetaObjectEndpoint *aliasEndpoints;
 
     v8::Persistent<v8::Array> varProperties;
     int firstVarPropertyIndex;
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_21580.qml b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_21580.qml
new file mode 100644
index 0000000..dc0066b
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_21580.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+QtObject {
+    property bool test: false
+
+    property list<QtObject> objects: [
+        QtObject {
+            id: first
+            property alias myAlias: other.myProperty
+            onMyAliasChanged: if (myAlias == 20) test = true
+        },
+        QtObject {
+            id: other
+            property real myProperty
+        }
+    ]
+
+    Component.onCompleted: {
+        other.myProperty = 20;
+    }
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index 492ed73..9fa0327 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -177,7 +177,7 @@ private slots:
     void sequenceConversionThreads();
     void sequenceConversionBindings();
     void sequenceConversionCopy();
-
+    void qtbug_21580();
     void bug1();
     void bug2();
     void dynamicCreationCrash();
@@ -1642,6 +1642,18 @@ void tst_qdeclarativeecmascript::undefinedResetsProperty()
     }
 }
 
+void tst_qdeclarativeecmascript::qtbug_21580()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
+
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+
+    QCOMPARE(object->property("test").toBool(), true);
+
+    delete object;
+}
+
 // QTBUG-6781
 void tst_qdeclarativeecmascript::bug1()
 {
