forked from qt-creator/qt-creator
Started merging the JS and QML editor plug-ins.
This commit is contained in:
16
src/plugins/qmljseditor/QmlJSEditor.mimetypes.xml
Normal file
16
src/plugins/qmljseditor/QmlJSEditor.mimetypes.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
|
||||
<mime-type type="application/x-qml">
|
||||
<sub-class-of type="text/plain"/>
|
||||
<comment>QML file</comment>
|
||||
<glob pattern="*.qml"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/javascript">
|
||||
<alias type="application/x-javascript"/>
|
||||
<alias type="text/javascript"/>
|
||||
<sub-class-of type="text/plain"/>
|
||||
<comment>Qt Script file</comment>
|
||||
<glob pattern="*.js"/>
|
||||
<glob pattern="*.qs"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
20
src/plugins/qmljseditor/QmlJSEditor.pluginspec
Normal file
20
src/plugins/qmljseditor/QmlJSEditor.pluginspec
Normal file
@@ -0,0 +1,20 @@
|
||||
<plugin name="QmlJSEditor" version="1.3.80" compatVersion="1.3.80">
|
||||
<vendor>Nokia Corporation</vendor>
|
||||
<copyright>(C) 2008-2009 Nokia Corporation</copyright>
|
||||
<license>
|
||||
Commercial Usage
|
||||
|
||||
Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and Nokia.
|
||||
|
||||
GNU Lesser General Public License Usage
|
||||
|
||||
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. 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.
|
||||
</license>
|
||||
<description>Editor for QML and JavaScript.</description>
|
||||
<url>http://qt.nokia.com</url>
|
||||
<dependencyList>
|
||||
<dependency name="Core" version="1.3.80"/>
|
||||
<dependency name="TextEditor" version="1.3.80"/>
|
||||
<dependency name="Help" version="1.3.80"/>
|
||||
</dependencyList>
|
||||
</plugin>
|
||||
230
src/plugins/qmljseditor/qmlcodecompletion.cpp
Normal file
230
src/plugins/qmljseditor/qmlcodecompletion.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlcodecompletion.h"
|
||||
#include "qmljseditor.h"
|
||||
#include "qmlmodelmanagerinterface.h"
|
||||
#include "qmlexpressionundercursor.h"
|
||||
#include "qmllookupcontext.h"
|
||||
#include "qmlresolveexpression.h"
|
||||
|
||||
#include <qmljs/qmlsymbol.h>
|
||||
#include <texteditor/basetexteditor.h>
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
using namespace QmlJSEditor;
|
||||
using namespace QmlJSEditor::Internal;
|
||||
|
||||
QmlCodeCompletion::QmlCodeCompletion(QmlModelManagerInterface *modelManager, Qml::QmlTypeSystem *typeSystem, QObject *parent)
|
||||
: TextEditor::ICompletionCollector(parent),
|
||||
m_modelManager(modelManager),
|
||||
m_editor(0),
|
||||
m_startPosition(0),
|
||||
m_caseSensitivity(Qt::CaseSensitive),
|
||||
m_typeSystem(typeSystem)
|
||||
{
|
||||
Q_ASSERT(modelManager);
|
||||
Q_ASSERT(typeSystem);
|
||||
}
|
||||
|
||||
QmlCodeCompletion::~QmlCodeCompletion()
|
||||
{ }
|
||||
|
||||
Qt::CaseSensitivity QmlCodeCompletion::caseSensitivity() const
|
||||
{ return m_caseSensitivity; }
|
||||
|
||||
void QmlCodeCompletion::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
|
||||
{ m_caseSensitivity = caseSensitivity; }
|
||||
|
||||
bool QmlCodeCompletion::supportsEditor(TextEditor::ITextEditable *editor)
|
||||
{
|
||||
if (qobject_cast<QmlJSTextEditor *>(editor->widget()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QmlCodeCompletion::triggersCompletion(TextEditor::ITextEditable *)
|
||||
{ return false; }
|
||||
|
||||
int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
||||
{
|
||||
m_editor = editor;
|
||||
|
||||
QmlJSTextEditor *edit = qobject_cast<QmlJSTextEditor *>(m_editor->widget());
|
||||
if (! edit)
|
||||
return -1;
|
||||
|
||||
int pos = editor->position();
|
||||
|
||||
while (editor->characterAt(pos - 1).isLetterOrNumber() || editor->characterAt(pos - 1) == QLatin1Char('_'))
|
||||
--pos;
|
||||
|
||||
m_startPosition = pos;
|
||||
m_completions.clear();
|
||||
|
||||
Qml::QmlDocument::Ptr qmlDocument = edit->qmlDocument();
|
||||
// qDebug() << "*** document:" << qmlDocument;
|
||||
if (qmlDocument.isNull())
|
||||
return pos;
|
||||
|
||||
if (!qmlDocument->program())
|
||||
qmlDocument = m_modelManager->snapshot().value(qmlDocument->fileName());
|
||||
|
||||
// FIXME: this completion strategy is not going to work when the document was never parsed correctly.
|
||||
if (qmlDocument && qmlDocument->program()) {
|
||||
QmlJS::AST::UiProgram *program = qmlDocument->program();
|
||||
// qDebug() << "*** program:" << program;
|
||||
|
||||
if (program) {
|
||||
QmlExpressionUnderCursor expressionUnderCursor;
|
||||
QTextCursor cursor(edit->document());
|
||||
cursor.setPosition(pos);
|
||||
expressionUnderCursor(cursor, qmlDocument);
|
||||
|
||||
QmlLookupContext context(expressionUnderCursor.expressionScopes(), qmlDocument, m_modelManager->snapshot(), m_typeSystem);
|
||||
QmlResolveExpression resolver(context);
|
||||
// qDebug()<<"*** expression under cursor:"<<expressionUnderCursor.expressionNode();
|
||||
QList<Qml::QmlSymbol*> symbols = resolver.visibleSymbols(expressionUnderCursor.expressionNode());
|
||||
// qDebug()<<"***"<<symbols.size()<<"visible symbols";
|
||||
|
||||
foreach (Qml::QmlSymbol *symbol, symbols) {
|
||||
QString word;
|
||||
|
||||
if (symbol->isIdSymbol()) {
|
||||
word = symbol->asIdSymbol()->id();
|
||||
} else {
|
||||
word = symbol->name();
|
||||
}
|
||||
|
||||
if (word.isEmpty())
|
||||
continue;
|
||||
|
||||
TextEditor::CompletionItem item(this);
|
||||
item.text = word;
|
||||
m_completions.append(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void QmlCodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)
|
||||
{
|
||||
// ### FIXME: this code needs to be generalized.
|
||||
|
||||
const int length = m_editor->position() - m_startPosition;
|
||||
|
||||
if (length == 0)
|
||||
*completions = m_completions;
|
||||
else if (length > 0) {
|
||||
const QString key = m_editor->textAt(m_startPosition, length);
|
||||
|
||||
/*
|
||||
* This code builds a regular expression in order to more intelligently match
|
||||
* camel-case style. This means upper-case characters will be rewritten as follows:
|
||||
*
|
||||
* A => [a-z0-9_]*A (for any but the first capital letter)
|
||||
*
|
||||
* Meaning it allows any sequence of lower-case characters to preceed an
|
||||
* upper-case character. So for example gAC matches getActionController.
|
||||
*/
|
||||
QString keyRegExp;
|
||||
keyRegExp += QLatin1Char('^');
|
||||
bool first = true;
|
||||
foreach (const QChar &c, key) {
|
||||
if (c.isUpper() && !first) {
|
||||
keyRegExp += QLatin1String("[a-z0-9_]*");
|
||||
keyRegExp += c;
|
||||
} else if (m_caseSensitivity == Qt::CaseInsensitive && c.isLower()) {
|
||||
keyRegExp += QLatin1Char('[');
|
||||
keyRegExp += c;
|
||||
keyRegExp += c.toUpper();
|
||||
keyRegExp += QLatin1Char(']');
|
||||
} else {
|
||||
keyRegExp += QRegExp::escape(c);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
const QRegExp regExp(keyRegExp, Qt::CaseSensitive);
|
||||
|
||||
foreach (TextEditor::CompletionItem item, m_completions) {
|
||||
if (regExp.indexIn(item.text) == 0) {
|
||||
item.relevance = (key.length() > 0 &&
|
||||
item.text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
|
||||
(*completions) << item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlCodeCompletion::complete(const TextEditor::CompletionItem &item)
|
||||
{
|
||||
const QString toInsert = item.text;
|
||||
const int length = m_editor->position() - m_startPosition;
|
||||
m_editor->setCurPos(m_startPosition);
|
||||
m_editor->replace(length, toInsert);
|
||||
}
|
||||
|
||||
bool QmlCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)
|
||||
{
|
||||
if (completionItems.count() == 1) {
|
||||
complete(completionItems.first());
|
||||
return true;
|
||||
} else {
|
||||
// Compute common prefix
|
||||
QString firstKey = completionItems.first().text;
|
||||
QString lastKey = completionItems.last().text;
|
||||
const int length = qMin(firstKey.length(), lastKey.length());
|
||||
firstKey.truncate(length);
|
||||
lastKey.truncate(length);
|
||||
|
||||
while (firstKey != lastKey) {
|
||||
firstKey.chop(1);
|
||||
lastKey.chop(1);
|
||||
}
|
||||
|
||||
int typedLength = m_editor->position() - m_startPosition;
|
||||
if (!firstKey.isEmpty() && firstKey.length() > typedLength) {
|
||||
m_editor->setCurPos(m_startPosition);
|
||||
m_editor->replace(typedLength, firstKey);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void QmlCodeCompletion::cleanup()
|
||||
{
|
||||
m_editor = 0;
|
||||
m_startPosition = 0;
|
||||
m_completions.clear();
|
||||
}
|
||||
|
||||
78
src/plugins/qmljseditor/qmlcodecompletion.h
Normal file
78
src/plugins/qmljseditor/qmlcodecompletion.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLCODECOMPLETION_H
|
||||
#define QMLCODECOMPLETION_H
|
||||
|
||||
#include <qmljs/qmltypesystem.h>
|
||||
#include <texteditor/icompletioncollector.h>
|
||||
|
||||
namespace TextEditor {
|
||||
class ITextEditable;
|
||||
}
|
||||
|
||||
namespace QmlJSEditor {
|
||||
|
||||
class QmlModelManagerInterface;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QmlCodeCompletion: public TextEditor::ICompletionCollector
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlCodeCompletion(QmlModelManagerInterface *modelManager, Qml::QmlTypeSystem *typeSystem, QObject *parent = 0);
|
||||
virtual ~QmlCodeCompletion();
|
||||
|
||||
Qt::CaseSensitivity caseSensitivity() const;
|
||||
void setCaseSensitivity(Qt::CaseSensitivity caseSensitivity);
|
||||
|
||||
virtual bool supportsEditor(TextEditor::ITextEditable *editor);
|
||||
virtual bool triggersCompletion(TextEditor::ITextEditable *editor);
|
||||
virtual int startCompletion(TextEditor::ITextEditable *editor);
|
||||
virtual void completions(QList<TextEditor::CompletionItem> *completions);
|
||||
virtual void complete(const TextEditor::CompletionItem &item);
|
||||
virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
|
||||
virtual void cleanup();
|
||||
|
||||
private:
|
||||
QmlModelManagerInterface *m_modelManager;
|
||||
TextEditor::ITextEditable *m_editor;
|
||||
int m_startPosition;
|
||||
QList<TextEditor::CompletionItem> m_completions;
|
||||
Qt::CaseSensitivity m_caseSensitivity;
|
||||
Qml::QmlTypeSystem *m_typeSystem;
|
||||
};
|
||||
|
||||
|
||||
} // end of namespace Internal
|
||||
} // end of namespace QmlJSEditor
|
||||
|
||||
#endif // QMLCODECOMPLETION_H
|
||||
119
src/plugins/qmljseditor/qmlcompletionvisitor.cpp
Normal file
119
src/plugins/qmljseditor/qmlcompletionvisitor.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "qmlcompletionvisitor.h"
|
||||
#include "qmljsast_p.h"
|
||||
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJS::AST;
|
||||
|
||||
namespace QmlEditor {
|
||||
namespace Internal {
|
||||
|
||||
QmlCompletionVisitor::QmlCompletionVisitor()
|
||||
{
|
||||
}
|
||||
|
||||
QSet<QString> QmlCompletionVisitor::operator()(QmlJS::AST::UiProgram *ast, int pos)
|
||||
{
|
||||
m_completions.clear();
|
||||
m_pos = (quint32) pos;
|
||||
|
||||
Node::acceptChild(ast, this);
|
||||
|
||||
return m_completions;
|
||||
}
|
||||
|
||||
bool QmlCompletionVisitor::preVisit(QmlJS::AST::Node *node)
|
||||
{
|
||||
if (!m_parentStack.isEmpty())
|
||||
m_nodeParents[node] = m_parentStack.top();
|
||||
m_parentStack.push(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
static QString toString(Statement *stmt)
|
||||
{
|
||||
if (ExpressionStatement *exprStmt = AST::cast<ExpressionStatement*>(stmt)) {
|
||||
if (IdentifierExpression *idExpr = AST::cast<IdentifierExpression *>(exprStmt->expression)) {
|
||||
return idExpr->name->asString();
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool QmlCompletionVisitor::visit(UiScriptBinding *ast)
|
||||
{
|
||||
if (!ast)
|
||||
return false;
|
||||
|
||||
UiObjectDefinition *parentObject = findParentObject(ast);
|
||||
|
||||
if (ast->qualifiedId && ast->qualifiedId->name->asString() == QLatin1String("id")) {
|
||||
const QString nodeId = toString(ast->statement);
|
||||
if (!nodeId.isEmpty())
|
||||
m_objectToId[parentObject] = nodeId;
|
||||
} else if (m_objectToId.contains(parentObject)) {
|
||||
if (ast->qualifiedId && ast->qualifiedId->name) {
|
||||
const QString parentId = m_objectToId[parentObject];
|
||||
m_completions.insert(parentId + "." + ast->qualifiedId->name->asString());
|
||||
}
|
||||
}
|
||||
|
||||
if (ast->firstSourceLocation().begin() >= m_pos && m_pos <= ast->lastSourceLocation().end()) {
|
||||
UiObjectDefinition *parentsParent = findParentObject(parentObject);
|
||||
|
||||
if (parentsParent) {
|
||||
m_completions.insert(QLatin1String("parent"));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
UiObjectDefinition *QmlCompletionVisitor::findParentObject(Node *node) const
|
||||
{
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
Node *candidate = m_nodeParents[node];
|
||||
if (candidate == 0)
|
||||
return 0;
|
||||
|
||||
if (UiObjectDefinition *parentObject = AST::cast<UiObjectDefinition *>(candidate))
|
||||
return parentObject;
|
||||
else
|
||||
return findParentObject(candidate);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlEditor
|
||||
72
src/plugins/qmljseditor/qmlcompletionvisitor.h
Normal file
72
src/plugins/qmljseditor/qmlcompletionvisitor.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef COMPLETIONVISITOR_H
|
||||
#define COMPLETIONVISITOR_H
|
||||
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QStack>
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include "qmljsastfwd_p.h"
|
||||
#include "qmljsastvisitor_p.h"
|
||||
#include "qmljsengine_p.h"
|
||||
|
||||
namespace QmlEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlCompletionVisitor: protected QmlJS::AST::Visitor
|
||||
{
|
||||
public:
|
||||
QmlCompletionVisitor();
|
||||
|
||||
QSet<QString> operator()(QmlJS::AST::UiProgram *ast, int pos);
|
||||
|
||||
protected:
|
||||
virtual bool preVisit(QmlJS::AST::Node *node);
|
||||
virtual void postVisit(QmlJS::AST::Node *) { m_parentStack.pop(); }
|
||||
|
||||
virtual bool visit(QmlJS::AST::UiScriptBinding *ast);
|
||||
|
||||
private:
|
||||
QmlJS::AST::UiObjectDefinition *findParentObject(QmlJS::AST::Node *node) const;
|
||||
|
||||
private:
|
||||
QSet<QString> m_completions;
|
||||
quint32 m_pos;
|
||||
QStack<QmlJS::AST::Node *> m_parentStack;
|
||||
QMap<QmlJS::AST::Node *, QmlJS::AST::Node *> m_nodeParents;
|
||||
QMap<QmlJS::AST::Node *, QString> m_objectToId;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlEditor
|
||||
|
||||
#endif // COMPLETIONVISITOR_H
|
||||
308
src/plugins/qmljseditor/qmlexpressionundercursor.cpp
Normal file
308
src/plugins/qmljseditor/qmlexpressionundercursor.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlexpressionundercursor.h"
|
||||
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||
#include <qmljs/parser/qmljsengine_p.h>
|
||||
#include <qmljs/parser/qmljslexer_p.h>
|
||||
#include <qmljs/parser/qmljsnodepool_p.h>
|
||||
#include <qmljs/parser/qmljsparser_p.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
using namespace Qml;
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJS::AST;
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
class PositionCalculator: protected Visitor
|
||||
{
|
||||
public:
|
||||
Node *operator()(Node *ast, int pos)
|
||||
{
|
||||
_pos = pos;
|
||||
_expression = 0;
|
||||
_offset = -1;
|
||||
_length = -1;
|
||||
|
||||
Node::accept(ast, this);
|
||||
|
||||
return _expression;
|
||||
}
|
||||
|
||||
int offset() const
|
||||
{ return _offset; }
|
||||
|
||||
int length() const
|
||||
{ return _length; }
|
||||
|
||||
protected:
|
||||
bool visit(FieldMemberExpression *ast)
|
||||
{
|
||||
if (ast->identifierToken.offset <= _pos && _pos <= ast->identifierToken.end()) {
|
||||
_expression = ast;
|
||||
_offset = ast->identifierToken.offset;
|
||||
_length = ast->identifierToken.length;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(IdentifierExpression *ast)
|
||||
{
|
||||
if (ast->firstSourceLocation().offset <= _pos && _pos <= ast->lastSourceLocation().end()) {
|
||||
_expression = ast;
|
||||
_offset = ast->firstSourceLocation().offset;
|
||||
_length = ast->lastSourceLocation().end() - _offset;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(UiImport * /*ast*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(UiQualifiedId *ast)
|
||||
{
|
||||
if (ast->identifierToken.offset <= _pos) {
|
||||
for (UiQualifiedId *iter = ast; iter; iter = iter->next) {
|
||||
if (_pos <= iter->identifierToken.end()) {
|
||||
// found it
|
||||
_expression = ast;
|
||||
_offset = ast->identifierToken.offset;
|
||||
|
||||
for (UiQualifiedId *iter2 = ast; iter2; iter2 = iter2->next) {
|
||||
_length = iter2->identifierToken.end() - _offset;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
quint32 _pos;
|
||||
Node *_expression;
|
||||
int _offset;
|
||||
int _length;
|
||||
};
|
||||
|
||||
class ScopeCalculator: protected Visitor
|
||||
{
|
||||
public:
|
||||
QStack<QmlSymbol*> operator()(const QmlDocument::Ptr &doc, int pos)
|
||||
{
|
||||
_doc = doc;
|
||||
_pos = pos;
|
||||
_scopes.clear();
|
||||
_currentSymbol = 0;
|
||||
Node::accept(doc->program(), this);
|
||||
return _scopes;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool visit(Block * /*ast*/)
|
||||
{
|
||||
// TODO
|
||||
// if (_pos > ast->lbraceToken.end() && _pos < ast->rbraceToken.offset) {
|
||||
// push(ast);
|
||||
// Node::accept(ast->statements, this);
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool visit(UiObjectBinding *ast)
|
||||
{
|
||||
if (ast->initializer && ast->initializer->lbraceToken.offset < _pos && _pos <= ast->initializer->rbraceToken.end()) {
|
||||
push(ast);
|
||||
Node::accept(ast->initializer, this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool visit(UiObjectDefinition *ast)
|
||||
{
|
||||
if (ast->initializer && ast->initializer->lbraceToken.offset < _pos && _pos <= ast->initializer->rbraceToken.end()) {
|
||||
push(ast);
|
||||
Node::accept(ast->initializer, this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool visit(UiArrayBinding *ast)
|
||||
{
|
||||
if (ast->lbracketToken.offset < _pos && _pos <= ast->rbracketToken.end()) {
|
||||
push(ast);
|
||||
Node::accept(ast->members, this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
void push(Node *node)
|
||||
{
|
||||
QmlSymbolFromFile* symbol;
|
||||
|
||||
if (_currentSymbol) {
|
||||
symbol = _currentSymbol->findMember(node);
|
||||
} else {
|
||||
symbol = _doc->findSymbol(node);
|
||||
}
|
||||
|
||||
if (symbol) {
|
||||
_currentSymbol = symbol;
|
||||
|
||||
if (!cast<UiArrayBinding*>(node))
|
||||
_scopes.push(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QmlDocument::Ptr _doc;
|
||||
quint32 _pos;
|
||||
QStack<QmlSymbol*> _scopes;
|
||||
QmlSymbolFromFile* _currentSymbol;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
using namespace QmlJSEditor;
|
||||
using namespace QmlJSEditor::Internal;
|
||||
|
||||
QmlExpressionUnderCursor::QmlExpressionUnderCursor()
|
||||
: _expressionNode(0),
|
||||
_pos(0), _engine(0), _nodePool(0)
|
||||
{
|
||||
}
|
||||
|
||||
QmlExpressionUnderCursor::~QmlExpressionUnderCursor()
|
||||
{
|
||||
if (_engine) { delete _engine; _engine = 0; }
|
||||
if (_nodePool) { delete _nodePool; _nodePool = 0; }
|
||||
}
|
||||
|
||||
void QmlExpressionUnderCursor::operator()(const QTextCursor &cursor,
|
||||
const QmlDocument::Ptr &doc)
|
||||
{
|
||||
if (_engine) { delete _engine; _engine = 0; }
|
||||
if (_nodePool) { delete _nodePool; _nodePool = 0; }
|
||||
|
||||
_pos = cursor.position();
|
||||
_expressionNode = 0;
|
||||
_expressionOffset = -1;
|
||||
_expressionLength = -1;
|
||||
_expressionScopes.clear();
|
||||
|
||||
const QTextBlock block = cursor.block();
|
||||
parseExpression(block);
|
||||
|
||||
if (_expressionOffset != -1) {
|
||||
ScopeCalculator calculator;
|
||||
_expressionScopes = calculator(doc, _expressionOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlExpressionUnderCursor::parseExpression(const QTextBlock &block)
|
||||
{
|
||||
int textPosition = _pos - block.position();
|
||||
const QString blockText = block.text();
|
||||
if (textPosition > 0) {
|
||||
if (blockText.at(textPosition - 1) == QLatin1Char('.'))
|
||||
--textPosition;
|
||||
} else {
|
||||
textPosition = 0;
|
||||
}
|
||||
|
||||
const QString text = blockText.left(textPosition);
|
||||
|
||||
Node *node = 0;
|
||||
|
||||
if (UiObjectMember *binding = tryBinding(text)) {
|
||||
// qDebug() << "**** binding";
|
||||
node = binding;
|
||||
} else if (Statement *stmt = tryStatement(text)) {
|
||||
// qDebug() << "**** statement";
|
||||
node = stmt;
|
||||
} else {
|
||||
// qDebug() << "**** none";
|
||||
}
|
||||
|
||||
if (node) {
|
||||
PositionCalculator calculator;
|
||||
_expressionNode = calculator(node, textPosition);
|
||||
_expressionOffset = calculator.offset() + block.position();
|
||||
_expressionLength = calculator.length();
|
||||
}
|
||||
}
|
||||
|
||||
Statement *QmlExpressionUnderCursor::tryStatement(const QString &text)
|
||||
{
|
||||
_engine = new Engine();
|
||||
_nodePool = new NodePool("", _engine);
|
||||
Lexer lexer(_engine);
|
||||
Parser parser(_engine);
|
||||
lexer.setCode(text, /*line = */ 1);
|
||||
|
||||
if (parser.parseStatement())
|
||||
return parser.statement();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
UiObjectMember *QmlExpressionUnderCursor::tryBinding(const QString &text)
|
||||
{
|
||||
_engine = new Engine();
|
||||
_nodePool = new NodePool("", _engine);
|
||||
Lexer lexer(_engine);
|
||||
Parser parser(_engine);
|
||||
lexer.setCode(text, /*line = */ 1);
|
||||
|
||||
if (parser.parseUiObjectMember()) {
|
||||
UiObjectMember *member = parser.uiObjectMember();
|
||||
|
||||
if (cast<UiObjectBinding*>(member) || cast<UiArrayBinding*>(member) || cast<UiScriptBinding*>(member))
|
||||
return member;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
88
src/plugins/qmljseditor/qmlexpressionundercursor.h
Normal file
88
src/plugins/qmljseditor/qmlexpressionundercursor.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLEXPRESSIONUNDERCURSOR_H
|
||||
#define QMLEXPRESSIONUNDERCURSOR_H
|
||||
|
||||
#include <qmljs/parser/qmljsastfwd_p.h>
|
||||
#include <qmljs/qmldocument.h>
|
||||
#include <qmljs/qmlsymbol.h>
|
||||
|
||||
#include <QStack>
|
||||
#include <QTextBlock>
|
||||
#include <QTextCursor>
|
||||
|
||||
namespace QmlJS {
|
||||
class Engine;
|
||||
class NodePool;
|
||||
}
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlExpressionUnderCursor
|
||||
{
|
||||
public:
|
||||
QmlExpressionUnderCursor();
|
||||
virtual ~QmlExpressionUnderCursor();
|
||||
|
||||
void operator()(const QTextCursor &cursor, const Qml::QmlDocument::Ptr &doc);
|
||||
|
||||
QStack<Qml::QmlSymbol *> expressionScopes() const
|
||||
{ return _expressionScopes; }
|
||||
|
||||
QmlJS::AST::Node *expressionNode() const
|
||||
{ return _expressionNode; }
|
||||
|
||||
int expressionOffset() const
|
||||
{ return _expressionOffset; }
|
||||
|
||||
int expressionLength() const
|
||||
{ return _expressionLength; }
|
||||
|
||||
private:
|
||||
void parseExpression(const QTextBlock &block);
|
||||
|
||||
QmlJS::AST::Statement *tryStatement(const QString &text);
|
||||
QmlJS::AST::UiObjectMember *tryBinding(const QString &text);
|
||||
|
||||
private:
|
||||
QStack<Qml::QmlSymbol *> _expressionScopes;
|
||||
QmlJS::AST::Node *_expressionNode;
|
||||
int _expressionOffset;
|
||||
int _expressionLength;
|
||||
quint32 _pos;
|
||||
QmlJS::Engine *_engine;
|
||||
QmlJS::NodePool *_nodePool;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLEXPRESSIONUNDERCURSOR_H
|
||||
74
src/plugins/qmljseditor/qmlfilewizard.cpp
Normal file
74
src/plugins/qmljseditor/qmlfilewizard.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljseditorconstants.h"
|
||||
#include "qmlfilewizard.h"
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QTextStream>
|
||||
|
||||
using namespace QmlJSEditor;
|
||||
|
||||
QmlFileWizard::QmlFileWizard(const BaseFileWizardParameters ¶meters,
|
||||
QObject *parent):
|
||||
Core::StandardFileWizard(parameters, parent)
|
||||
{
|
||||
}
|
||||
|
||||
Core::GeneratedFiles QmlFileWizard::generateFilesFromPath(const QString &path,
|
||||
const QString &name,
|
||||
QString * /*errorMessage*/) const
|
||||
|
||||
{
|
||||
const QString mimeType = QLatin1String(Constants::QMLJSEDITOR_MIMETYPE);
|
||||
const QString fileName = Core::BaseFileWizard::buildFileName(path, name, preferredSuffix(mimeType));
|
||||
|
||||
Core::GeneratedFile file(fileName);
|
||||
file.setEditorId(QLatin1String(Constants::C_QMLJSEDITOR_ID));
|
||||
file.setContents(fileContents(fileName));
|
||||
|
||||
return Core::GeneratedFiles() << file;
|
||||
}
|
||||
|
||||
QString QmlFileWizard::fileContents(const QString &fileName) const
|
||||
{
|
||||
const QString baseName = QFileInfo(fileName).completeBaseName();
|
||||
QString contents;
|
||||
QTextStream str(&contents);
|
||||
// str << CppTools::AbstractEditorSupport::licenseTemplate();
|
||||
|
||||
str << QLatin1String("import Qt 4.6\n")
|
||||
<< QLatin1String("\n")
|
||||
<< QLatin1String("Rectangle {\n")
|
||||
<< QLatin1String(" width: 640\n")
|
||||
<< QLatin1String(" height: 480\n")
|
||||
<< QLatin1String("}\n");
|
||||
|
||||
return contents;
|
||||
}
|
||||
58
src/plugins/qmljseditor/qmlfilewizard.h
Normal file
58
src/plugins/qmljseditor/qmlfilewizard.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLFILEWIZARD_H
|
||||
#define QMLFILEWIZARD_H
|
||||
|
||||
#include <coreplugin/basefilewizard.h>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
|
||||
class QmlFileWizard: public Core::StandardFileWizard
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef Core::BaseFileWizardParameters BaseFileWizardParameters;
|
||||
|
||||
QmlFileWizard(const BaseFileWizardParameters ¶meters,
|
||||
QObject *parent = 0);
|
||||
|
||||
protected:
|
||||
QString fileContents(const QString &baseName) const;
|
||||
|
||||
protected:
|
||||
Core::GeneratedFiles generateFilesFromPath(const QString &path,
|
||||
const QString &fileName,
|
||||
QString *errorMessage) const;
|
||||
};
|
||||
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLFILEWIZARD_H
|
||||
114
src/plugins/qmljseditor/qmlhighlighter.cpp
Normal file
114
src/plugins/qmljseditor/qmlhighlighter.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlhighlighter.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
using namespace QmlJSEditor;
|
||||
using namespace QmlJSEditor::Internal;
|
||||
|
||||
QmlHighlighter::QmlHighlighter(QTextDocument *parent) :
|
||||
SharedTools::QScriptHighlighter(true, parent)
|
||||
{
|
||||
m_currentBlockParentheses.reserve(20);
|
||||
m_braceDepth = 0;
|
||||
|
||||
QSet<QString> qmlKeywords(keywords());
|
||||
qmlKeywords << QLatin1String("property");
|
||||
qmlKeywords << QLatin1String("signal");
|
||||
qmlKeywords << QLatin1String("readonly");
|
||||
m_scanner.setKeywords(qmlKeywords);
|
||||
}
|
||||
|
||||
int QmlHighlighter::onBlockStart()
|
||||
{
|
||||
m_currentBlockParentheses.clear();
|
||||
m_braceDepth = 0;
|
||||
|
||||
int state = 0;
|
||||
int previousState = previousBlockState();
|
||||
if (previousState != -1) {
|
||||
state = previousState & 0xff;
|
||||
m_braceDepth = previousState >> 8;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void QmlHighlighter::onOpeningParenthesis(QChar parenthesis, int pos)
|
||||
{
|
||||
if (parenthesis == QLatin1Char('{')
|
||||
|| parenthesis == QLatin1Char('['))
|
||||
++m_braceDepth;
|
||||
m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Opened, parenthesis, pos));
|
||||
}
|
||||
|
||||
void QmlHighlighter::onClosingParenthesis(QChar parenthesis, int pos)
|
||||
{
|
||||
if (parenthesis == QLatin1Char('}')
|
||||
|| parenthesis == QLatin1Char(']'))
|
||||
--m_braceDepth;
|
||||
m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Closed, parenthesis, pos));
|
||||
}
|
||||
|
||||
void QmlHighlighter::onBlockEnd(int state, int firstNonSpace)
|
||||
{
|
||||
typedef TextEditor::TextBlockUserData TextEditorBlockData;
|
||||
|
||||
setCurrentBlockState((m_braceDepth << 8) | state);
|
||||
|
||||
// Set block data parentheses. Force creation of block data unless empty
|
||||
TextEditorBlockData *blockData = 0;
|
||||
|
||||
if (QTextBlockUserData *userData = currentBlockUserData())
|
||||
blockData = static_cast<TextEditorBlockData *>(userData);
|
||||
|
||||
if (!blockData && !m_currentBlockParentheses.empty()) {
|
||||
blockData = new TextEditorBlockData;
|
||||
setCurrentBlockUserData(blockData);
|
||||
}
|
||||
if (blockData) {
|
||||
blockData->setParentheses(m_currentBlockParentheses);
|
||||
blockData->setClosingCollapseMode(TextEditor::TextBlockUserData::NoClosingCollapse);
|
||||
blockData->setCollapseMode(TextEditor::TextBlockUserData::NoCollapse);
|
||||
}
|
||||
if (!m_currentBlockParentheses.isEmpty()) {
|
||||
QTC_ASSERT(blockData, return);
|
||||
int collapse = Parenthesis::collapseAtPos(m_currentBlockParentheses);
|
||||
if (collapse >= 0) {
|
||||
if (collapse == firstNonSpace)
|
||||
blockData->setCollapseMode(TextEditor::TextBlockUserData::CollapseThis);
|
||||
else
|
||||
blockData->setCollapseMode(TextEditor::TextBlockUserData::CollapseAfter);
|
||||
}
|
||||
if (Parenthesis::hasClosingCollapse(m_currentBlockParentheses))
|
||||
blockData->setClosingCollapseMode(TextEditor::TextBlockUserData::NoClosingCollapse);
|
||||
}
|
||||
}
|
||||
64
src/plugins/qmljseditor/qmlhighlighter.h
Normal file
64
src/plugins/qmljseditor/qmlhighlighter.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLSYNTAXHIGHLIGHTER_H
|
||||
#define QMLSYNTAXHIGHLIGHTER_H
|
||||
|
||||
#include <qscripthighlighter/qscripthighlighter.h>
|
||||
#include <texteditor/basetexteditor.h>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
// Highlighter for Scripts that stores
|
||||
// the parentheses encountered in the block data
|
||||
// for parentheses matching to work.
|
||||
|
||||
class QmlHighlighter : public SharedTools::QScriptHighlighter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QmlHighlighter(QTextDocument *parent = 0);
|
||||
|
||||
private:
|
||||
virtual int onBlockStart();
|
||||
virtual void onOpeningParenthesis(QChar parenthesis, int pos);
|
||||
virtual void onClosingParenthesis(QChar parenthesis, int pos);
|
||||
virtual void onBlockEnd(int state, int firstNonSpace);
|
||||
|
||||
typedef TextEditor::Parenthesis Parenthesis;
|
||||
typedef TextEditor::Parentheses Parentheses;
|
||||
Parentheses m_currentBlockParentheses;
|
||||
int m_braceDepth;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLSYNTAXHIGHLIGHTER_H
|
||||
227
src/plugins/qmljseditor/qmlhoverhandler.cpp
Normal file
227
src/plugins/qmljseditor/qmlhoverhandler.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljseditor.h"
|
||||
#include "qmlexpressionundercursor.h"
|
||||
#include "qmlhoverhandler.h"
|
||||
#include "qmllookupcontext.h"
|
||||
#include "qmlresolveexpression.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/uniqueidmanager.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <qmljs/qmlsymbol.h>
|
||||
#include <texteditor/itexteditor.h>
|
||||
#include <texteditor/basetexteditor.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtGui/QToolTip>
|
||||
#include <QtGui/QTextCursor>
|
||||
#include <QtGui/QTextBlock>
|
||||
#include <QtHelp/QHelpEngineCore>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Qml;
|
||||
using namespace QmlJSEditor;
|
||||
using namespace QmlJSEditor::Internal;
|
||||
|
||||
QmlHoverHandler::QmlHoverHandler(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_helpEngineNeedsSetup(false)
|
||||
{
|
||||
m_modelManager = ExtensionSystem::PluginManager::instance()->getObject<QmlModelManagerInterface>();
|
||||
|
||||
ICore *core = ICore::instance();
|
||||
QFileInfo fi(core->settings()->fileName());
|
||||
// FIXME shouldn't the help engine create the directory if it doesn't exist?
|
||||
QDir directory(fi.absolutePath()+"/qtcreator");
|
||||
if (!directory.exists())
|
||||
directory.mkpath(directory.absolutePath());
|
||||
|
||||
m_helpEngine = new QHelpEngineCore(directory.absolutePath()
|
||||
+ QLatin1String("/helpcollection.qhc"), this);
|
||||
//m_helpEngine->setAutoSaveFilter(false);
|
||||
if (!m_helpEngine->setupData())
|
||||
qWarning() << "Could not initialize help engine:" << m_helpEngine->error();
|
||||
m_helpEngine->setCurrentFilter(tr("Unfiltered"));
|
||||
m_helpEngineNeedsSetup = m_helpEngine->registeredDocumentations().count() == 0;
|
||||
|
||||
// Listen for editor opened events in order to connect to tooltip/helpid requests
|
||||
connect(core->editorManager(), SIGNAL(editorOpened(Core::IEditor *)),
|
||||
this, SLOT(editorOpened(Core::IEditor *)));
|
||||
}
|
||||
|
||||
void QmlHoverHandler::editorOpened(IEditor *editor)
|
||||
{
|
||||
QmlJSEditorEditable *qmlEditor = qobject_cast<QmlJSEditorEditable *>(editor);
|
||||
if (!qmlEditor)
|
||||
return;
|
||||
|
||||
connect(qmlEditor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*, QPoint, int)),
|
||||
this, SLOT(showToolTip(TextEditor::ITextEditor*, QPoint, int)));
|
||||
|
||||
connect(qmlEditor, SIGNAL(contextHelpIdRequested(TextEditor::ITextEditor*, int)),
|
||||
this, SLOT(updateContextHelpId(TextEditor::ITextEditor*, int)));
|
||||
}
|
||||
|
||||
void QmlHoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos)
|
||||
{
|
||||
if (! editor)
|
||||
return;
|
||||
|
||||
ICore *core = ICore::instance();
|
||||
const int dbgcontext = core->uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_GDBDEBUGGER);
|
||||
|
||||
if (core->hasContext(dbgcontext))
|
||||
return;
|
||||
|
||||
updateHelpIdAndTooltip(editor, pos);
|
||||
|
||||
if (m_toolTip.isEmpty())
|
||||
QToolTip::hideText();
|
||||
else {
|
||||
const QPoint pnt = point - QPoint(0,
|
||||
#ifdef Q_WS_WIN
|
||||
24
|
||||
#else
|
||||
16
|
||||
#endif
|
||||
);
|
||||
|
||||
QToolTip::showText(pnt, m_toolTip);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos)
|
||||
{
|
||||
updateHelpIdAndTooltip(editor, pos);
|
||||
}
|
||||
|
||||
static QString buildHelpId(QmlSymbol *symbol)
|
||||
{
|
||||
if (!symbol)
|
||||
return QString();
|
||||
|
||||
const QString idTemplate(QLatin1String("QML.%1"));
|
||||
|
||||
return idTemplate.arg(symbol->name());
|
||||
}
|
||||
|
||||
void QmlHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int pos)
|
||||
{
|
||||
m_helpId.clear();
|
||||
m_toolTip.clear();
|
||||
|
||||
if (!m_modelManager)
|
||||
return;
|
||||
|
||||
QmlJSTextEditor *scriptEditor = qobject_cast<QmlJSTextEditor *>(editor->widget());
|
||||
if (!scriptEditor)
|
||||
return;
|
||||
|
||||
const Snapshot documents = m_modelManager->snapshot();
|
||||
const QString fileName = editor->file()->fileName();
|
||||
QmlDocument::Ptr doc = documents.value(fileName);
|
||||
if (!doc)
|
||||
return; // nothing to do
|
||||
|
||||
QTextCursor tc(scriptEditor->document());
|
||||
tc.setPosition(pos);
|
||||
const unsigned lineNumber = tc.block().blockNumber() + 1;
|
||||
|
||||
// We only want to show F1 if the tooltip matches the help id
|
||||
bool showF1 = true;
|
||||
|
||||
foreach (const QmlJS::DiagnosticMessage &m, scriptEditor->diagnosticMessages()) {
|
||||
if (m.loc.startLine == lineNumber) {
|
||||
m_toolTip = m.message;
|
||||
showF1 = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString symbolName = QLatin1String("<unknown>");
|
||||
if (m_helpId.isEmpty()) {
|
||||
// Move to the end of a qualified name
|
||||
bool stop = false;
|
||||
while (!stop) {
|
||||
const QChar ch = editor->characterAt(tc.position());
|
||||
if (ch.isLetterOrNumber() || ch == QLatin1Char('_') || ch == QLatin1Char('.')) {
|
||||
tc.setPosition(tc.position() + 1);
|
||||
} else {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the expression's code
|
||||
QmlExpressionUnderCursor expressionUnderCursor;
|
||||
expressionUnderCursor(tc, doc);
|
||||
|
||||
Qml::QmlTypeSystem *typeSystem = ExtensionSystem::PluginManager::instance()->getObject<Qml::QmlTypeSystem>();
|
||||
|
||||
QmlLookupContext context(expressionUnderCursor.expressionScopes(), doc, m_modelManager->snapshot(), typeSystem);
|
||||
QmlResolveExpression resolver(context);
|
||||
QmlSymbol *resolvedSymbol = resolver.typeOf(expressionUnderCursor.expressionNode());
|
||||
|
||||
if (resolvedSymbol) {
|
||||
symbolName = resolvedSymbol->name();
|
||||
|
||||
if (resolvedSymbol->isBuildInSymbol())
|
||||
m_helpId = buildHelpId(resolvedSymbol);
|
||||
else if (QmlSymbolFromFile *symbolFromFile = resolvedSymbol->asSymbolFromFile())
|
||||
m_toolTip = symbolFromFile->fileName();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_helpEngineNeedsSetup && m_helpEngine->registeredDocumentations().count() > 0) {
|
||||
m_helpEngine->setupData();
|
||||
m_helpEngineNeedsSetup = false;
|
||||
}
|
||||
|
||||
if (!m_toolTip.isEmpty())
|
||||
m_toolTip = Qt::escape(m_toolTip);
|
||||
|
||||
if (!m_helpId.isEmpty() && !m_helpEngine->linksForIdentifier(m_helpId).isEmpty()) {
|
||||
if (showF1) {
|
||||
m_toolTip = QString(QLatin1String("<table><tr><td valign=middle><nobr>%1</td>"
|
||||
"<td><img src=\":/cppeditor/images/f1.svg\"></td></tr></table>"))
|
||||
.arg(m_toolTip);
|
||||
}
|
||||
editor->setContextHelpId(m_helpId);
|
||||
} else if (!m_toolTip.isEmpty()) {
|
||||
m_toolTip = QString(QLatin1String("<nobr>%1")).arg(m_toolTip);
|
||||
} else if (!m_helpId.isEmpty()) {
|
||||
m_toolTip = QString(QLatin1String("<nobr>No help available for \"%1\"")).arg(symbolName);
|
||||
}
|
||||
}
|
||||
81
src/plugins/qmljseditor/qmlhoverhandler.h
Normal file
81
src/plugins/qmljseditor/qmlhoverhandler.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLHOVERHANDLER_H
|
||||
#define QMLHOVERHANDLER_H
|
||||
|
||||
#include "qmlmodelmanagerinterface.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QHelpEngineCore;
|
||||
class QPoint;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Core {
|
||||
class IEditor;
|
||||
}
|
||||
|
||||
namespace TextEditor {
|
||||
class ITextEditor;
|
||||
}
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlHoverHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlHoverHandler(QObject *parent = 0);
|
||||
|
||||
public slots:
|
||||
void showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos);
|
||||
void updateContextHelpId(TextEditor::ITextEditor *editor, int pos);
|
||||
|
||||
private slots:
|
||||
void editorOpened(Core::IEditor *editor);
|
||||
|
||||
private:
|
||||
void updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int pos);
|
||||
|
||||
private:
|
||||
QmlModelManagerInterface *m_modelManager;
|
||||
QHelpEngineCore *m_helpEngine;
|
||||
QString m_helpId;
|
||||
QString m_toolTip;
|
||||
bool m_helpEngineNeedsSetup;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLHOVERHANDLER_H
|
||||
866
src/plugins/qmljseditor/qmljseditor.cpp
Normal file
866
src/plugins/qmljseditor/qmljseditor.cpp
Normal file
@@ -0,0 +1,866 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljseditor.h"
|
||||
#include "qmljseditorconstants.h"
|
||||
#include "qmlhighlighter.h"
|
||||
#include "qmljseditorplugin.h"
|
||||
#include "qmlmodelmanager.h"
|
||||
|
||||
#include "qmlexpressionundercursor.h"
|
||||
#include "qmllookupcontext.h"
|
||||
#include "qmlresolveexpression.h"
|
||||
|
||||
#include <qscripthighlighter/qscriptindenter.h>
|
||||
|
||||
#include <qmljs/qmltypesystem.h>
|
||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <qmljs/parser/qmljsengine_p.h>
|
||||
#include <qmljs/qmldocument.h>
|
||||
#include <qmljs/qmlidcollector.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/uniqueidmanager.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <texteditor/basetextdocument.h>
|
||||
#include <texteditor/fontsettings.h>
|
||||
#include <texteditor/textblockiterator.h>
|
||||
#include <texteditor/texteditorconstants.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
|
||||
#include <utils/changeset.h>
|
||||
#include <utils/uncommentselection.h>
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <QtGui/QMenu>
|
||||
#include <QtGui/QComboBox>
|
||||
#include <QtGui/QInputDialog>
|
||||
#include <QtGui/QMainWindow>
|
||||
#include <QtGui/QToolBar>
|
||||
|
||||
enum {
|
||||
UPDATE_DOCUMENT_DEFAULT_INTERVAL = 250,
|
||||
UPDATE_USES_DEFAULT_INTERVAL = 150
|
||||
};
|
||||
|
||||
using namespace Qml;
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJS::AST;
|
||||
using namespace SharedTools;
|
||||
|
||||
namespace {
|
||||
int blockBraceDepth(const QTextBlock &block)
|
||||
{
|
||||
int state = block.userState();
|
||||
if (state == -1)
|
||||
return 0;
|
||||
|
||||
return (state >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
int blockStartState(const QTextBlock &block)
|
||||
{
|
||||
int state = block.userState();
|
||||
|
||||
if (state == -1)
|
||||
return 0;
|
||||
else
|
||||
return state & 0xff;
|
||||
}
|
||||
} // end of anonymous namespace
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class FindIdDeclarations: protected Visitor
|
||||
{
|
||||
public:
|
||||
typedef QMap<QString, QList<AST::SourceLocation> > Result;
|
||||
|
||||
Result operator()(AST::Node *node)
|
||||
{
|
||||
_ids.clear();
|
||||
_maybeIds.clear();
|
||||
accept(node);
|
||||
return _ids;
|
||||
}
|
||||
|
||||
protected:
|
||||
QString asString(AST::UiQualifiedId *id)
|
||||
{
|
||||
QString text;
|
||||
for (; id; id = id->next) {
|
||||
if (id->name)
|
||||
text += id->name->asString();
|
||||
else
|
||||
text += QLatin1Char('?');
|
||||
|
||||
if (id->next)
|
||||
text += QLatin1Char('.');
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void accept(AST::Node *node)
|
||||
{ AST::Node::acceptChild(node, this); }
|
||||
|
||||
using Visitor::visit;
|
||||
using Visitor::endVisit;
|
||||
|
||||
virtual bool visit(AST::UiScriptBinding *node)
|
||||
{
|
||||
if (asString(node->qualifiedId) == QLatin1String("id")) {
|
||||
if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement*>(node->statement)) {
|
||||
if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(stmt->expression)) {
|
||||
if (idExpr->name) {
|
||||
const QString id = idExpr->name->asString();
|
||||
QList<AST::SourceLocation> *locs = &_ids[id];
|
||||
locs->append(idExpr->firstSourceLocation());
|
||||
locs->append(_maybeIds.value(id));
|
||||
_maybeIds.remove(id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accept(node->statement);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool visit(AST::IdentifierExpression *node)
|
||||
{
|
||||
if (node->name) {
|
||||
const QString name = node->name->asString();
|
||||
|
||||
if (_ids.contains(name))
|
||||
_ids[name].append(node->identifierToken);
|
||||
else
|
||||
_maybeIds[name].append(node->identifierToken);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
Result _ids;
|
||||
Result _maybeIds;
|
||||
};
|
||||
|
||||
class FindDeclarations: protected Visitor
|
||||
{
|
||||
QList<Declaration> _declarations;
|
||||
int _depth;
|
||||
|
||||
public:
|
||||
QList<Declaration> operator()(AST::Node *node)
|
||||
{
|
||||
_depth = -1;
|
||||
_declarations.clear();
|
||||
accept(node);
|
||||
return _declarations;
|
||||
}
|
||||
|
||||
protected:
|
||||
using Visitor::visit;
|
||||
using Visitor::endVisit;
|
||||
|
||||
QString asString(AST::UiQualifiedId *id)
|
||||
{
|
||||
QString text;
|
||||
for (; id; id = id->next) {
|
||||
if (id->name)
|
||||
text += id->name->asString();
|
||||
else
|
||||
text += QLatin1Char('?');
|
||||
|
||||
if (id->next)
|
||||
text += QLatin1Char('.');
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void accept(AST::Node *node)
|
||||
{ AST::Node::acceptChild(node, this); }
|
||||
|
||||
void init(Declaration *decl, AST::UiObjectMember *member)
|
||||
{
|
||||
const SourceLocation first = member->firstSourceLocation();
|
||||
const SourceLocation last = member->lastSourceLocation();
|
||||
decl->startLine = first.startLine;
|
||||
decl->startColumn = first.startColumn;
|
||||
decl->endLine = last.startLine;
|
||||
decl->endColumn = last.startColumn + last.length;
|
||||
}
|
||||
|
||||
virtual bool visit(AST::UiObjectDefinition *node)
|
||||
{
|
||||
++_depth;
|
||||
|
||||
Declaration decl;
|
||||
init(&decl, node);
|
||||
|
||||
decl.text.fill(QLatin1Char(' '), _depth);
|
||||
if (node->qualifiedTypeNameId)
|
||||
decl.text.append(asString(node->qualifiedTypeNameId));
|
||||
else
|
||||
decl.text.append(QLatin1Char('?'));
|
||||
|
||||
_declarations.append(decl);
|
||||
|
||||
return true; // search for more bindings
|
||||
}
|
||||
|
||||
virtual void endVisit(AST::UiObjectDefinition *)
|
||||
{
|
||||
--_depth;
|
||||
}
|
||||
|
||||
virtual bool visit(AST::UiObjectBinding *node)
|
||||
{
|
||||
++_depth;
|
||||
|
||||
Declaration decl;
|
||||
init(&decl, node);
|
||||
|
||||
decl.text.fill(QLatin1Char(' '), _depth);
|
||||
|
||||
decl.text.append(asString(node->qualifiedId));
|
||||
decl.text.append(QLatin1String(": "));
|
||||
|
||||
if (node->qualifiedTypeNameId)
|
||||
decl.text.append(asString(node->qualifiedTypeNameId));
|
||||
else
|
||||
decl.text.append(QLatin1Char('?'));
|
||||
|
||||
_declarations.append(decl);
|
||||
|
||||
return true; // search for more bindings
|
||||
}
|
||||
|
||||
virtual void endVisit(AST::UiObjectBinding *)
|
||||
{
|
||||
--_depth;
|
||||
}
|
||||
|
||||
#if 0 // ### ignore script bindings for now.
|
||||
virtual bool visit(AST::UiScriptBinding *node)
|
||||
{
|
||||
++_depth;
|
||||
|
||||
Declaration decl;
|
||||
init(&decl, node);
|
||||
|
||||
decl.text.fill(QLatin1Char(' '), _depth);
|
||||
decl.text.append(asString(node->qualifiedId));
|
||||
|
||||
_declarations.append(decl);
|
||||
|
||||
return false; // more more bindings in this subtree.
|
||||
}
|
||||
|
||||
virtual void endVisit(AST::UiScriptBinding *)
|
||||
{
|
||||
--_depth;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
QmlJSEditorEditable::QmlJSEditorEditable(QmlJSTextEditor *editor)
|
||||
: BaseTextEditorEditable(editor)
|
||||
{
|
||||
|
||||
Core::UniqueIDManager *uidm = Core::UniqueIDManager::instance();
|
||||
m_context << uidm->uniqueIdentifier(QmlJSEditor::Constants::C_QMLJSEDITOR_ID);
|
||||
m_context << uidm->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
|
||||
}
|
||||
|
||||
QmlJSTextEditor::QmlJSTextEditor(QWidget *parent) :
|
||||
TextEditor::BaseTextEditor(parent),
|
||||
m_methodCombo(0),
|
||||
m_modelManager(0),
|
||||
m_typeSystem(0)
|
||||
{
|
||||
m_idsRevision = -1;
|
||||
setParenthesesMatchingEnabled(true);
|
||||
setMarksVisible(true);
|
||||
setCodeFoldingSupported(true);
|
||||
setCodeFoldingVisible(true);
|
||||
setMimeType(QmlJSEditor::Constants::QMLJSEDITOR_MIMETYPE);
|
||||
|
||||
m_updateDocumentTimer = new QTimer(this);
|
||||
m_updateDocumentTimer->setInterval(UPDATE_DOCUMENT_DEFAULT_INTERVAL);
|
||||
m_updateDocumentTimer->setSingleShot(true);
|
||||
connect(m_updateDocumentTimer, SIGNAL(timeout()), this, SLOT(updateDocumentNow()));
|
||||
|
||||
m_updateUsesTimer = new QTimer(this);
|
||||
m_updateUsesTimer->setInterval(UPDATE_USES_DEFAULT_INTERVAL);
|
||||
m_updateUsesTimer->setSingleShot(true);
|
||||
connect(m_updateUsesTimer, SIGNAL(timeout()), this, SLOT(updateUsesNow()));
|
||||
|
||||
connect(this, SIGNAL(textChanged()), this, SLOT(updateDocument()));
|
||||
connect(this, SIGNAL(textChanged()), this, SLOT(updateUses()));
|
||||
|
||||
baseTextDocument()->setSyntaxHighlighter(new QmlHighlighter);
|
||||
|
||||
m_modelManager = ExtensionSystem::PluginManager::instance()->getObject<QmlModelManagerInterface>();
|
||||
m_typeSystem = ExtensionSystem::PluginManager::instance()->getObject<Qml::QmlTypeSystem>();
|
||||
|
||||
if (m_modelManager) {
|
||||
connect(m_modelManager, SIGNAL(documentUpdated(Qml::QmlDocument::Ptr)),
|
||||
this, SLOT(onDocumentUpdated(Qml::QmlDocument::Ptr)));
|
||||
}
|
||||
}
|
||||
|
||||
QmlJSTextEditor::~QmlJSTextEditor()
|
||||
{
|
||||
}
|
||||
|
||||
QList<Declaration> QmlJSTextEditor::declarations() const
|
||||
{ return m_declarations; }
|
||||
|
||||
Core::IEditor *QmlJSEditorEditable::duplicate(QWidget *parent)
|
||||
{
|
||||
QmlJSTextEditor *newEditor = new QmlJSTextEditor(parent);
|
||||
newEditor->duplicateFrom(editor());
|
||||
QmlJSEditorPlugin::instance()->initializeEditor(newEditor);
|
||||
return newEditor->editableInterface();
|
||||
}
|
||||
|
||||
QString QmlJSEditorEditable::id() const
|
||||
{
|
||||
return QLatin1String(QmlJSEditor::Constants::C_QMLJSEDITOR_ID);
|
||||
}
|
||||
|
||||
QmlJSTextEditor::Context QmlJSEditorEditable::context() const
|
||||
{
|
||||
return m_context;
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateDocument()
|
||||
{
|
||||
m_updateDocumentTimer->start(UPDATE_DOCUMENT_DEFAULT_INTERVAL);
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateDocumentNow()
|
||||
{
|
||||
// ### move in the parser thread.
|
||||
|
||||
m_updateDocumentTimer->stop();
|
||||
|
||||
const QString fileName = file()->fileName();
|
||||
|
||||
m_modelManager->updateSourceFiles(QStringList() << fileName);
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::onDocumentUpdated(Qml::QmlDocument::Ptr doc)
|
||||
{
|
||||
if (file()->fileName() != doc->fileName())
|
||||
return;
|
||||
|
||||
m_document = doc;
|
||||
|
||||
FindIdDeclarations updateIds;
|
||||
m_idsRevision = document()->revision();
|
||||
m_ids = updateIds(doc->program());
|
||||
|
||||
if (doc->isParsedCorrectly()) {
|
||||
FindDeclarations findDeclarations;
|
||||
m_declarations = findDeclarations(doc->program());
|
||||
|
||||
QStringList items;
|
||||
items.append(tr("<Select Symbol>"));
|
||||
|
||||
foreach (Declaration decl, m_declarations)
|
||||
items.append(decl.text);
|
||||
|
||||
m_methodCombo->clear();
|
||||
m_methodCombo->addItems(items);
|
||||
updateMethodBoxIndex();
|
||||
}
|
||||
|
||||
QList<QTextEdit::ExtraSelection> selections;
|
||||
|
||||
QTextCharFormat errorFormat;
|
||||
errorFormat.setUnderlineColor(Qt::red);
|
||||
errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
||||
|
||||
QTextEdit::ExtraSelection sel;
|
||||
|
||||
m_diagnosticMessages = doc->diagnosticMessages();
|
||||
|
||||
foreach (const DiagnosticMessage &d, m_diagnosticMessages) {
|
||||
int line = d.loc.startLine;
|
||||
int column = d.loc.startColumn;
|
||||
|
||||
if (column == 0)
|
||||
column = 1;
|
||||
|
||||
QTextCursor c(document()->findBlockByNumber(line - 1));
|
||||
sel.cursor = c;
|
||||
|
||||
sel.cursor.setPosition(c.position() + column - 1);
|
||||
if (sel.cursor.atBlockEnd())
|
||||
sel.cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
|
||||
else
|
||||
sel.cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
|
||||
sel.format = errorFormat;
|
||||
|
||||
selections.append(sel);
|
||||
}
|
||||
|
||||
setExtraSelections(CodeWarningsSelection, selections);
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::jumpToMethod(int index)
|
||||
{
|
||||
if (index) {
|
||||
Declaration d = m_declarations.at(index - 1);
|
||||
gotoLine(d.startLine, d.startColumn - 1);
|
||||
setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateMethodBoxIndex()
|
||||
{
|
||||
int line = 0, column = 0;
|
||||
convertPosition(position(), &line, &column);
|
||||
|
||||
int currentSymbolIndex = 0;
|
||||
|
||||
int index = 0;
|
||||
while (index < m_declarations.size()) {
|
||||
const Declaration &d = m_declarations.at(index++);
|
||||
|
||||
if (line < d.startLine)
|
||||
break;
|
||||
else
|
||||
currentSymbolIndex = index;
|
||||
}
|
||||
|
||||
m_methodCombo->setCurrentIndex(currentSymbolIndex);
|
||||
updateUses();
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateUses()
|
||||
{
|
||||
m_updateUsesTimer->start();
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateUsesNow()
|
||||
{
|
||||
if (document()->revision() != m_idsRevision) {
|
||||
updateUses();
|
||||
return;
|
||||
}
|
||||
|
||||
m_updateUsesTimer->stop();
|
||||
|
||||
QList<QTextEdit::ExtraSelection> selections;
|
||||
foreach (const AST::SourceLocation &loc, m_ids.value(wordUnderCursor())) {
|
||||
if (! loc.isValid())
|
||||
continue;
|
||||
|
||||
QTextEdit::ExtraSelection sel;
|
||||
sel.format = m_occurrencesFormat;
|
||||
sel.cursor = textCursor();
|
||||
sel.cursor.setPosition(loc.begin());
|
||||
sel.cursor.setPosition(loc.end(), QTextCursor::KeepAnchor);
|
||||
selections.append(sel);
|
||||
}
|
||||
|
||||
setExtraSelections(CodeSemanticsSelection, selections);
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateMethodBoxToolTip()
|
||||
{
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateFileName()
|
||||
{
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::renameIdUnderCursor()
|
||||
{
|
||||
const QString id = wordUnderCursor();
|
||||
bool ok = false;
|
||||
const QString newId = QInputDialog::getText(Core::ICore::instance()->mainWindow(),
|
||||
tr("Rename..."),
|
||||
tr("New id:"),
|
||||
QLineEdit::Normal,
|
||||
id, &ok);
|
||||
if (ok) {
|
||||
Utils::ChangeSet changeSet;
|
||||
|
||||
foreach (const AST::SourceLocation &loc, m_ids.value(id)) {
|
||||
changeSet.replace(loc.offset, loc.length, newId);
|
||||
}
|
||||
|
||||
QTextCursor tc = textCursor();
|
||||
changeSet.apply(&tc);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList QmlJSTextEditor::keywords() const
|
||||
{
|
||||
QStringList words;
|
||||
|
||||
if (QmlHighlighter *highlighter = qobject_cast<QmlHighlighter*>(baseTextDocument()->syntaxHighlighter()))
|
||||
words = highlighter->keywords().toList();
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::setFontSettings(const TextEditor::FontSettings &fs)
|
||||
{
|
||||
TextEditor::BaseTextEditor::setFontSettings(fs);
|
||||
QmlHighlighter *highlighter = qobject_cast<QmlHighlighter*>(baseTextDocument()->syntaxHighlighter());
|
||||
if (!highlighter)
|
||||
return;
|
||||
|
||||
static QVector<QString> categories;
|
||||
if (categories.isEmpty()) {
|
||||
categories << QLatin1String(TextEditor::Constants::C_NUMBER)
|
||||
<< QLatin1String(TextEditor::Constants::C_STRING)
|
||||
<< QLatin1String(TextEditor::Constants::C_TYPE)
|
||||
<< QLatin1String(TextEditor::Constants::C_KEYWORD)
|
||||
<< QLatin1String(TextEditor::Constants::C_PREPROCESSOR)
|
||||
<< QLatin1String(TextEditor::Constants::C_LABEL)
|
||||
<< QLatin1String(TextEditor::Constants::C_COMMENT)
|
||||
<< QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE);
|
||||
}
|
||||
|
||||
m_occurrencesFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES));
|
||||
m_occurrencesFormat.clearForeground();
|
||||
|
||||
highlighter->setFormats(fs.toTextCharFormats(categories));
|
||||
highlighter->rehighlight();
|
||||
}
|
||||
|
||||
QString QmlJSTextEditor::wordUnderCursor() const
|
||||
{
|
||||
QTextCursor tc = textCursor();
|
||||
tc.movePosition(QTextCursor::StartOfWord);
|
||||
tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
const QString word= tc.selectedText();
|
||||
return word;
|
||||
}
|
||||
|
||||
bool QmlJSTextEditor::isElectricCharacter(const QChar &ch) const
|
||||
{
|
||||
if (ch == QLatin1Char('}')
|
||||
|| ch == QLatin1Char(']'))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QmlJSTextEditor::isClosingBrace(const QList<QScriptIncrementalScanner::Token> &tokens) const
|
||||
{
|
||||
|
||||
if (tokens.size() == 1) {
|
||||
const QScriptIncrementalScanner::Token firstToken = tokens.first();
|
||||
|
||||
return firstToken.is(QScriptIncrementalScanner::Token::RightBrace) || firstToken.is(QScriptIncrementalScanner::Token::RightBracket);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
|
||||
{
|
||||
TextEditor::TabSettings ts = tabSettings();
|
||||
SharedTools::QScriptIndenter indenter;
|
||||
indenter.setTabSize(ts.m_tabSize);
|
||||
indenter.setIndentSize(ts.m_indentSize);
|
||||
|
||||
const int indent = indenter.indentForBottomLine(doc->begin(), block.next(), typedChar);
|
||||
ts.indentLine(block, indent);
|
||||
}
|
||||
|
||||
TextEditor::BaseTextEditorEditable *QmlJSTextEditor::createEditableInterface()
|
||||
{
|
||||
QmlJSEditorEditable *editable = new QmlJSEditorEditable(this);
|
||||
createToolBar(editable);
|
||||
return editable;
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::createToolBar(QmlJSEditorEditable *editable)
|
||||
{
|
||||
m_methodCombo = new QComboBox;
|
||||
m_methodCombo->setMinimumContentsLength(22);
|
||||
//m_methodCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
|
||||
// Make the combo box prefer to expand
|
||||
QSizePolicy policy = m_methodCombo->sizePolicy();
|
||||
policy.setHorizontalPolicy(QSizePolicy::Expanding);
|
||||
m_methodCombo->setSizePolicy(policy);
|
||||
|
||||
connect(m_methodCombo, SIGNAL(activated(int)), this, SLOT(jumpToMethod(int)));
|
||||
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateMethodBoxIndex()));
|
||||
connect(m_methodCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMethodBoxToolTip()));
|
||||
|
||||
connect(file(), SIGNAL(changed()), this, SLOT(updateFileName()));
|
||||
|
||||
QToolBar *toolBar = static_cast<QToolBar*>(editable->toolBar());
|
||||
|
||||
QList<QAction*> actions = toolBar->actions();
|
||||
toolBar->insertWidget(actions.first(), m_methodCombo);
|
||||
}
|
||||
|
||||
TextEditor::BaseTextEditor::Link QmlJSTextEditor::findLinkAt(const QTextCursor &cursor, bool /*resolveTarget*/)
|
||||
{
|
||||
Link link;
|
||||
|
||||
if (!m_modelManager)
|
||||
return link;
|
||||
|
||||
const Snapshot snapshot = m_modelManager->snapshot();
|
||||
QmlDocument::Ptr doc = snapshot.document(file()->fileName());
|
||||
if (!doc)
|
||||
return link;
|
||||
|
||||
QTextCursor expressionCursor(cursor);
|
||||
{
|
||||
// correct the position by moving to the end of an identifier (if we're hovering over one):
|
||||
int pos = cursor.position();
|
||||
forever {
|
||||
const QChar ch = characterAt(pos);
|
||||
|
||||
if (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
|
||||
++pos;
|
||||
else
|
||||
break;
|
||||
}
|
||||
expressionCursor.setPosition(pos);
|
||||
}
|
||||
|
||||
QmlExpressionUnderCursor expressionUnderCursor;
|
||||
expressionUnderCursor(expressionCursor, doc);
|
||||
|
||||
QmlLookupContext context(expressionUnderCursor.expressionScopes(), doc, snapshot, m_typeSystem);
|
||||
QmlResolveExpression resolver(context);
|
||||
QmlSymbol *symbol = resolver.typeOf(expressionUnderCursor.expressionNode());
|
||||
|
||||
if (!symbol)
|
||||
return link;
|
||||
|
||||
if (const QmlSymbolFromFile *target = symbol->asSymbolFromFile()) {
|
||||
link.pos = expressionUnderCursor.expressionOffset();
|
||||
link.length = expressionUnderCursor.expressionLength();
|
||||
link.fileName = target->fileName();
|
||||
link.line = target->line();
|
||||
link.column = target->column();
|
||||
if (link.column > 0)
|
||||
--link.column;
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::contextMenuEvent(QContextMenuEvent *e)
|
||||
{
|
||||
QMenu *menu = new QMenu();
|
||||
|
||||
if (Core::ActionContainer *mcontext = Core::ICore::instance()->actionManager()->actionContainer(QmlJSEditor::Constants::M_CONTEXT)) {
|
||||
QMenu *contextMenu = mcontext->menu();
|
||||
foreach (QAction *action, contextMenu->actions())
|
||||
menu->addAction(action);
|
||||
}
|
||||
|
||||
const QString id = wordUnderCursor();
|
||||
const QList<AST::SourceLocation> &locations = m_ids.value(id);
|
||||
if (! locations.isEmpty()) {
|
||||
menu->addSeparator();
|
||||
QAction *a = menu->addAction(tr("Rename id '%1'...").arg(id));
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(renameIdUnderCursor()));
|
||||
}
|
||||
|
||||
appendStandardContextMenuActions(menu);
|
||||
|
||||
menu->exec(e->globalPos());
|
||||
menu->deleteLater();
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::unCommentSelection()
|
||||
{
|
||||
Utils::unCommentSelection(this);
|
||||
}
|
||||
|
||||
static bool isCompleteStringLiteral(const QStringRef &text)
|
||||
{
|
||||
if (text.length() < 2)
|
||||
return false;
|
||||
|
||||
const QChar quote = text.at(0);
|
||||
|
||||
if (text.at(text.length() - 1) == quote)
|
||||
return text.at(text.length() - 2) != QLatin1Char('\\'); // ### not exactly.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QmlJSTextEditor::contextAllowsAutoParentheses(const QTextCursor &cursor, const QString &textToInsert) const
|
||||
{
|
||||
QChar ch;
|
||||
|
||||
if (! textToInsert.isEmpty())
|
||||
ch = textToInsert.at(0);
|
||||
|
||||
switch (ch.unicode()) {
|
||||
case '\'':
|
||||
case '"':
|
||||
|
||||
case '(':
|
||||
case '[':
|
||||
case '{':
|
||||
|
||||
case ')':
|
||||
case ']':
|
||||
case '}':
|
||||
|
||||
case ';':
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ch.isNull())
|
||||
break;
|
||||
|
||||
return false;
|
||||
} // end of switch
|
||||
|
||||
const QString blockText = cursor.block().text();
|
||||
const int blockState = blockStartState(cursor.block());
|
||||
|
||||
QScriptIncrementalScanner tokenize;
|
||||
const QList<QScriptIncrementalScanner::Token> tokens = tokenize(blockText, blockState);
|
||||
const int pos = cursor.columnNumber();
|
||||
|
||||
int tokenIndex = 0;
|
||||
for (; tokenIndex < tokens.size(); ++tokenIndex) {
|
||||
const QScriptIncrementalScanner::Token &token = tokens.at(tokenIndex);
|
||||
|
||||
if (pos >= token.begin()) {
|
||||
if (pos < token.end())
|
||||
break;
|
||||
|
||||
else if (pos == token.end() && (token.is(QScriptIncrementalScanner::Token::Comment) ||
|
||||
token.is(QScriptIncrementalScanner::Token::String)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenIndex != tokens.size()) {
|
||||
const QScriptIncrementalScanner::Token &token = tokens.at(tokenIndex);
|
||||
|
||||
switch (token.kind) {
|
||||
case QScriptIncrementalScanner::Token::Comment:
|
||||
return false;
|
||||
|
||||
case QScriptIncrementalScanner::Token::String: {
|
||||
const QStringRef tokenText = blockText.midRef(token.offset, token.length);
|
||||
const QChar quote = tokenText.at(0);
|
||||
|
||||
if (ch == quote && isCompleteStringLiteral(tokenText))
|
||||
break;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
} // end of switch
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QmlJSTextEditor::isInComment(const QTextCursor &) const
|
||||
{
|
||||
// ### implement me
|
||||
return false;
|
||||
}
|
||||
|
||||
QString QmlJSTextEditor::insertMatchingBrace(const QTextCursor &tc, const QString &text, const QChar &, int *skippedChars) const
|
||||
{
|
||||
if (text.length() != 1)
|
||||
return QString();
|
||||
|
||||
const QChar la = characterAt(tc.position());
|
||||
|
||||
const QChar ch = text.at(0);
|
||||
switch (ch.unicode()) {
|
||||
case '\'':
|
||||
if (la != ch)
|
||||
return QString(ch);
|
||||
++*skippedChars;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
if (la != ch)
|
||||
return QString(ch);
|
||||
++*skippedChars;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
return QString(QLatin1Char(')'));
|
||||
|
||||
case '[':
|
||||
return QString(QLatin1Char(']'));
|
||||
|
||||
case '{':
|
||||
return QString(); // nothing to do.
|
||||
|
||||
case ')':
|
||||
case ']':
|
||||
case '}':
|
||||
case ';':
|
||||
if (la == ch)
|
||||
++*skippedChars;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
} // end of switch
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString QmlJSTextEditor::insertParagraphSeparator(const QTextCursor &) const
|
||||
{
|
||||
return QLatin1String("}\n");
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
169
src/plugins/qmljseditor/qmljseditor.h
Normal file
169
src/plugins/qmljseditor/qmljseditor.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSEDITOR_H
|
||||
#define QMLJSEDITOR_H
|
||||
|
||||
#include <qmljs/qmldocument.h>
|
||||
#include <qscripthighlighter/qscriptincrementalscanner.h>
|
||||
#include <texteditor/basetexteditor.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QComboBox;
|
||||
class QTimer;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Core {
|
||||
class ICore;
|
||||
}
|
||||
|
||||
namespace Qml {
|
||||
class QmlTypeSystem;
|
||||
}
|
||||
|
||||
namespace QmlJSEditor {
|
||||
|
||||
class QmlModelManagerInterface;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QmlHighlighter;
|
||||
class QmlJSTextEditor;
|
||||
|
||||
class QmlJSEditorEditable : public TextEditor::BaseTextEditorEditable
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlJSEditorEditable(QmlJSTextEditor *);
|
||||
QList<int> context() const;
|
||||
|
||||
bool duplicateSupported() const { return true; }
|
||||
Core::IEditor *duplicate(QWidget *parent);
|
||||
QString id() const;
|
||||
bool isTemporary() const { return false; }
|
||||
|
||||
private:
|
||||
QList<int> m_context;
|
||||
};
|
||||
|
||||
|
||||
struct Declaration
|
||||
{
|
||||
QString text;
|
||||
int startLine;
|
||||
int startColumn;
|
||||
int endLine;
|
||||
int endColumn;
|
||||
|
||||
Declaration()
|
||||
: startLine(0),
|
||||
startColumn(0),
|
||||
endLine(0),
|
||||
endColumn(0)
|
||||
{ }
|
||||
};
|
||||
|
||||
class QmlJSTextEditor : public TextEditor::BaseTextEditor
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef QList<int> Context;
|
||||
|
||||
QmlJSTextEditor(QWidget *parent = 0);
|
||||
~QmlJSTextEditor();
|
||||
|
||||
QList<Declaration> declarations() const;
|
||||
QStringList keywords() const;
|
||||
|
||||
QList<QmlJS::DiagnosticMessage> diagnosticMessages() const
|
||||
{ return m_diagnosticMessages; }
|
||||
|
||||
virtual void unCommentSelection();
|
||||
|
||||
Qml::QmlDocument::Ptr qmlDocument() const { return m_document; }
|
||||
|
||||
public slots:
|
||||
virtual void setFontSettings(const TextEditor::FontSettings &);
|
||||
|
||||
private slots:
|
||||
void onDocumentUpdated(Qml::QmlDocument::Ptr doc);
|
||||
|
||||
void updateDocument();
|
||||
void updateDocumentNow();
|
||||
void jumpToMethod(int index);
|
||||
void updateMethodBoxIndex();
|
||||
void updateMethodBoxToolTip();
|
||||
void updateFileName();
|
||||
|
||||
void updateUses();
|
||||
void updateUsesNow();
|
||||
|
||||
// refactoring ops
|
||||
void renameIdUnderCursor();
|
||||
|
||||
protected:
|
||||
void contextMenuEvent(QContextMenuEvent *e);
|
||||
TextEditor::BaseTextEditorEditable *createEditableInterface();
|
||||
void createToolBar(QmlJSEditorEditable *editable);
|
||||
TextEditor::BaseTextEditor::Link findLinkAt(const QTextCursor &cursor, bool resolveTarget = true);
|
||||
|
||||
//// brace matching
|
||||
virtual bool contextAllowsAutoParentheses(const QTextCursor &cursor, const QString &textToInsert = QString()) const;
|
||||
virtual bool isInComment(const QTextCursor &cursor) const;
|
||||
virtual QString insertMatchingBrace(const QTextCursor &tc, const QString &text, const QChar &la, int *skippedChars) const;
|
||||
virtual QString insertParagraphSeparator(const QTextCursor &tc) const;
|
||||
|
||||
private:
|
||||
virtual bool isElectricCharacter(const QChar &ch) const;
|
||||
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
|
||||
bool isClosingBrace(const QList<SharedTools::QScriptIncrementalScanner::Token> &tokens) const;
|
||||
|
||||
QString wordUnderCursor() const;
|
||||
|
||||
const Context m_context;
|
||||
|
||||
QTimer *m_updateDocumentTimer;
|
||||
QTimer *m_updateUsesTimer;
|
||||
QComboBox *m_methodCombo;
|
||||
QList<Declaration> m_declarations;
|
||||
QMap<QString, QList<QmlJS::AST::SourceLocation> > m_ids; // ### use QMultiMap
|
||||
int m_idsRevision;
|
||||
QList<QmlJS::DiagnosticMessage> m_diagnosticMessages;
|
||||
Qml::QmlDocument::Ptr m_document;
|
||||
QmlModelManagerInterface *m_modelManager;
|
||||
Qml::QmlTypeSystem *m_typeSystem;
|
||||
QTextCharFormat m_occurrencesFormat;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLJSEDITOR_H
|
||||
3
src/plugins/qmljseditor/qmljseditor.pri
Normal file
3
src/plugins/qmljseditor/qmljseditor.pri
Normal file
@@ -0,0 +1,3 @@
|
||||
include(qmljseditor_dependencies.pri)
|
||||
|
||||
LIBS *= -l$$qtLibraryTarget(QmlJSEditor)
|
||||
48
src/plugins/qmljseditor/qmljseditor.pro
Normal file
48
src/plugins/qmljseditor/qmljseditor.pro
Normal file
@@ -0,0 +1,48 @@
|
||||
TEMPLATE = lib
|
||||
TARGET = QmlJSEditor
|
||||
include(../../qtcreatorplugin.pri)
|
||||
include(qmljseditor_dependencies.pri)
|
||||
|
||||
include(../../shared/qscripthighlighter/qscripthighlighter.pri)
|
||||
DEPENDPATH += ../../shared/qscripthighlighter
|
||||
|
||||
|
||||
CONFIG += help
|
||||
DEFINES += \
|
||||
QMLJSEDITOR_LIBRARY \
|
||||
QT_CREATOR
|
||||
|
||||
HEADERS += \
|
||||
qmlcodecompletion.h \
|
||||
qmljseditor.h \
|
||||
qmljseditor_global.h \
|
||||
qmljseditoractionhandler.h \
|
||||
qmljseditorconstants.h \
|
||||
qmljseditorfactory.h \
|
||||
qmljseditorplugin.h \
|
||||
qmlexpressionundercursor.h \
|
||||
qmlfilewizard.h \
|
||||
qmlhighlighter.h \
|
||||
qmlhoverhandler.h \
|
||||
qmllookupcontext.h \
|
||||
qmlmodelmanager.h \
|
||||
qmlmodelmanagerinterface.h \
|
||||
qmlresolveexpression.h
|
||||
|
||||
SOURCES += \
|
||||
qmlcodecompletion.cpp \
|
||||
qmljseditor.cpp \
|
||||
qmljseditoractionhandler.cpp \
|
||||
qmljseditorfactory.cpp \
|
||||
qmljseditorplugin.cpp \
|
||||
qmlexpressionundercursor.cpp \
|
||||
qmlfilewizard.cpp \
|
||||
qmlhighlighter.cpp \
|
||||
qmlhoverhandler.cpp \
|
||||
qmllookupcontext.cpp \
|
||||
qmlmodelmanager.cpp \
|
||||
qmlmodelmanagerinterface.cpp \
|
||||
qmlresolveexpression.cpp
|
||||
|
||||
RESOURCES += qmljseditor.qrc
|
||||
OTHER_FILES += QmlJSEditor.pluginspec QmlJSEditor.mimetypes.xml
|
||||
5
src/plugins/qmljseditor/qmljseditor.qrc
Normal file
5
src/plugins/qmljseditor/qmljseditor.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/qmljseditor" >
|
||||
<file>QmlJSEditor.mimetypes.xml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
6
src/plugins/qmljseditor/qmljseditor_dependencies.pri
Normal file
6
src/plugins/qmljseditor/qmljseditor_dependencies.pri
Normal file
@@ -0,0 +1,6 @@
|
||||
include(../../plugins/coreplugin/coreplugin.pri)
|
||||
include(../../plugins/texteditor/texteditor.pri)
|
||||
include(../../plugins/help/help.pri)
|
||||
include(../../shared/indenter/indenter.pri)
|
||||
include(../../libs/qmljs/qmljs.pri)
|
||||
include(../../libs/utils/utils.pri)
|
||||
41
src/plugins/qmljseditor/qmljseditor_global.h
Normal file
41
src/plugins/qmljseditor/qmljseditor_global.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSEDITOR_GLOBAL_H
|
||||
#define QMLJSEDITOR_GLOBAL_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(QMLJSEDITOR_LIBRARY)
|
||||
# define QMLJSEDITOR_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define QMLJSEDITOR_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // QMLJSEDITOR_GLOBAL_H
|
||||
58
src/plugins/qmljseditor/qmljseditoractionhandler.cpp
Normal file
58
src/plugins/qmljseditor/qmljseditoractionhandler.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljseditoractionhandler.h"
|
||||
#include "qmljseditorconstants.h"
|
||||
#include "qmljseditor.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QMainWindow>
|
||||
#include <QtGui/QMessageBox>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
QmlJSEditorActionHandler::QmlJSEditorActionHandler()
|
||||
: TextEditor::TextEditorActionHandler(QLatin1String(QmlJSEditor::Constants::C_QMLJSEDITOR_ID),
|
||||
Format)
|
||||
{
|
||||
}
|
||||
|
||||
void QmlJSEditorActionHandler::createActions()
|
||||
{
|
||||
TextEditor::TextEditorActionHandler::createActions();
|
||||
}
|
||||
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
51
src/plugins/qmljseditor/qmljseditoractionhandler.h
Normal file
51
src/plugins/qmljseditor/qmljseditoractionhandler.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLDITORACTIONHANDLER_H
|
||||
#define QMLDITORACTIONHANDLER_H
|
||||
|
||||
#include <texteditor/texteditoractionhandler.h>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlJSEditorActionHandler : public TextEditor::TextEditorActionHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlJSEditorActionHandler();
|
||||
|
||||
void createActions();
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLDITORACTIONHANDLER_H
|
||||
49
src/plugins/qmljseditor/qmljseditorconstants.h
Normal file
49
src/plugins/qmljseditor/qmljseditorconstants.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSEDITOR_CONSTANTS_H
|
||||
#define QMLJSEDITOR_CONSTANTS_H
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Constants {
|
||||
|
||||
const char * const M_CONTEXT = "QML JS Editor.ContextMenu";
|
||||
const char * const RUN_SEP = "QmlJSEditor.Run.Separator";
|
||||
const char * const C_QMLJSEDITOR_ID = "QMLProjectManager.QMLJSEditor";
|
||||
const char * const C_QMLJSEDITOR_DISPLAY_NAME = QT_TRANSLATE_NOOP("OpenWith::Editors", "QMLJS Editor");
|
||||
const char * const TASK_INDEX = "QmlJSEditor.TaskIndex";
|
||||
|
||||
const char * const QMLJSEDITOR_MIMETYPE = "application/x-qml";
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLJSEDITOR_CONSTANTS_H
|
||||
85
src/plugins/qmljseditor/qmljseditorfactory.cpp
Normal file
85
src/plugins/qmljseditor/qmljseditorfactory.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljseditorfactory.h"
|
||||
#include "qmljseditor.h"
|
||||
#include "qmljseditoractionhandler.h"
|
||||
#include "qmljseditorconstants.h"
|
||||
#include "qmljseditorplugin.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
using namespace QmlJSEditor::Internal;
|
||||
using namespace QmlJSEditor::Constants;
|
||||
|
||||
QmlJSEditorFactory::QmlJSEditorFactory(QObject *parent)
|
||||
: Core::IEditorFactory(parent),
|
||||
m_mimeTypes(QLatin1String(QmlJSEditor::Constants::QMLJSEDITOR_MIMETYPE))
|
||||
{
|
||||
}
|
||||
|
||||
QmlJSEditorFactory::~QmlJSEditorFactory()
|
||||
{
|
||||
}
|
||||
|
||||
QString QmlJSEditorFactory::id() const
|
||||
{
|
||||
return QLatin1String(C_QMLJSEDITOR_ID);
|
||||
}
|
||||
|
||||
QString QmlJSEditorFactory::displayName() const
|
||||
{
|
||||
return tr(C_QMLJSEDITOR_DISPLAY_NAME);
|
||||
}
|
||||
|
||||
|
||||
Core::IFile *QmlJSEditorFactory::open(const QString &fileName)
|
||||
{
|
||||
Core::IEditor *iface = Core::EditorManager::instance()->openEditor(fileName, id());
|
||||
if (!iface) {
|
||||
qWarning() << "QmlEditorFactory::open: openEditor failed for " << fileName;
|
||||
return 0;
|
||||
}
|
||||
return iface->file();
|
||||
}
|
||||
|
||||
Core::IEditor *QmlJSEditorFactory::createEditor(QWidget *parent)
|
||||
{
|
||||
QmlJSTextEditor *rc = new QmlJSTextEditor(parent);
|
||||
QmlJSEditorPlugin::instance()->initializeEditor(rc);
|
||||
return rc->editableInterface();
|
||||
}
|
||||
|
||||
QStringList QmlJSEditorFactory::mimeTypes() const
|
||||
{
|
||||
return m_mimeTypes;
|
||||
}
|
||||
68
src/plugins/qmljseditor/qmljseditorfactory.h
Normal file
68
src/plugins/qmljseditor/qmljseditorfactory.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSEDITORFACTORY_H
|
||||
#define QMLJSEDITORFACTORY_H
|
||||
|
||||
#include <coreplugin/editormanager/ieditorfactory.h>
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
namespace TextEditor {
|
||||
class TextEditorActionHandler;
|
||||
}
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlJSEditorActionHandler;
|
||||
|
||||
class QmlJSEditorFactory : public Core::IEditorFactory
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlJSEditorFactory(QObject *parent);
|
||||
~QmlJSEditorFactory();
|
||||
|
||||
virtual QStringList mimeTypes() const;
|
||||
// IEditorFactory
|
||||
QString id() const;
|
||||
QString displayName() const;
|
||||
Core::IFile *open(const QString &fileName);
|
||||
Core::IEditor *createEditor(QWidget *parent);
|
||||
|
||||
private:
|
||||
const QStringList m_mimeTypes;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLJSEDITORFACTORY_H
|
||||
182
src/plugins/qmljseditor/qmljseditorplugin.cpp
Normal file
182
src/plugins/qmljseditor/qmljseditorplugin.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljseditorplugin.h"
|
||||
|
||||
#include "qmlhighlighter.h"
|
||||
#include "qmljseditor.h"
|
||||
#include "qmljseditorconstants.h"
|
||||
#include "qmljseditorfactory.h"
|
||||
#include "qmlcodecompletion.h"
|
||||
#include "qmlhoverhandler.h"
|
||||
#include "qmlmodelmanager.h"
|
||||
#include "qmlfilewizard.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/mimedatabase.h>
|
||||
#include <coreplugin/uniqueidmanager.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <texteditor/fontsettings.h>
|
||||
#include <texteditor/storagesettings.h>
|
||||
#include <texteditor/texteditorconstants.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
#include <texteditor/textfilewizard.h>
|
||||
#include <texteditor/texteditoractionhandler.h>
|
||||
#include <texteditor/completionsupport.h>
|
||||
#include <help/helpplugin.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QtPlugin>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtGui/QAction>
|
||||
|
||||
using namespace QmlJSEditor;
|
||||
using namespace QmlJSEditor::Internal;
|
||||
using namespace QmlJSEditor::Constants;
|
||||
|
||||
QmlJSEditorPlugin *QmlJSEditorPlugin::m_instance = 0;
|
||||
|
||||
QmlJSEditorPlugin::QmlJSEditorPlugin() :
|
||||
m_modelManager(0),
|
||||
m_wizard(0),
|
||||
m_editor(0),
|
||||
m_actionHandler(0),
|
||||
m_completion(0)
|
||||
{
|
||||
m_instance = this;
|
||||
}
|
||||
|
||||
QmlJSEditorPlugin::~QmlJSEditorPlugin()
|
||||
{
|
||||
removeObject(m_editor);
|
||||
delete m_actionHandler;
|
||||
m_instance = 0;
|
||||
}
|
||||
|
||||
bool QmlJSEditorPlugin::initialize(const QStringList & /*arguments*/, QString *error_message)
|
||||
{
|
||||
Core::ICore *core = Core::ICore::instance();
|
||||
if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/qmljseditor/QmlJSEditor.mimetypes.xml"), error_message))
|
||||
return false;
|
||||
|
||||
m_modelManager = new QmlModelManager(this);
|
||||
addAutoReleasedObject(m_modelManager);
|
||||
Qml::QmlTypeSystem *typeSystem = new Qml::QmlTypeSystem;
|
||||
addAutoReleasedObject(typeSystem);
|
||||
|
||||
QList<int> context;
|
||||
context<< core->uniqueIDManager()->uniqueIdentifier(QmlJSEditor::Constants::C_QMLJSEDITOR_ID);
|
||||
|
||||
m_editor = new QmlJSEditorFactory(this);
|
||||
addObject(m_editor);
|
||||
|
||||
Core::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
|
||||
wizardParameters.setCategory(QLatin1String(Core::Constants::WIZARD_CATEGORY_QT));
|
||||
wizardParameters.setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::WIZARD_TR_CATEGORY_QT));
|
||||
wizardParameters.setDescription(tr("Creates a Qt QML file."));
|
||||
wizardParameters.setDisplayName(tr("Qt QML File"));
|
||||
wizardParameters.setId(QLatin1String("Q.Qml"));
|
||||
addAutoReleasedObject(new QmlFileWizard(wizardParameters, core));
|
||||
|
||||
m_actionHandler = new TextEditor::TextEditorActionHandler(QmlJSEditor::Constants::C_QMLJSEDITOR_ID,
|
||||
TextEditor::TextEditorActionHandler::Format
|
||||
| TextEditor::TextEditorActionHandler::UnCommentSelection
|
||||
| TextEditor::TextEditorActionHandler::UnCollapseAll);
|
||||
m_actionHandler->initializeActions();
|
||||
|
||||
Core::ActionManager *am = core->actionManager();
|
||||
Core::ActionContainer *contextMenu= am->createMenu(QmlJSEditor::Constants::M_CONTEXT);
|
||||
Core::Command *cmd = am->command(TextEditor::Constants::AUTO_INDENT_SELECTION);
|
||||
contextMenu->addAction(cmd);
|
||||
cmd = am->command(TextEditor::Constants::UN_COMMENT_SELECTION);
|
||||
contextMenu->addAction(cmd);
|
||||
|
||||
m_completion = new QmlCodeCompletion(m_modelManager, typeSystem);
|
||||
addAutoReleasedObject(m_completion);
|
||||
|
||||
addAutoReleasedObject(new QmlHoverHandler());
|
||||
|
||||
// Restore settings
|
||||
QSettings *settings = Core::ICore::instance()->settings();
|
||||
settings->beginGroup(QLatin1String("CppTools")); // ### FIXME:
|
||||
settings->beginGroup(QLatin1String("Completion"));
|
||||
const bool caseSensitive = settings->value(QLatin1String("CaseSensitive"), true).toBool();
|
||||
m_completion->setCaseSensitivity(caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
||||
settings->endGroup();
|
||||
settings->endGroup();
|
||||
|
||||
error_message->clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QmlJSEditorPlugin::extensionsInitialized()
|
||||
{
|
||||
//
|
||||
// Explicitly register qml.qch if located in creator directory.
|
||||
//
|
||||
// This is only needed for the creator-qml package, were we
|
||||
// want to ship the documentation without a qt development version.
|
||||
//
|
||||
|
||||
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
|
||||
Help::HelpManager *helpManager = pluginManager->getObject<Help::HelpManager>();
|
||||
|
||||
Q_ASSERT(helpManager);
|
||||
|
||||
const QString qmlHelpFile =
|
||||
QDir::cleanPath(QCoreApplication::applicationDirPath()
|
||||
#if defined(Q_OS_MAC)
|
||||
+ QLatin1String("/../Resources/doc/qml.qch"));
|
||||
#else
|
||||
+ QLatin1String("../../share/doc/qtcreator/qml.qch"));
|
||||
#endif
|
||||
|
||||
helpManager->registerDocumentation(QStringList(qmlHelpFile));
|
||||
}
|
||||
|
||||
void QmlJSEditorPlugin::initializeEditor(QmlJSEditor::Internal::QmlJSTextEditor *editor)
|
||||
{
|
||||
QTC_ASSERT(m_instance, /**/);
|
||||
|
||||
m_actionHandler->setupActions(editor);
|
||||
|
||||
TextEditor::TextEditorSettings::instance()->initializeEditor(editor);
|
||||
|
||||
// auto completion
|
||||
connect(editor, SIGNAL(requestAutoCompletion(TextEditor::ITextEditable*, bool)),
|
||||
TextEditor::Internal::CompletionSupport::instance(), SLOT(autoComplete(TextEditor::ITextEditable*, bool)));
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN(QmlJSEditorPlugin)
|
||||
80
src/plugins/qmljseditor/qmljseditorplugin.h
Normal file
80
src/plugins/qmljseditor/qmljseditorplugin.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSEDITORPLUGIN_H
|
||||
#define QMLJSEDITORPLUGIN_H
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
|
||||
namespace TextEditor {
|
||||
class TextEditorActionHandler;
|
||||
} // namespace TextEditor
|
||||
|
||||
namespace QmlJSEditor {
|
||||
|
||||
class QmlModelManagerInterface;
|
||||
class QmlFileWizard;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QmlJSEditorFactory;
|
||||
class QmlCodeCompletion;
|
||||
class QmlJSTextEditor;
|
||||
|
||||
class QmlJSEditorPlugin : public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlJSEditorPlugin();
|
||||
virtual ~QmlJSEditorPlugin();
|
||||
|
||||
// IPlugin
|
||||
bool initialize(const QStringList &arguments, QString *errorMessage = 0);
|
||||
void extensionsInitialized();
|
||||
|
||||
static QmlJSEditorPlugin *instance()
|
||||
{ return m_instance; }
|
||||
|
||||
void initializeEditor(QmlJSTextEditor *editor);
|
||||
|
||||
private:
|
||||
static QmlJSEditorPlugin *m_instance;
|
||||
|
||||
QmlModelManagerInterface *m_modelManager;
|
||||
QmlFileWizard *m_wizard;
|
||||
QmlJSEditorFactory *m_editor;
|
||||
TextEditor::TextEditorActionHandler *m_actionHandler;
|
||||
QmlCodeCompletion *m_completion;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLJSEDITORPLUGIN_H
|
||||
299
src/plugins/qmljseditor/qmllookupcontext.cpp
Normal file
299
src/plugins/qmljseditor/qmllookupcontext.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlexpressionundercursor.h"
|
||||
#include "qmllookupcontext.h"
|
||||
#include "qmlresolveexpression.h"
|
||||
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <qmljs/parser/qmljsengine_p.h>
|
||||
#include <qmljs/qmltypesystem.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
using namespace Qml;
|
||||
using namespace QmlJSEditor;
|
||||
using namespace QmlJSEditor::Internal;
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJS::AST;
|
||||
|
||||
QmlLookupContext::QmlLookupContext(const QStack<QmlSymbol *> &scopes,
|
||||
const QmlDocument::Ptr &doc,
|
||||
const Snapshot &snapshot,
|
||||
QmlTypeSystem *typeSystem):
|
||||
_scopes(scopes),
|
||||
_doc(doc),
|
||||
_snapshot(snapshot),
|
||||
m_typeSystem(typeSystem)
|
||||
{
|
||||
Q_ASSERT(typeSystem != 0);
|
||||
}
|
||||
|
||||
static inline int findFirstQmlObjectScope(const QStack<QmlSymbol*> &scopes, int startIdx)
|
||||
{
|
||||
if (startIdx < 0 || startIdx >= scopes.size())
|
||||
return -1;
|
||||
|
||||
for (int i = startIdx; i >= 0; --i) {
|
||||
QmlSymbol *current = scopes.at(i);
|
||||
|
||||
if (current->isSymbolFromFile()) {
|
||||
Node *node = current->asSymbolFromFile()->node();
|
||||
|
||||
if (cast<UiObjectBinding*>(node) || cast<UiObjectDefinition*>(node)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline QmlSymbol *resolveParent(const QStack<QmlSymbol*> &scopes)
|
||||
{
|
||||
int idx = findFirstQmlObjectScope(scopes, scopes.size() - 1);
|
||||
if (idx < 1)
|
||||
return 0;
|
||||
|
||||
idx = findFirstQmlObjectScope(scopes, idx - 1);
|
||||
|
||||
if (idx < 0)
|
||||
return 0;
|
||||
else
|
||||
return scopes.at(idx);
|
||||
}
|
||||
|
||||
QmlSymbol *QmlLookupContext::resolve(const QString &name)
|
||||
{
|
||||
// find element type names
|
||||
if (QmlSymbol *type = resolveType(name))
|
||||
return type;
|
||||
|
||||
// find ids
|
||||
const QmlDocument::IdTable ids = _doc->ids();
|
||||
if (ids.contains(name))
|
||||
return ids[name];
|
||||
|
||||
if (name == "parent") {
|
||||
return resolveParent(_scopes);
|
||||
}
|
||||
|
||||
// find script methods
|
||||
// ### TODO
|
||||
|
||||
// find properties of the scope object
|
||||
int scopeObjectIndex = findFirstQmlObjectScope(_scopes, _scopes.size() - 1);
|
||||
if (scopeObjectIndex != -1)
|
||||
if (QmlSymbol *propertySymbol = resolveProperty(name, _scopes.at(scopeObjectIndex), _doc->fileName()))
|
||||
return propertySymbol;
|
||||
|
||||
// find properties of the component's root object
|
||||
if (!_doc->symbols().isEmpty())
|
||||
if (QmlSymbol *propertySymbol = resolveProperty(name, _doc->symbols()[0], _doc->fileName()))
|
||||
return propertySymbol;
|
||||
|
||||
// component chain
|
||||
// ### TODO: Might lead to ambiguity.
|
||||
|
||||
// context chain
|
||||
// ### TODO: ?
|
||||
|
||||
// global object
|
||||
// ### TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QmlSymbol *QmlLookupContext::resolveType(const QString &name, const QString &fileName)
|
||||
{
|
||||
// TODO: handle import-as.
|
||||
QmlDocument::Ptr document = _snapshot[fileName];
|
||||
if (document.isNull())
|
||||
return 0;
|
||||
|
||||
UiProgram *prog = document->program();
|
||||
if (!prog)
|
||||
return 0;
|
||||
|
||||
UiImportList *imports = prog->imports;
|
||||
if (!imports)
|
||||
return 0;
|
||||
|
||||
for (UiImportList *iter = imports; iter; iter = iter->next) {
|
||||
UiImport *import = iter->import;
|
||||
if (!import)
|
||||
continue;
|
||||
|
||||
// TODO: handle Qt imports
|
||||
|
||||
if (!(import->fileName))
|
||||
continue;
|
||||
|
||||
const QString path = import->fileName->asString();
|
||||
|
||||
const QMap<QString, QmlDocument::Ptr> importedTypes = _snapshot.componentsDefinedByImportedDocuments(document, path);
|
||||
if (importedTypes.contains(name)) {
|
||||
QmlDocument::Ptr importedDoc = importedTypes.value(name);
|
||||
|
||||
return importedDoc->symbols().at(0);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: handle Qt imports, hack for now:
|
||||
return resolveBuildinType(name);
|
||||
}
|
||||
|
||||
QmlSymbol *QmlLookupContext::resolveBuildinType(const QString &name)
|
||||
{
|
||||
QList<Qml::PackageInfo> packages;
|
||||
// FIXME:
|
||||
packages.append(PackageInfo("Qt", 4, 6));
|
||||
return m_typeSystem->resolve(name, packages);
|
||||
}
|
||||
|
||||
QmlSymbol *QmlLookupContext::resolveProperty(const QString &name, QmlSymbol *scope, const QString &fileName)
|
||||
{
|
||||
foreach (QmlSymbol *symbol, scope->members())
|
||||
if (symbol->isProperty() && symbol->name() == name)
|
||||
return symbol;
|
||||
|
||||
UiQualifiedId *typeName = 0;
|
||||
|
||||
if (scope->isSymbolFromFile()) {
|
||||
Node *ast = scope->asSymbolFromFile()->node();
|
||||
|
||||
if (UiObjectBinding *binding = cast<UiObjectBinding*>(ast)) {
|
||||
typeName = binding->qualifiedTypeNameId;
|
||||
} else if (UiObjectDefinition *definition = cast<UiObjectDefinition*>(ast)) {
|
||||
typeName = definition->qualifiedTypeNameId;
|
||||
} // TODO: extend this to handle (JavaScript) block scopes.
|
||||
}
|
||||
|
||||
if (typeName == 0)
|
||||
return 0;
|
||||
|
||||
QmlSymbol *typeSymbol = resolveType(toString(typeName), fileName);
|
||||
if (!typeSymbol)
|
||||
return 0;
|
||||
|
||||
if (typeSymbol->isSymbolFromFile()) {
|
||||
return resolveProperty(name, typeSymbol->asSymbolFromFile(), typeSymbol->asSymbolFromFile()->fileName());
|
||||
} else if (QmlBuildInSymbol *builtinSymbol = typeSymbol->asBuildInSymbol()) {
|
||||
foreach (QmlSymbol *member, builtinSymbol->members(true)) {
|
||||
if (member->isProperty() && member->name() == name)
|
||||
return member;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString QmlLookupContext::toString(UiQualifiedId *id)
|
||||
{
|
||||
QString str;
|
||||
|
||||
for (UiQualifiedId *iter = id; iter; iter = iter->next) {
|
||||
if (!(iter->name))
|
||||
continue;
|
||||
|
||||
str.append(iter->name->asString());
|
||||
|
||||
if (iter->next)
|
||||
str.append('.');
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
QList<QmlSymbol*> QmlLookupContext::visibleSymbolsInScope()
|
||||
{
|
||||
QList<QmlSymbol*> result;
|
||||
|
||||
if (!_scopes.isEmpty()) {
|
||||
QmlSymbol *scope = _scopes.top();
|
||||
|
||||
// add members defined in this symbol:
|
||||
result.append(scope->members());
|
||||
|
||||
// add the members of the type of this scope (= object):
|
||||
result.append(expandType(scope));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<QmlSymbol*> QmlLookupContext::visibleTypes()
|
||||
{
|
||||
QList<QmlSymbol*> result;
|
||||
|
||||
UiProgram *program = _doc->program();
|
||||
if (!program)
|
||||
return result;
|
||||
|
||||
for (UiImportList *iter = program->imports; iter; iter = iter->next) {
|
||||
UiImport *import = iter->import;
|
||||
if (!import)
|
||||
continue;
|
||||
|
||||
if (!(import->fileName))
|
||||
continue;
|
||||
const QString path = import->fileName->asString();
|
||||
|
||||
// TODO: handle "import as".
|
||||
|
||||
const QMap<QString, QmlDocument::Ptr> types = _snapshot.componentsDefinedByImportedDocuments(_doc, path);
|
||||
foreach (const QmlDocument::Ptr typeDoc, types) {
|
||||
result.append(typeDoc->symbols().at(0));
|
||||
}
|
||||
}
|
||||
|
||||
result.append(m_typeSystem->availableTypes("Qt", 4, 6));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<QmlSymbol*> QmlLookupContext::expandType(Qml::QmlSymbol *symbol)
|
||||
{
|
||||
if (symbol == 0) {
|
||||
return QList<QmlSymbol*>();
|
||||
} else if (QmlBuildInSymbol *buildInSymbol = symbol->asBuildInSymbol()) {
|
||||
return buildInSymbol->members(true);
|
||||
} else if (QmlSymbolFromFile *symbolFromFile = symbol->asSymbolFromFile()){
|
||||
QList<QmlSymbol*> result;
|
||||
|
||||
if (QmlSymbol *superTypeSymbol = resolveType(symbolFromFile->name(), symbolFromFile->fileName())) {
|
||||
result.append(superTypeSymbol->members());
|
||||
result.append(expandType(superTypeSymbol));
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return QList<QmlSymbol*>();
|
||||
}
|
||||
}
|
||||
82
src/plugins/qmljseditor/qmllookupcontext.h
Normal file
82
src/plugins/qmljseditor/qmllookupcontext.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLLOOKUPCONTEXT_H
|
||||
#define QMLLOOKUPCONTEXT_H
|
||||
|
||||
#include <qmljs/qmltypesystem.h>
|
||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||
#include <qmljs/qmldocument.h>
|
||||
#include <qmljs/qmlsymbol.h>
|
||||
|
||||
#include <QStack>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlLookupContext
|
||||
{
|
||||
public:
|
||||
QmlLookupContext(const QStack<Qml::QmlSymbol *> &scopes,
|
||||
const Qml::QmlDocument::Ptr &doc,
|
||||
const Qml::Snapshot &snapshot,
|
||||
Qml::QmlTypeSystem *typeSystem);
|
||||
|
||||
Qml::QmlSymbol *resolve(const QString &name);
|
||||
Qml::QmlSymbol *resolveType(const QString &name)
|
||||
{ return resolveType(name, _doc->fileName()); }
|
||||
Qml::QmlSymbol *resolveType(QmlJS::AST::UiQualifiedId *name)
|
||||
{ return resolveType(toString(name), _doc->fileName()); }
|
||||
|
||||
Qml::QmlDocument::Ptr document() const
|
||||
{ return _doc; }
|
||||
|
||||
QList<Qml::QmlSymbol*> visibleSymbolsInScope();
|
||||
QList<Qml::QmlSymbol*> visibleTypes();
|
||||
|
||||
QList<Qml::QmlSymbol*> expandType(Qml::QmlSymbol *symbol);
|
||||
|
||||
private:
|
||||
Qml::QmlSymbol *resolveType(const QString &name, const QString &fileName);
|
||||
Qml::QmlSymbol *resolveProperty(const QString &name, Qml::QmlSymbol *scope, const QString &fileName);
|
||||
Qml::QmlSymbol *resolveBuildinType(const QString &name);
|
||||
|
||||
static QString toString(QmlJS::AST::UiQualifiedId *id);
|
||||
|
||||
private:
|
||||
QStack<Qml::QmlSymbol *> _scopes;
|
||||
Qml::QmlDocument::Ptr _doc;
|
||||
Qml::Snapshot _snapshot;
|
||||
Qml::QmlTypeSystem *m_typeSystem;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLLOOKUPCONTEXT_H
|
||||
165
src/plugins/qmljseditor/qmlmodelmanager.cpp
Normal file
165
src/plugins/qmljseditor/qmlmodelmanager.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include <QFile>
|
||||
#include <QtConcurrentRun>
|
||||
#include <qtconcurrent/runextensions.h>
|
||||
#include <QTextStream>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
|
||||
#include <texteditor/itexteditor.h>
|
||||
|
||||
#include "qmljseditorconstants.h"
|
||||
#include "qmlmodelmanager.h"
|
||||
|
||||
#include <QtCore/QMetaType>
|
||||
|
||||
using namespace QmlJSEditor;
|
||||
using namespace QmlJSEditor::Internal;
|
||||
|
||||
QmlModelManager::QmlModelManager(QObject *parent):
|
||||
QmlModelManagerInterface(parent),
|
||||
m_core(Core::ICore::instance())
|
||||
{
|
||||
m_synchronizer.setCancelOnWait(true);
|
||||
|
||||
qRegisterMetaType<Qml::QmlDocument::Ptr>("Qml::QmlDocument::Ptr");
|
||||
|
||||
connect(this, SIGNAL(documentUpdated(Qml::QmlDocument::Ptr)),
|
||||
this, SLOT(onDocumentUpdated(Qml::QmlDocument::Ptr)));
|
||||
}
|
||||
|
||||
Qml::Snapshot QmlModelManager::snapshot() const
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
return _snapshot;
|
||||
}
|
||||
|
||||
void QmlModelManager::updateSourceFiles(const QStringList &files)
|
||||
{
|
||||
refreshSourceFiles(files);
|
||||
}
|
||||
|
||||
QFuture<void> QmlModelManager::refreshSourceFiles(const QStringList &sourceFiles)
|
||||
{
|
||||
if (sourceFiles.isEmpty()) {
|
||||
return QFuture<void>();
|
||||
}
|
||||
|
||||
const QMap<QString, QString> workingCopy = buildWorkingCopyList();
|
||||
|
||||
QFuture<void> result = QtConcurrent::run(&QmlModelManager::parse,
|
||||
workingCopy, sourceFiles,
|
||||
this);
|
||||
|
||||
if (m_synchronizer.futures().size() > 10) {
|
||||
QList<QFuture<void> > futures = m_synchronizer.futures();
|
||||
|
||||
m_synchronizer.clearFutures();
|
||||
|
||||
foreach (QFuture<void> future, futures) {
|
||||
if (! (future.isFinished() || future.isCanceled()))
|
||||
m_synchronizer.addFuture(future);
|
||||
}
|
||||
}
|
||||
|
||||
m_synchronizer.addFuture(result);
|
||||
|
||||
if (sourceFiles.count() > 1) {
|
||||
m_core->progressManager()->addTask(result, tr("Indexing"),
|
||||
QmlJSEditor::Constants::TASK_INDEX);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QMap<QString, QString> QmlModelManager::buildWorkingCopyList()
|
||||
{
|
||||
QMap<QString, QString> workingCopy;
|
||||
Core::EditorManager *editorManager = m_core->editorManager();
|
||||
|
||||
foreach (Core::IEditor *editor, editorManager->openedEditors()) {
|
||||
const QString key = editor->file()->fileName();
|
||||
|
||||
if (TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor)) {
|
||||
workingCopy[key] = textEditor->contents();
|
||||
}
|
||||
}
|
||||
|
||||
return workingCopy;
|
||||
}
|
||||
|
||||
void QmlModelManager::emitDocumentUpdated(Qml::QmlDocument::Ptr doc)
|
||||
{ emit documentUpdated(doc); }
|
||||
|
||||
void QmlModelManager::onDocumentUpdated(Qml::QmlDocument::Ptr doc)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
_snapshot.insert(doc);
|
||||
}
|
||||
|
||||
void QmlModelManager::parse(QFutureInterface<void> &future,
|
||||
QMap<QString, QString> workingCopy,
|
||||
QStringList files,
|
||||
QmlModelManager *modelManager)
|
||||
{
|
||||
future.setProgressRange(0, files.size());
|
||||
|
||||
for (int i = 0; i < files.size(); ++i) {
|
||||
future.setProgressValue(i);
|
||||
|
||||
const QString fileName = files.at(i);
|
||||
QString contents;
|
||||
|
||||
if (workingCopy.contains(fileName)) {
|
||||
contents = workingCopy.value(fileName);
|
||||
} else {
|
||||
QFile inFile(fileName);
|
||||
|
||||
if (inFile.open(QIODevice::ReadOnly)) {
|
||||
QTextStream ins(&inFile);
|
||||
contents = ins.readAll();
|
||||
inFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
Qml::QmlDocument::Ptr doc = Qml::QmlDocument::create(fileName);
|
||||
doc->setSource(contents);
|
||||
doc->parse();
|
||||
|
||||
modelManager->emitDocumentUpdated(doc);
|
||||
}
|
||||
|
||||
future.setProgressValue(files.size());
|
||||
}
|
||||
88
src/plugins/qmljseditor/qmlmodelmanager.h
Normal file
88
src/plugins/qmljseditor/qmlmodelmanager.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLMODELMANAGER_H
|
||||
#define QMLMODELMANAGER_H
|
||||
|
||||
#include "qmlmodelmanagerinterface.h"
|
||||
|
||||
#include <qmljs/qmldocument.h>
|
||||
|
||||
#include <QFuture>
|
||||
#include <QFutureSynchronizer>
|
||||
#include <QMutex>
|
||||
|
||||
namespace Core {
|
||||
class ICore;
|
||||
}
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlModelManager: public QmlModelManagerInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlModelManager(QObject *parent = 0);
|
||||
|
||||
virtual Qml::Snapshot snapshot() const;
|
||||
virtual void updateSourceFiles(const QStringList &files);
|
||||
|
||||
void emitDocumentUpdated(Qml::QmlDocument::Ptr doc);
|
||||
|
||||
Q_SIGNALS:
|
||||
void projectPathChanged(const QString &projectPath);
|
||||
void aboutToRemoveFiles(const QStringList &files);
|
||||
|
||||
private Q_SLOTS:
|
||||
// this should be executed in the GUI thread.
|
||||
void onDocumentUpdated(Qml::QmlDocument::Ptr doc);
|
||||
|
||||
protected:
|
||||
QFuture<void> refreshSourceFiles(const QStringList &sourceFiles);
|
||||
QMap<QString, QString> buildWorkingCopyList();
|
||||
|
||||
static void parse(QFutureInterface<void> &future,
|
||||
QMap<QString, QString> workingCopy,
|
||||
QStringList files,
|
||||
QmlModelManager *modelManager);
|
||||
|
||||
private:
|
||||
mutable QMutex m_mutex;
|
||||
Core::ICore *m_core;
|
||||
Qml::Snapshot _snapshot;
|
||||
|
||||
QFutureSynchronizer<void> m_synchronizer;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLMODELMANAGER_H
|
||||
41
src/plugins/qmljseditor/qmlmodelmanagerinterface.cpp
Normal file
41
src/plugins/qmljseditor/qmlmodelmanagerinterface.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlmodelmanagerinterface.h"
|
||||
|
||||
using namespace QmlJSEditor;
|
||||
|
||||
QmlModelManagerInterface::QmlModelManagerInterface(QObject *parent):
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QmlModelManagerInterface::~QmlModelManagerInterface()
|
||||
{
|
||||
}
|
||||
65
src/plugins/qmljseditor/qmlmodelmanagerinterface.h
Normal file
65
src/plugins/qmljseditor/qmlmodelmanagerinterface.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLMODELMANAGERINTERFACE_H
|
||||
#define QMLMODELMANAGERINTERFACE_H
|
||||
|
||||
#include "qmljseditor_global.h"
|
||||
|
||||
#include <qmljs/qmldocument.h>
|
||||
#include <qmljs/qmltypesystem.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace Qml {
|
||||
class Snapshot;
|
||||
}
|
||||
|
||||
namespace QmlJSEditor {
|
||||
|
||||
class QMLJSEDITOR_EXPORT QmlModelManagerInterface: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlModelManagerInterface(QObject *parent = 0);
|
||||
virtual ~QmlModelManagerInterface();
|
||||
|
||||
virtual Qml::Snapshot snapshot() const = 0;
|
||||
virtual void updateSourceFiles(const QStringList &files) = 0;
|
||||
|
||||
signals:
|
||||
void documentUpdated(Qml::QmlDocument::Ptr doc);
|
||||
};
|
||||
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLMODELMANAGERINTERFACE_H
|
||||
132
src/plugins/qmljseditor/qmlresolveexpression.cpp
Normal file
132
src/plugins/qmljseditor/qmlresolveexpression.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlresolveexpression.h"
|
||||
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <qmljs/parser/qmljsengine_p.h>
|
||||
|
||||
using namespace Qml;
|
||||
using namespace QmlJSEditor;
|
||||
using namespace QmlJSEditor::Internal;
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJS::AST;
|
||||
|
||||
QmlResolveExpression::QmlResolveExpression(const QmlLookupContext &context)
|
||||
: _context(context), _value(0)
|
||||
{
|
||||
}
|
||||
|
||||
QmlSymbol *QmlResolveExpression::typeOf(Node *node)
|
||||
{
|
||||
QmlSymbol *previousValue = switchValue(0);
|
||||
Node::accept(node, this);
|
||||
return switchValue(previousValue);
|
||||
}
|
||||
|
||||
QList<QmlSymbol*> QmlResolveExpression::visibleSymbols(Node *node)
|
||||
{
|
||||
QList<QmlSymbol*> result;
|
||||
|
||||
QmlSymbol *symbol = typeOf(node);
|
||||
if (symbol) {
|
||||
if (symbol->isIdSymbol())
|
||||
symbol = symbol->asIdSymbol()->parentNode();
|
||||
result.append(symbol->members());
|
||||
|
||||
// TODO: also add symbols from super-types
|
||||
} else {
|
||||
result.append(_context.visibleTypes());
|
||||
}
|
||||
|
||||
if (node) {
|
||||
foreach (QmlIdSymbol *idSymbol, _context.document()->ids().values())
|
||||
result.append(idSymbol);
|
||||
}
|
||||
|
||||
result.append(_context.visibleSymbolsInScope());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QmlSymbol *QmlResolveExpression::switchValue(QmlSymbol *value)
|
||||
{
|
||||
QmlSymbol *previousValue = _value;
|
||||
_value = value;
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
bool QmlResolveExpression::visit(IdentifierExpression *ast)
|
||||
{
|
||||
const QString name = ast->name->asString();
|
||||
_value = _context.resolve(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool matches(UiQualifiedId *candidate, const QString &wanted)
|
||||
{
|
||||
if (!candidate)
|
||||
return false;
|
||||
|
||||
if (!(candidate->name))
|
||||
return false;
|
||||
|
||||
if (candidate->next)
|
||||
return false; // TODO: verify this!
|
||||
|
||||
return wanted == candidate->name->asString();
|
||||
}
|
||||
|
||||
bool QmlResolveExpression::visit(FieldMemberExpression *ast)
|
||||
{
|
||||
const QString memberName = ast->name->asString();
|
||||
|
||||
QmlSymbol *base = typeOf(ast->base);
|
||||
if (!base)
|
||||
return false;
|
||||
|
||||
if (base->isIdSymbol())
|
||||
base = base->asIdSymbol()->parentNode();
|
||||
|
||||
if (!base)
|
||||
return false;
|
||||
|
||||
foreach (QmlSymbol *memberSymbol, base->members())
|
||||
if (memberSymbol->name() == memberName)
|
||||
_value = memberSymbol;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QmlResolveExpression::visit(QmlJS::AST::UiQualifiedId *ast)
|
||||
{
|
||||
_value = _context.resolveType(ast);
|
||||
|
||||
return false;
|
||||
}
|
||||
66
src/plugins/qmljseditor/qmlresolveexpression.h
Normal file
66
src/plugins/qmljseditor/qmlresolveexpression.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLRESOLVEEXPRESSION_H
|
||||
#define QMLRESOLVEEXPRESSION_H
|
||||
|
||||
#include "qmllookupcontext.h"
|
||||
|
||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||
#include <qmljs/qmlsymbol.h>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlResolveExpression: protected QmlJS::AST::Visitor
|
||||
{
|
||||
public:
|
||||
QmlResolveExpression(const QmlLookupContext &context);
|
||||
|
||||
Qml::QmlSymbol *typeOf(QmlJS::AST::Node *node);
|
||||
QList<Qml::QmlSymbol*> visibleSymbols(QmlJS::AST::Node *node);
|
||||
|
||||
protected:
|
||||
using QmlJS::AST::Visitor::visit;
|
||||
|
||||
Qml::QmlSymbol *switchValue(Qml::QmlSymbol *symbol);
|
||||
|
||||
virtual bool visit(QmlJS::AST::FieldMemberExpression *ast);
|
||||
virtual bool visit(QmlJS::AST::IdentifierExpression *ast);
|
||||
virtual bool visit(QmlJS::AST::UiQualifiedId *ast);
|
||||
|
||||
private:
|
||||
QmlLookupContext _context;
|
||||
Qml::QmlSymbol *_value;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLRESOLVEEXPRESSION_H
|
||||
Reference in New Issue
Block a user