forked from qt-creator/qt-creator
qmljs: add infrastructure handling qml dialects better
QmlBundles enables us to treat the different qml dialects differently. Add imports completion. Change-log: [Qml/JS Support] Corrected handling of QtQuick2 only features. Change-log: [Qml/JS Support] Added import completion in editor. Task-number: QTCREATORBUG-8750 Task-number: QTCREATORBUG-8624 Task-number: QTCREATORBUG-8584 Task-number: QTCREATORBUG-8583 Task-number: QTCREATORBUG-8429 Change-Id: I1384b1b23136a85b4d077895ea86f92960da9e71 Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "qbs",
|
||||
"searchPaths": [
|
||||
"$(QBS_IMPORT_PATH)"],
|
||||
"installPaths": [
|
||||
"$(QBS_IMPORT_PATH)"],
|
||||
"implicitImports": [
|
||||
"__javascriptQt5__"],
|
||||
"supportedImports": [
|
||||
"qbs.base 1.0",
|
||||
"qbs 1.0",
|
||||
"qbs.fileinfo 1.0",
|
||||
"qbs.probe 1.0"]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "qmlproject",
|
||||
"searchPaths": [
|
||||
""],
|
||||
"installPaths": [
|
||||
""],
|
||||
"implicitImports": [
|
||||
""],
|
||||
"supportedImports": [
|
||||
"QmlProject 1.0",
|
||||
"QmlProject 1.1"]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name":"qmltypes",
|
||||
"searchPaths":[],
|
||||
"installPaths":[],
|
||||
"implicitImports":[],
|
||||
"supportedImports":[
|
||||
"QtQuick.tooling 1.1",
|
||||
"QtQuick.tooling 1.0"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "QtQuick1",
|
||||
"searchPaths": [
|
||||
"$(QT_INSTALL_IMPORTS)"],
|
||||
"installPaths": [
|
||||
"$(QT_INSTALL_IMPORTS)"],
|
||||
"implicitImports": [
|
||||
"__javascriptQt4__"],
|
||||
"supportedImports": [
|
||||
"QtQuick 1.0",
|
||||
"QtQuick 1.1",
|
||||
"Qt.labs.gestures 1.0",
|
||||
"Qt.labs.particles 1.0",
|
||||
"Qt.labs.shaders 1.0",
|
||||
"Qt.labs.folderlistmodel 1.0",
|
||||
"QtWebKit 1.0"]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "QtQuick1",
|
||||
"searchPaths": [
|
||||
"$(QT_INSTALL_IMPORTS)"],
|
||||
"installPaths": [
|
||||
"$(QT_INSTALL_IMPORTS)"],
|
||||
"implicitImports": [
|
||||
"__javascriptQt5__"],
|
||||
"supportedImports": [
|
||||
"QtQuick 1.1",
|
||||
"Qt.labs.gestures 1.0",
|
||||
"Qt.labs.particles 1.0",
|
||||
"Qt.labs.shaders 1.0",
|
||||
"Qt.labs.folderlistmodel 1.0",
|
||||
"QtWebKit 1.0"]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "QtQuick2",
|
||||
"searchPaths": [
|
||||
"$(QT_INSTALL_QML)"],
|
||||
"installPaths": [
|
||||
"$(QT_INSTALL_QML)"],
|
||||
"implicitImports": [
|
||||
"__javascriptQt5__"],
|
||||
"supportedImports": [
|
||||
"Qt.labs.folderlistmodel 2.0",
|
||||
"QtAudioEngine 1.0",
|
||||
"QtMultimedia 5.0",
|
||||
"QtQuick.LocalStorage 2.0",
|
||||
"QtQuick.Particles 2.0",
|
||||
"QtQuick.Window 2.0",
|
||||
"QtQuick.XmlListModel 2.0",
|
||||
"QtQuick 2.0",
|
||||
"QtTest 1.0",
|
||||
"QtWebKit 3.0"]
|
||||
}
|
||||
@@ -261,6 +261,54 @@ QStringList TrieNode::stringList(const TrieNode::Ptr &trie)
|
||||
return a.res;
|
||||
}
|
||||
|
||||
bool TrieNode::isSame(const TrieNode::Ptr &trie1, const TrieNode::Ptr &trie2)
|
||||
{
|
||||
if (trie1.data() == trie2.data())
|
||||
return true;
|
||||
if (trie1.isNull() || trie2.isNull())
|
||||
return false; // assume never to generate non null empty tries
|
||||
if (trie1->prefix != trie2->prefix)
|
||||
return false; // assume no excess splitting
|
||||
QList<TrieNode::Ptr> t1 = trie1->postfixes, t2 =trie2->postfixes;
|
||||
int nEl = t1.size();
|
||||
if (nEl != t2.size()) return false;
|
||||
// different order = different trie
|
||||
for (int i = 0; i < nEl; ++i) {
|
||||
if (!isSame(t1.value(i), t2.value(i)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class ReplaceInTrie
|
||||
{
|
||||
public:
|
||||
TrieNode::Ptr trie;
|
||||
QHash<QString, QString> replacements;
|
||||
ReplaceInTrie() { }
|
||||
void operator()(QString s)
|
||||
{
|
||||
QHashIterator<QString, QString> i(replacements);
|
||||
QString res = s;
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
res.replace(i.key(), i.value());
|
||||
}
|
||||
trie = TrieNode::insertF(trie,res);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TrieNode::Ptr TrieNode::replaceF(const TrieNode::Ptr &trie, const QHash<QString, QString> &replacements)
|
||||
{
|
||||
// inefficient...
|
||||
ReplaceInTrie rep;
|
||||
rep.replacements = replacements;
|
||||
enumerateTrieNode<ReplaceInTrie>(trie, rep, QString());
|
||||
return rep.trie;
|
||||
}
|
||||
|
||||
std::pair<TrieNode::Ptr,int> TrieNode::intersectF(
|
||||
const TrieNode::Ptr &v1, const TrieNode::Ptr &v2, int index1)
|
||||
{
|
||||
@@ -553,6 +601,26 @@ void Trie::merge(const Trie &v)
|
||||
trie = TrieNode::mergeF(trie, v.trie).first;
|
||||
}
|
||||
|
||||
void Trie::replace(const QHash<QString, QString> &replacements)
|
||||
{
|
||||
trie = TrieNode::replaceF(trie, replacements);
|
||||
}
|
||||
|
||||
bool Trie::isEmpty() const
|
||||
{
|
||||
return trie.isNull(); // assuming to never generate an empty non null trie
|
||||
}
|
||||
|
||||
bool Trie::operator==(const Trie &o)
|
||||
{
|
||||
return TrieNode::isSame(trie,o.trie);
|
||||
}
|
||||
|
||||
bool Trie::operator!=(const Trie &o)
|
||||
{
|
||||
return !TrieNode::isSame(trie,o.trie);
|
||||
}
|
||||
|
||||
Trie Trie::insertF(const QString &value) const
|
||||
{
|
||||
return Trie(TrieNode::insertF(trie, value));
|
||||
@@ -568,13 +636,19 @@ Trie Trie::mergeF(const Trie &v) const
|
||||
return Trie(TrieNode::mergeF(trie, v.trie).first);
|
||||
}
|
||||
|
||||
Trie Trie::replaceF(const QHash<QString, QString> &replacements) const
|
||||
{
|
||||
return Trie(TrieNode::replaceF(trie, replacements));
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn int matchStrength(const QString &searchStr, const QString &str)
|
||||
|
||||
Returns a number defining how well the serachStr matches str.
|
||||
|
||||
Quite simplistic, looks only at the first match, and prefers contiguos
|
||||
matches, or matches to ca capitalized or separated word.
|
||||
matches, or matches to capitalized or separated words.
|
||||
Match to the last char is also preferred.
|
||||
*/
|
||||
int matchStrength(const QString &searchStr, const QString &str)
|
||||
{
|
||||
@@ -601,6 +675,8 @@ int matchStrength(const QString &searchStr, const QString &str)
|
||||
}
|
||||
if (i != iEnd)
|
||||
return iEnd - i;
|
||||
if (j == jEnd)
|
||||
++res;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <qmljs/qmljs_global.h>
|
||||
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QSharedPointer>
|
||||
|
||||
@@ -67,7 +68,9 @@ public:
|
||||
const QString &base = QString(), LookupFlags flags = LookupFlags(CaseInsensitive|Partial));
|
||||
static bool contains(const Ptr &trie, const QString &value, LookupFlags flags = LookupFlags(0));
|
||||
static QStringList stringList(const Ptr &trie);
|
||||
static bool isSame(const Ptr &trie1, const Ptr &trie2);
|
||||
|
||||
static Ptr replaceF(const Ptr &trie, const QHash<QString, QString> &replacements);
|
||||
static Ptr insertF(const Ptr &trie, const QString &value);
|
||||
static std::pair<Ptr,int> intersectF(const Ptr &v1, const Ptr &v2, int index1=0);
|
||||
static std::pair<Ptr,int> mergeF(const Ptr &v1, const Ptr &v2);
|
||||
@@ -91,10 +94,16 @@ public:
|
||||
Trie insertF(const QString &value) const;
|
||||
Trie intersectF(const Trie &v) const;
|
||||
Trie mergeF(const Trie &v) const;
|
||||
Trie replaceF(const QHash<QString, QString> &replacements) const;
|
||||
|
||||
void insert(const QString &value);
|
||||
void intersect(const Trie &v);
|
||||
void merge(const Trie &v);
|
||||
void replace(const QHash<QString, QString> &replacements);
|
||||
|
||||
bool isEmpty() const;
|
||||
bool operator==(const Trie &o);
|
||||
bool operator!=(const Trie &o);
|
||||
|
||||
friend QMLJS_EXPORT QDebug &operator<<(QDebug &dbg, const TrieNode::Ptr &trie);
|
||||
friend QMLJS_EXPORT QDebug &operator<<(QDebug &dbg, const Trie &trie);
|
||||
|
||||
@@ -11,6 +11,7 @@ INCLUDEPATH += $$PWD/..
|
||||
HEADERS += \
|
||||
$$PWD/qmljs_global.h \
|
||||
$$PWD/qmljsbind.h \
|
||||
$$PWD/qmljsbundle.h \
|
||||
$$PWD/qmljsevaluate.h \
|
||||
$$PWD/qmljsdocument.h \
|
||||
$$PWD/qmljsscanner.h \
|
||||
@@ -42,6 +43,7 @@ HEADERS += \
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/qmljsbind.cpp \
|
||||
$$PWD/qmljsbundle.cpp \
|
||||
$$PWD/qmljsevaluate.cpp \
|
||||
$$PWD/qmljsdocument.cpp \
|
||||
$$PWD/qmljsscanner.cpp \
|
||||
|
||||
@@ -23,6 +23,8 @@ QtcLibrary {
|
||||
"qmljs_global.h",
|
||||
"qmljsbind.cpp",
|
||||
"qmljsbind.h",
|
||||
"qmljsbundle.cpp",
|
||||
"qmljsbundle.h",
|
||||
"qmljscheck.cpp",
|
||||
"qmljscheck.h",
|
||||
"qmljscodeformatter.cpp",
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "qmljsbind.h"
|
||||
#include "qmljsutils.h"
|
||||
#include "qmljsdocument.h"
|
||||
#include "qmljsmodelmanagerinterface.h"
|
||||
|
||||
#include <languageutils/componentversion.h>
|
||||
|
||||
@@ -204,15 +205,27 @@ bool Bind::visit(UiImport *ast)
|
||||
_diagnosticMessages->append(
|
||||
errorMessage(ast, tr("package import requires a version number")));
|
||||
}
|
||||
_imports += ImportInfo::moduleImport(toString(ast->importUri), version,
|
||||
ImportInfo import = ImportInfo::moduleImport(toString(ast->importUri), version,
|
||||
ast->importId.toString(), ast);
|
||||
if (_doc->language() == Document::QmlLanguage) {
|
||||
QString importStr = import.name() + ast->importId.toString();
|
||||
QmlLanguageBundles langBundles = ModelManagerInterface::instance()->extendedBundles();
|
||||
QmlBundle qq1 = langBundles.bundleForLanguage(Document::QmlQtQuick1Language);
|
||||
QmlBundle qq2 = langBundles.bundleForLanguage(Document::QmlQtQuick2Language);
|
||||
bool isQQ1 = qq1.supportedImports().contains(importStr);
|
||||
bool isQQ2 = qq2.supportedImports().contains(importStr);
|
||||
if (isQQ1 && ! isQQ2)
|
||||
_doc->setLanguage(Document::QmlQtQuick1Language);
|
||||
if (isQQ2 && ! isQQ1)
|
||||
_doc->setLanguage(Document::QmlQtQuick2Language);
|
||||
}
|
||||
_imports += import;
|
||||
} else if (!ast->fileName.isEmpty()) {
|
||||
_imports += ImportInfo::pathImport(_doc->path(), ast->fileName.toString(),
|
||||
version, ast->importId.toString(), ast);
|
||||
} else {
|
||||
_imports += ImportInfo::invalidImport(ast);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmljsbundle.h"
|
||||
|
||||
#include <utils/json.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QHash>
|
||||
|
||||
namespace QmlJS {
|
||||
typedef PersistentTrie::Trie Trie;
|
||||
|
||||
QmlBundle::QmlBundle(const QmlBundle &o)
|
||||
: m_name(o.m_name), m_searchPaths(o.searchPaths()), m_installPaths(o.installPaths()),
|
||||
m_supportedImports(o.m_supportedImports), m_implicitImports(o.m_implicitImports)
|
||||
{ }
|
||||
|
||||
QmlBundle::QmlBundle()
|
||||
{ }
|
||||
|
||||
QmlBundle::QmlBundle(const QString &bundleName, const Trie &searchPaths,
|
||||
const Trie &installPaths, const Trie &supportedImports,
|
||||
const Trie &implicitImports)
|
||||
: m_name(bundleName), m_searchPaths(searchPaths), m_installPaths(installPaths),
|
||||
m_supportedImports(supportedImports), m_implicitImports(implicitImports)
|
||||
{ }
|
||||
|
||||
|
||||
QString QmlBundle::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
Trie QmlBundle::installPaths() const
|
||||
{
|
||||
return m_installPaths;
|
||||
}
|
||||
|
||||
Trie QmlBundle::searchPaths() const
|
||||
{
|
||||
return m_searchPaths;
|
||||
}
|
||||
|
||||
Trie QmlBundle::implicitImports() const
|
||||
{
|
||||
return m_implicitImports;
|
||||
}
|
||||
|
||||
|
||||
Trie QmlBundle::supportedImports() const
|
||||
{
|
||||
return m_supportedImports;
|
||||
}
|
||||
|
||||
|
||||
void QmlBundle::merge(const QmlBundle &o)
|
||||
{
|
||||
*this = mergeF(o);
|
||||
}
|
||||
|
||||
|
||||
void QmlBundle::intersect(const QmlBundle &o)
|
||||
{
|
||||
*this = intersectF(o);
|
||||
}
|
||||
|
||||
|
||||
QmlBundle QmlBundle::mergeF(const QmlBundle &o) const
|
||||
{
|
||||
return QmlBundle(QString::fromLatin1("(%1)||(%2)").arg(name()).arg(o.name()),
|
||||
searchPaths().mergeF(o.searchPaths()),
|
||||
installPaths().mergeF(o.installPaths()),
|
||||
supportedImports().mergeF(o.supportedImports()),
|
||||
implicitImports().mergeF(o.implicitImports()));
|
||||
}
|
||||
|
||||
QmlBundle QmlBundle::intersectF(const QmlBundle &o) const
|
||||
{
|
||||
return QmlBundle(QString::fromLatin1("(%1)&&(%2)").arg(name()).arg(o.name()),
|
||||
searchPaths().mergeF(o.searchPaths()),
|
||||
installPaths().mergeF(o.installPaths()),
|
||||
supportedImports().intersectF(o.supportedImports()),
|
||||
implicitImports().mergeF(o.implicitImports()));
|
||||
}
|
||||
|
||||
bool QmlBundle::isEmpty() const
|
||||
{
|
||||
return m_implicitImports.isEmpty() && m_installPaths.isEmpty()
|
||||
&& m_searchPaths.isEmpty() && m_supportedImports.isEmpty();
|
||||
}
|
||||
|
||||
void QmlBundle::replaceVars(const QHash<QString, QString> &replacements)
|
||||
{
|
||||
m_implicitImports.replace(replacements);
|
||||
m_installPaths.replace(replacements);
|
||||
m_searchPaths.replace(replacements);
|
||||
m_supportedImports.replace(replacements);
|
||||
}
|
||||
|
||||
QmlBundle QmlBundle::replaceVarsF(const QHash<QString, QString> &replacements) const
|
||||
{
|
||||
QmlBundle res(*this);
|
||||
res.replaceVars(replacements);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool QmlBundle::writeTo(const QString &path) const
|
||||
{
|
||||
QFile f(path);
|
||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return false;
|
||||
QTextStream stream(&f);
|
||||
return writeTo(stream);
|
||||
}
|
||||
|
||||
bool QmlBundle::operator==(const QmlBundle &o) const
|
||||
{
|
||||
return o.implicitImports() == implicitImports()
|
||||
&& o.installPaths() == installPaths()
|
||||
&& o.supportedImports() == supportedImports(); // name is not considered
|
||||
}
|
||||
|
||||
bool QmlBundle::operator!=(const QmlBundle &o) const
|
||||
{
|
||||
return !((*this) == o);
|
||||
}
|
||||
|
||||
void QmlBundle::printEscaped(QTextStream &s, const QString &str)
|
||||
{
|
||||
s << QLatin1Char('"');
|
||||
QString::const_iterator i = str.constBegin(), iLast = str.constBegin(),
|
||||
iEnd = str.constEnd();
|
||||
while (i != iEnd) {
|
||||
if ((*i) != QLatin1Char('"')) {
|
||||
s << QStringRef(&str, static_cast<int>(iLast - str.constBegin())
|
||||
, static_cast<int>(i - iLast) ).toString()
|
||||
<< QLatin1Char('\\');
|
||||
iLast = i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
s << QStringRef(&str, static_cast<int>(iLast - str.constBegin())
|
||||
, static_cast<int>(i - iLast) ).toString();
|
||||
}
|
||||
|
||||
void QmlBundle::writeTrie(QTextStream &stream, const Trie &t, const QString &indent) {
|
||||
stream << QLatin1Char('[');
|
||||
bool firstLine = true;
|
||||
foreach (const QString &i, t.stringList()) {
|
||||
if (firstLine)
|
||||
firstLine = false;
|
||||
else
|
||||
stream << QLatin1Char(',');
|
||||
stream << QLatin1String("\n") << indent << QLatin1String(" ");
|
||||
printEscaped(stream, i);
|
||||
}
|
||||
stream << QLatin1Char(']');
|
||||
}
|
||||
|
||||
bool QmlBundle::writeTo(QTextStream &stream, const QString &indent) const
|
||||
{
|
||||
QString innerIndent = QString::fromLatin1(" ").append(indent);
|
||||
stream << indent << QLatin1String("{\n")
|
||||
<< indent << QLatin1String(" \"name\": ");
|
||||
printEscaped(stream, name());
|
||||
stream << QLatin1String(",\n")
|
||||
<< indent << QLatin1String(" \"searchPaths\": ");
|
||||
writeTrie(stream, searchPaths(), innerIndent);
|
||||
stream << QLatin1String(",\n")
|
||||
<< indent << QLatin1String(" \"installPaths\": ");
|
||||
writeTrie(stream, installPaths(), innerIndent);
|
||||
stream << QLatin1String(",\n")
|
||||
<< indent << QLatin1String(" \"supportedImports\": ");
|
||||
writeTrie(stream, supportedImports(), innerIndent);
|
||||
stream << QLatin1String(",\n")
|
||||
<< QLatin1String(" \"implicitImports\": ");
|
||||
writeTrie(stream, implicitImports(), innerIndent);
|
||||
stream << QLatin1String("\n")
|
||||
<< indent << QLatin1Char('}');
|
||||
return true;
|
||||
}
|
||||
|
||||
QString QmlBundle::toString(const QString &indent)
|
||||
{
|
||||
QString res;
|
||||
QTextStream s(&res);
|
||||
writeTo(s, indent);
|
||||
return res;
|
||||
}
|
||||
|
||||
QStringList QmlBundle::maybeReadTrie(Trie &trie, Utils::JsonObjectValue *config,
|
||||
const QString &path, const QString &propertyName, bool required)
|
||||
{
|
||||
QStringList res;
|
||||
if (!config->hasMember(propertyName)) {
|
||||
if (required)
|
||||
res << tr("Missing required property \"%1\" from %2").arg(propertyName, path);
|
||||
return res;
|
||||
}
|
||||
Utils::JsonValue *imp0 = config->member(propertyName);
|
||||
Utils::JsonArrayValue *imp = ((imp0 != 0) ? imp0->toArray() : 0);
|
||||
if (imp != 0) {
|
||||
foreach (Utils::JsonValue *v, imp->elements()) {
|
||||
Utils::JsonStringValue *impStr = ((v != 0) ? v->toString() : 0);
|
||||
if (impStr != 0) {
|
||||
trie.insert(impStr->value());
|
||||
} else {
|
||||
res.append(tr("Expected all elements of array in property \"%1\" to be strings in QmlBundle at %2.")
|
||||
.arg(propertyName).arg(path));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res.append(tr("Expected string array in property \"%1\" in QmlBundle at %2.")
|
||||
.arg(propertyName).arg(path));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool QmlBundle::readFrom(QString path, QStringList *errors)
|
||||
{
|
||||
using namespace Utils;
|
||||
QFile f(path);
|
||||
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
if (errors)
|
||||
(*errors) << tr("Could not open QmlBundle at %1 .").arg(path);
|
||||
return false;
|
||||
}
|
||||
JsonObjectValue *config = JsonValue::create(QString::fromUtf8(f.readAll()))->toObject();
|
||||
if (config == 0) {
|
||||
if (errors)
|
||||
(*errors) << tr("Could not parse json object in QmlBundle at %1 .").arg(path);
|
||||
return false;
|
||||
}
|
||||
QStringList errs;
|
||||
if (config->hasMember(QLatin1String("name"))) {
|
||||
JsonValue *n0 = config->member(QLatin1String("name"));
|
||||
JsonStringValue *n = ((n0 != 0) ? n0->toString() : 0);
|
||||
if (n != 0)
|
||||
m_name = n->value();
|
||||
else
|
||||
errs.append(tr("Property \"name\" in QmlBundle at %1 is expected to be a string.")
|
||||
.arg(path));
|
||||
} else {
|
||||
errs.append(tr("Missing required property \"name\" in QmlBundle at %1 .").arg(path));
|
||||
}
|
||||
errs << maybeReadTrie(m_searchPaths, config, path, QLatin1String("searchPaths"));
|
||||
errs << maybeReadTrie(m_installPaths, config, path, QLatin1String("installPaths"));
|
||||
errs << maybeReadTrie(m_supportedImports, config, path, QLatin1String("supportedImports")
|
||||
, true);
|
||||
errs << maybeReadTrie(m_implicitImports, config, path, QLatin1String("implicitImports"));
|
||||
if (errors)
|
||||
(*errors) << errs;
|
||||
return errs.isEmpty();
|
||||
}
|
||||
|
||||
QmlBundle QmlLanguageBundles::bundleForLanguage(Document::Language l) const
|
||||
{
|
||||
if (m_bundles.contains(l))
|
||||
return m_bundles.value(l);
|
||||
return QmlBundle();
|
||||
}
|
||||
|
||||
void QmlLanguageBundles::mergeBundleForLanguage(Document::Language l, const QmlBundle &bundle)
|
||||
{
|
||||
if (bundle.isEmpty())
|
||||
return;
|
||||
if (m_bundles.contains(l))
|
||||
m_bundles[l].merge(bundle);
|
||||
else
|
||||
m_bundles.insert(l,bundle);
|
||||
}
|
||||
|
||||
QList<Document::Language> QmlLanguageBundles::languages() const
|
||||
{
|
||||
return m_bundles.keys();
|
||||
}
|
||||
|
||||
void QmlLanguageBundles::mergeLanguageBundles(const QmlLanguageBundles &o)
|
||||
{
|
||||
foreach (Document::Language l, o.languages())
|
||||
mergeBundleForLanguage(l, o.bundleForLanguage(l));
|
||||
}
|
||||
|
||||
} // end namespace QmlJS
|
||||
@@ -0,0 +1,116 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLJSBUNDLE_H
|
||||
#define QMLJSBUNDLE_H
|
||||
|
||||
#include <qmljs/qmljs_global.h>
|
||||
#include <qmljs/persistenttrie.h>
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QCoreApplication>
|
||||
#include <QHash>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QTextStream)
|
||||
|
||||
namespace Utils {
|
||||
class JsonObjectValue;
|
||||
}
|
||||
|
||||
namespace QmlJS {
|
||||
|
||||
/* !
|
||||
\class QmlJS::QmlBundle
|
||||
|
||||
A Qmlbundle represents a set of qml libraries, with a list of their exports
|
||||
|
||||
Note that searchPaths, installPaths and implicitImports are PersistentTries
|
||||
and not QStringLists.
|
||||
This makes merging easier, and the order is not important for our use case.
|
||||
*/
|
||||
class QMLJS_EXPORT QmlBundle
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(QmlJS::QmlBundle)
|
||||
typedef PersistentTrie::Trie Trie;
|
||||
public:
|
||||
QmlBundle(const QmlBundle &o);
|
||||
QmlBundle();
|
||||
QmlBundle(const QString &name,
|
||||
const Trie &searchPaths,
|
||||
const Trie &installPaths,
|
||||
const Trie &supportedImports,
|
||||
const Trie &implicitImports);
|
||||
|
||||
QString name() const;
|
||||
Trie installPaths() const;
|
||||
Trie searchPaths() const;
|
||||
Trie implicitImports() const;
|
||||
Trie supportedImports() const;
|
||||
|
||||
void merge(const QmlBundle &o);
|
||||
void intersect(const QmlBundle &o);
|
||||
QmlBundle mergeF(const QmlBundle &o) const;
|
||||
QmlBundle intersectF(const QmlBundle &o) const;
|
||||
bool isEmpty() const;
|
||||
void replaceVars(const QHash<QString, QString> &replacements);
|
||||
QmlBundle replaceVarsF(const QHash<QString, QString> &replacements) const;
|
||||
|
||||
bool writeTo(const QString &path) const;
|
||||
bool writeTo(QTextStream &stream, const QString &indent = QString()) const;
|
||||
QString toString(const QString &indent = QString());
|
||||
bool readFrom(QString path, QStringList *errors);
|
||||
bool operator==(const QmlBundle &o) const;
|
||||
bool operator!=(const QmlBundle &o) const;
|
||||
private:
|
||||
static void printEscaped(QTextStream &s, const QString &str);
|
||||
static void writeTrie(QTextStream &stream, const Trie &t, const QString &indent);
|
||||
QStringList maybeReadTrie(Trie &trie, Utils::JsonObjectValue *config, const QString &path,
|
||||
const QString &propertyName, bool required = false);
|
||||
|
||||
QString m_name;
|
||||
Trie m_searchPaths;
|
||||
Trie m_installPaths;
|
||||
Trie m_supportedImports;
|
||||
Trie m_implicitImports;
|
||||
};
|
||||
|
||||
class QMLJS_EXPORT QmlLanguageBundles
|
||||
{
|
||||
public:
|
||||
QmlBundle bundleForLanguage(Document::Language l) const;
|
||||
void mergeBundleForLanguage(Document::Language l, const QmlBundle &bundle);
|
||||
QList<Document::Language> languages() const;
|
||||
void mergeLanguageBundles(const QmlLanguageBundles &);
|
||||
private:
|
||||
QHash<Document::Language,QmlBundle> m_bundles;
|
||||
};
|
||||
} // namespace QmlJS
|
||||
|
||||
#endif // QMLJSBUNDLE_H
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTextDocument>
|
||||
#include <QStringList>
|
||||
|
||||
using namespace QmlJS;
|
||||
|
||||
@@ -204,6 +205,8 @@ void CompletionContextFinder::checkImport()
|
||||
|
||||
//qDebug() << "Start line:" << *yyLine << m_startTokenIndex;
|
||||
|
||||
QStringList libVersionImport;
|
||||
int isInLibVersionImport;
|
||||
int i = m_startTokenIndex;
|
||||
bool stop = false;
|
||||
enum State {
|
||||
@@ -216,6 +219,7 @@ void CompletionContextFinder::checkImport()
|
||||
ExpectAs = 1 << 5
|
||||
};
|
||||
State state = Unknown;
|
||||
isInLibVersionImport = -1;
|
||||
|
||||
while (!stop) {
|
||||
if (i < 0) {
|
||||
@@ -233,17 +237,27 @@ void CompletionContextFinder::checkImport()
|
||||
case Token::Identifier: {
|
||||
const QStringRef tokenString = yyLine->midRef(token.begin(), token.length);
|
||||
if (tokenString == QLatin1String("as")) {
|
||||
isInLibVersionImport = 0;
|
||||
if (state == Unknown) {
|
||||
state = State(ExpectAnyTarget | ExpectVersion);
|
||||
break;
|
||||
}
|
||||
} else if (tokenString == QLatin1String("import")) {
|
||||
if (state == Unknown || (state & ExpectImport))
|
||||
if (state == Unknown || (state & ExpectImport)) {
|
||||
if (isInLibVersionImport == -1 && token.end() < m_cursor.position())
|
||||
isInLibVersionImport = 1;
|
||||
m_inImport = true;
|
||||
}
|
||||
} else {
|
||||
if (state == Unknown || (state & ExpectAnyTarget)
|
||||
|| (state & ExpectTargetIdentifier)) {
|
||||
state = State(ExpectImport | ExpectTargetDot);
|
||||
libVersionImport.prepend(tokenString.toString());
|
||||
if (isInLibVersionImport == -1) {
|
||||
if (token.end() < m_cursor.position())
|
||||
libVersionImport.append(QLatin1String(" "));
|
||||
isInLibVersionImport = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -260,6 +274,10 @@ void CompletionContextFinder::checkImport()
|
||||
case Token::Number:
|
||||
if (state == Unknown || (state & ExpectVersion)) {
|
||||
state = ExpectAnyTarget;
|
||||
libVersionImport.prepend(yyLine->midRef(token.begin(), token.length).toString());
|
||||
libVersionImport.prepend(QLatin1String(" "));
|
||||
if (isInLibVersionImport == -1)
|
||||
isInLibVersionImport = 1;
|
||||
break;
|
||||
}
|
||||
stop = true;
|
||||
@@ -267,6 +285,9 @@ void CompletionContextFinder::checkImport()
|
||||
case Token::Dot:
|
||||
if (state == Unknown || (state & ExpectTargetDot)) {
|
||||
state = ExpectTargetIdentifier;
|
||||
libVersionImport.prepend(QLatin1String("."));
|
||||
if (isInLibVersionImport == -1)
|
||||
isInLibVersionImport = 1;
|
||||
break;
|
||||
}
|
||||
stop = true;
|
||||
@@ -276,11 +297,19 @@ void CompletionContextFinder::checkImport()
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isInLibVersionImport == -1)
|
||||
isInLibVersionImport = 0;
|
||||
--i;
|
||||
}
|
||||
|
||||
YY_RESTORE();
|
||||
if (m_inImport && isInLibVersionImport == 1) {
|
||||
m_libVersion = libVersionImport.join(QLatin1String(""));
|
||||
if (m_libVersion.isNull())
|
||||
m_libVersion = QLatin1String("");
|
||||
} else {
|
||||
m_libVersion = QString();
|
||||
}
|
||||
}
|
||||
|
||||
QStringList CompletionContextFinder::qmlObjectTypeName() const
|
||||
@@ -327,6 +356,11 @@ bool QmlJS::CompletionContextFinder::isInImport() const
|
||||
return m_inImport;
|
||||
}
|
||||
|
||||
QString CompletionContextFinder::libVersionImport() const
|
||||
{
|
||||
return m_libVersion;
|
||||
}
|
||||
|
||||
int CompletionContextFinder::findOpeningBrace(int startTokenIndex)
|
||||
{
|
||||
YY_SAVE();
|
||||
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
|
||||
bool isInStringLiteral() const;
|
||||
bool isInImport() const;
|
||||
QString libVersionImport() const;
|
||||
|
||||
private:
|
||||
int findOpeningBrace(int startTokenIndex);
|
||||
@@ -69,6 +70,7 @@ private:
|
||||
bool m_behaviorBinding;
|
||||
bool m_inStringLiteral;
|
||||
bool m_inImport;
|
||||
QString m_libVersion;
|
||||
};
|
||||
|
||||
} // namespace QmlJS
|
||||
|
||||
@@ -166,6 +166,11 @@ Document::Language Document::language() const
|
||||
return _language;
|
||||
}
|
||||
|
||||
void Document::setLanguage(Document::Language l)
|
||||
{
|
||||
_language = l;
|
||||
}
|
||||
|
||||
AST::UiProgram *Document::qmlProgram() const
|
||||
{
|
||||
return cast<UiProgram *>(_ast);
|
||||
|
||||
@@ -78,6 +78,7 @@ public:
|
||||
|
||||
bool isQmlDocument() const;
|
||||
Language language() const;
|
||||
void setLanguage(Language l);
|
||||
|
||||
AST::UiProgram *qmlProgram() const;
|
||||
AST::Program *jsProgram() const;
|
||||
|
||||
@@ -68,3 +68,4 @@ ModelManagerInterface *ModelManagerInterface::instance()
|
||||
{
|
||||
return g_instance;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "qmljs_global.h"
|
||||
#include "qmljsdocument.h"
|
||||
#include "qmljsbundle.h"
|
||||
|
||||
#include <utils/environment.h>
|
||||
|
||||
@@ -73,6 +74,8 @@ public:
|
||||
bool isNull() const
|
||||
{ return project.isNull(); }
|
||||
|
||||
QStringList completeImportPaths();
|
||||
|
||||
public: // attributes
|
||||
QPointer<ProjectExplorer::Project> project;
|
||||
QStringList sourceFiles;
|
||||
@@ -86,6 +89,8 @@ public:
|
||||
QString qtImportsPath;
|
||||
QString qtQmlPath;
|
||||
QString qtVersionString;
|
||||
QmlJS::QmlLanguageBundles activeBundle;
|
||||
QmlJS::QmlLanguageBundles extendedBundle;
|
||||
};
|
||||
|
||||
class WorkingCopy
|
||||
@@ -141,8 +146,11 @@ public:
|
||||
virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const = 0;
|
||||
virtual void updateProjectInfo(const ProjectInfo &pinfo) = 0;
|
||||
Q_SLOT virtual void removeProjectInfo(ProjectExplorer::Project *project) = 0;
|
||||
virtual ProjectInfo projectInfoForPath(QString path) = 0;
|
||||
|
||||
virtual QStringList importPaths() const = 0;
|
||||
virtual QmlJS::QmlLanguageBundles activeBundles() const = 0;
|
||||
virtual QmlJS::QmlLanguageBundles extendedBundles() const = 0;
|
||||
|
||||
virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath,
|
||||
const QString &importUri, const QString &importVersion) = 0;
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
#include <qmljstools/qmljsmodelmanager.h>
|
||||
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
|
||||
@@ -603,61 +604,10 @@ void QbsProject::updateCppCodeModel(const qbs::ProjectData *prj)
|
||||
|
||||
void QbsProject::updateQmlJsCodeModel(const qbs::ProjectData *prj)
|
||||
{
|
||||
// FIXME: No information about import directories, so ignore this for now.
|
||||
#if 1
|
||||
Q_UNUSED(prj);
|
||||
#else
|
||||
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
if (!modelManager)
|
||||
return;
|
||||
|
||||
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager->projectInfo(this);
|
||||
projectInfo.sourceFiles = m_projectFiles->files[QMLType];
|
||||
|
||||
FindQt4ProFiles findQt4ProFiles;
|
||||
QList<Qt4ProFileNode *> proFiles = findQt4ProFiles(rootProjectNode());
|
||||
|
||||
projectInfo.importPaths.clear();
|
||||
foreach (Qt4ProFileNode *node, proFiles) {
|
||||
projectInfo.importPaths.append(node->variableValue(QmlImportPathVar));
|
||||
}
|
||||
|
||||
bool preferDebugDump = false;
|
||||
projectInfo.tryQmlDump = false;
|
||||
|
||||
ProjectExplorer::Target *t = activeTarget();
|
||||
ProjectExplorer::Kit *k = t ? t->kit() : ProjectExplorer::KitManager::instance()->defaultKit();
|
||||
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k);
|
||||
|
||||
if (t) {
|
||||
if (Qt4BuildConfiguration *bc = qobject_cast<Qt4BuildConfiguration *>(t->activeBuildConfiguration()))
|
||||
preferDebugDump = bc->qmakeBuildConfiguration() & QtSupport::BaseQtVersion::DebugBuild;
|
||||
} else {
|
||||
if (qtVersion)
|
||||
preferDebugDump = qtVersion->defaultBuildConfig() & QtSupport::BaseQtVersion::DebugBuild;
|
||||
}
|
||||
if (qtVersion && qtVersion->isValid()) {
|
||||
projectInfo.tryQmlDump = qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT)
|
||||
|| qtVersion->type() == QLatin1String(QtSupport::Constants::SIMULATORQT);
|
||||
projectInfo.qtImportsPath = qtVersion->qmakeProperty("QT_INSTALL_IMPORTS");
|
||||
if (!projectInfo.qtImportsPath.isEmpty())
|
||||
projectInfo.importPaths += projectInfo.qtImportsPath;
|
||||
projectInfo.qtVersionString = qtVersion->qtVersionString();
|
||||
}
|
||||
projectInfo.importPaths.removeDuplicates();
|
||||
|
||||
if (projectInfo.tryQmlDump) {
|
||||
QtSupport::QmlDumpTool::pathAndEnvironment(this, qtVersion,
|
||||
ToolChainKitInformation::toolChain(k),
|
||||
preferDebugDump, &projectInfo.qmlDumpPath,
|
||||
&projectInfo.qmlDumpEnvironment);
|
||||
} else {
|
||||
projectInfo.qmlDumpPath.clear();
|
||||
projectInfo.qmlDumpEnvironment.clear();
|
||||
}
|
||||
|
||||
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
|
||||
QmlJSTools::defaultProjectInfoForProject(this);
|
||||
modelManager->updateProjectInfo(projectInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -17,6 +17,7 @@ QtcPlugin {
|
||||
Depends { name: "TextEditor" }
|
||||
Depends { name: "QtSupport" }
|
||||
Depends { name: "QmlJS" }
|
||||
Depends { name: "QmlJSTools" }
|
||||
|
||||
Depends { name: "cpp" }
|
||||
|
||||
|
||||
@@ -2,3 +2,4 @@ include(../../plugins/projectexplorer/projectexplorer.pri)
|
||||
include(../../plugins/cpptools/cpptools.pri)
|
||||
include(../../plugins/texteditor/texteditor.pri)
|
||||
include(../../plugins/qtsupport/qtsupport.pri)
|
||||
include(../../plugins/qmljstools/qmljstools.pri)
|
||||
|
||||
@@ -51,7 +51,9 @@
|
||||
#include <qmljs/qmljsscanner.h>
|
||||
#include <qmljs/qmljsbind.h>
|
||||
#include <qmljs/qmljscompletioncontextfinder.h>
|
||||
#include <qmljs/qmljsbundle.h>
|
||||
#include <qmljs/qmljsscopebuilder.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
@@ -61,6 +63,7 @@
|
||||
#include <QDirIterator>
|
||||
#include <QStringList>
|
||||
#include <QIcon>
|
||||
#include <QTextDocumentFragment>
|
||||
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJSEditor;
|
||||
@@ -645,8 +648,37 @@ IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface
|
||||
}
|
||||
|
||||
// currently path-in-stringliteral is the only completion available in imports
|
||||
if (contextFinder.isInImport())
|
||||
if (contextFinder.isInImport()) {
|
||||
QmlJS::ModelManagerInterface::ProjectInfo pInfo = QmlJS::ModelManagerInterface::instance()
|
||||
->projectInfo(ProjectExplorer::ProjectExplorerPlugin::currentProject());
|
||||
QmlBundle platform = pInfo.extendedBundle.bundleForLanguage(document->language());
|
||||
if (!platform.supportedImports().isEmpty()) {
|
||||
QTextCursor tc(qmlInterface->textDocument());
|
||||
tc.setPosition(qmlInterface->position());
|
||||
QmlExpressionUnderCursor expressionUnderCursor;
|
||||
expressionUnderCursor(tc);
|
||||
QString libVersion = contextFinder.libVersionImport();
|
||||
if (!libVersion.isNull()) {
|
||||
QStringList completions=platform.supportedImports().complete(libVersion, QString(), QmlJS::PersistentTrie::LookupFlags(QmlJS::PersistentTrie::CaseInsensitive|QmlJS::PersistentTrie::SkipChars|QmlJS::PersistentTrie::SkipSpaces));
|
||||
completions = QmlJS::PersistentTrie::matchStrengthSort(libVersion, completions);
|
||||
|
||||
int toSkip = qMax(libVersion.lastIndexOf(QLatin1Char(' '))
|
||||
, libVersion.lastIndexOf(QLatin1Char('.')));
|
||||
if (++toSkip > 0) {
|
||||
QStringList nCompletions;
|
||||
QString prefix(libVersion.left(toSkip));
|
||||
nCompletions.reserve(completions.size());
|
||||
foreach (QString completion, completions)
|
||||
if (completion.startsWith(prefix))
|
||||
nCompletions.append(completion.right(completion.size()-toSkip));
|
||||
completions = nCompletions;
|
||||
}
|
||||
addCompletions(&m_completions, completions, m_interface->fileNameIcon(), KeywordOrder);
|
||||
return createContentProposal();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// member "a.bc<complete>" or function "foo(<complete>" completion
|
||||
if (completionOperator == QLatin1Char('.')
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmljsbundleprovider.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <projectexplorer/kit.h>
|
||||
#include <projectexplorer/kit.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <qmljs/qmljsbundle.h>
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
#include <qtsupport/qtsupportconstants.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QHash>
|
||||
#include <QHashIterator>
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QtAlgorithms>
|
||||
|
||||
namespace QmlJSTools {
|
||||
|
||||
namespace {
|
||||
typedef QmlJS::Document::Language Language;
|
||||
typedef QmlJS::QmlBundle QmlBundle;
|
||||
typedef QmlJS::QmlLanguageBundles QmlLanguageBundles;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QmlJSEditor::BasicBundleProvider
|
||||
|
||||
\brief a class that sets up the default bundles for qt and various qml states.
|
||||
*/
|
||||
BasicBundleProvider::BasicBundleProvider(QObject *parent) :
|
||||
IBundleProvider(parent)
|
||||
{ }
|
||||
|
||||
QmlBundle BasicBundleProvider::defaultBundle(const QString &bundleInfoName)
|
||||
{
|
||||
static bool wroteErrors = false;
|
||||
QmlBundle res;
|
||||
QString defaultBundlePath = Core::ICore::resourcePath()
|
||||
+ QLatin1String("/qml-type-descriptions/")
|
||||
+ bundleInfoName;
|
||||
if (!QFileInfo(defaultBundlePath).exists()) {
|
||||
qWarning() << "BasicBundleProvider: ERROR " << defaultBundlePath
|
||||
<< " not found";
|
||||
return res;
|
||||
}
|
||||
QStringList errors;
|
||||
if (!res.readFrom(defaultBundlePath, &errors) && ! wroteErrors) {
|
||||
qWarning() << "BasicBundleProvider: ERROR reading " << defaultBundlePath
|
||||
<< " : " << errors;
|
||||
wroteErrors = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
QmlBundle BasicBundleProvider::defaultQt4QtQuick1Bundle()
|
||||
{
|
||||
return defaultBundle(QLatin1String("qt4QtQuick1-bundle.json"));
|
||||
}
|
||||
|
||||
QmlBundle BasicBundleProvider::defaultQt5QtQuick1Bundle()
|
||||
{
|
||||
return defaultBundle(QLatin1String("qt5QtQuick1-bundle.json"));
|
||||
}
|
||||
|
||||
QmlBundle BasicBundleProvider::defaultQt5QtQuick2Bundle()
|
||||
{
|
||||
return defaultBundle(QLatin1String("qt5QtQuick2-bundle.json"));
|
||||
}
|
||||
|
||||
QmlBundle BasicBundleProvider::defaultQbsBundle()
|
||||
{
|
||||
return defaultBundle(QLatin1String("qbs-bundle.json"));
|
||||
}
|
||||
|
||||
QmlBundle BasicBundleProvider::defaultQmltypesBundle()
|
||||
{
|
||||
return defaultBundle(QLatin1String("qmltypes-bundle.json"));
|
||||
}
|
||||
|
||||
QmlBundle BasicBundleProvider::defaultQmlprojectBundle()
|
||||
{
|
||||
return defaultBundle(QLatin1String("qmlproject-bundle.json"));
|
||||
}
|
||||
|
||||
void BasicBundleProvider::mergeBundlesForKit(ProjectExplorer::Kit *kit
|
||||
, QmlJS::QmlLanguageBundles &bundles
|
||||
, const QHash<QString,QString> &replacements)
|
||||
{
|
||||
typedef QmlJS::Document Doc;
|
||||
QHash<QString,QString> myReplacements = replacements;
|
||||
|
||||
bundles.mergeBundleForLanguage(Doc::QmlQbsLanguage, defaultQbsBundle());
|
||||
bundles.mergeBundleForLanguage(Doc::QmlTypeInfoLanguage, defaultQmltypesBundle());
|
||||
bundles.mergeBundleForLanguage(Doc::QmlProjectLanguage, defaultQmlprojectBundle());
|
||||
|
||||
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(kit);
|
||||
if (!qtVersion) {
|
||||
QmlBundle b1(defaultQt4QtQuick1Bundle());
|
||||
bundles.mergeBundleForLanguage(Doc::QmlLanguage, b1);
|
||||
bundles.mergeBundleForLanguage(Doc::QmlQtQuick1Language, b1);
|
||||
QmlBundle b11(defaultQt5QtQuick1Bundle());
|
||||
bundles.mergeBundleForLanguage(Doc::QmlLanguage, b11);
|
||||
bundles.mergeBundleForLanguage(Doc::QmlQtQuick1Language, b11);
|
||||
QmlBundle b2(defaultQt5QtQuick2Bundle());
|
||||
bundles.mergeBundleForLanguage(Doc::QmlLanguage, b2);
|
||||
bundles.mergeBundleForLanguage(Doc::QmlQtQuick2Language, b2);
|
||||
return;
|
||||
}
|
||||
QString qtImportsPath = qtVersion->qmakeProperty("QT_INSTALL_IMPORTS");
|
||||
QString qtQmlPath = qtVersion->qmakeProperty("QT_INSTALL_QML");
|
||||
|
||||
Core::FeatureSet features = qtVersion->availableFeatures();
|
||||
if (features.contains(Core::Feature(QtSupport::Constants::FEATURE_QT_QUICK))
|
||||
|| features.contains(Core::Feature(QtSupport::Constants::FEATURE_QT_QUICK_1))
|
||||
|| features.contains(Core::Feature(QtSupport::Constants::FEATURE_QT_QUICK_1_1))) {
|
||||
myReplacements.insert(QLatin1String("$(CURRENT_DIRECTORY)"), qtImportsPath);
|
||||
QDir qtQuick1Bundles(qtImportsPath);
|
||||
qtQuick1Bundles.setNameFilters(QStringList(QLatin1String("*-bundle.json")));
|
||||
QmlBundle qtQuick1Bundle;
|
||||
QFileInfoList list = qtQuick1Bundles.entryInfoList();
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
QmlBundle bAtt;
|
||||
QStringList errors;
|
||||
if (!bAtt.readFrom(list.value(i).filePath(), &errors))
|
||||
qWarning() << "BasicBundleProvider: ERROR reading " << list[i].filePath() << " : "
|
||||
<< errors;
|
||||
qtQuick1Bundle.merge(bAtt);
|
||||
}
|
||||
if (!qtQuick1Bundle.supportedImports().contains(QLatin1String("QtQuick 1."),
|
||||
QmlJS::PersistentTrie::Partial)) {
|
||||
if (qtVersion->qtVersion().majorVersion == 4)
|
||||
qtQuick1Bundle.merge(defaultQt4QtQuick1Bundle());
|
||||
else if (qtVersion->qtVersion().majorVersion > 4)
|
||||
qtQuick1Bundle.merge(defaultQt5QtQuick1Bundle());
|
||||
}
|
||||
qtQuick1Bundle.replaceVars(myReplacements);
|
||||
bundles.mergeBundleForLanguage(Doc::QmlLanguage, qtQuick1Bundle);
|
||||
bundles.mergeBundleForLanguage(Doc::QmlQtQuick1Language, qtQuick1Bundle);
|
||||
}
|
||||
if (features.contains(Core::Feature(QtSupport::Constants::FEATURE_QT_QUICK_2))) {
|
||||
myReplacements.insert(QLatin1String("$(CURRENT_DIRECTORY)"), qtQmlPath);
|
||||
QDir qtQuick2Bundles(qtQmlPath);
|
||||
qtQuick2Bundles.setNameFilters(QStringList(QLatin1String("*-bundle.json")));
|
||||
QmlBundle qtQuick2Bundle;
|
||||
QFileInfoList list = qtQuick2Bundles.entryInfoList();
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
QmlBundle bAtt;
|
||||
QStringList errors;
|
||||
if (!bAtt.readFrom(list.value(i).filePath(), &errors))
|
||||
qWarning() << "BasicBundleProvider: ERROR reading " << list[i].filePath() << " : "
|
||||
<< errors;
|
||||
qtQuick2Bundle.merge(bAtt);
|
||||
}
|
||||
if (!qtQuick2Bundle.supportedImports().contains(QLatin1String("QtQuick 2."),
|
||||
QmlJS::PersistentTrie::Partial)) {
|
||||
qtQuick2Bundle.merge(defaultQt5QtQuick2Bundle());
|
||||
}
|
||||
qtQuick2Bundle.replaceVars(myReplacements);
|
||||
bundles.mergeBundleForLanguage(Doc::QmlLanguage, qtQuick2Bundle);
|
||||
bundles.mergeBundleForLanguage(Doc::QmlQtQuick2Language, qtQuick2Bundle);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace QmlJSTools
|
||||
@@ -0,0 +1,80 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLJSBUNDLEPROVIDER_H
|
||||
#define QMLJSBUNDLEPROVIDER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <qmljs/qmljsbundle.h>
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
|
||||
#include "qmljstools_global.h"
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Kit;
|
||||
class Project;
|
||||
class Target;
|
||||
}
|
||||
|
||||
namespace QmlJSTools {
|
||||
|
||||
class QMLJSTOOLS_EXPORT IBundleProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IBundleProvider(QObject *parent = 0)
|
||||
: QObject(parent)
|
||||
{ }
|
||||
|
||||
virtual void mergeBundlesForKit(ProjectExplorer::Kit *kit, QmlJS::QmlLanguageBundles &bundles
|
||||
, const QHash<QString,QString> &replacements) = 0;
|
||||
};
|
||||
|
||||
class QMLJSTOOLS_EXPORT BasicBundleProvider : public IBundleProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BasicBundleProvider(QObject *parent = 0);
|
||||
|
||||
virtual void mergeBundlesForKit(ProjectExplorer::Kit *kit, QmlJS::QmlLanguageBundles &bundles
|
||||
, const QHash<QString,QString> &replacements);
|
||||
|
||||
static QmlJS::QmlBundle defaultBundle(const QString &bundleInfoName);
|
||||
static QmlJS::QmlBundle defaultQt4QtQuick1Bundle();
|
||||
static QmlJS::QmlBundle defaultQt5QtQuick1Bundle();
|
||||
static QmlJS::QmlBundle defaultQt5QtQuick2Bundle();
|
||||
static QmlJS::QmlBundle defaultQbsBundle();
|
||||
static QmlJS::QmlBundle defaultQmltypesBundle();
|
||||
static QmlJS::QmlBundle defaultQmlprojectBundle();
|
||||
};
|
||||
|
||||
} // end QmlJSTools namespace
|
||||
|
||||
#endif // QMLJSBUNDLEPROVIDER_H
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "qmljsplugindumper.h"
|
||||
#include "qmljsfindexportedcpptypes.h"
|
||||
#include "qmljssemanticinfo.h"
|
||||
#include "qmljsbundleprovider.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
@@ -42,15 +43,25 @@
|
||||
#include <cplusplus/CppDocument.h>
|
||||
#include <qmljs/qmljscontext.h>
|
||||
#include <qmljs/qmljsbind.h>
|
||||
#include <qmljs/qmljsbundle.h>
|
||||
#include <qmljs/parser/qmldirparser_p.h>
|
||||
#include <texteditor/itexteditor.h>
|
||||
#include <texteditor/basetexteditor.h>
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/kit.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/session.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/toolchain.h>
|
||||
#include <qtsupport/baseqtversion.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
#include <qtsupport/qmldumptool.h>
|
||||
#include <qtsupport/qtsupportconstants.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
@@ -61,6 +72,7 @@
|
||||
#include <QTextStream>
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
#include <QRegExp>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
@@ -68,6 +80,104 @@ using namespace QmlJS;
|
||||
using namespace QmlJSTools;
|
||||
using namespace QmlJSTools::Internal;
|
||||
|
||||
|
||||
ModelManagerInterface::ProjectInfo QmlJSTools::defaultProjectInfoForProject(
|
||||
ProjectExplorer::Project *project)
|
||||
{
|
||||
ModelManagerInterface::ProjectInfo projectInfo(project);
|
||||
ProjectExplorer::Target *activeTarget = 0;
|
||||
if (project) {
|
||||
Core::MimeDatabase *db = Core::ICore::mimeDatabase();
|
||||
QList<Core::MimeGlobPattern> globs;
|
||||
QList<Core::MimeType> mimeTypes = db->mimeTypes();
|
||||
foreach (const Core::MimeType &mimeType, mimeTypes)
|
||||
if (mimeType.type() == QLatin1String(Constants::QML_MIMETYPE)
|
||||
|| mimeType.subClassesOf().contains(QLatin1String(Constants::QML_MIMETYPE)))
|
||||
globs << mimeType.globPatterns();
|
||||
if (globs.isEmpty())
|
||||
globs << Core::MimeGlobPattern(QRegExp(QLatin1String(".*\\.(?:qbs|qml|qmltypes|qmlproject)$")));
|
||||
foreach (const QString &filePath
|
||||
, project->files(ProjectExplorer::Project::ExcludeGeneratedFiles))
|
||||
foreach (const Core::MimeGlobPattern &glob, globs)
|
||||
if (glob.regExp().exactMatch(filePath))
|
||||
projectInfo.sourceFiles << filePath;
|
||||
activeTarget = project->activeTarget();
|
||||
}
|
||||
ProjectExplorer::Kit *activeKit = activeTarget ? activeTarget->kit() :
|
||||
ProjectExplorer::KitManager::instance()->defaultKit();
|
||||
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(activeKit);
|
||||
|
||||
bool preferDebugDump = false;
|
||||
bool setPreferDump = false;
|
||||
projectInfo.tryQmlDump = false;
|
||||
|
||||
if (activeTarget) {
|
||||
if (ProjectExplorer::BuildConfiguration *bc = activeTarget->activeBuildConfiguration()) {
|
||||
preferDebugDump = bc->buildType() == ProjectExplorer::BuildConfiguration::Debug;
|
||||
setPreferDump = true;
|
||||
}
|
||||
}
|
||||
if (!setPreferDump && qtVersion)
|
||||
preferDebugDump = (qtVersion->defaultBuildConfig() & QtSupport::BaseQtVersion::DebugBuild);
|
||||
if (qtVersion && qtVersion->isValid()) {
|
||||
projectInfo.tryQmlDump = project && (
|
||||
qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT)
|
||||
|| qtVersion->type() == QLatin1String(QtSupport::Constants::SIMULATORQT));
|
||||
projectInfo.qtQmlPath = qtVersion->qmakeProperty("QT_INSTALL_QML");
|
||||
projectInfo.qtImportsPath = qtVersion->qmakeProperty("QT_INSTALL_IMPORTS");
|
||||
projectInfo.qtVersionString = qtVersion->qtVersionString();
|
||||
}
|
||||
|
||||
if (projectInfo.tryQmlDump) {
|
||||
ProjectExplorer::ToolChain *toolChain =
|
||||
ProjectExplorer::ToolChainKitInformation::toolChain(activeKit);
|
||||
QtSupport::QmlDumpTool::pathAndEnvironment(project, qtVersion,
|
||||
toolChain,
|
||||
preferDebugDump, &projectInfo.qmlDumpPath,
|
||||
&projectInfo.qmlDumpEnvironment);
|
||||
} else {
|
||||
projectInfo.qmlDumpPath.clear();
|
||||
projectInfo.qmlDumpEnvironment.clear();
|
||||
}
|
||||
setupProjectInfoQmlBundles(projectInfo);
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
void QmlJSTools::setupProjectInfoQmlBundles(ModelManagerInterface::ProjectInfo &projectInfo)
|
||||
{
|
||||
ProjectExplorer::Target *activeTarget = 0;
|
||||
if (projectInfo.project) {
|
||||
activeTarget = projectInfo.project->activeTarget();
|
||||
}
|
||||
ProjectExplorer::Kit *activeKit = activeTarget
|
||||
? activeTarget->kit() : ProjectExplorer::KitManager::instance()->defaultKit();
|
||||
QHash<QString, QString> replacements;
|
||||
replacements.insert(QLatin1String("$(QT_INSTALL_IMPORTS)"), projectInfo.qtImportsPath);
|
||||
replacements.insert(QLatin1String("$(QT_INSTALL_QML)"), projectInfo.qtQmlPath);
|
||||
|
||||
QList<IBundleProvider *> bundleProviders =
|
||||
ExtensionSystem::PluginManager::getObjects<IBundleProvider>();
|
||||
|
||||
foreach (IBundleProvider *bp, bundleProviders) {
|
||||
if (bp)
|
||||
bp->mergeBundlesForKit(activeKit, projectInfo.activeBundle, replacements);
|
||||
}
|
||||
projectInfo.extendedBundle = projectInfo.activeBundle;
|
||||
|
||||
if (projectInfo.project) {
|
||||
QSet<ProjectExplorer::Kit *> currentKits;
|
||||
foreach (const ProjectExplorer::Target *t, projectInfo.project->targets())
|
||||
if (t->kit())
|
||||
currentKits.insert(t->kit());
|
||||
currentKits.remove(activeKit);
|
||||
foreach (ProjectExplorer::Kit *kit, currentKits) {
|
||||
foreach (IBundleProvider *bp, bundleProviders)
|
||||
if (bp)
|
||||
bp->mergeBundlesForKit(kit, projectInfo.extendedBundle, replacements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QStringList environmentImportPaths();
|
||||
|
||||
static void mergeSuffixes(QStringList &l1, const QStringList &l2)
|
||||
@@ -373,6 +483,7 @@ void ModelManager::updateProjectInfo(const ProjectInfo &pinfo)
|
||||
void ModelManager::removeProjectInfo(ProjectExplorer::Project *project)
|
||||
{
|
||||
ProjectInfo info(project);
|
||||
info.sourceFiles.clear();
|
||||
// update with an empty project info to clear data
|
||||
updateProjectInfo(info);
|
||||
|
||||
@@ -382,6 +493,16 @@ void ModelManager::removeProjectInfo(ProjectExplorer::Project *project)
|
||||
}
|
||||
}
|
||||
|
||||
ModelManagerInterface::ProjectInfo ModelManager::projectInfoForPath(QString path)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
foreach (const ProjectInfo &p, m_projects)
|
||||
if (p.sourceFiles.contains(path))
|
||||
return p;
|
||||
return ProjectInfo();
|
||||
}
|
||||
|
||||
void ModelManager::emitDocumentChangedOnDisk(Document::Ptr doc)
|
||||
{ emit documentChangedOnDisk(doc); }
|
||||
|
||||
@@ -660,6 +781,18 @@ QStringList ModelManager::importPaths() const
|
||||
return m_allImportPaths;
|
||||
}
|
||||
|
||||
QmlLanguageBundles ModelManager::activeBundles() const
|
||||
{
|
||||
QMutexLocker l(&m_mutex);
|
||||
return m_activeBundles;
|
||||
}
|
||||
|
||||
QmlLanguageBundles ModelManager::extendedBundles() const
|
||||
{
|
||||
QMutexLocker l(&m_mutex);
|
||||
return m_extendedBundles;
|
||||
}
|
||||
|
||||
static QStringList environmentImportPaths()
|
||||
{
|
||||
QStringList paths;
|
||||
@@ -679,6 +812,8 @@ static QStringList environmentImportPaths()
|
||||
void ModelManager::updateImportPaths()
|
||||
{
|
||||
QStringList allImportPaths;
|
||||
QmlLanguageBundles activeBundles;
|
||||
QmlLanguageBundles extendedBundles;
|
||||
QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
@@ -688,12 +823,40 @@ void ModelManager::updateImportPaths()
|
||||
allImportPaths += canonicalPath;
|
||||
}
|
||||
}
|
||||
it.toFront();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
activeBundles.mergeLanguageBundles(it.value().activeBundle);
|
||||
foreach (Document::Language l, it.value().activeBundle.languages()) {
|
||||
foreach (const QString &path, it.value().activeBundle.bundleForLanguage(l)
|
||||
.searchPaths().stringList()) {
|
||||
const QString canonicalPath = QFileInfo(path).canonicalFilePath();
|
||||
if (!canonicalPath.isEmpty())
|
||||
allImportPaths += canonicalPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
it.toFront();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
extendedBundles.mergeLanguageBundles(it.value().extendedBundle);
|
||||
foreach (Document::Language l, it.value().extendedBundle.languages()) {
|
||||
foreach (const QString &path, it.value().extendedBundle.bundleForLanguage(l)
|
||||
.searchPaths().stringList()) {
|
||||
const QString canonicalPath = QFileInfo(path).canonicalFilePath();
|
||||
if (!canonicalPath.isEmpty())
|
||||
allImportPaths += canonicalPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
allImportPaths += m_defaultImportPaths;
|
||||
allImportPaths.removeDuplicates();
|
||||
|
||||
{
|
||||
QMutexLocker l(&m_mutex);
|
||||
m_allImportPaths = allImportPaths;
|
||||
m_activeBundles = activeBundles;
|
||||
m_extendedBundles = extendedBundles;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -82,12 +82,15 @@ public:
|
||||
virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const;
|
||||
virtual void updateProjectInfo(const ProjectInfo &pinfo);
|
||||
Q_SLOT virtual void removeProjectInfo(ProjectExplorer::Project *project);
|
||||
virtual ProjectInfo projectInfoForPath(QString path);
|
||||
|
||||
void updateDocument(QmlJS::Document::Ptr doc);
|
||||
void updateLibraryInfo(const QString &path, const QmlJS::LibraryInfo &info);
|
||||
void emitDocumentChangedOnDisk(QmlJS::Document::Ptr doc);
|
||||
|
||||
virtual QStringList importPaths() const;
|
||||
virtual QmlJS::QmlLanguageBundles activeBundles() const;
|
||||
virtual QmlJS::QmlLanguageBundles extendedBundles() const;
|
||||
|
||||
virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath,
|
||||
const QString &importUri, const QString &importVersion);
|
||||
@@ -136,6 +139,8 @@ private:
|
||||
QmlJS::Snapshot _newestSnapshot;
|
||||
QStringList m_allImportPaths;
|
||||
QStringList m_defaultImportPaths;
|
||||
QmlJS::QmlLanguageBundles m_activeBundles;
|
||||
QmlJS::QmlLanguageBundles m_extendedBundles;
|
||||
|
||||
QFutureSynchronizer<void> m_synchronizer;
|
||||
|
||||
@@ -153,6 +158,11 @@ private:
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
QMLJSTOOLS_EXPORT QmlJS::ModelManagerInterface::ProjectInfo defaultProjectInfoForProject(
|
||||
ProjectExplorer::Project *project);
|
||||
QMLJSTOOLS_EXPORT void setupProjectInfoQmlBundles(QmlJS::ModelManagerInterface::ProjectInfo &projectInfo);
|
||||
|
||||
} // namespace QmlJSTools
|
||||
|
||||
#endif // QMLJSMODELMANAGER_H
|
||||
|
||||
@@ -10,6 +10,7 @@ DEFINES += QMLJSTOOLS_LIBRARY
|
||||
}
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/qmljsbundleprovider.h \
|
||||
$$PWD/qmljstoolsplugin.h \
|
||||
$$PWD/qmljstoolsconstants.h \
|
||||
$$PWD/qmljstoolssettings.h \
|
||||
@@ -36,6 +37,7 @@ HEADERS += \
|
||||
$$PWD/qmlconsoleproxymodel.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/qmljsbundleprovider.cpp \
|
||||
$$PWD/qmljstoolsplugin.cpp \
|
||||
$$PWD/qmljstoolssettings.cpp \
|
||||
$$PWD/qmljscodestylepreferencesfactory.cpp \
|
||||
|
||||
@@ -21,6 +21,8 @@ QtcPlugin {
|
||||
cpp.includePaths: base.concat("../../libs/3rdparty")
|
||||
|
||||
files: [
|
||||
"qmljsbundleprovider.cpp",
|
||||
"qmljsbundleprovider.h",
|
||||
"qmljscodestylepreferencesfactory.cpp",
|
||||
"qmljscodestylepreferencesfactory.h",
|
||||
"qmljscodestylesettingspage.cpp",
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "qmljstoolsconstants.h"
|
||||
#include "qmljstoolssettings.h"
|
||||
#include "qmlconsolemanager.h"
|
||||
#include "qmljsbundleprovider.h"
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
@@ -94,6 +95,7 @@ bool QmlJSToolsPlugin::initialize(const QStringList &arguments, QString *error)
|
||||
addAutoReleasedObject(locatorData);
|
||||
addAutoReleasedObject(new FunctionFilter(locatorData));
|
||||
addAutoReleasedObject(new QmlJSCodeStyleSettingsPage);
|
||||
addAutoReleasedObject(new BasicBundleProvider);
|
||||
|
||||
// Menus
|
||||
Core::ActionContainer *mtools = Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <qtsupport/qtversionmanager.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <qmljstools/qmljsmodelmanager.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
@@ -184,32 +185,10 @@ void QmlProject::refresh(RefreshOptions options)
|
||||
if (options & Files)
|
||||
m_rootNode->refresh();
|
||||
|
||||
QmlJS::ModelManagerInterface::ProjectInfo projectInfo(this);
|
||||
projectInfo.sourceFiles = files();
|
||||
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
|
||||
QmlJSTools::defaultProjectInfoForProject(this);
|
||||
projectInfo.importPaths = customImportPaths();
|
||||
|
||||
QtSupport::BaseQtVersion *qtVersion = 0;
|
||||
{
|
||||
ProjectExplorer::Target *target = activeTarget();
|
||||
ProjectExplorer::Kit *kit = target ? target->kit() : ProjectExplorer::KitManager::instance()->defaultKit();
|
||||
ProjectExplorer::ToolChain *toolChain = ProjectExplorer::ToolChainKitInformation::toolChain(kit);
|
||||
qtVersion = QtSupport::QtKitInformation::qtVersion(kit);
|
||||
QtSupport::QmlDumpTool::pathAndEnvironment(this, qtVersion, toolChain, false,
|
||||
&projectInfo.qmlDumpPath, &projectInfo.qmlDumpEnvironment);
|
||||
}
|
||||
|
||||
if (qtVersion) {
|
||||
projectInfo.tryQmlDump = true;
|
||||
projectInfo.qtImportsPath = qtVersion->qmakeProperty("QT_INSTALL_IMPORTS");
|
||||
projectInfo.qtQmlPath = qtVersion->qmakeProperty("QT_INSTALL_QML");
|
||||
projectInfo.qtVersionString = qtVersion->qtVersionString();
|
||||
|
||||
if (!projectInfo.qtQmlPath.isEmpty())
|
||||
projectInfo.importPaths += projectInfo.qtQmlPath;
|
||||
if (!projectInfo.qtImportsPath.isEmpty())
|
||||
projectInfo.importPaths += projectInfo.qtImportsPath;
|
||||
|
||||
}
|
||||
m_modelManager->updateProjectInfo(projectInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <cpptools/ModelManagerInterface.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <qmljstools/qmljsmodelmanager.h>
|
||||
#include <projectexplorer/buildtargetinfo.h>
|
||||
#include <projectexplorer/deploymentdata.h>
|
||||
#include <projectexplorer/toolchain.h>
|
||||
@@ -592,8 +593,8 @@ void Qt4Project::updateQmlJSCodeModel()
|
||||
if (!modelManager)
|
||||
return;
|
||||
|
||||
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager->projectInfo(this);
|
||||
projectInfo.sourceFiles = m_projectFiles->files[QMLType];
|
||||
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
|
||||
QmlJSTools::defaultProjectInfoForProject(this);
|
||||
|
||||
FindQt4ProFiles findQt4ProFiles;
|
||||
QList<Qt4ProFileNode *> proFiles = findQt4ProFiles(rootProjectNode());
|
||||
@@ -616,47 +617,12 @@ void Qt4Project::updateQmlJSCodeModel()
|
||||
// This assumption fails when there are no QDeclarativeEngine/QDeclarativeView (QtQuick 1)
|
||||
// or QQmlEngine/QQuickView (QtQuick 2) instances.
|
||||
Core::Context pl(ProjectExplorer::Constants::LANG_CXX);
|
||||
if (projectInfo.sourceFiles.count() && hasQmlLib)
|
||||
if (m_projectFiles->files[QMLType].count() && hasQmlLib)
|
||||
pl.add(ProjectExplorer::Constants::LANG_QMLJS);
|
||||
setProjectLanguages(pl);
|
||||
|
||||
bool preferDebugDump = false;
|
||||
projectInfo.tryQmlDump = false;
|
||||
|
||||
ProjectExplorer::Target *t = activeTarget();
|
||||
ProjectExplorer::Kit *k = t ? t->kit() : ProjectExplorer::KitManager::instance()->defaultKit();
|
||||
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k);
|
||||
|
||||
if (t) {
|
||||
if (Qt4BuildConfiguration *bc = qobject_cast<Qt4BuildConfiguration *>(t->activeBuildConfiguration()))
|
||||
preferDebugDump = bc->qmakeBuildConfiguration() & QtSupport::BaseQtVersion::DebugBuild;
|
||||
} else {
|
||||
if (qtVersion)
|
||||
preferDebugDump = qtVersion->defaultBuildConfig() & QtSupport::BaseQtVersion::DebugBuild;
|
||||
}
|
||||
if (qtVersion && qtVersion->isValid()) {
|
||||
projectInfo.tryQmlDump = qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT)
|
||||
|| qtVersion->type() == QLatin1String(QtSupport::Constants::SIMULATORQT);
|
||||
projectInfo.qtQmlPath = qtVersion->qmakeProperty("QT_INSTALL_QML");
|
||||
if (!projectInfo.qtQmlPath.isEmpty())
|
||||
projectInfo.importPaths += projectInfo.qtQmlPath;
|
||||
projectInfo.qtImportsPath = qtVersion->qmakeProperty("QT_INSTALL_IMPORTS");
|
||||
if (!projectInfo.qtImportsPath.isEmpty())
|
||||
projectInfo.importPaths += projectInfo.qtImportsPath;
|
||||
projectInfo.qtVersionString = qtVersion->qtVersionString();
|
||||
}
|
||||
projectInfo.importPaths.removeDuplicates();
|
||||
|
||||
if (projectInfo.tryQmlDump) {
|
||||
QtSupport::QmlDumpTool::pathAndEnvironment(this, qtVersion,
|
||||
ToolChainKitInformation::toolChain(k),
|
||||
preferDebugDump, &projectInfo.qmlDumpPath,
|
||||
&projectInfo.qmlDumpEnvironment);
|
||||
} else {
|
||||
projectInfo.qmlDumpPath.clear();
|
||||
projectInfo.qmlDumpEnvironment.clear();
|
||||
}
|
||||
|
||||
modelManager->updateProjectInfo(projectInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ QtcPlugin {
|
||||
Depends { name: "QmlJS" }
|
||||
Depends { name: "CPlusPlus" }
|
||||
Depends { name: "TextEditor" }
|
||||
Depends { name: "QmlJSTools" }
|
||||
|
||||
Depends { name: "cpp" }
|
||||
cpp.defines: base.concat([
|
||||
|
||||
@@ -3,3 +3,4 @@ include(../../plugins/qtsupport/qtsupport.pri)
|
||||
include(../../plugins/cpptools/cpptools.pri)
|
||||
include(../../plugins/debugger/debugger.pri)
|
||||
include(../../libs/qmljs/qmljs.pri)
|
||||
include(../../plugins/qmljstools/qmljstools.pri)
|
||||
|
||||
Reference in New Issue
Block a user