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 "qdeclarativeimport_p.h"
44 #include <QtCore/qdebug.h>
45 #include <QtCore/qdir.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qpluginloader.h>
48 #include <QtCore/qlibraryinfo.h>
49 #include <QtDeclarative/qdeclarativeextensioninterface.h>
50 #include <private/qdeclarativeglobal_p.h>
51 #include <private/qdeclarativetypenamecache_p.h>
52 #include <private/qdeclarativeengine_p.h>
55 #include "private/qcore_symbian_p.h"
60 DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE)
61 DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES)
63 static bool greaterThan(const QString &s1, const QString &s2)
68 typedef QMap<QString, QString> StringStringMap;
69 Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri
71 class QDeclarativeImportedNamespace
76 QList<int> majversions;
77 QList<int> minversions;
78 QList<bool> isLibrary;
79 QList<QDeclarativeDirComponents> qmlDirComponents;
82 bool find_helper(int i, const QByteArray& type, int *vmajor, int *vminor,
83 QDeclarativeType** type_return, QUrl* url_return,
84 QUrl *base = 0, bool *typeRecursionDetected = 0);
85 bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
86 QUrl* url_return, QUrl *base = 0, QString *errorString = 0);
89 class QDeclarativeImportsPrivate {
91 QDeclarativeImportsPrivate();
92 ~QDeclarativeImportsPrivate();
94 bool importExtension(const QString &absoluteFilePath, const QString &uri,
95 QDeclarativeImportDatabase *database, QDeclarativeDirComponents* components,
96 QString *errorString);
98 QString resolvedUri(const QString &dir_arg, QDeclarativeImportDatabase *database);
99 bool add(const QDeclarativeDirComponents &qmldircomponentsnetwork,
100 const QString& uri_arg, const QString& prefix,
101 int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType,
102 QDeclarativeImportDatabase *database, QString *errorString);
103 bool find(const QByteArray& type, int *vmajor, int *vminor,
104 QDeclarativeType** type_return, QUrl* url_return, QString *errorString);
106 QDeclarativeImportedNamespace *findNamespace(const QString& type);
111 QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded;
112 QDeclarativeImportedNamespace unqualifiedset;
113 QHash<QString,QDeclarativeImportedNamespace* > set;
117 \class QDeclarativeImports
118 \brief The QDeclarativeImports class encapsulates one QML document's import statements.
121 QDeclarativeImports::QDeclarativeImports(const QDeclarativeImports ©)
127 QDeclarativeImports &
128 QDeclarativeImports::operator =(const QDeclarativeImports ©)
137 QDeclarativeImports::QDeclarativeImports()
138 : d(new QDeclarativeImportsPrivate)
142 QDeclarativeImports::~QDeclarativeImports()
149 Sets the base URL to be used for all relative file imports added.
151 void QDeclarativeImports::setBaseUrl(const QUrl& url)
157 Returns the base URL to be used for all relative file imports added.
159 QUrl QDeclarativeImports::baseUrl() const
164 static QDeclarativeTypeNameCache *
165 cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespace &set,
166 QDeclarativeTypeNameCache *cache)
169 cache = new QDeclarativeTypeNameCache(engine);
171 QList<QDeclarativeType *> types = QDeclarativeMetaType::qmlTypes();
173 for (int ii = 0; ii < set.uris.count(); ++ii) {
174 QByteArray base = set.uris.at(ii).toUtf8() + '/';
175 int major = set.majversions.at(ii);
176 int minor = set.minversions.at(ii);
178 foreach (QDeclarativeType *type, types) {
179 if (type->qmlTypeName().startsWith(base) &&
180 type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) &&
181 type->availableInVersion(major,minor))
183 QString name = QString::fromUtf8(type->qmlTypeName().mid(base.length()));
185 cache->add(name, type);
193 void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *engine) const
195 const QDeclarativeImportedNamespace &set = d->unqualifiedset;
197 for (QHash<QString,QDeclarativeImportedNamespace* >::ConstIterator iter = d->set.begin();
198 iter != d->set.end(); ++iter) {
200 QDeclarativeTypeNameCache::Data *d = cache->data(iter.key());
202 if (!d->typeNamespace)
203 cacheForNamespace(engine, *(*iter), d->typeNamespace);
205 QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0);
206 cache->add(iter.key(), nc);
211 cacheForNamespace(engine, set, cache);
217 The given (namespace qualified) \a type is resolved to either
219 \o a QDeclarativeImportedNamespace stored at \a ns_return,
220 \o a QDeclarativeType stored at \a type_return, or
221 \o a component located at \a url_return.
224 If any return pointer is 0, the corresponding search is not done.
228 bool QDeclarativeImports::resolveType(const QByteArray& type,
229 QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin,
230 QDeclarativeImportedNamespace** ns_return, QString *errorString) const
232 QDeclarativeImportedNamespace* ns = d->findNamespace(QString::fromUtf8(type));
238 if (type_return || url_return) {
239 if (d->find(type,vmaj,vmin,type_return,url_return, errorString)) {
240 if (qmlImportTrace()) {
241 if (type_return && *type_return && url_return && !url_return->isEmpty())
242 qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
243 << type << " => " << (*type_return)->typeName() << " " << *url_return;
244 if (type_return && *type_return)
245 qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
246 << type << " => " << (*type_return)->typeName();
247 if (url_return && !url_return->isEmpty())
248 qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
249 << type << " => " << *url_return;
260 Searching \e only in the namespace \a ns (previously returned in a call to
261 resolveType(), \a type is found and returned to either
262 a QDeclarativeType stored at \a type_return, or
263 a component located at \a url_return.
265 If either return pointer is 0, the corresponding search is not done.
267 bool QDeclarativeImports::resolveType(QDeclarativeImportedNamespace* ns, const QByteArray& type,
268 QDeclarativeType** type_return, QUrl* url_return,
269 int *vmaj, int *vmin) const
271 return ns->find(type,vmaj,vmin,type_return,url_return);
274 bool QDeclarativeImportedNamespace::find_helper(int i, const QByteArray& type, int *vmajor, int *vminor,
275 QDeclarativeType** type_return, QUrl* url_return,
276 QUrl *base, bool *typeRecursionDetected)
278 int vmaj = majversions.at(i);
279 int vmin = minversions.at(i);
281 QByteArray qt = uris.at(i).toUtf8();
285 QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin);
287 if (vmajor) *vmajor = vmaj;
288 if (vminor) *vminor = vmin;
294 QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
295 QDeclarativeDirComponents qmldircomponents = qmlDirComponents.at(i);
297 bool typeWasDeclaredInQmldir = false;
298 if (!qmldircomponents.isEmpty()) {
299 const QString typeName = QString::fromUtf8(type);
300 foreach (const QDeclarativeDirParser::Component &c, qmldircomponents) {
301 if (c.typeName == typeName) {
302 typeWasDeclaredInQmldir = true;
304 // importing version -1 means import ALL versions
305 if ((vmaj == -1) || (c.majorVersion < vmaj || (c.majorVersion == vmaj && vmin >= c.minorVersion))) {
306 QUrl candidate = url.resolved(QUrl(c.fileName));
307 if (c.internal && base) {
308 if (base->resolved(QUrl(c.fileName)) != candidate)
309 continue; // failed attempt to access an internal type
311 if (base && *base == candidate) {
312 if (typeRecursionDetected)
313 *typeRecursionDetected = true;
314 continue; // no recursion
317 *url_return = candidate;
324 if (!typeWasDeclaredInQmldir && !isLibrary.at(i)) {
325 // XXX search non-files too! (eg. zip files, see QT-524)
326 QFileInfo f(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url));
328 if (base && *base == url) { // no recursion
329 if (typeRecursionDetected)
330 *typeRecursionDetected = true;
341 QDeclarativeImportsPrivate::QDeclarativeImportsPrivate()
346 QDeclarativeImportsPrivate::~QDeclarativeImportsPrivate()
348 foreach (QDeclarativeImportedNamespace* s, set.values())
352 bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri,
353 QDeclarativeImportDatabase *database,
354 QDeclarativeDirComponents* components, QString *errorString)
356 QFile file(absoluteFilePath);
358 if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
360 *errorString = QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath);
362 } else if (file.open(QFile::ReadOnly)) {
363 filecontent = QString::fromUtf8(file.readAll());
364 if (qmlImportTrace())
365 qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base.toString()) << "::importExtension: "
366 << "loaded " << absoluteFilePath;
369 *errorString = QDeclarativeImportDatabase::tr("module \"%1\" definition \"%2\" not readable").arg(uri).arg(absoluteFilePath);
372 QDir dir = QFileInfo(file).dir();
374 QDeclarativeDirParser qmldirParser;
375 qmldirParser.setSource(filecontent);
376 qmldirParser.parse();
378 if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) {
379 qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath);
382 foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser.plugins()) {
384 QString resolvedFilePath = database->resolvePlugin(dir, plugin.path, plugin.name);
385 #if defined(QT_LIBINFIX) && defined(Q_OS_SYMBIAN)
386 if (resolvedFilePath.isEmpty()) {
387 // In case of libinfixed build, attempt to load libinfixed version, too.
388 QString infixedPluginName = plugin.name + QLatin1String(QT_LIBINFIX);
389 resolvedFilePath = database->resolvePlugin(dir, plugin.path, infixedPluginName);
392 if (!resolvedFilePath.isEmpty()) {
393 if (!database->importPlugin(resolvedFilePath, uri, errorString)) {
395 *errorString = QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(*errorString);
400 *errorString = QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name);
407 *components = qmldirParser.components();
412 QString QDeclarativeImportsPrivate::resolvedUri(const QString &dir_arg, QDeclarativeImportDatabase *database)
414 QString dir = dir_arg;
415 if (dir.endsWith(QLatin1Char('/')) || dir.endsWith(QLatin1Char('\\')))
418 QStringList paths = database->fileImportPath;
419 qSort(paths.begin(), paths.end(), greaterThan); // Ensure subdirs preceed their parents.
421 QString stableRelativePath = dir;
422 foreach(const QString &path, paths) {
423 if (dir.startsWith(path)) {
424 stableRelativePath = dir.mid(path.length()+1);
429 stableRelativePath.replace(QLatin1Char('\\'), QLatin1Char('/'));
431 // remove optional versioning in dot notation from uri
432 int lastSlash = stableRelativePath.lastIndexOf(QLatin1Char('/'));
433 if (lastSlash >= 0) {
434 int versionDot = stableRelativePath.indexOf(QLatin1Char('.'), lastSlash);
436 stableRelativePath = stableRelativePath.left(versionDot);
439 stableRelativePath.replace(QLatin1Char('/'), QLatin1Char('.'));
440 return stableRelativePath;
443 bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomponentsnetwork,
444 const QString& uri_arg, const QString& prefix, int vmaj, int vmin,
445 QDeclarativeScriptParser::Import::Type importType,
446 QDeclarativeImportDatabase *database, QString *errorString)
448 QDeclarativeDirComponents qmldircomponents = qmldircomponentsnetwork;
449 QString uri = uri_arg;
450 QDeclarativeImportedNamespace *s;
451 if (prefix.isEmpty()) {
454 s = set.value(prefix);
456 set.insert(prefix,(s=new QDeclarativeImportedNamespace));
460 bool versionFound = false;
461 if (importType == QDeclarativeScriptParser::Import::Library) {
462 url.replace(QLatin1Char('.'), QLatin1Char('/'));
467 // step 1: search for extension with fully encoded version number
468 if (vmaj >= 0 && vmin >= 0) {
469 foreach (const QString &p, database->fileImportPath) {
470 dir = p+QLatin1Char('/')+url;
472 QFileInfo fi(dir+QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin)+QLatin1String("/qmldir"));
473 const QString absoluteFilePath = fi.absoluteFilePath();
478 url = QUrl::fromLocalFile(fi.absolutePath()).toString();
479 uri = resolvedUri(dir, database);
480 if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
486 // step 2: search for extension with encoded version major
487 if (vmaj >= 0 && vmin >= 0) {
488 foreach (const QString &p, database->fileImportPath) {
489 dir = p+QLatin1Char('/')+url;
491 QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir"));
492 const QString absoluteFilePath = fi.absoluteFilePath();
497 url = QUrl::fromLocalFile(fi.absolutePath()).toString();
498 uri = resolvedUri(dir, database);
499 if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
506 // step 3: search for extension without version number
508 foreach (const QString &p, database->fileImportPath) {
509 dir = p+QLatin1Char('/')+url;
511 QFileInfo fi(dir+QLatin1String("/qmldir"));
512 const QString absoluteFilePath = fi.absoluteFilePath();
517 url = QUrl::fromLocalFile(fi.absolutePath()).toString();
518 uri = resolvedUri(dir, database);
519 if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
526 if (QDeclarativeMetaType::isModule(uri.toUtf8(), vmaj, vmin))
529 if (!versionFound && qmldircomponents.isEmpty()) {
531 bool anyversion = QDeclarativeMetaType::isModule(uri.toUtf8(), -1, -1);
533 *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
535 *errorString = QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg);
541 if (importType == QDeclarativeScriptParser::Import::File && qmldircomponents.isEmpty()) {
542 QUrl importUrl = base.resolved(QUrl(uri + QLatin1String("/qmldir")));
543 QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl);
544 if (!localFileOrQrc.isEmpty()) {
545 QString dir = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
546 QFileInfo dirinfo(dir);
547 if (dir.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
549 *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg);
550 return false; // local import dirs must exist
552 uri = resolvedUri(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))), database);
553 if (uri.endsWith(QLatin1Char('/')))
555 if (QFile::exists(localFileOrQrc)) {
556 if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errorString))
560 if (prefix.isEmpty()) {
561 // directory must at least exist for valid import
562 QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
563 QFileInfo dirinfo(localFileOrQrc);
564 if (localFileOrQrc.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
566 if (localFileOrQrc.isEmpty())
567 *errorString = QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri);
569 *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri);
577 url = base.resolved(QUrl(url)).toString();
578 if (url.endsWith(QLatin1Char('/')))
582 if (!versionFound && vmaj > -1 && vmin > -1 && !qmldircomponents.isEmpty()) {
583 QList<QDeclarativeDirParser::Component>::ConstIterator it = qmldircomponents.begin();
584 int lowest_maj = INT_MAX;
585 int lowest_min = INT_MAX;
586 int highest_maj = INT_MIN;
587 int highest_min = INT_MIN;
588 for (; it != qmldircomponents.end(); ++it) {
589 if (it->majorVersion > highest_maj || (it->majorVersion == highest_maj && it->minorVersion > highest_min)) {
590 highest_maj = it->majorVersion;
591 highest_min = it->minorVersion;
593 if (it->majorVersion < lowest_maj || (it->majorVersion == lowest_maj && it->minorVersion < lowest_min)) {
594 lowest_maj = it->majorVersion;
595 lowest_min = it->minorVersion;
598 if (lowest_maj > vmaj || (lowest_maj == vmaj && lowest_min > vmin)
599 || highest_maj < vmaj || (highest_maj == vmaj && highest_min < vmin))
601 *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
606 s->uris.prepend(uri);
607 s->urls.prepend(url);
608 s->majversions.prepend(vmaj);
609 s->minversions.prepend(vmin);
610 s->isLibrary.prepend(importType == QDeclarativeScriptParser::Import::Library);
611 s->qmlDirComponents.prepend(qmldircomponents);
615 bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
616 QUrl* url_return, QString *errorString)
618 QDeclarativeImportedNamespace *s = 0;
619 int slash = type.indexOf('/');
621 QString namespaceName = QString::fromUtf8(type.left(slash));
622 s = set.value(namespaceName);
625 *errorString = QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName);
628 int nslash = type.indexOf('/',slash+1);
631 *errorString = QDeclarativeImportDatabase::tr("- nested namespaces not allowed");
637 QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
639 if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errorString))
641 if (s->urls.count() == 1 && !s->isLibrary[0] && url_return && s != &unqualifiedset) {
642 // qualified, and only 1 url
643 *url_return = QUrl(s->urls[0]+QLatin1Char('/')).resolved(QUrl(QString::fromUtf8(unqualifiedtype) + QLatin1String(".qml")));
651 QDeclarativeImportedNamespace *QDeclarativeImportsPrivate::findNamespace(const QString& type)
653 return set.value(type);
656 bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
657 QUrl* url_return, QUrl *base, QString *errorString)
659 bool typeRecursionDetected = false;
660 for (int i=0; i<urls.count(); ++i) {
661 if (find_helper(i, type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) {
662 if (qmlCheckTypes()) {
663 // check for type clashes
664 for (int j = i+1; j<urls.count(); ++j) {
665 if (find_helper(j, type, vmajor, vminor, 0, 0, base)) {
667 QString u1 = urls.at(i);
668 QString u2 = urls.at(j);
670 QString b = base->toString();
671 int slash = b.lastIndexOf(QLatin1Char('/'));
674 QString l = b.left(slash);
675 if (u1.startsWith(b))
676 u1 = u1.mid(b.count());
678 u1 = QDeclarativeImportDatabase::tr("local directory");
679 if (u2.startsWith(b))
680 u2 = u2.mid(b.count());
682 u2 = QDeclarativeImportDatabase::tr("local directory");
688 = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2")
692 = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
694 .arg(majversions.at(i)).arg(minversions.at(i))
695 .arg(majversions.at(j)).arg(minversions.at(j));
705 if (typeRecursionDetected)
706 *errorString = QDeclarativeImportDatabase::tr("is instantiated recursively");
708 *errorString = QDeclarativeImportDatabase::tr("is not a type");
714 \class QDeclarativeImportDatabase
715 \brief The QDeclarativeImportDatabase class manages the QML imports for a QDeclarativeEngine.
718 QDeclarativeImportDatabase::QDeclarativeImportDatabase(QDeclarativeEngine *e)
721 filePluginPath << QLatin1String(".");
723 // Search order is applicationDirPath(), $QML_IMPORT_PATH, QLibraryInfo::ImportsPath
725 #ifndef QT_NO_SETTINGS
726 QString installImportsPath = QLibraryInfo::location(QLibraryInfo::ImportsPath);
728 #if defined(Q_OS_SYMBIAN)
729 // Append imports path for all available drives in Symbian
730 if (installImportsPath.at(1) != QChar(QLatin1Char(':'))) {
731 QString tempPath = installImportsPath;
732 if (tempPath.at(tempPath.length() - 1) != QDir::separator()) {
733 tempPath += QDir::separator();
735 RFs& fs = qt_s60GetRFs();
736 TPtrC tempPathPtr(reinterpret_cast<const TText*> (tempPath.constData()));
737 TFindFile finder(fs);
738 TInt err = finder.FindByDir(tempPathPtr, tempPathPtr);
739 while (err == KErrNone) {
740 QString foundDir(reinterpret_cast<const QChar *>(finder.File().Ptr()),
741 finder.File().Length());
742 foundDir = QDir(foundDir).canonicalPath();
743 addImportPath(foundDir);
747 addImportPath(installImportsPath);
750 addImportPath(installImportsPath);
753 #endif // QT_NO_SETTINGS
756 QByteArray envImportPath = qgetenv("QML_IMPORT_PATH");
757 if (!envImportPath.isEmpty()) {
758 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
759 QLatin1Char pathSep(';');
761 QLatin1Char pathSep(':');
763 QStringList paths = QString::fromLatin1(envImportPath).split(pathSep, QString::SkipEmptyParts);
764 for (int ii = paths.count() - 1; ii >= 0; --ii)
765 addImportPath(paths.at(ii));
768 addImportPath(QCoreApplication::applicationDirPath());
771 QDeclarativeImportDatabase::~QDeclarativeImportDatabase()
778 Adds information to \a imports such that subsequent calls to resolveType()
779 will resolve types qualified by \a prefix by considering types found at the given \a uri.
781 The uri is either a directory (if importType is FileImport), or a URI resolved using paths
782 added via addImportPath() (if importType is LibraryImport).
784 The \a prefix may be empty, in which case the import location is considered for
787 The base URL must already have been set with Import::setBaseUrl().
789 bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
790 const QString& uri, const QString& prefix, int vmaj, int vmin,
791 QDeclarativeScriptParser::Import::Type importType,
792 const QDeclarativeDirComponents &qmldircomponentsnetwork,
793 QString *errorString)
795 if (qmlImportTrace())
796 qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: "
797 << uri << " " << vmaj << '.' << vmin << " "
798 << (importType==QDeclarativeScriptParser::Import::Library? "Library" : "File")
801 return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errorString);
807 Returns the result of the merge of \a baseName with \a path, \a suffixes, and \a prefix.
808 The \a prefix must contain the dot.
810 \a qmldirPath is the location of the qmldir file.
812 QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath,
813 const QString &baseName, const QStringList &suffixes,
814 const QString &prefix)
816 QStringList searchPaths = filePluginPath;
817 bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath);
818 if (!qmldirPluginPathIsRelative)
819 searchPaths.prepend(qmldirPluginPath);
821 foreach (const QString &pluginPath, searchPaths) {
823 QString resolvedPath;
825 if (pluginPath == QLatin1String(".")) {
826 if (qmldirPluginPathIsRelative)
827 resolvedPath = qmldirPath.absoluteFilePath(qmldirPluginPath);
829 resolvedPath = qmldirPath.absolutePath();
831 resolvedPath = pluginPath;
834 // hack for resources, should probably go away
835 if (resolvedPath.startsWith(QLatin1Char(':')))
836 resolvedPath = QCoreApplication::applicationDirPath();
838 QDir dir(resolvedPath);
839 foreach (const QString &suffix, suffixes) {
840 QString pluginFileName = prefix;
842 pluginFileName += baseName;
843 pluginFileName += suffix;
845 QFileInfo fileInfo(dir, pluginFileName);
847 if (fileInfo.exists())
848 return fileInfo.absoluteFilePath();
852 if (qmlImportTrace())
853 qDebug() << "QDeclarativeImportDatabase::resolvePlugin: Could not resolve plugin" << baseName
854 << "in" << qmldirPath.absolutePath();
862 Returns the result of the merge of \a baseName with \a dir and the platform suffix.
865 \header \i Platform \i Valid suffixes
866 \row \i Windows \i \c .dll
867 \row \i Unix/Linux \i \c .so
869 \row \i HP-UX \i \c .sl, \c .so (HP-UXi)
870 \row \i Mac OS X \i \c .dylib, \c .bundle, \c .so
871 \row \i Symbian \i \c .dll
874 Version number on unix are ignored.
876 QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath,
877 const QString &baseName)
879 #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
880 return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
883 << QLatin1String("d.dll") // try a qmake-style debug build first
885 << QLatin1String(".dll"));
886 #elif defined(Q_OS_SYMBIAN)
887 return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
889 << QLatin1String(".dll")
890 << QLatin1String(".qtplugin"));
893 # if defined(Q_OS_DARWIN)
895 return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
898 << QLatin1String("_debug.dylib") // try a qmake-style debug build first
899 << QLatin1String(".dylib")
901 << QLatin1String(".dylib")
902 << QLatin1String("_debug.dylib") // try a qmake-style debug build after
904 << QLatin1String(".so")
905 << QLatin1String(".bundle"),
906 QLatin1String("lib"));
907 # else // Generic Unix
908 QStringList validSuffixList;
910 # if defined(Q_OS_HPUX)
912 See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF":
913 "In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit),
914 the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix."
916 validSuffixList << QLatin1String(".sl");
918 validSuffixList << QLatin1String(".so");
920 # elif defined(Q_OS_AIX)
921 validSuffixList << QLatin1String(".a") << QLatin1String(".so");
922 # elif defined(Q_OS_UNIX)
923 validSuffixList << QLatin1String(".so");
926 // Examples of valid library names:
929 return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib"));
938 QStringList QDeclarativeImportDatabase::pluginPathList() const
940 return filePluginPath;
946 void QDeclarativeImportDatabase::setPluginPathList(const QStringList &paths)
948 filePluginPath = paths;
954 void QDeclarativeImportDatabase::addPluginPath(const QString& path)
956 if (qmlImportTrace())
957 qDebug().nospace() << "QDeclarativeImportDatabase::addPluginPath: " << path;
959 QUrl url = QUrl(path);
960 if (url.isRelative() || url.scheme() == QLatin1String("file")
961 || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
962 QDir dir = QDir(path);
963 filePluginPath.prepend(dir.canonicalPath());
965 filePluginPath.prepend(path);
972 void QDeclarativeImportDatabase::addImportPath(const QString& path)
974 if (qmlImportTrace())
975 qDebug().nospace() << "QDeclarativeImportDatabase::addImportPath: " << path;
980 QUrl url = QUrl(path);
983 if (url.isRelative() || url.scheme() == QLatin1String("file")
984 || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
985 QDir dir = QDir(path);
986 cPath = dir.canonicalPath();
989 cPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
993 && !fileImportPath.contains(cPath))
994 fileImportPath.prepend(cPath);
1000 QStringList QDeclarativeImportDatabase::importPathList() const
1002 return fileImportPath;
1008 void QDeclarativeImportDatabase::setImportPathList(const QStringList &paths)
1010 fileImportPath = paths;
1016 bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
1018 if (qmlImportTrace())
1019 qDebug().nospace() << "QDeclarativeImportDatabase::importPlugin: " << uri << " from " << filePath;
1021 #ifndef QT_NO_LIBRARY
1022 QFileInfo fileInfo(filePath);
1023 const QString absoluteFilePath = fileInfo.absoluteFilePath();
1025 bool engineInitialized = initializedPlugins.contains(absoluteFilePath);
1026 bool typesRegistered = qmlEnginePluginsWithRegisteredTypes()->contains(absoluteFilePath);
1028 if (typesRegistered) {
1029 Q_ASSERT_X(qmlEnginePluginsWithRegisteredTypes()->value(absoluteFilePath) == uri,
1030 "QDeclarativeImportDatabase::importExtension",
1031 "Internal error: Plugin imported previously with different uri");
1034 if (!engineInitialized || !typesRegistered) {
1035 if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
1037 *errorString = tr("File name case mismatch for \"%2\"").arg(absoluteFilePath);
1040 QPluginLoader loader(absoluteFilePath);
1042 if (!loader.load()) {
1044 *errorString = loader.errorString();
1048 if (QDeclarativeExtensionInterface *iface = qobject_cast<QDeclarativeExtensionInterface *>(loader.instance())) {
1050 const QByteArray bytes = uri.toUtf8();
1051 const char *moduleId = bytes.constData();
1052 if (!typesRegistered) {
1054 // ### this code should probably be protected with a mutex.
1055 qmlEnginePluginsWithRegisteredTypes()->insert(absoluteFilePath, uri);
1056 iface->registerTypes(moduleId);
1058 if (!engineInitialized) {
1059 // things on the engine (eg. adding new global objects) have to be done for every engine.
1061 // protect against double initialization
1062 initializedPlugins.insert(absoluteFilePath);
1063 iface->initializeEngine(engine, moduleId);
1067 *errorString = loader.errorString();