+// This is a lame object that we need to ensure that slots connected to
+// QNetworkReply get called in the correct thread (the loader thread).
+// As QDeclarativeDataLoader lives in the main thread, and we can't use
+// Qt::DirectConnection connections from a QNetworkReply (because then
+// sender() wont work), we need to insert this object in the middle.
+class QDeclarativeDataLoaderNetworkReplyProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeDataLoaderNetworkReplyProxy(QDeclarativeDataLoader *l);
+
+public slots:
+ void finished();
+ void downloadProgress(qint64, qint64);
+
+private:
+ QDeclarativeDataLoader *l;
+};
+
+class QDeclarativeDataLoaderThread : public QDeclarativeThread
+{
+ typedef QDeclarativeDataLoaderThread This;
+
+public:
+ QDeclarativeDataLoaderThread(QDeclarativeDataLoader *loader);
+ QNetworkAccessManager *networkAccessManager() const;
+ QDeclarativeDataLoaderNetworkReplyProxy *networkReplyProxy() const;
+
+ void load(QDeclarativeDataBlob *b);
+ void loadAsync(QDeclarativeDataBlob *b);
+ void loadWithStaticData(QDeclarativeDataBlob *b, const QByteArray &);
+ void loadWithStaticDataAsync(QDeclarativeDataBlob *b, const QByteArray &);
+ void callCompleted(QDeclarativeDataBlob *b);
+ void callDownloadProgressChanged(QDeclarativeDataBlob *b, qreal p);
+ void initializeEngine(QDeclarativeExtensionInterface *, const char *);
+
+protected:
+ virtual void shutdownThread();
+
+private:
+ void loadThread(QDeclarativeDataBlob *b);
+ void loadWithStaticDataThread(QDeclarativeDataBlob *b, const QByteArray &);
+ void callCompletedMain(QDeclarativeDataBlob *b);
+ void callDownloadProgressChangedMain(QDeclarativeDataBlob *b, qreal p);
+ void initializeEngineMain(QDeclarativeExtensionInterface *iface, const char *uri);
+
+ QDeclarativeDataLoader *m_loader;
+ mutable QNetworkAccessManager *m_networkAccessManager;
+ mutable QDeclarativeDataLoaderNetworkReplyProxy *m_networkReplyProxy;
+};
+
+
+QDeclarativeDataLoaderNetworkReplyProxy::QDeclarativeDataLoaderNetworkReplyProxy(QDeclarativeDataLoader *l)
+: l(l)
+{
+}
+
+void QDeclarativeDataLoaderNetworkReplyProxy::finished()
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyFinished(reply);
+}
+
+void QDeclarativeDataLoaderNetworkReplyProxy::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyProgress(reply, bytesReceived, bytesTotal);
+}
+
+/*
+Returns the set of QML files in path (qmldir, *.qml, *.js). The caller
+is responsible for deleting the returned data.
+Returns 0 if the directory does not exist.
+*/
+#if defined (Q_OS_UNIX) && !defined(Q_OS_DARWIN)
+static QStringHash<bool> *qmlFilesInDirectory(const QString &path)
+{
+ QByteArray name(QFile::encodeName(path));
+ DIR *dd = opendir(name);
+ if (!dd)
+ return 0;
+
+ struct dirent *result;
+ union {
+ struct dirent d;
+ char b[offsetof (struct dirent, d_name) + NAME_MAX + 1];
+ } u;
+
+ QStringHash<bool> *files = new QStringHash<bool>;
+ while (readdir_r(dd, &u.d, &result) == 0 && result != 0) {
+ if (!strcmp(u.d.d_name, "qmldir")) {
+ files->insert(QLatin1String("qmldir"), true);
+ continue;
+ }
+ int len = strlen(u.d.d_name);
+ if (len < 4)
+ continue;
+ if (!strcmp(u.d.d_name+len-4, ".qml") || !strcmp(u.d.d_name+len-3, ".js"))
+ files->insert(QFile::decodeName(u.d.d_name), true);
+#if defined(Q_OS_DARWIN)
+ else if ((len > 6 && !strcmp(u.d.d_name+len-6, ".dylib")) || !strcmp(u.d.d_name+len-3, ".so")
+ || (len > 7 && !strcmp(u.d.d_name+len-7, ".bundle")))
+ files->insert(QFile::decodeName(u.d.d_name), true);
+#else // Unix
+ else if (!strcmp(u.d.d_name+len-3, ".so") || !strcmp(u.d.d_name+len-3, ".sl"))
+ files->insert(QFile::decodeName(u.d.d_name), true);
+#endif
+ }
+
+ closedir(dd);
+ return files;
+}
+#else
+static QStringHash<bool> *qmlFilesInDirectory(const QString &path)
+{
+ QDirIterator dir(path, QDir::Files);
+ if (!dir.hasNext())
+ return 0;
+ QStringHash<bool> *files = new QStringHash<bool>;
+ while (dir.hasNext()) {
+ dir.next();
+ QString fileName = dir.fileName();
+ if (fileName == QLatin1String("qmldir")
+ || fileName.endsWith(QLatin1String(".qml"))
+ || fileName.endsWith(QLatin1String(".js"))
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ || fileName.endsWith(QLatin1String(".dll"))
+#elif defined(Q_OS_DARWIN)
+ || fileName.endsWith(QLatin1String(".dylib"))
+ || fileName.endsWith(QLatin1String(".so"))
+ || fileName.endsWith(QLatin1String(".bundle"))
+#else // Unix
+ || fileName.endsWith(QLatin1String(".so"))
+ || fileName.endsWith(QLatin1String(".sl"))
+#endif
+ ) {
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_DARWIN)
+ fileName = fileName.toLower();
+#endif
+ files->insert(fileName, true);
+ }
+ }
+ return files;
+}
+#endif
+
+