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)
384 notifyAllWaitingOnMe();
389 void QDeclarativeDataBlob::cancelAllWaitingFor()
391 while (m_waitingFor.count()) {
392 QDeclarativeDataBlob *blob = m_waitingFor.takeLast();
394 Q_ASSERT(blob->m_waitingOnMe.contains(this));
396 blob->m_waitingOnMe.removeOne(this);
402 void QDeclarativeDataBlob::notifyAllWaitingOnMe()
404 while (m_waitingOnMe.count()) {
405 QDeclarativeDataBlob *blob = m_waitingOnMe.takeLast();
407 Q_ASSERT(blob->m_waitingFor.contains(this));
409 blob->notifyComplete(this);
413 void QDeclarativeDataBlob::notifyComplete(QDeclarativeDataBlob *blob)
415 Q_ASSERT(m_waitingFor.contains(blob));
416 Q_ASSERT(blob->status() == Error || blob->status() == Complete);
420 if (blob->status() == Error) {
421 dependencyError(blob);
422 } else if (blob->status() == Complete) {
423 dependencyComplete(blob);
426 m_waitingFor.removeOne(blob);
429 if (!isError() && m_waitingFor.isEmpty())
430 allDependenciesDone();
432 m_inCallback = false;
438 \class QDeclarativeDataLoader
439 \brief The QDeclarativeDataLoader class abstracts loading files and their dependencies over the network.
442 The QDeclarativeDataLoader class is provided for the exclusive use of the QDeclarativeTypeLoader class.
444 Clients create QDeclarativeDataBlob instances and submit them to the QDeclarativeDataLoader class
445 through the QDeclarativeDataLoader::load() or QDeclarativeDataLoader::loadWithStaticData() methods.
446 The loader then fetches the data over the network or from the local file system in an efficient way.
447 QDeclarativeDataBlob is an abstract class, so should always be specialized.
449 Once data is received, the QDeclarativeDataBlob::dataReceived() method is invoked on the blob. The
450 derived class should use this callback to process the received data. Processing of the data can
451 result in an error being set (QDeclarativeDataBlob::setError()), or one or more dependencies being
452 created (QDeclarativeDataBlob::addDependency()). Dependencies are other QDeclarativeDataBlob's that
453 are required before processing can fully complete.
455 To complete processing, the QDeclarativeDataBlob::done() callback is invoked. done() is called when
456 one of these three preconditions are met.
459 \o The QDeclarativeDataBlob has no dependencies.
460 \o The QDeclarativeDataBlob has an error set.
461 \o All the QDeclarativeDataBlob's dependencies are themselves "done()".
464 Thus QDeclarativeDataBlob::done() will always eventually be called, even if the blob has an error set.
468 Create a new QDeclarativeDataLoader for \a engine.
470 QDeclarativeDataLoader::QDeclarativeDataLoader(QDeclarativeEngine *engine)
476 QDeclarativeDataLoader::~QDeclarativeDataLoader()
478 for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
483 Load the provided \a blob from the network or filesystem.
485 void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob)
487 Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
488 Q_ASSERT(blob->m_manager == 0);
490 blob->m_status = QDeclarativeDataBlob::Loading;
492 if (blob->m_url.isEmpty()) {
493 QDeclarativeError error;
494 error.setDescription(QLatin1String("Invalid null URL"));
495 blob->setError(error);
499 QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(blob->m_url);
502 if (!QDeclarative_isFileCaseCorrect(lf)) {
503 QDeclarativeError error;
504 error.setUrl(blob->m_url);
505 error.setDescription(QLatin1String("File name case mismatch"));
506 blob->setError(error);
510 if (file.open(QFile::ReadOnly)) {
511 QByteArray data = file.readAll();
513 blob->m_progress = 1.;
514 blob->downloadProgressChanged(1.);
518 blob->networkError(QNetworkReply::ContentNotFoundError);
523 blob->m_manager = this;
524 QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(blob->m_url));
525 QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
526 this, SLOT(networkReplyProgress(qint64,qint64)));
527 QObject::connect(reply, SIGNAL(finished()),
528 this, SLOT(networkReplyFinished()));
529 m_networkReplies.insert(reply, blob);
535 #define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
537 void QDeclarativeDataLoader::networkReplyFinished()
539 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
540 reply->deleteLater();
542 QDeclarativeDataBlob *blob = m_networkReplies.take(reply);
546 blob->m_redirectCount++;
548 if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) {
549 QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
550 if (redirect.isValid()) {
551 QUrl url = reply->url().resolved(redirect.toUrl());
552 blob->m_finalUrl = url;
554 QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(url));
555 QObject::connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
556 m_networkReplies.insert(reply, blob);
561 if (reply->error()) {
562 blob->networkError(reply->error());
564 QByteArray data = reply->readAll();
571 void QDeclarativeDataLoader::networkReplyProgress(qint64 bytesReceived, qint64 bytesTotal)
573 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
574 QDeclarativeDataBlob *blob = m_networkReplies.value(reply);
578 if (bytesTotal != 0) {
579 blob->m_progress = bytesReceived / bytesTotal;
580 blob->downloadProgressChanged(blob->m_progress);
585 Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case.
587 void QDeclarativeDataLoader::loadWithStaticData(QDeclarativeDataBlob *blob, const QByteArray &data)
589 Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
590 Q_ASSERT(blob->m_manager == 0);
592 blob->m_status = QDeclarativeDataBlob::Loading;
598 Return the QDeclarativeEngine associated with this loader
600 QDeclarativeEngine *QDeclarativeDataLoader::engine() const
605 void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArray &data)
607 blob->m_inCallback = true;
609 blob->dataReceived(data);
611 if (!blob->isError() && !blob->isWaiting())
612 blob->allDependenciesDone();
614 if (blob->status() != QDeclarativeDataBlob::Error)
615 blob->m_status = QDeclarativeDataBlob::WaitingForDependencies;
617 blob->m_inCallback = false;
623 Constructs a new type loader that uses the given \a engine.
625 QDeclarativeTypeLoader::QDeclarativeTypeLoader(QDeclarativeEngine *engine)
626 : QDeclarativeDataLoader(engine)
631 Destroys the type loader, first clearing the cache of any information about
634 QDeclarativeTypeLoader::~QDeclarativeTypeLoader()
640 \enum QDeclarativeTypeLoader::Option
642 This enum defines the options that control the way type data is handled.
644 \value None The default value, indicating that no other options
646 \value PreserveParser The parser used to handle the type data is preserved
647 after the data has been parsed.
651 Returns a QDeclarativeTypeData for the specified \a url. The QDeclarativeTypeData may be cached.
653 QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QUrl &url)
655 Q_ASSERT(!url.isRelative() &&
656 (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
657 !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
659 QDeclarativeTypeData *typeData = m_typeCache.value(url);
662 typeData = new QDeclarativeTypeData(url, None, this);
663 m_typeCache.insert(url, typeData);
664 QDeclarativeDataLoader::load(typeData);
672 Returns a QDeclarativeTypeData for the given \a data with the provided base \a url. The
673 QDeclarativeTypeData will not be cached.
675 The specified \a options control how the loader handles type data.
677 QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const QUrl &url, Options options)
679 QDeclarativeTypeData *typeData = new QDeclarativeTypeData(url, options, this);
680 QDeclarativeDataLoader::loadWithStaticData(typeData, data);
685 Return a QDeclarativeScriptBlob for \a url. The QDeclarativeScriptData may be cached.
687 QDeclarativeScriptBlob *QDeclarativeTypeLoader::getScript(const QUrl &url)
689 Q_ASSERT(!url.isRelative() &&
690 (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
691 !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
693 QDeclarativeScriptBlob *scriptBlob = m_scriptCache.value(url);
696 scriptBlob = new QDeclarativeScriptBlob(url, this);
697 m_scriptCache.insert(url, scriptBlob);
698 QDeclarativeDataLoader::load(scriptBlob);
705 Returns a QDeclarativeQmldirData for \a url. The QDeclarativeQmldirData may be cached.
707 QDeclarativeQmldirData *QDeclarativeTypeLoader::getQmldir(const QUrl &url)
709 Q_ASSERT(!url.isRelative() &&
710 (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
711 !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
713 QDeclarativeQmldirData *qmldirData = m_qmldirCache.value(url);
716 qmldirData = new QDeclarativeQmldirData(url);
717 m_qmldirCache.insert(url, qmldirData);
718 QDeclarativeDataLoader::load(qmldirData);
721 qmldirData->addref();
726 Clears cached information about loaded files, including any type data, scripts
727 and qmldir information.
729 void QDeclarativeTypeLoader::clearCache()
731 for (TypeCache::Iterator iter = m_typeCache.begin(); iter != m_typeCache.end(); ++iter)
733 for (ScriptCache::Iterator iter = m_scriptCache.begin(); iter != m_scriptCache.end(); ++iter)
735 for (QmldirCache::Iterator iter = m_qmldirCache.begin(); iter != m_qmldirCache.end(); ++iter)
739 m_scriptCache.clear();
740 m_qmldirCache.clear();
744 QDeclarativeTypeData::QDeclarativeTypeData(const QUrl &url, QDeclarativeTypeLoader::Options options,
745 QDeclarativeTypeLoader *manager)
746 : QDeclarativeDataBlob(url, QmlFile), m_options(options), m_typesResolved(false),
747 m_compiledData(0), m_typeLoader(manager)
751 QDeclarativeTypeData::~QDeclarativeTypeData()
753 for (int ii = 0; ii < m_scripts.count(); ++ii)
754 m_scripts.at(ii).script->release();
755 for (int ii = 0; ii < m_qmldirs.count(); ++ii)
756 m_qmldirs.at(ii)->release();
757 for (int ii = 0; ii < m_types.count(); ++ii)
758 if (m_types.at(ii).typeData) m_types.at(ii).typeData->release();
760 m_compiledData->release();
763 QDeclarativeTypeLoader *QDeclarativeTypeData::typeLoader() const
768 const QDeclarativeImports &QDeclarativeTypeData::imports() const
773 const QDeclarativeScriptParser &QDeclarativeTypeData::parser() const
778 const QList<QDeclarativeTypeData::TypeReference> &QDeclarativeTypeData::resolvedTypes() const
783 const QList<QDeclarativeTypeData::ScriptReference> &QDeclarativeTypeData::resolvedScripts() const
788 QDeclarativeCompiledData *QDeclarativeTypeData::compiledData() const
791 m_compiledData->addref();
793 return m_compiledData;
796 void QDeclarativeTypeData::registerCallback(TypeDataCallback *callback)
798 Q_ASSERT(!m_callbacks.contains(callback));
799 m_callbacks.append(callback);
802 void QDeclarativeTypeData::unregisterCallback(TypeDataCallback *callback)
804 Q_ASSERT(m_callbacks.contains(callback));
805 m_callbacks.removeOne(callback);
806 Q_ASSERT(!m_callbacks.contains(callback));
809 void QDeclarativeTypeData::done()
813 // Check all script dependencies for errors
814 for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
815 const ScriptReference &script = m_scripts.at(ii);
816 Q_ASSERT(script.script->isCompleteOrError());
817 if (script.script->isError()) {
818 QList<QDeclarativeError> errors = script.script->errors();
819 QDeclarativeError error;
820 error.setUrl(finalUrl());
821 error.setLine(script.location.line);
822 error.setColumn(script.location.column);
823 error.setDescription(QDeclarativeTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
824 errors.prepend(error);
829 // Check all type dependencies for errors
830 for (int ii = 0; !isError() && ii < m_types.count(); ++ii) {
831 const TypeReference &type = m_types.at(ii);
832 Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
833 if (type.typeData && type.typeData->isError()) {
834 QString typeName = scriptParser.referencedTypes().at(ii)->name;
836 QList<QDeclarativeError> errors = type.typeData->errors();
837 QDeclarativeError error;
838 error.setUrl(finalUrl());
839 error.setLine(type.location.line);
840 error.setColumn(type.location.column);
841 error.setDescription(QDeclarativeTypeLoader::tr("Type %1 unavailable").arg(typeName));
842 errors.prepend(error);
851 if (!(m_options & QDeclarativeTypeLoader::PreserveParser))
852 scriptParser.clear();
855 while (!m_callbacks.isEmpty()) {
856 TypeDataCallback *callback = m_callbacks.takeFirst();
857 callback->typeDataReady(this);
863 void QDeclarativeTypeData::dataReceived(const QByteArray &data)
865 if (!scriptParser.parse(data, finalUrl())) {
866 setError(scriptParser.errors());
870 m_imports.setBaseUrl(finalUrl());
872 foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
873 if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
874 QUrl importUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
875 if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
876 QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl);
880 } else if (import.type == QDeclarativeScriptParser::Import::Script) {
881 QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
882 QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
886 ref.location = import.location.start;
887 ref.qualifier = import.qualifier;
895 if (!finalUrl().scheme().isEmpty()) {
896 QUrl importUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
897 if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
898 QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl);
905 void QDeclarativeTypeData::allDependenciesDone()
907 if (!m_typesResolved) {
909 m_typesResolved = true;
913 void QDeclarativeTypeData::downloadProgressChanged(qreal p)
915 for (int ii = 0; ii < m_callbacks.count(); ++ii) {
916 TypeDataCallback *callback = m_callbacks.at(ii);
917 callback->typeDataProgress(this, p);
921 void QDeclarativeTypeData::compile()
923 Q_ASSERT(m_compiledData == 0);
924 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Compiling);
926 m_compiledData = new QDeclarativeCompiledData(typeLoader()->engine());
927 m_compiledData->url = m_imports.baseUrl();
928 m_compiledData->name = m_compiledData->url.toString();
929 QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Compiling, m_compiledData->name);
931 QDeclarativeCompiler compiler;
932 if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) {
933 setError(compiler.errors());
934 m_compiledData->release();
937 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Compiling);
940 void QDeclarativeTypeData::resolveTypes()
942 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine());
943 QDeclarativeImportDatabase *importDatabase = &ep->importDatabase;
945 // For local urls, add an implicit import "." as first (most overridden) lookup.
946 // This will also trigger the loading of the qmldir and the import of any native
947 // types from available plugins.
948 QList<QDeclarativeError> errors;
949 if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) {
950 m_imports.addImport(importDatabase, QLatin1String("."),
951 QString(), -1, -1, QDeclarativeScriptParser::Import::File,
952 qmldir->dirComponents(), &errors);
954 m_imports.addImport(importDatabase, QLatin1String("."),
955 QString(), -1, -1, QDeclarativeScriptParser::Import::File,
956 QDeclarativeDirComponents(), &errors);
959 // remove any errors which are due to the implicit import which aren't real errors.
960 // for example, if the implicitly included qmldir file doesn't exist, that is not an error.
961 QList<QDeclarativeError> realErrors;
962 for (int i = 0; i < errors.size(); ++i) {
963 if (errors.at(i).description() != QDeclarativeImportDatabase::tr("import \".\" has no qmldir and no namespace")
964 && errors.at(i).description() != QDeclarativeImportDatabase::tr("\".\": no such directory")) {
965 realErrors.prepend(errors.at(i)); // this is a real error.
969 // report any real errors which occurred during plugin loading or qmldir parsing.
970 if (!realErrors.isEmpty()) {
971 setError(realErrors);
975 foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
976 QDeclarativeDirComponents qmldircomponentsnetwork;
977 if (import.type == QDeclarativeScriptParser::Import::Script)
980 if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
981 QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
982 if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
983 qmldircomponentsnetwork = qmldir->dirComponents();
988 import.extractVersion(&vmaj, &vmin);
990 QList<QDeclarativeError> errors;
991 if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
992 vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) {
993 QDeclarativeError error;
995 error = errors.takeFirst();
997 // this should not be possible!
998 // Description should come from error provided by addImport() function.
999 error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
1001 error.setUrl(m_imports.baseUrl());
1002 error.setLine(import.location.start.line);
1003 error.setColumn(import.location.start.column);
1004 errors.prepend(error); // put it back on the list after filling out information.
1011 foreach (QDeclarativeScriptParser::TypeReference *parserRef, scriptParser.referencedTypes()) {
1012 QByteArray typeName = parserRef->name.toUtf8();
1019 QDeclarativeImportedNamespace *typeNamespace = 0;
1020 QList<QDeclarativeError> errors;
1022 if (!m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion,
1023 &typeNamespace, &errors) || typeNamespace) {
1024 // Known to not be a type:
1025 // - known to be a namespace (Namespace {})
1026 // - type with unknown namespace (UnknownNamespace.SomeType {})
1027 QDeclarativeError error;
1028 QString userTypeName = parserRef->name;
1029 userTypeName.replace(QLatin1Char('/'),QLatin1Char('.'));
1030 if (typeNamespace) {
1031 error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName));
1033 if (errors.size()) {
1034 error = errors.takeFirst();
1036 // this should not be possible!
1037 // Description should come from error provided by addImport() function.
1038 error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
1040 error.setUrl(m_imports.baseUrl());
1041 error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(error.description()));
1044 if (!parserRef->refObjects.isEmpty()) {
1045 QDeclarativeParser::Object *obj = parserRef->refObjects.first();
1046 error.setLine(obj->location.start.line);
1047 error.setColumn(obj->location.start.column);
1050 errors.prepend(error);
1056 ref.majorVersion = majorVersion;
1057 ref.minorVersion = minorVersion;
1059 ref.typeData = typeLoader()->get(url);
1060 addDependency(ref.typeData);
1063 if (parserRef->refObjects.count())
1064 ref.location = parserRef->refObjects.first()->location.start;
1070 QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url)
1072 for (int ii = 0; ii < m_qmldirs.count(); ++ii) {
1073 if (m_qmldirs.at(ii)->url() == url)
1074 return m_qmldirs.at(ii);
1079 QDeclarativeScriptData::QDeclarativeScriptData(QDeclarativeEngine *engine)
1080 : QDeclarativeCleanup(engine), importCache(0), pragmas(QDeclarativeParser::Object::ScriptBlock::None),
1085 QDeclarativeScriptData::~QDeclarativeScriptData()
1090 void QDeclarativeScriptData::clear()
1093 importCache->release();
1097 for (int ii = 0; ii < scripts.count(); ++ii)
1098 scripts.at(ii)->release();
1101 qPersistentDispose(m_program);
1102 qPersistentDispose(m_value);
1105 QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
1106 : QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None),
1107 m_scriptData(0), m_typeLoader(loader)
1111 QDeclarativeScriptBlob::~QDeclarativeScriptBlob()
1114 m_scriptData->release();
1119 QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptBlob::pragmas() const
1124 QString QDeclarativeScriptBlob::scriptSource() const
1129 QDeclarativeTypeLoader *QDeclarativeScriptBlob::typeLoader() const
1131 return m_typeLoader;
1134 const QDeclarativeImports &QDeclarativeScriptBlob::imports() const
1139 QDeclarativeScriptData *QDeclarativeScriptBlob::scriptData() const
1141 return m_scriptData;
1144 void QDeclarativeScriptBlob::dataReceived(const QByteArray &data)
1146 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine());
1147 QDeclarativeImportDatabase *importDatabase = &ep->importDatabase;
1149 m_source = QString::fromUtf8(data);
1151 QDeclarativeScriptParser::JavaScriptMetaData metadata =
1152 QDeclarativeScriptParser::extractMetaData(m_source);
1154 m_imports.setBaseUrl(finalUrl());
1156 m_pragmas = metadata.pragmas;
1158 foreach (const QDeclarativeScriptParser::Import &import, metadata.imports) {
1159 Q_ASSERT(import.type != QDeclarativeScriptParser::Import::File);
1161 if (import.type == QDeclarativeScriptParser::Import::Script) {
1162 QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
1163 QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
1164 addDependency(blob);
1166 ScriptReference ref;
1167 ref.location = import.location.start;
1168 ref.qualifier = import.qualifier;
1173 Q_ASSERT(import.type == QDeclarativeScriptParser::Import::Library);
1176 import.extractVersion(&vmaj, &vmin);
1178 QList<QDeclarativeError> errors;
1179 if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
1180 import.type, QDeclarativeDirComponents(), &errors)) {
1181 QDeclarativeError error = errors.takeFirst();
1182 // description should be set by addImport().
1183 error.setUrl(m_imports.baseUrl());
1184 error.setLine(import.location.start.line);
1185 error.setColumn(import.location.start.column);
1186 errors.prepend(error);
1195 void QDeclarativeScriptBlob::done()
1197 // Check all script dependencies for errors
1198 for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
1199 const ScriptReference &script = m_scripts.at(ii);
1200 Q_ASSERT(script.script->isCompleteOrError());
1201 if (script.script->isError()) {
1202 QList<QDeclarativeError> errors = script.script->errors();
1203 QDeclarativeError error;
1204 error.setUrl(finalUrl());
1205 error.setLine(script.location.line);
1206 error.setColumn(script.location.column);
1207 error.setDescription(typeLoader()->tr("Script %1 unavailable").arg(script.script->url().toString()));
1208 errors.prepend(error);
1216 QDeclarativeEngine *engine = typeLoader()->engine();
1217 m_scriptData = new QDeclarativeScriptData(engine);
1218 m_scriptData->url = finalUrl();
1219 m_scriptData->importCache = new QDeclarativeTypeNameCache(engine);
1221 for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
1222 const ScriptReference &script = m_scripts.at(ii);
1224 m_scriptData->scripts.append(script.script);
1225 m_scriptData->importCache->add(script.qualifier, ii);
1228 m_imports.populateCache(m_scriptData->importCache, engine);
1230 m_scriptData->pragmas = m_pragmas;
1232 // XXX TODO: Handle errors that occur duing the script compile
1233 QV8Engine *v8engine = QDeclarativeEnginePrivate::get(engine)->v8engine();
1234 v8::HandleScope handle_scope;
1235 v8::Context::Scope scope(v8engine->context());
1236 v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_source, finalUrl().toString(), 1);
1237 m_scriptData->m_program = qPersistentNew<v8::Script>(program);
1240 QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
1241 : QDeclarativeDataBlob(url, QmldirFile)
1245 const QDeclarativeDirComponents &QDeclarativeQmldirData::dirComponents() const
1247 return m_components;
1250 void QDeclarativeQmldirData::dataReceived(const QByteArray &data)
1252 QDeclarativeDirParser parser;
1253 parser.setSource(QString::fromUtf8(data));
1255 m_components = parser.components();