diff options
Diffstat (limited to 'src/declarative/qml/qdeclarativetypeloader.cpp')
-rw-r--r-- | src/declarative/qml/qdeclarativetypeloader.cpp | 244 |
1 files changed, 199 insertions, 45 deletions
diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp index 168c1512e2..a413305e28 100644 --- a/src/declarative/qml/qdeclarativetypeloader.cpp +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -609,7 +609,7 @@ void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArra if (!blob->isError() && !blob->isWaiting()) blob->allDependenciesDone(); - if (blob->status() != QDeclarativeDataBlob::Error) + if (blob->status() != QDeclarativeDataBlob::Error) blob->m_status = QDeclarativeDataBlob::WaitingForDependencies; blob->m_inCallback = false; @@ -680,24 +680,23 @@ QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const } /*! -Returns a QDeclarativeScriptData for \a url. The QDeclarativeScriptData may be cached. +Return a QDeclarativeScriptBlob for \a url. The QDeclarativeScriptData may be cached. */ -QDeclarativeScriptData *QDeclarativeTypeLoader::getScript(const QUrl &url) +QDeclarativeScriptBlob *QDeclarativeTypeLoader::getScript(const QUrl &url) { Q_ASSERT(!url.isRelative() && (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() || !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url)))); - QDeclarativeScriptData *scriptData = m_scriptCache.value(url); + QDeclarativeScriptBlob *scriptBlob = m_scriptCache.value(url); - if (!scriptData) { - scriptData = new QDeclarativeScriptData(url); - m_scriptCache.insert(url, scriptData); - QDeclarativeDataLoader::load(scriptData); + if (!scriptBlob) { + scriptBlob = new QDeclarativeScriptBlob(url, this); + m_scriptCache.insert(url, scriptBlob); + QDeclarativeDataLoader::load(scriptBlob); } - scriptData->addref(); - return scriptData; + return scriptBlob; } /*! @@ -878,13 +877,14 @@ void QDeclarativeTypeData::dataReceived(const QByteArray &data) } } else if (import.type == QDeclarativeScriptParser::Import::Script) { QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri)); - QDeclarativeScriptData *data = typeLoader()->getScript(scriptUrl); - addDependency(data); + QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl); + addDependency(blob); ScriptReference ref; ref.location = import.location.start; ref.qualifier = import.qualifier; - ref.script = data; + ref.script = blob; + blob->addref(); m_scripts << ref; } @@ -943,14 +943,31 @@ void QDeclarativeTypeData::resolveTypes() // For local urls, add an implicit import "." as first (most overridden) lookup. // This will also trigger the loading of the qmldir and the import of any native // types from available plugins. + QList<QDeclarativeError> errors; if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) { m_imports.addImport(importDatabase, QLatin1String("."), QString(), -1, -1, QDeclarativeScriptParser::Import::File, - qmldir->dirComponents(), 0); + qmldir->dirComponents(), &errors); } else { m_imports.addImport(importDatabase, QLatin1String("."), QString(), -1, -1, QDeclarativeScriptParser::Import::File, - QDeclarativeDirComponents(), 0); + QDeclarativeDirComponents(), &errors); + } + + // remove any errors which are due to the implicit import which aren't real errors. + // for example, if the implicitly included qmldir file doesn't exist, that is not an error. + QList<QDeclarativeError> realErrors; + for (int i = 0; i < errors.size(); ++i) { + if (errors.at(i).description() != QDeclarativeImportDatabase::tr("import \".\" has no qmldir and no namespace") + && errors.at(i).description() != QDeclarativeImportDatabase::tr("\".\": no such directory")) { + realErrors.prepend(errors.at(i)); // this is a real error. + } + } + + // report any real errors which occurred during plugin loading or qmldir parsing. + if (!realErrors.isEmpty()) { + setError(realErrors); + return; } foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) { @@ -960,34 +977,31 @@ void QDeclarativeTypeData::resolveTypes() if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) { QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir"))); - if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl)) + if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl)) qmldircomponentsnetwork = qmldir->dirComponents(); } int vmaj = -1; int vmin = -1; + import.extractVersion(&vmaj, &vmin); - if (!import.version.isEmpty()) { - int dot = import.version.indexOf(QLatin1Char('.')); - if (dot < 0) { - vmaj = import.version.toInt(); - vmin = 0; - } else { - vmaj = import.version.left(dot).toInt(); - vmin = import.version.mid(dot+1).toInt(); - } - } - - QString errorString; + QList<QDeclarativeError> errors; if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, - vmaj, vmin, import.type, qmldircomponentsnetwork, &errorString)) { + vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) { QDeclarativeError error; + if (errors.size()) { + error = errors.takeFirst(); + } else { + // this should not be possible! + // Description should come from error provided by addImport() function. + error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database")); + } error.setUrl(m_imports.baseUrl()); - error.setDescription(errorString); error.setLine(import.location.start.line); error.setColumn(import.location.start.column); + errors.prepend(error); // put it back on the list after filling out information. - setError(error); + setError(errors); return; } } @@ -1001,29 +1015,38 @@ void QDeclarativeTypeData::resolveTypes() int majorVersion; int minorVersion; QDeclarativeImportedNamespace *typeNamespace = 0; - QString errorString; + QList<QDeclarativeError> errors; if (!m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion, - &typeNamespace, &errorString) || typeNamespace) { + &typeNamespace, &errors) || typeNamespace) { // Known to not be a type: // - known to be a namespace (Namespace {}) // - type with unknown namespace (UnknownNamespace.SomeType {}) QDeclarativeError error; - error.setUrl(m_imports.baseUrl()); QString userTypeName = parserRef->name; userTypeName.replace(QLatin1Char('/'),QLatin1Char('.')); - if (typeNamespace) + if (typeNamespace) { error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName)); - else - error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(errorString)); + } else { + if (errors.size()) { + error = errors.takeFirst(); + } else { + // this should not be possible! + // Description should come from error provided by addImport() function. + error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database")); + } + error.setUrl(m_imports.baseUrl()); + error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(error.description())); + } if (!parserRef->refObjects.isEmpty()) { QDeclarativeParser::Object *obj = parserRef->refObjects.first(); error.setLine(obj->location.start.line); error.setColumn(obj->location.start.column); } - - setError(error); + + errors.prepend(error); + setError(errors); return; } @@ -1056,25 +1079,156 @@ QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url) return 0; } -QDeclarativeScriptData::QDeclarativeScriptData(const QUrl &url) -: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None) +QDeclarativeScriptData::QDeclarativeScriptData(QDeclarativeEngine *engine) +: QDeclarativeCleanup(engine), importCache(0), pragmas(QDeclarativeParser::Object::ScriptBlock::None), + m_loaded(false) +{ +} + +QDeclarativeScriptData::~QDeclarativeScriptData() { + clear(); } -QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptData::pragmas() const +void QDeclarativeScriptData::clear() +{ + if (importCache) { + importCache->release(); + importCache = 0; + } + + for (int ii = 0; ii < scripts.count(); ++ii) + scripts.at(ii)->release(); + scripts.clear(); +} + +QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader) +: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None), + m_scriptData(0), m_typeLoader(loader) +{ +} + +QDeclarativeScriptBlob::~QDeclarativeScriptBlob() +{ + if (m_scriptData) { + m_scriptData->release(); + m_scriptData = 0; + } +} + +QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptBlob::pragmas() const { return m_pragmas; } -QString QDeclarativeScriptData::scriptSource() const +QString QDeclarativeScriptBlob::scriptSource() const { return m_source; } -void QDeclarativeScriptData::dataReceived(const QByteArray &data) +QDeclarativeTypeLoader *QDeclarativeScriptBlob::typeLoader() const +{ + return m_typeLoader; +} + +const QDeclarativeImports &QDeclarativeScriptBlob::imports() const +{ + return m_imports; +} + +QDeclarativeScriptData *QDeclarativeScriptBlob::scriptData() const +{ + return m_scriptData; +} + +void QDeclarativeScriptBlob::dataReceived(const QByteArray &data) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine()); + QDeclarativeImportDatabase *importDatabase = &ep->importDatabase; + m_source = QString::fromUtf8(data); - m_pragmas = QDeclarativeScriptParser::extractPragmas(m_source); + + QDeclarativeScriptParser::JavaScriptMetaData metadata = + QDeclarativeScriptParser::extractMetaData(m_source); + + m_imports.setBaseUrl(finalUrl()); + + m_pragmas = metadata.pragmas; + + foreach (const QDeclarativeScriptParser::Import &import, metadata.imports) { + Q_ASSERT(import.type != QDeclarativeScriptParser::Import::File); + + if (import.type == QDeclarativeScriptParser::Import::Script) { + QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri)); + QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl); + addDependency(blob); + + ScriptReference ref; + ref.location = import.location.start; + ref.qualifier = import.qualifier; + ref.script = blob; + blob->addref(); + m_scripts << ref; + } else { + Q_ASSERT(import.type == QDeclarativeScriptParser::Import::Library); + int vmaj = -1; + int vmin = -1; + import.extractVersion(&vmaj, &vmin); + + QList<QDeclarativeError> errors; + if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin, + import.type, QDeclarativeDirComponents(), &errors)) { + QDeclarativeError error = errors.takeFirst(); + // description should be set by addImport(). + error.setUrl(m_imports.baseUrl()); + error.setLine(import.location.start.line); + error.setColumn(import.location.start.column); + errors.prepend(error); + + setError(errors); + return; + } + } + } +} + +void QDeclarativeScriptBlob::done() +{ + // Check all script dependencies for errors + for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) { + const ScriptReference &script = m_scripts.at(ii); + Q_ASSERT(script.script->isCompleteOrError()); + if (script.script->isError()) { + QList<QDeclarativeError> errors = script.script->errors(); + QDeclarativeError error; + error.setUrl(finalUrl()); + error.setLine(script.location.line); + error.setColumn(script.location.column); + error.setDescription(typeLoader()->tr("Script %1 unavailable").arg(script.script->url().toString())); + errors.prepend(error); + setError(errors); + } + } + + if (isError()) + return; + + QDeclarativeEngine *engine = typeLoader()->engine(); + m_scriptData = new QDeclarativeScriptData(engine); + m_scriptData->url = finalUrl(); + m_scriptData->importCache = new QDeclarativeTypeNameCache(engine); + + for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) { + const ScriptReference &script = m_scripts.at(ii); + + m_scriptData->scripts.append(script.script); + m_scriptData->importCache->add(script.qualifier, ii); + } + + m_imports.populateCache(m_scriptData->importCache, engine); + + m_scriptData->pragmas = m_pragmas; + m_scriptData->m_program = QScriptProgram(m_source, finalUrl().toString()); } QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url) |