1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qdeclarativetypeloader_p.h"
44 #include <private/qdeclarativeengine_p.h>
45 #include <private/qdeclarativecompiler_p.h>
46 #include <private/qdeclarativecomponent_p.h>
47 #include <private/qdeclarativeglobal_p.h>
48 #include <private/qdeclarativedebugtrace_p.h>
50 #include <QtDeclarative/qdeclarativecomponent.h>
51 #include <QtCore/qdebug.h>
52 #include <QtCore/qdir.h>
53 #include <QtCore/qfile.h>
58 \class QDeclarativeDataBlob
59 \brief The QDeclarativeDataBlob encapsulates a data request that can be issued to a QDeclarativeDataLoader.
62 QDeclarativeDataBlob's are loaded by a QDeclarativeDataLoader. The user creates the QDeclarativeDataBlob
63 and then calls QDeclarativeDataLoader::load() or QDeclarativeDataLoader::loadWithStaticData() to load it.
64 The QDeclarativeDataLoader invokes callbacks on the QDeclarativeDataBlob as data becomes available.
68 \enum QDeclarativeDataBlob::Status
70 This enum describes the status of the data blob.
73 \o Null The blob has not yet been loaded by a QDeclarativeDataLoader
74 \o Loading The blob is loading network data. The QDeclarativeDataBlob::setData() callback has not yet been
75 invoked or has not yet returned.
76 \o WaitingForDependencies The blob is waiting for dependencies to be done before continueing. This status
77 only occurs after the QDeclarativeDataBlob::setData() callback has been made, and when the blob has outstanding
79 \o Complete The blob's data has been loaded and all dependencies are done.
80 \o Error An error has been set on this blob.
85 \enum QDeclarativeDataBlob::Type
87 This enum describes the type of the data blob.
90 \o QmlFile This is a QDeclarativeTypeData
91 \o JavaScriptFile This is a QDeclarativeScriptData
92 \o QmldirFile This is a QDeclarativeQmldirData
97 Create a new QDeclarativeDataBlob for \a url and of the provided \a type.
99 QDeclarativeDataBlob::QDeclarativeDataBlob(const QUrl &url, Type type)
100 : m_type(type), m_status(Null), m_progress(0), m_url(url), m_finalUrl(url), m_manager(0),
101 m_redirectCount(0), m_inCallback(false), m_isDone(false)
106 QDeclarativeDataBlob::~QDeclarativeDataBlob()
108 Q_ASSERT(m_waitingOnMe.isEmpty());
110 cancelAllWaitingFor();
114 Returns the type provided to the constructor.
116 QDeclarativeDataBlob::Type QDeclarativeDataBlob::type() const
122 Returns the blob's status.
124 QDeclarativeDataBlob::Status QDeclarativeDataBlob::status() const
130 Returns true if the status is Null.
132 bool QDeclarativeDataBlob::isNull() const
134 return m_status == Null;
138 Returns true if the status is Loading.
140 bool QDeclarativeDataBlob::isLoading() const
142 return m_status == Loading;
146 Returns true if the status is WaitingForDependencies.
148 bool QDeclarativeDataBlob::isWaiting() const
150 return m_status == WaitingForDependencies;
154 Returns true if the status is Complete.
156 bool QDeclarativeDataBlob::isComplete() const
158 return m_status == Complete;
162 Returns true if the status is Error.
164 bool QDeclarativeDataBlob::isError() const
166 return m_status == Error;
170 Returns true if the status is Complete or Error.
172 bool QDeclarativeDataBlob::isCompleteOrError() const
174 return isComplete() || isError();
178 Returns the data download progress from 0 to 1.
180 qreal QDeclarativeDataBlob::progress() const
186 Returns the blob url passed to the constructor. If a network redirect
187 happens while fetching the data, this url remains the same.
191 QUrl QDeclarativeDataBlob::url() const
197 Returns the final url of the data. Initially this is the same as
198 url(), but if a network redirect happens while fetching the data, this url
199 is updated to reflect the new location.
201 QUrl QDeclarativeDataBlob::finalUrl() const
207 Return the errors on this blob.
209 QList<QDeclarativeError> QDeclarativeDataBlob::errors() const
215 Mark this blob as having \a errors.
217 All outstanding dependencies will be cancelled. Requests to add new dependencies
218 will be ignored. Entry into the Error state is irreversable, although you can change the
219 specific errors by additional calls to setError.
221 void QDeclarativeDataBlob::setError(const QDeclarativeError &errors)
223 QList<QDeclarativeError> l;
231 void QDeclarativeDataBlob::setError(const QList<QDeclarativeError> &errors)
236 cancelAllWaitingFor();
243 Wait for \a blob to become complete or to error. If \a blob is already
244 complete or in error, or this blob is already complete, this has no effect.
246 void QDeclarativeDataBlob::addDependency(QDeclarativeDataBlob *blob)
248 Q_ASSERT(status() != Null);
251 blob->status() == Error || blob->status() == Complete ||
252 status() == Error || status() == Complete ||
253 m_waitingFor.contains(blob))
257 m_status = WaitingForDependencies;
258 m_waitingFor.append(blob);
259 blob->m_waitingOnMe.append(this);
263 \fn void QDeclarativeDataBlob::dataReceived(const QByteArray &data)
265 Invoked when data for the blob is received. Implementors should use this callback
266 to determine a blob's dependencies. Within this callback you may call setError()
271 Invoked once data has either been received or a network error occurred, and all
272 dependencies are complete.
274 You can set an error in this method, but you cannot add new dependencies. Implementors
275 should use this callback to finalize processing of data.
277 The default implementation does nothing.
279 void QDeclarativeDataBlob::done()
284 Invoked if there is a network error while fetching this blob.
286 The default implementation sets an appropriate QDeclarativeError.
288 void QDeclarativeDataBlob::networkError(QNetworkReply::NetworkError networkError)
290 Q_UNUSED(networkError);
292 QDeclarativeError error;
293 error.setUrl(m_finalUrl);
295 const char *errorString = 0;
296 switch (networkError) {
298 errorString = "Network error";
300 case QNetworkReply::ConnectionRefusedError:
301 errorString = "Connection refused";
303 case QNetworkReply::RemoteHostClosedError:
304 errorString = "Remote host closed the connection";
306 case QNetworkReply::HostNotFoundError:
307 errorString = "Host not found";
309 case QNetworkReply::TimeoutError:
310 errorString = "Timeout";
312 case QNetworkReply::ProxyConnectionRefusedError:
313 case QNetworkReply::ProxyConnectionClosedError:
314 case QNetworkReply::ProxyNotFoundError:
315 case QNetworkReply::ProxyTimeoutError:
316 case QNetworkReply::ProxyAuthenticationRequiredError:
317 case QNetworkReply::UnknownProxyError:
318 errorString = "Proxy error";
320 case QNetworkReply::ContentAccessDenied:
321 errorString = "Access denied";
323 case QNetworkReply::ContentNotFoundError:
324 errorString = "File not found";
326 case QNetworkReply::AuthenticationRequiredError:
327 errorString = "Authentication required";
331 error.setDescription(QLatin1String(errorString));
337 Called if \a blob, which was previously waited for, has an error.
339 The default implementation does nothing.
341 void QDeclarativeDataBlob::dependencyError(QDeclarativeDataBlob *blob)
347 Called if \a blob, which was previously waited for, has completed.
349 The default implementation does nothing.
351 void QDeclarativeDataBlob::dependencyComplete(QDeclarativeDataBlob *blob)
357 Called when all blobs waited for have completed. This occurs regardless of
358 whether they are in error, or complete state.
360 The default implementation does nothing.
362 void QDeclarativeDataBlob::allDependenciesDone()
367 Called when the download progress of this blob changes. \a progress goes
370 void QDeclarativeDataBlob::downloadProgressChanged(qreal progress)
375 void QDeclarativeDataBlob::tryDone()
377 if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
378 if (status() != Error)
383 notifyAllWaitingOnMe();
387 void QDeclarativeDataBlob::cancelAllWaitingFor()
389 while (m_waitingFor.count()) {
390 QDeclarativeDataBlob *blob = m_waitingFor.takeLast();
392 Q_ASSERT(blob->m_waitingOnMe.contains(this));
394 blob->m_waitingOnMe.removeOne(this);
400 void QDeclarativeDataBlob::notifyAllWaitingOnMe()
402 while (m_waitingOnMe.count()) {
403 QDeclarativeDataBlob *blob = m_waitingOnMe.takeLast();
405 Q_ASSERT(blob->m_waitingFor.contains(this));
407 blob->notifyComplete(this);
411 void QDeclarativeDataBlob::notifyComplete(QDeclarativeDataBlob *blob)
413 Q_ASSERT(m_waitingFor.contains(blob));
414 Q_ASSERT(blob->status() == Error || blob->status() == Complete);
418 if (blob->status() == Error) {
419 dependencyError(blob);
420 } else if (blob->status() == Complete) {
421 dependencyComplete(blob);
424 m_waitingFor.removeOne(blob);
427 if (!isError() && m_waitingFor.isEmpty())
428 allDependenciesDone();
430 m_inCallback = false;
436 \class QDeclarativeDataLoader
437 \brief The QDeclarativeDataLoader class abstracts loading files and their dependecies over the network.
440 The QDeclarativeDataLoader class is provided for the exclusive use of the QDeclarativeTypeLoader class.
442 Clients create QDeclarativeDataBlob instances and submit them to the QDeclarativeDataLoader class
443 through the QDeclarativeDataLoader::load() or QDeclarativeDataLoader::loadWithStaticData() methods.
444 The loader then fetches the data over the network or from the local file system in an efficient way.
445 QDeclarativeDataBlob is an abstract class, so should always be specialized.
447 Once data is received, the QDeclarativeDataBlob::dataReceived() method is invoked on the blob. The
448 derived class should use this callback to process the received data. Processing of the data can
449 result in an error being set (QDeclarativeDataBlob::setError()), or one or more dependencies being
450 created (QDeclarativeDataBlob::addDependency()). Dependencies are other QDeclarativeDataBlob's that
451 are required before processing can fully complete.
453 To complete processing, the QDeclarativeDataBlob::done() callback is invoked. done() is called when
454 one of these three preconditions are met.
456 1. The QDeclarativeDataBlob has no dependencies.
457 2. The QDeclarativeDataBlob has an error set.
458 3. All the QDeclarativeDataBlob's dependencies are themselves "done()".
460 Thus QDeclarativeDataBlob::done() will always eventually be called, even if the blob has an error set.
464 Create a new QDeclarativeDataLoader for \a engine.
466 QDeclarativeDataLoader::QDeclarativeDataLoader(QDeclarativeEngine *engine)
472 QDeclarativeDataLoader::~QDeclarativeDataLoader()
474 for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
479 Load the provided \a blob from the network or filesystem.
481 void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob)
483 Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
484 Q_ASSERT(blob->m_manager == 0);
486 blob->m_status = QDeclarativeDataBlob::Loading;
488 if (blob->m_url.isEmpty()) {
489 QDeclarativeError error;
490 error.setDescription(QLatin1String("Invalid null URL"));
491 blob->setError(error);
495 QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(blob->m_url);
498 if (!QDeclarative_isFileCaseCorrect(lf)) {
499 QDeclarativeError error;
500 error.setUrl(blob->m_url);
501 error.setDescription(QLatin1String("File name case mismatch"));
502 blob->setError(error);
506 if (file.open(QFile::ReadOnly)) {
507 QByteArray data = file.readAll();
509 blob->m_progress = 1.;
510 blob->downloadProgressChanged(1.);
514 blob->networkError(QNetworkReply::ContentNotFoundError);
519 blob->m_manager = this;
520 QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(blob->m_url));
521 QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
522 this, SLOT(networkReplyProgress(qint64,qint64)));
523 QObject::connect(reply, SIGNAL(finished()),
524 this, SLOT(networkReplyFinished()));
525 m_networkReplies.insert(reply, blob);
531 #define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
533 void QDeclarativeDataLoader::networkReplyFinished()
535 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
536 reply->deleteLater();
538 QDeclarativeDataBlob *blob = m_networkReplies.take(reply);
542 blob->m_redirectCount++;
544 if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) {
545 QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
546 if (redirect.isValid()) {
547 QUrl url = reply->url().resolved(redirect.toUrl());
548 blob->m_finalUrl = url;
550 QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(url));
551 QObject::connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
552 m_networkReplies.insert(reply, blob);
557 if (reply->error()) {
558 blob->networkError(reply->error());
560 QByteArray data = reply->readAll();
567 void QDeclarativeDataLoader::networkReplyProgress(qint64 bytesReceived, qint64 bytesTotal)
569 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
570 QDeclarativeDataBlob *blob = m_networkReplies.value(reply);
574 if (bytesTotal != 0) {
575 blob->m_progress = bytesReceived / bytesTotal;
576 blob->downloadProgressChanged(blob->m_progress);
581 Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case.
583 void QDeclarativeDataLoader::loadWithStaticData(QDeclarativeDataBlob *blob, const QByteArray &data)
585 Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
586 Q_ASSERT(blob->m_manager == 0);
588 blob->m_status = QDeclarativeDataBlob::Loading;
594 Return the QDeclarativeEngine associated with this loader
596 QDeclarativeEngine *QDeclarativeDataLoader::engine() const
601 void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArray &data)
603 blob->m_inCallback = true;
605 blob->dataReceived(data);
607 if (!blob->isError() && !blob->isWaiting())
608 blob->allDependenciesDone();
610 if (blob->status() != QDeclarativeDataBlob::Error)
611 blob->m_status = QDeclarativeDataBlob::WaitingForDependencies;
613 blob->m_inCallback = false;
619 \class QDeclarativeTypeLoader
621 QDeclarativeTypeLoader::QDeclarativeTypeLoader(QDeclarativeEngine *engine)
622 : QDeclarativeDataLoader(engine)
626 QDeclarativeTypeLoader::~QDeclarativeTypeLoader()
632 \enum QDeclarativeTypeLoader::Option
634 This enum defines the options that control the way type data is handled.
636 \value None The default value, indicating that no other options
638 \value PreserveParser The parser used to handle the type data is preserved
639 after the data has been parsed.
643 Returns a QDeclarativeTypeData for the specified \a url. The QDeclarativeTypeData may be cached.
645 QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QUrl &url)
647 Q_ASSERT(!url.isRelative() &&
648 (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
649 !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
651 QDeclarativeTypeData *typeData = m_typeCache.value(url);
654 typeData = new QDeclarativeTypeData(url, None, this);
655 m_typeCache.insert(url, typeData);
656 QDeclarativeDataLoader::load(typeData);
664 Returns a QDeclarativeTypeData for the given \a data with the provided base \a url. The
665 QDeclarativeTypeData will not be cached.
667 The specified \a options control how the loader handles type data.
669 QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const QUrl &url, Options options)
671 QDeclarativeTypeData *typeData = new QDeclarativeTypeData(url, options, this);
672 QDeclarativeDataLoader::loadWithStaticData(typeData, data);
677 Return a QDeclarativeScriptData for \a url. The QDeclarativeScriptData may be cached.
679 QDeclarativeScriptData *QDeclarativeTypeLoader::getScript(const QUrl &url)
681 Q_ASSERT(!url.isRelative() &&
682 (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
683 !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
685 QDeclarativeScriptData *scriptData = m_scriptCache.value(url);
688 scriptData = new QDeclarativeScriptData(url);
689 m_scriptCache.insert(url, scriptData);
690 QDeclarativeDataLoader::load(scriptData);
693 scriptData->addref();
698 Return a QDeclarativeQmldirData for \a url. The QDeclarativeQmldirData may be cached.
700 QDeclarativeQmldirData *QDeclarativeTypeLoader::getQmldir(const QUrl &url)
702 Q_ASSERT(!url.isRelative() &&
703 (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
704 !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
706 QDeclarativeQmldirData *qmldirData = m_qmldirCache.value(url);
709 qmldirData = new QDeclarativeQmldirData(url);
710 m_qmldirCache.insert(url, qmldirData);
711 QDeclarativeDataLoader::load(qmldirData);
714 qmldirData->addref();
718 void QDeclarativeTypeLoader::clearCache()
720 for (TypeCache::Iterator iter = m_typeCache.begin(); iter != m_typeCache.end(); ++iter)
722 for (ScriptCache::Iterator iter = m_scriptCache.begin(); iter != m_scriptCache.end(); ++iter)
724 for (QmldirCache::Iterator iter = m_qmldirCache.begin(); iter != m_qmldirCache.end(); ++iter)
728 m_scriptCache.clear();
729 m_qmldirCache.clear();
733 QDeclarativeTypeData::QDeclarativeTypeData(const QUrl &url, QDeclarativeTypeLoader::Options options,
734 QDeclarativeTypeLoader *manager)
735 : QDeclarativeDataBlob(url, QmlFile), m_options(options), m_typesResolved(false),
736 m_compiledData(0), m_typeLoader(manager)
740 QDeclarativeTypeData::~QDeclarativeTypeData()
742 for (int ii = 0; ii < m_scripts.count(); ++ii)
743 m_scripts.at(ii).script->release();
744 for (int ii = 0; ii < m_qmldirs.count(); ++ii)
745 m_qmldirs.at(ii)->release();
746 for (int ii = 0; ii < m_types.count(); ++ii)
747 if (m_types.at(ii).typeData) m_types.at(ii).typeData->release();
749 m_compiledData->release();
752 QDeclarativeTypeLoader *QDeclarativeTypeData::typeLoader() const
757 const QDeclarativeImports &QDeclarativeTypeData::imports() const
762 const QDeclarativeScriptParser &QDeclarativeTypeData::parser() const
767 const QList<QDeclarativeTypeData::TypeReference> &QDeclarativeTypeData::resolvedTypes() const
772 const QList<QDeclarativeTypeData::ScriptReference> &QDeclarativeTypeData::resolvedScripts() const
777 QDeclarativeCompiledData *QDeclarativeTypeData::compiledData() const
780 m_compiledData->addref();
782 return m_compiledData;
785 void QDeclarativeTypeData::registerCallback(TypeDataCallback *callback)
787 Q_ASSERT(!m_callbacks.contains(callback));
788 m_callbacks.append(callback);
791 void QDeclarativeTypeData::unregisterCallback(TypeDataCallback *callback)
793 Q_ASSERT(m_callbacks.contains(callback));
794 m_callbacks.removeOne(callback);
795 Q_ASSERT(!m_callbacks.contains(callback));
798 void QDeclarativeTypeData::done()
802 // Check all script dependencies for errors
803 for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
804 const ScriptReference &script = m_scripts.at(ii);
805 Q_ASSERT(script.script->isCompleteOrError());
806 if (script.script->isError()) {
807 QList<QDeclarativeError> errors = script.script->errors();
808 QDeclarativeError error;
809 error.setUrl(finalUrl());
810 error.setLine(script.location.line);
811 error.setColumn(script.location.column);
812 error.setDescription(QDeclarativeTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
813 errors.prepend(error);
818 // Check all type dependencies for errors
819 for (int ii = 0; !isError() && ii < m_types.count(); ++ii) {
820 const TypeReference &type = m_types.at(ii);
821 Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
822 if (type.typeData && type.typeData->isError()) {
823 QString typeName = scriptParser.referencedTypes().at(ii)->name;
825 QList<QDeclarativeError> errors = type.typeData->errors();
826 QDeclarativeError error;
827 error.setUrl(finalUrl());
828 error.setLine(type.location.line);
829 error.setColumn(type.location.column);
830 error.setDescription(QDeclarativeTypeLoader::tr("Type %1 unavailable").arg(typeName));
831 errors.prepend(error);
840 if (!(m_options & QDeclarativeTypeLoader::PreserveParser))
841 scriptParser.clear();
844 while (!m_callbacks.isEmpty()) {
845 TypeDataCallback *callback = m_callbacks.takeFirst();
846 callback->typeDataReady(this);
852 void QDeclarativeTypeData::dataReceived(const QByteArray &data)
854 if (!scriptParser.parse(data, finalUrl())) {
855 setError(scriptParser.errors());
859 m_imports.setBaseUrl(finalUrl());
861 foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
862 if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
863 QUrl importUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
864 if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
865 QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl);
869 } else if (import.type == QDeclarativeScriptParser::Import::Script) {
870 QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
871 QDeclarativeScriptData *data = typeLoader()->getScript(scriptUrl);
875 ref.location = import.location.start;
876 ref.qualifier = import.qualifier;
883 if (!finalUrl().scheme().isEmpty()) {
884 QUrl importUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
885 if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
886 QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl);
893 void QDeclarativeTypeData::allDependenciesDone()
895 if (!m_typesResolved) {
897 m_typesResolved = true;
901 void QDeclarativeTypeData::downloadProgressChanged(qreal p)
903 for (int ii = 0; ii < m_callbacks.count(); ++ii) {
904 TypeDataCallback *callback = m_callbacks.at(ii);
905 callback->typeDataProgress(this, p);
909 void QDeclarativeTypeData::compile()
911 Q_ASSERT(m_compiledData == 0);
912 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Compiling);
914 m_compiledData = new QDeclarativeCompiledData(typeLoader()->engine());
915 m_compiledData->url = m_imports.baseUrl();
916 m_compiledData->name = m_compiledData->url.toString();
917 QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Compiling, m_compiledData->name);
919 QDeclarativeCompiler compiler;
920 if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) {
921 setError(compiler.errors());
922 m_compiledData->release();
925 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Compiling);
928 void QDeclarativeTypeData::resolveTypes()
930 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine());
931 QDeclarativeImportDatabase *importDatabase = &ep->importDatabase;
933 // For local urls, add an implicit import "." as first (most overridden) lookup.
934 // This will also trigger the loading of the qmldir and the import of any native
935 // types from available plugins.
936 if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) {
937 m_imports.addImport(importDatabase, QLatin1String("."),
938 QString(), -1, -1, QDeclarativeScriptParser::Import::File,
939 qmldir->dirComponents(), 0);
941 m_imports.addImport(importDatabase, QLatin1String("."),
942 QString(), -1, -1, QDeclarativeScriptParser::Import::File,
943 QDeclarativeDirComponents(), 0);
946 foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
947 QDeclarativeDirComponents qmldircomponentsnetwork;
948 if (import.type == QDeclarativeScriptParser::Import::Script)
951 if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
952 QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
953 if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
954 qmldircomponentsnetwork = qmldir->dirComponents();
960 if (!import.version.isEmpty()) {
961 int dot = import.version.indexOf(QLatin1Char('.'));
963 vmaj = import.version.toInt();
966 vmaj = import.version.left(dot).toInt();
967 vmin = import.version.mid(dot+1).toInt();
972 if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
973 vmaj, vmin, import.type, qmldircomponentsnetwork, &errorString)) {
974 QDeclarativeError error;
975 error.setUrl(m_imports.baseUrl());
976 error.setDescription(errorString);
977 error.setLine(import.location.start.line);
978 error.setColumn(import.location.start.column);
985 foreach (QDeclarativeScriptParser::TypeReference *parserRef, scriptParser.referencedTypes()) {
986 QByteArray typeName = parserRef->name.toUtf8();
993 QDeclarativeImportedNamespace *typeNamespace = 0;
996 if (!m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion,
997 &typeNamespace, &errorString) || typeNamespace) {
998 // Known to not be a type:
999 // - known to be a namespace (Namespace {})
1000 // - type with unknown namespace (UnknownNamespace.SomeType {})
1001 QDeclarativeError error;
1002 error.setUrl(m_imports.baseUrl());
1003 QString userTypeName = parserRef->name;
1004 userTypeName.replace(QLatin1Char('/'),QLatin1Char('.'));
1006 error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName));
1008 error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(errorString));
1010 if (!parserRef->refObjects.isEmpty()) {
1011 QDeclarativeParser::Object *obj = parserRef->refObjects.first();
1012 error.setLine(obj->location.start.line);
1013 error.setColumn(obj->location.start.column);
1021 ref.majorVersion = majorVersion;
1022 ref.minorVersion = minorVersion;
1023 foreach (QDeclarativeParser::Object *obj, parserRef->refObjects) {
1024 // store namespace for DOM
1025 obj->majorVersion = majorVersion;
1026 obj->minorVersion = minorVersion;
1029 ref.typeData = typeLoader()->get(url);
1030 addDependency(ref.typeData);
1033 if (parserRef->refObjects.count())
1034 ref.location = parserRef->refObjects.first()->location.start;
1040 QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url)
1042 for (int ii = 0; ii < m_qmldirs.count(); ++ii) {
1043 if (m_qmldirs.at(ii)->url() == url)
1044 return m_qmldirs.at(ii);
1049 QDeclarativeScriptData::QDeclarativeScriptData(const QUrl &url)
1050 : QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None)
1054 QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptData::pragmas() const
1059 QString QDeclarativeScriptData::scriptSource() const
1064 void QDeclarativeScriptData::dataReceived(const QByteArray &data)
1066 m_source = QString::fromUtf8(data);
1067 m_pragmas = QDeclarativeScriptParser::extractPragmas(m_source);
1070 QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
1071 : QDeclarativeDataBlob(url, QmldirFile)
1075 const QDeclarativeDirComponents &QDeclarativeQmldirData::dirComponents() const
1077 return m_components;
1080 void QDeclarativeQmldirData::dataReceived(const QByteArray &data)
1082 QDeclarativeDirParser parser;
1083 parser.setSource(QString::fromUtf8(data));
1085 m_components = parser.components();