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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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 dependencies 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.
457 \o The QDeclarativeDataBlob has no dependencies.
458 \o The QDeclarativeDataBlob has an error set.
459 \o All the QDeclarativeDataBlob's dependencies are themselves "done()".
462 Thus QDeclarativeDataBlob::done() will always eventually be called, even if the blob has an error set.
466 Create a new QDeclarativeDataLoader for \a engine.
468 QDeclarativeDataLoader::QDeclarativeDataLoader(QDeclarativeEngine *engine)
474 QDeclarativeDataLoader::~QDeclarativeDataLoader()
476 for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
481 Load the provided \a blob from the network or filesystem.
483 void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob)
485 Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
486 Q_ASSERT(blob->m_manager == 0);
488 blob->m_status = QDeclarativeDataBlob::Loading;
490 if (blob->m_url.isEmpty()) {
491 QDeclarativeError error;
492 error.setDescription(QLatin1String("Invalid null URL"));
493 blob->setError(error);
497 QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(blob->m_url);
500 if (!QDeclarative_isFileCaseCorrect(lf)) {
501 QDeclarativeError error;
502 error.setUrl(blob->m_url);
503 error.setDescription(QLatin1String("File name case mismatch"));
504 blob->setError(error);
508 if (file.open(QFile::ReadOnly)) {
509 QByteArray data = file.readAll();
511 blob->m_progress = 1.;
512 blob->downloadProgressChanged(1.);
516 blob->networkError(QNetworkReply::ContentNotFoundError);
521 blob->m_manager = this;
522 QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(blob->m_url));
523 QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
524 this, SLOT(networkReplyProgress(qint64,qint64)));
525 QObject::connect(reply, SIGNAL(finished()),
526 this, SLOT(networkReplyFinished()));
527 m_networkReplies.insert(reply, blob);
533 #define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
535 void QDeclarativeDataLoader::networkReplyFinished()
537 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
538 reply->deleteLater();
540 QDeclarativeDataBlob *blob = m_networkReplies.take(reply);
544 blob->m_redirectCount++;
546 if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) {
547 QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
548 if (redirect.isValid()) {
549 QUrl url = reply->url().resolved(redirect.toUrl());
550 blob->m_finalUrl = url;
552 QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(url));
553 QObject::connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
554 m_networkReplies.insert(reply, blob);
559 if (reply->error()) {
560 blob->networkError(reply->error());
562 QByteArray data = reply->readAll();
569 void QDeclarativeDataLoader::networkReplyProgress(qint64 bytesReceived, qint64 bytesTotal)
571 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
572 QDeclarativeDataBlob *blob = m_networkReplies.value(reply);
576 if (bytesTotal != 0) {
577 blob->m_progress = bytesReceived / bytesTotal;
578 blob->downloadProgressChanged(blob->m_progress);
583 Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case.
585 void QDeclarativeDataLoader::loadWithStaticData(QDeclarativeDataBlob *blob, const QByteArray &data)
587 Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
588 Q_ASSERT(blob->m_manager == 0);
590 blob->m_status = QDeclarativeDataBlob::Loading;
596 Return the QDeclarativeEngine associated with this loader
598 QDeclarativeEngine *QDeclarativeDataLoader::engine() const
603 void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArray &data)
605 blob->m_inCallback = true;
607 blob->dataReceived(data);
609 if (!blob->isError() && !blob->isWaiting())
610 blob->allDependenciesDone();
612 if (blob->status() != QDeclarativeDataBlob::Error)
613 blob->m_status = QDeclarativeDataBlob::WaitingForDependencies;
615 blob->m_inCallback = false;
621 Constructs a new type loader that uses the given \a engine.
623 QDeclarativeTypeLoader::QDeclarativeTypeLoader(QDeclarativeEngine *engine)
624 : QDeclarativeDataLoader(engine)
629 Destroys the type loader, first clearing the cache of any information about
632 QDeclarativeTypeLoader::~QDeclarativeTypeLoader()
638 \enum QDeclarativeTypeLoader::Option
640 This enum defines the options that control the way type data is handled.
642 \value None The default value, indicating that no other options
644 \value PreserveParser The parser used to handle the type data is preserved
645 after the data has been parsed.
649 Returns a QDeclarativeTypeData for the specified \a url. The QDeclarativeTypeData may be cached.
651 QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QUrl &url)
653 Q_ASSERT(!url.isRelative() &&
654 (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
655 !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
657 QDeclarativeTypeData *typeData = m_typeCache.value(url);
660 typeData = new QDeclarativeTypeData(url, None, this);
661 m_typeCache.insert(url, typeData);
662 QDeclarativeDataLoader::load(typeData);
670 Returns a QDeclarativeTypeData for the given \a data with the provided base \a url. The
671 QDeclarativeTypeData will not be cached.
673 The specified \a options control how the loader handles type data.
675 QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const QUrl &url, Options options)
677 QDeclarativeTypeData *typeData = new QDeclarativeTypeData(url, options, this);
678 QDeclarativeDataLoader::loadWithStaticData(typeData, data);
683 Return a QDeclarativeScriptBlob for \a url. The QDeclarativeScriptData may be cached.
685 QDeclarativeScriptBlob *QDeclarativeTypeLoader::getScript(const QUrl &url)
687 Q_ASSERT(!url.isRelative() &&
688 (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
689 !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
691 QDeclarativeScriptBlob *scriptBlob = m_scriptCache.value(url);
694 scriptBlob = new QDeclarativeScriptBlob(url, this);
695 m_scriptCache.insert(url, scriptBlob);
696 QDeclarativeDataLoader::load(scriptBlob);
703 Returns a QDeclarativeQmldirData for \a url. The QDeclarativeQmldirData may be cached.
705 QDeclarativeQmldirData *QDeclarativeTypeLoader::getQmldir(const QUrl &url)
707 Q_ASSERT(!url.isRelative() &&
708 (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
709 !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
711 QDeclarativeQmldirData *qmldirData = m_qmldirCache.value(url);
714 qmldirData = new QDeclarativeQmldirData(url);
715 m_qmldirCache.insert(url, qmldirData);
716 QDeclarativeDataLoader::load(qmldirData);
719 qmldirData->addref();
724 Clears cached information about loaded files, including any type data, scripts
725 and qmldir information.
727 void QDeclarativeTypeLoader::clearCache()
729 for (TypeCache::Iterator iter = m_typeCache.begin(); iter != m_typeCache.end(); ++iter)
731 for (ScriptCache::Iterator iter = m_scriptCache.begin(); iter != m_scriptCache.end(); ++iter)
733 for (QmldirCache::Iterator iter = m_qmldirCache.begin(); iter != m_qmldirCache.end(); ++iter)
737 m_scriptCache.clear();
738 m_qmldirCache.clear();
742 QDeclarativeTypeData::QDeclarativeTypeData(const QUrl &url, QDeclarativeTypeLoader::Options options,
743 QDeclarativeTypeLoader *manager)
744 : QDeclarativeDataBlob(url, QmlFile), m_options(options), m_typesResolved(false),
745 m_compiledData(0), m_typeLoader(manager)
749 QDeclarativeTypeData::~QDeclarativeTypeData()
751 for (int ii = 0; ii < m_scripts.count(); ++ii)
752 m_scripts.at(ii).script->release();
753 for (int ii = 0; ii < m_qmldirs.count(); ++ii)
754 m_qmldirs.at(ii)->release();
755 for (int ii = 0; ii < m_types.count(); ++ii)
756 if (m_types.at(ii).typeData) m_types.at(ii).typeData->release();
758 m_compiledData->release();
761 QDeclarativeTypeLoader *QDeclarativeTypeData::typeLoader() const
766 const QDeclarativeImports &QDeclarativeTypeData::imports() const
771 const QDeclarativeScriptParser &QDeclarativeTypeData::parser() const
776 const QList<QDeclarativeTypeData::TypeReference> &QDeclarativeTypeData::resolvedTypes() const
781 const QList<QDeclarativeTypeData::ScriptReference> &QDeclarativeTypeData::resolvedScripts() const
786 QDeclarativeCompiledData *QDeclarativeTypeData::compiledData() const
789 m_compiledData->addref();
791 return m_compiledData;
794 void QDeclarativeTypeData::registerCallback(TypeDataCallback *callback)
796 Q_ASSERT(!m_callbacks.contains(callback));
797 m_callbacks.append(callback);
800 void QDeclarativeTypeData::unregisterCallback(TypeDataCallback *callback)
802 Q_ASSERT(m_callbacks.contains(callback));
803 m_callbacks.removeOne(callback);
804 Q_ASSERT(!m_callbacks.contains(callback));
807 void QDeclarativeTypeData::done()
811 // Check all script dependencies for errors
812 for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
813 const ScriptReference &script = m_scripts.at(ii);
814 Q_ASSERT(script.script->isCompleteOrError());
815 if (script.script->isError()) {
816 QList<QDeclarativeError> errors = script.script->errors();
817 QDeclarativeError error;
818 error.setUrl(finalUrl());
819 error.setLine(script.location.line);
820 error.setColumn(script.location.column);
821 error.setDescription(QDeclarativeTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
822 errors.prepend(error);
827 // Check all type dependencies for errors
828 for (int ii = 0; !isError() && ii < m_types.count(); ++ii) {
829 const TypeReference &type = m_types.at(ii);
830 Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
831 if (type.typeData && type.typeData->isError()) {
832 QString typeName = scriptParser.referencedTypes().at(ii)->name;
834 QList<QDeclarativeError> errors = type.typeData->errors();
835 QDeclarativeError error;
836 error.setUrl(finalUrl());
837 error.setLine(type.location.line);
838 error.setColumn(type.location.column);
839 error.setDescription(QDeclarativeTypeLoader::tr("Type %1 unavailable").arg(typeName));
840 errors.prepend(error);
849 if (!(m_options & QDeclarativeTypeLoader::PreserveParser))
850 scriptParser.clear();
853 while (!m_callbacks.isEmpty()) {
854 TypeDataCallback *callback = m_callbacks.takeFirst();
855 callback->typeDataReady(this);
861 void QDeclarativeTypeData::dataReceived(const QByteArray &data)
863 if (!scriptParser.parse(data, finalUrl())) {
864 setError(scriptParser.errors());
868 m_imports.setBaseUrl(finalUrl());
870 foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
871 if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
872 QUrl importUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
873 if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
874 QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl);
878 } else if (import.type == QDeclarativeScriptParser::Import::Script) {
879 QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
880 QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
884 ref.location = import.location.start;
885 ref.qualifier = import.qualifier;
893 if (!finalUrl().scheme().isEmpty()) {
894 QUrl importUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
895 if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
896 QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl);
903 void QDeclarativeTypeData::allDependenciesDone()
905 if (!m_typesResolved) {
907 m_typesResolved = true;
911 void QDeclarativeTypeData::downloadProgressChanged(qreal p)
913 for (int ii = 0; ii < m_callbacks.count(); ++ii) {
914 TypeDataCallback *callback = m_callbacks.at(ii);
915 callback->typeDataProgress(this, p);
919 void QDeclarativeTypeData::compile()
921 Q_ASSERT(m_compiledData == 0);
922 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Compiling);
924 m_compiledData = new QDeclarativeCompiledData(typeLoader()->engine());
925 m_compiledData->url = m_imports.baseUrl();
926 m_compiledData->name = m_compiledData->url.toString();
927 QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Compiling, m_compiledData->name);
929 QDeclarativeCompiler compiler;
930 if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) {
931 setError(compiler.errors());
932 m_compiledData->release();
935 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Compiling);
938 void QDeclarativeTypeData::resolveTypes()
940 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine());
941 QDeclarativeImportDatabase *importDatabase = &ep->importDatabase;
943 // For local urls, add an implicit import "." as first (most overridden) lookup.
944 // This will also trigger the loading of the qmldir and the import of any native
945 // types from available plugins.
946 QList<QDeclarativeError> errors;
947 if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) {
948 m_imports.addImport(importDatabase, QLatin1String("."),
949 QString(), -1, -1, QDeclarativeScriptParser::Import::File,
950 qmldir->dirComponents(), &errors);
952 m_imports.addImport(importDatabase, QLatin1String("."),
953 QString(), -1, -1, QDeclarativeScriptParser::Import::File,
954 QDeclarativeDirComponents(), &errors);
957 // remove any errors which are due to the implicit import which aren't real errors.
958 // for example, if the implicitly included qmldir file doesn't exist, that is not an error.
959 QList<QDeclarativeError> realErrors;
960 for (int i = 0; i < errors.size(); ++i) {
961 if (errors.at(i).description() != QDeclarativeImportDatabase::tr("import \".\" has no qmldir and no namespace")
962 && errors.at(i).description() != QDeclarativeImportDatabase::tr("\".\": no such directory")) {
963 realErrors.prepend(errors.at(i)); // this is a real error.
967 // report any real errors which occurred during plugin loading or qmldir parsing.
968 if (!realErrors.isEmpty()) {
969 setError(realErrors);
973 foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
974 QDeclarativeDirComponents qmldircomponentsnetwork;
975 if (import.type == QDeclarativeScriptParser::Import::Script)
978 if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
979 QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
980 if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
981 qmldircomponentsnetwork = qmldir->dirComponents();
986 import.extractVersion(&vmaj, &vmin);
988 QList<QDeclarativeError> errors;
989 if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
990 vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) {
991 QDeclarativeError error;
993 error = errors.takeFirst();
995 // this should not be possible!
996 // Description should come from error provided by addImport() function.
997 error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
999 error.setUrl(m_imports.baseUrl());
1000 error.setLine(import.location.start.line);
1001 error.setColumn(import.location.start.column);
1002 errors.prepend(error); // put it back on the list after filling out information.
1009 foreach (QDeclarativeScriptParser::TypeReference *parserRef, scriptParser.referencedTypes()) {
1010 QByteArray typeName = parserRef->name.toUtf8();
1017 QDeclarativeImportedNamespace *typeNamespace = 0;
1018 QList<QDeclarativeError> errors;
1020 if (!m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion,
1021 &typeNamespace, &errors) || typeNamespace) {
1022 // Known to not be a type:
1023 // - known to be a namespace (Namespace {})
1024 // - type with unknown namespace (UnknownNamespace.SomeType {})
1025 QDeclarativeError error;
1026 QString userTypeName = parserRef->name;
1027 userTypeName.replace(QLatin1Char('/'),QLatin1Char('.'));
1028 if (typeNamespace) {
1029 error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName));
1031 if (errors.size()) {
1032 error = errors.takeFirst();
1034 // this should not be possible!
1035 // Description should come from error provided by addImport() function.
1036 error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
1038 error.setUrl(m_imports.baseUrl());
1039 error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(error.description()));
1042 if (!parserRef->refObjects.isEmpty()) {
1043 QDeclarativeParser::Object *obj = parserRef->refObjects.first();
1044 error.setLine(obj->location.start.line);
1045 error.setColumn(obj->location.start.column);
1048 errors.prepend(error);
1054 ref.majorVersion = majorVersion;
1055 ref.minorVersion = minorVersion;
1056 foreach (QDeclarativeParser::Object *obj, parserRef->refObjects) {
1057 // store namespace for DOM
1058 obj->majorVersion = majorVersion;
1059 obj->minorVersion = minorVersion;
1062 ref.typeData = typeLoader()->get(url);
1063 addDependency(ref.typeData);
1066 if (parserRef->refObjects.count())
1067 ref.location = parserRef->refObjects.first()->location.start;
1073 QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url)
1075 for (int ii = 0; ii < m_qmldirs.count(); ++ii) {
1076 if (m_qmldirs.at(ii)->url() == url)
1077 return m_qmldirs.at(ii);
1082 QDeclarativeScriptData::QDeclarativeScriptData(QDeclarativeEngine *engine)
1083 : QDeclarativeCleanup(engine), importCache(0), pragmas(QDeclarativeParser::Object::ScriptBlock::None),
1088 QDeclarativeScriptData::~QDeclarativeScriptData()
1093 void QDeclarativeScriptData::clear()
1096 importCache->release();
1100 for (int ii = 0; ii < scripts.count(); ++ii)
1101 scripts.at(ii)->release();
1104 qPersistentDispose(m_program);
1105 qPersistentDispose(m_value);
1108 QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
1109 : QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None),
1110 m_scriptData(0), m_typeLoader(loader)
1114 QDeclarativeScriptBlob::~QDeclarativeScriptBlob()
1117 m_scriptData->release();
1122 QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptBlob::pragmas() const
1127 QString QDeclarativeScriptBlob::scriptSource() const
1132 QDeclarativeTypeLoader *QDeclarativeScriptBlob::typeLoader() const
1134 return m_typeLoader;
1137 const QDeclarativeImports &QDeclarativeScriptBlob::imports() const
1142 QDeclarativeScriptData *QDeclarativeScriptBlob::scriptData() const
1144 return m_scriptData;
1147 void QDeclarativeScriptBlob::dataReceived(const QByteArray &data)
1149 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine());
1150 QDeclarativeImportDatabase *importDatabase = &ep->importDatabase;
1152 m_source = QString::fromUtf8(data);
1154 QDeclarativeScriptParser::JavaScriptMetaData metadata =
1155 QDeclarativeScriptParser::extractMetaData(m_source);
1157 m_imports.setBaseUrl(finalUrl());
1159 m_pragmas = metadata.pragmas;
1161 foreach (const QDeclarativeScriptParser::Import &import, metadata.imports) {
1162 Q_ASSERT(import.type != QDeclarativeScriptParser::Import::File);
1164 if (import.type == QDeclarativeScriptParser::Import::Script) {
1165 QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
1166 QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
1167 addDependency(blob);
1169 ScriptReference ref;
1170 ref.location = import.location.start;
1171 ref.qualifier = import.qualifier;
1176 Q_ASSERT(import.type == QDeclarativeScriptParser::Import::Library);
1179 import.extractVersion(&vmaj, &vmin);
1181 QList<QDeclarativeError> errors;
1182 if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
1183 import.type, QDeclarativeDirComponents(), &errors)) {
1184 QDeclarativeError error = errors.takeFirst();
1185 // description should be set by addImport().
1186 error.setUrl(m_imports.baseUrl());
1187 error.setLine(import.location.start.line);
1188 error.setColumn(import.location.start.column);
1189 errors.prepend(error);
1198 void QDeclarativeScriptBlob::done()
1200 // Check all script dependencies for errors
1201 for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
1202 const ScriptReference &script = m_scripts.at(ii);
1203 Q_ASSERT(script.script->isCompleteOrError());
1204 if (script.script->isError()) {
1205 QList<QDeclarativeError> errors = script.script->errors();
1206 QDeclarativeError error;
1207 error.setUrl(finalUrl());
1208 error.setLine(script.location.line);
1209 error.setColumn(script.location.column);
1210 error.setDescription(typeLoader()->tr("Script %1 unavailable").arg(script.script->url().toString()));
1211 errors.prepend(error);
1219 QDeclarativeEngine *engine = typeLoader()->engine();
1220 m_scriptData = new QDeclarativeScriptData(engine);
1221 m_scriptData->url = finalUrl();
1222 m_scriptData->importCache = new QDeclarativeTypeNameCache(engine);
1224 for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
1225 const ScriptReference &script = m_scripts.at(ii);
1227 m_scriptData->scripts.append(script.script);
1228 m_scriptData->importCache->add(script.qualifier, ii);
1231 m_imports.populateCache(m_scriptData->importCache, engine);
1233 m_scriptData->pragmas = m_pragmas;
1235 // XXX TODO: Handle errors that occur duing the script compile
1236 QV8Engine *v8engine = &QDeclarativeEnginePrivate::get(engine)->v8engine;
1237 v8::HandleScope handle_scope;
1238 v8::Context::Scope scope(v8engine->context());
1239 v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_source, finalUrl().toString(), 1);
1240 m_scriptData->m_program = qPersistentNew<v8::Script>(program);
1243 QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
1244 : QDeclarativeDataBlob(url, QmldirFile)
1248 const QDeclarativeDirComponents &QDeclarativeQmldirData::dirComponents() const
1250 return m_components;
1253 void QDeclarativeQmldirData::dataReceived(const QByteArray &data)
1255 QDeclarativeDirParser parser;
1256 parser.setSource(QString::fromUtf8(data));
1258 m_components = parser.components();