forked from qt-creator/qt-creator
New code assist API
This is a re-work of our completion engine. Primary goals are: - Allow the computation to run in a separate thread so the GUI is not locked. - Support a model-based approach. QStrings are still needed (filtering, etc), but internal structures are free to use more efficient representations. - Unifiy all kinds of *assist* into a more reusable and extensible framework. - Remove unnecessary dependencies on the text editor so we have more generic and easily "plugable" components (still things to be resolved).
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,114 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSCODECOMPLETION_H
|
||||
#define QMLJSCODECOMPLETION_H
|
||||
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
#include <texteditor/icompletioncollector.h>
|
||||
#include <texteditor/snippets/snippetcollector.h>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QPointer>
|
||||
|
||||
namespace TextEditor {
|
||||
class ITextEditor;
|
||||
}
|
||||
|
||||
namespace QmlJS {
|
||||
class ModelManagerInterface;
|
||||
|
||||
namespace Interpreter {
|
||||
class Value;
|
||||
}
|
||||
}
|
||||
|
||||
namespace QmlJSEditor {
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class FunctionArgumentWidget;
|
||||
|
||||
class CodeCompletion: public TextEditor::ICompletionCollector
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CodeCompletion(QmlJS::ModelManagerInterface *modelManager, QObject *parent = 0);
|
||||
virtual ~CodeCompletion();
|
||||
|
||||
virtual TextEditor::ITextEditor *editor() const;
|
||||
virtual int startPosition() const;
|
||||
virtual bool shouldRestartCompletion();
|
||||
virtual bool supportsEditor(TextEditor::ITextEditor *editor) const;
|
||||
virtual bool supportsPolicy(TextEditor::CompletionPolicy policy) const;
|
||||
virtual bool triggersCompletion(TextEditor::ITextEditor *editor);
|
||||
virtual int startCompletion(TextEditor::ITextEditor *editor);
|
||||
virtual void completions(QList<TextEditor::CompletionItem> *completions);
|
||||
virtual bool typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar);
|
||||
virtual void complete(const TextEditor::CompletionItem &item, QChar typedChar);
|
||||
virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
|
||||
virtual QList<TextEditor::CompletionItem> getCompletions();
|
||||
virtual void sortCompletion(QList<TextEditor::CompletionItem> &completionItems);
|
||||
|
||||
virtual void cleanup();
|
||||
|
||||
private:
|
||||
|
||||
bool maybeTriggersCompletion(TextEditor::ITextEditor *editor);
|
||||
bool isDelimiter(QChar ch) const;
|
||||
|
||||
bool completeUrl(const QString &relativeBasePath, const QString &urlString);
|
||||
bool completeFileName(const QString &relativeBasePath, const QString &fileName,
|
||||
const QStringList &patterns = QStringList());
|
||||
|
||||
void addCompletions(const QHash<QString, const QmlJS::Interpreter::Value *> &newCompletions,
|
||||
const QIcon &icon, int relevance);
|
||||
void addCompletions(const QStringList &newCompletions,
|
||||
const QIcon &icon, int relevance);
|
||||
void addCompletionsPropertyLhs(
|
||||
const QHash<QString, const QmlJS::Interpreter::Value *> &newCompletions,
|
||||
const QIcon &icon, int relevance, bool afterOn);
|
||||
|
||||
QmlJS::ModelManagerInterface *m_modelManager;
|
||||
TextEditor::ITextEditor *m_editor;
|
||||
int m_startPosition;
|
||||
bool m_restartCompletion;
|
||||
TextEditor::SnippetCollector m_snippetProvider;
|
||||
QList<TextEditor::CompletionItem> m_completions;
|
||||
QPointer<FunctionArgumentWidget> m_functionArgumentWidget;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLJSCODECOMPLETION_H
|
||||
854
src/plugins/qmljseditor/qmljscompletionassist.cpp
Normal file
854
src/plugins/qmljseditor/qmljscompletionassist.cpp
Normal file
@@ -0,0 +1,854 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljscompletionassist.h"
|
||||
#include "qmljseditorconstants.h"
|
||||
#include "qmljsreuse.h"
|
||||
#include "qmlexpressionundercursor.h"
|
||||
|
||||
#include <coreplugin/ifile.h>
|
||||
|
||||
#include <texteditor/codeassist/iassistinterface.h>
|
||||
#include <texteditor/codeassist/genericproposal.h>
|
||||
#include <texteditor/codeassist/functionhintproposal.h>
|
||||
#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <qmljs/qmljsinterpreter.h>
|
||||
#include <qmljs/qmljslookupcontext.h>
|
||||
#include <qmljs/qmljsscanner.h>
|
||||
#include <qmljs/qmljsbind.h>
|
||||
#include <qmljs/qmljscompletioncontextfinder.h>
|
||||
#include <qmljs/qmljsscopebuilder.h>
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QtAlgorithms>
|
||||
#include <QtCore/QDirIterator>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtGui/QIcon>
|
||||
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJSEditor;
|
||||
using namespace Internal;
|
||||
using namespace TextEditor;
|
||||
|
||||
namespace {
|
||||
|
||||
enum CompletionOrder {
|
||||
EnumValueOrder = -5,
|
||||
SnippetOrder = -15,
|
||||
PropertyOrder = -10,
|
||||
SymbolOrder = -20,
|
||||
KeywordOrder = -25,
|
||||
TypeOrder = -30
|
||||
};
|
||||
|
||||
class EnumerateProperties: private Interpreter::MemberProcessor
|
||||
{
|
||||
QSet<const Interpreter::ObjectValue *> _processed;
|
||||
QHash<QString, const Interpreter::Value *> _properties;
|
||||
bool _globalCompletion;
|
||||
bool _enumerateGeneratedSlots;
|
||||
const Interpreter::Context *_context;
|
||||
const Interpreter::ObjectValue *_currentObject;
|
||||
|
||||
public:
|
||||
EnumerateProperties(const Interpreter::Context *context)
|
||||
: _globalCompletion(false),
|
||||
_enumerateGeneratedSlots(false),
|
||||
_context(context),
|
||||
_currentObject(0)
|
||||
{
|
||||
}
|
||||
|
||||
void setGlobalCompletion(bool globalCompletion)
|
||||
{
|
||||
_globalCompletion = globalCompletion;
|
||||
}
|
||||
|
||||
void setEnumerateGeneratedSlots(bool enumerate)
|
||||
{
|
||||
_enumerateGeneratedSlots = enumerate;
|
||||
}
|
||||
|
||||
QHash<QString, const Interpreter::Value *> operator ()(const Interpreter::Value *value)
|
||||
{
|
||||
_processed.clear();
|
||||
_properties.clear();
|
||||
_currentObject = Interpreter::value_cast<const Interpreter::ObjectValue *>(value);
|
||||
|
||||
enumerateProperties(value);
|
||||
|
||||
return _properties;
|
||||
}
|
||||
|
||||
QHash<QString, const Interpreter::Value *> operator ()()
|
||||
{
|
||||
_processed.clear();
|
||||
_properties.clear();
|
||||
_currentObject = 0;
|
||||
|
||||
foreach (const Interpreter::ObjectValue *scope, _context->scopeChain().all())
|
||||
enumerateProperties(scope);
|
||||
|
||||
return _properties;
|
||||
}
|
||||
|
||||
private:
|
||||
void insertProperty(const QString &name, const Interpreter::Value *value)
|
||||
{
|
||||
_properties.insert(name, value);
|
||||
}
|
||||
|
||||
virtual bool processProperty(const QString &name, const Interpreter::Value *value)
|
||||
{
|
||||
insertProperty(name, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool processEnumerator(const QString &name, const Interpreter::Value *value)
|
||||
{
|
||||
if (! _globalCompletion)
|
||||
insertProperty(name, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool processSignal(const QString &, const Interpreter::Value *)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool processSlot(const QString &name, const Interpreter::Value *value)
|
||||
{
|
||||
insertProperty(name, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool processGeneratedSlot(const QString &name, const Interpreter::Value *value)
|
||||
{
|
||||
if (_enumerateGeneratedSlots || (_currentObject && _currentObject->className().endsWith(QLatin1String("Keys")))) {
|
||||
// ### FIXME: add support for attached properties.
|
||||
insertProperty(name, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void enumerateProperties(const Interpreter::Value *value)
|
||||
{
|
||||
if (! value)
|
||||
return;
|
||||
else if (const Interpreter::ObjectValue *object = value->asObjectValue()) {
|
||||
enumerateProperties(object);
|
||||
}
|
||||
}
|
||||
|
||||
void enumerateProperties(const Interpreter::ObjectValue *object)
|
||||
{
|
||||
if (! object || _processed.contains(object))
|
||||
return;
|
||||
|
||||
_processed.insert(object);
|
||||
enumerateProperties(object->prototype(_context));
|
||||
|
||||
object->processMembers(this);
|
||||
}
|
||||
};
|
||||
|
||||
const Interpreter::Value *getPropertyValue(const Interpreter::ObjectValue *object,
|
||||
const QStringList &propertyNames,
|
||||
const Interpreter::Context *context)
|
||||
{
|
||||
if (propertyNames.isEmpty() || !object)
|
||||
return 0;
|
||||
|
||||
const Interpreter::Value *value = object;
|
||||
foreach (const QString &name, propertyNames) {
|
||||
if (const Interpreter::ObjectValue *objectValue = value->asObjectValue()) {
|
||||
value = objectValue->property(name, context);
|
||||
if (!value)
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool isLiteral(AST::Node *ast)
|
||||
{
|
||||
if (AST::cast<AST::StringLiteral *>(ast))
|
||||
return true;
|
||||
else if (AST::cast<AST::NumericLiteral *>(ast))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
} // Anonymous
|
||||
|
||||
// -----------------------
|
||||
// QmlJSAssistProposalItem
|
||||
// -----------------------
|
||||
bool QmlJSAssistProposalItem::prematurelyApplies(const QChar &c) const
|
||||
{
|
||||
if (data().canConvert<QString>()) // snippet
|
||||
return false;
|
||||
|
||||
return (text().endsWith(QLatin1String(": ")) && c == QLatin1Char(':'))
|
||||
|| (text().endsWith(QLatin1Char('.')) && c == QLatin1Char('.'));
|
||||
}
|
||||
|
||||
void QmlJSAssistProposalItem::applyContextualContent(TextEditor::BaseTextEditor *editor,
|
||||
int basePosition) const
|
||||
{
|
||||
const int currentPosition = editor->position();
|
||||
editor->setCursorPosition(basePosition);
|
||||
editor->remove(currentPosition - basePosition);
|
||||
|
||||
QString replaceable;
|
||||
const QString &content = text();
|
||||
if (content.endsWith(QLatin1String(": ")))
|
||||
replaceable = QLatin1String(": ");
|
||||
else if (content.endsWith(QLatin1Char('.')))
|
||||
replaceable = QLatin1String(".");
|
||||
int replacedLength = 0;
|
||||
for (int i = 0; i < replaceable.length(); ++i) {
|
||||
const QChar a = replaceable.at(i);
|
||||
const QChar b = editor->characterAt(editor->position() + i);
|
||||
if (a == b)
|
||||
++replacedLength;
|
||||
else
|
||||
break;
|
||||
}
|
||||
const int length = editor->position() - basePosition + replacedLength;
|
||||
editor->replace(length, content);
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// FunctionHintProposalModel
|
||||
// -------------------------
|
||||
class FunctionHintProposalModel : public TextEditor::IFunctionHintProposalModel
|
||||
{
|
||||
public:
|
||||
FunctionHintProposalModel(const QString &functionName, const QStringList &signature)
|
||||
: m_functionName(functionName)
|
||||
, m_signature(signature)
|
||||
, m_minimumArgumentCount(signature.size())
|
||||
{}
|
||||
|
||||
virtual void reset() {}
|
||||
virtual int size() const { return 1; }
|
||||
virtual QString text(int index) const;
|
||||
virtual int activeArgument(const QString &prefix) const;
|
||||
|
||||
private:
|
||||
QString m_functionName;
|
||||
QStringList m_signature;
|
||||
int m_minimumArgumentCount;
|
||||
};
|
||||
|
||||
QString FunctionHintProposalModel::text(int index) const
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
|
||||
QString prettyMethod;
|
||||
prettyMethod += QString::fromLatin1("function ");
|
||||
prettyMethod += m_functionName;
|
||||
prettyMethod += QLatin1Char('(');
|
||||
for (int i = 0; i < m_minimumArgumentCount; ++i) {
|
||||
if (i != 0)
|
||||
prettyMethod += QLatin1String(", ");
|
||||
|
||||
QString arg = m_signature.at(i);
|
||||
if (arg.isEmpty()) {
|
||||
arg = QLatin1String("arg");
|
||||
arg += QString::number(i + 1);
|
||||
}
|
||||
|
||||
prettyMethod += arg;
|
||||
}
|
||||
prettyMethod += QLatin1Char(')');
|
||||
return prettyMethod;
|
||||
}
|
||||
|
||||
int FunctionHintProposalModel::activeArgument(const QString &prefix) const
|
||||
{
|
||||
int argnr = 0;
|
||||
int parcount = 0;
|
||||
Scanner tokenize;
|
||||
const QList<Token> tokens = tokenize(prefix);
|
||||
for (int i = 0; i < tokens.count(); ++i) {
|
||||
const Token &tk = tokens.at(i);
|
||||
if (tk.is(Token::LeftParenthesis))
|
||||
++parcount;
|
||||
else if (tk.is(Token::RightParenthesis))
|
||||
--parcount;
|
||||
else if (! parcount && tk.is(Token::Colon))
|
||||
++argnr;
|
||||
}
|
||||
|
||||
if (parcount < 0)
|
||||
return -1;
|
||||
|
||||
return argnr;
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// QmlJSCompletionAssistProvider
|
||||
// -----------------------------
|
||||
bool QmlJSCompletionAssistProvider::supportsEditor(const QString &editorId) const
|
||||
{
|
||||
return editorId == QLatin1String(Constants::C_QMLJSEDITOR_ID);
|
||||
}
|
||||
|
||||
int QmlJSCompletionAssistProvider::activationCharSequenceLength() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool QmlJSCompletionAssistProvider::isActivationCharSequence(const QString &sequence) const
|
||||
{
|
||||
return isActivationChar(sequence.at(0));
|
||||
}
|
||||
|
||||
bool QmlJSCompletionAssistProvider::isContinuationChar(const QChar &c) const
|
||||
{
|
||||
return isIdentifierChar(c, false);
|
||||
}
|
||||
|
||||
IAssistProcessor *QmlJSCompletionAssistProvider::createProcessor() const
|
||||
{
|
||||
return new QmlJSCompletionAssistProcessor;
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// QmlJSCompletionAssistProcessor
|
||||
// ------------------------------
|
||||
QmlJSCompletionAssistProcessor::QmlJSCompletionAssistProcessor()
|
||||
: m_startPosition(0)
|
||||
, m_snippetCollector(Constants::QML_SNIPPETS_GROUP_ID, iconForColor(Qt::red), SnippetOrder)
|
||||
{}
|
||||
|
||||
QmlJSCompletionAssistProcessor::~QmlJSCompletionAssistProcessor()
|
||||
{}
|
||||
|
||||
IAssistProposal *QmlJSCompletionAssistProcessor::createContentProposal() const
|
||||
{
|
||||
IGenericProposalModel *model = new QmlJSAssistProposalModel(m_completions);
|
||||
IAssistProposal *proposal = new GenericProposal(m_startPosition, model);
|
||||
return proposal;
|
||||
}
|
||||
|
||||
IAssistProposal *QmlJSCompletionAssistProcessor::createHintProposal(const QString &functionName,
|
||||
const QStringList &signature) const
|
||||
{
|
||||
IFunctionHintProposalModel *model = new FunctionHintProposalModel(functionName, signature);
|
||||
IAssistProposal *proposal = new FunctionHintProposal(m_startPosition, model);
|
||||
return proposal;
|
||||
}
|
||||
|
||||
IAssistProposal *QmlJSCompletionAssistProcessor::perform(const IAssistInterface *assistInterface)
|
||||
{
|
||||
m_interface.reset(static_cast<const QmlJSCompletionAssistInterface *>(assistInterface));
|
||||
|
||||
if (assistInterface->reason() == IdleEditor && !acceptsIdleEditor())
|
||||
return 0;
|
||||
|
||||
const QString &fileName = m_interface->file()->fileName();
|
||||
|
||||
m_startPosition = assistInterface->position();
|
||||
while (isIdentifierChar(m_interface->document()->characterAt(m_startPosition - 1), false, false))
|
||||
--m_startPosition;
|
||||
|
||||
m_completions.clear();
|
||||
|
||||
const QmlJSCompletionAssistInterface *qmlInterface =
|
||||
static_cast<const QmlJSCompletionAssistInterface *>(assistInterface);
|
||||
const SemanticInfo &semanticInfo = qmlInterface->semanticInfo();
|
||||
if (!semanticInfo.isValid())
|
||||
return 0;
|
||||
|
||||
const Document::Ptr document = semanticInfo.document;
|
||||
const QFileInfo currentFileInfo(fileName);
|
||||
|
||||
bool isQmlFile = false;
|
||||
if (currentFileInfo.suffix() == QLatin1String("qml"))
|
||||
isQmlFile = true;
|
||||
|
||||
const QList<AST::Node *> path = semanticInfo.astPath(m_interface->position());
|
||||
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(path);
|
||||
const Interpreter::Context *context = lookupContext->context();
|
||||
|
||||
// Search for the operator that triggered the completion.
|
||||
QChar completionOperator;
|
||||
if (m_startPosition > 0)
|
||||
completionOperator = m_interface->document()->characterAt(m_startPosition - 1);
|
||||
|
||||
QTextCursor startPositionCursor(qmlInterface->document());
|
||||
startPositionCursor.setPosition(m_startPosition);
|
||||
CompletionContextFinder contextFinder(startPositionCursor);
|
||||
|
||||
const Interpreter::ObjectValue *qmlScopeType = 0;
|
||||
if (contextFinder.isInQmlContext()) {
|
||||
// ### this should use semanticInfo.declaringMember instead, but that may also return functions
|
||||
for (int i = path.size() - 1; i >= 0; --i) {
|
||||
AST::Node *node = path[i];
|
||||
if (AST::cast<AST::UiObjectDefinition *>(node) || AST::cast<AST::UiObjectBinding *>(node)) {
|
||||
qmlScopeType = document->bind()->findQmlObject(node);
|
||||
if (qmlScopeType)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fallback to getting the base type object
|
||||
if (!qmlScopeType)
|
||||
qmlScopeType = context->lookupType(document.data(), contextFinder.qmlObjectTypeName());
|
||||
}
|
||||
|
||||
if (contextFinder.isInStringLiteral()) {
|
||||
// get the text of the literal up to the cursor position
|
||||
//QTextCursor tc = textWidget->textCursor();
|
||||
QTextCursor tc(qmlInterface->document());
|
||||
tc.setPosition(qmlInterface->position());
|
||||
QmlExpressionUnderCursor expressionUnderCursor;
|
||||
expressionUnderCursor(tc);
|
||||
QString literalText = expressionUnderCursor.text();
|
||||
QTC_ASSERT(!literalText.isEmpty() && (
|
||||
literalText.at(0) == QLatin1Char('"')
|
||||
|| literalText.at(0) == QLatin1Char('\'')), return 0);
|
||||
literalText = literalText.mid(1);
|
||||
|
||||
if (contextFinder.isInImport()) {
|
||||
QStringList patterns;
|
||||
patterns << QLatin1String("*.qml") << QLatin1String("*.js");
|
||||
if (completeFileName(document->path(), literalText, patterns))
|
||||
return createContentProposal();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Interpreter::Value *value =
|
||||
getPropertyValue(qmlScopeType, contextFinder.bindingPropertyName(), context);
|
||||
if (!value) {
|
||||
// do nothing
|
||||
} else if (value->asUrlValue()) {
|
||||
if (completeUrl(document->path(), literalText))
|
||||
return createContentProposal();
|
||||
}
|
||||
|
||||
// ### enum completion?
|
||||
|
||||
// completion gets triggered for / in string literals, if we don't
|
||||
// return here, this will mean the snippet completion pops up for
|
||||
// each / in a string literal that is not triggering file completion
|
||||
return 0;
|
||||
} else if (completionOperator.isSpace()
|
||||
|| completionOperator.isNull()
|
||||
|| isDelimiterChar(completionOperator)
|
||||
|| (completionOperator == QLatin1Char('(')
|
||||
&& m_startPosition != m_interface->position())) {
|
||||
|
||||
bool doGlobalCompletion = true;
|
||||
bool doQmlKeywordCompletion = true;
|
||||
bool doJsKeywordCompletion = true;
|
||||
bool doQmlTypeCompletion = false;
|
||||
|
||||
if (contextFinder.isInLhsOfBinding() && qmlScopeType) {
|
||||
doGlobalCompletion = false;
|
||||
doJsKeywordCompletion = false;
|
||||
doQmlTypeCompletion = true;
|
||||
|
||||
EnumerateProperties enumerateProperties(context);
|
||||
enumerateProperties.setGlobalCompletion(true);
|
||||
enumerateProperties.setEnumerateGeneratedSlots(true);
|
||||
|
||||
// id: is special
|
||||
BasicProposalItem *idProposalItem = new QmlJSAssistProposalItem;
|
||||
idProposalItem->setText(QLatin1String("id: "));
|
||||
idProposalItem->setIcon(m_interface->symbolIcon());
|
||||
idProposalItem->setOrder(PropertyOrder);
|
||||
m_completions.append(idProposalItem);
|
||||
|
||||
addCompletionsPropertyLhs(enumerateProperties(qmlScopeType),
|
||||
m_interface->symbolIcon(),
|
||||
PropertyOrder,
|
||||
contextFinder.isAfterOnInLhsOfBinding());
|
||||
|
||||
if (ScopeBuilder::isPropertyChangesObject(context, qmlScopeType)
|
||||
&& context->scopeChain().qmlScopeObjects.size() == 2) {
|
||||
addCompletions(enumerateProperties(context->scopeChain().qmlScopeObjects.first()),
|
||||
m_interface->symbolIcon(),
|
||||
SymbolOrder);
|
||||
}
|
||||
}
|
||||
|
||||
if (contextFinder.isInRhsOfBinding() && qmlScopeType) {
|
||||
doQmlKeywordCompletion = false;
|
||||
|
||||
// complete enum values for enum properties
|
||||
const Interpreter::Value *value =
|
||||
getPropertyValue(qmlScopeType, contextFinder.bindingPropertyName(), context);
|
||||
if (const Interpreter::QmlEnumValue *enumValue =
|
||||
dynamic_cast<const Interpreter::QmlEnumValue *>(value)) {
|
||||
foreach (const QString &key, enumValue->keys())
|
||||
addCompletion(key, m_interface->symbolIcon(),
|
||||
EnumValueOrder, QString("\"%1\"").arg(key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!contextFinder.isInImport() && !contextFinder.isInQmlContext())
|
||||
doQmlTypeCompletion = true;
|
||||
|
||||
if (doQmlTypeCompletion) {
|
||||
if (const Interpreter::ObjectValue *qmlTypes = context->scopeChain().qmlTypes) {
|
||||
EnumerateProperties enumerateProperties(context);
|
||||
addCompletions(enumerateProperties(qmlTypes), m_interface->symbolIcon(), TypeOrder);
|
||||
}
|
||||
}
|
||||
|
||||
if (doGlobalCompletion) {
|
||||
// It's a global completion.
|
||||
EnumerateProperties enumerateProperties(context);
|
||||
enumerateProperties.setGlobalCompletion(true);
|
||||
addCompletions(enumerateProperties(), m_interface->symbolIcon(), SymbolOrder);
|
||||
}
|
||||
|
||||
if (doJsKeywordCompletion) {
|
||||
// add js keywords
|
||||
addCompletions(Scanner::keywords(), m_interface->keywordIcon(), KeywordOrder);
|
||||
}
|
||||
|
||||
// add qml extra words
|
||||
if (doQmlKeywordCompletion && isQmlFile) {
|
||||
static QStringList qmlWords;
|
||||
static QStringList qmlWordsAlsoInJs;
|
||||
|
||||
if (qmlWords.isEmpty()) {
|
||||
qmlWords << QLatin1String("property")
|
||||
//<< QLatin1String("readonly")
|
||||
<< QLatin1String("signal")
|
||||
<< QLatin1String("import");
|
||||
}
|
||||
if (qmlWordsAlsoInJs.isEmpty())
|
||||
qmlWordsAlsoInJs << QLatin1String("default") << QLatin1String("function");
|
||||
|
||||
addCompletions(qmlWords, m_interface->keywordIcon(), KeywordOrder);
|
||||
if (!doJsKeywordCompletion)
|
||||
addCompletions(qmlWordsAlsoInJs, m_interface->keywordIcon(), KeywordOrder);
|
||||
}
|
||||
}
|
||||
|
||||
else if (completionOperator == QLatin1Char('.') || completionOperator == QLatin1Char('(')) {
|
||||
// Look at the expression under cursor.
|
||||
//QTextCursor tc = textWidget->textCursor();
|
||||
QTextCursor tc(qmlInterface->document());
|
||||
tc.setPosition(m_startPosition - 1);
|
||||
|
||||
QmlExpressionUnderCursor expressionUnderCursor;
|
||||
QmlJS::AST::ExpressionNode *expression = expressionUnderCursor(tc);
|
||||
|
||||
if (expression != 0 && ! isLiteral(expression)) {
|
||||
// Evaluate the expression under cursor.
|
||||
Interpreter::Engine *interp = lookupContext->engine();
|
||||
const Interpreter::Value *value =
|
||||
interp->convertToObject(lookupContext->evaluate(expression));
|
||||
//qDebug() << "type:" << interp.typeId(value);
|
||||
|
||||
if (value && completionOperator == QLatin1Char('.')) { // member completion
|
||||
EnumerateProperties enumerateProperties(context);
|
||||
if (contextFinder.isInLhsOfBinding() && qmlScopeType) {
|
||||
enumerateProperties.setEnumerateGeneratedSlots(true);
|
||||
addCompletionsPropertyLhs(enumerateProperties(value),
|
||||
m_interface->symbolIcon(),
|
||||
PropertyOrder,
|
||||
contextFinder.isAfterOnInLhsOfBinding());
|
||||
} else
|
||||
addCompletions(enumerateProperties(value), m_interface->symbolIcon(), SymbolOrder);
|
||||
} else if (value
|
||||
&& completionOperator == QLatin1Char('(')
|
||||
&& m_startPosition == m_interface->position()) {
|
||||
// function completion
|
||||
if (const Interpreter::FunctionValue *f = value->asFunctionValue()) {
|
||||
QString functionName = expressionUnderCursor.text();
|
||||
int indexOfDot = functionName.lastIndexOf(QLatin1Char('.'));
|
||||
if (indexOfDot != -1)
|
||||
functionName = functionName.mid(indexOfDot + 1);
|
||||
|
||||
QStringList signature;
|
||||
for (int i = 0; i < f->argumentCount(); ++i)
|
||||
signature.append(f->argumentName(i));
|
||||
|
||||
return createHintProposal(functionName.trimmed(), signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! m_completions.isEmpty())
|
||||
return createContentProposal();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isQmlFile
|
||||
&& (completionOperator.isNull()
|
||||
|| completionOperator.isSpace()
|
||||
|| isDelimiterChar(completionOperator))) {
|
||||
m_completions.append(m_snippetCollector.collect());
|
||||
}
|
||||
|
||||
if (! m_completions.isEmpty())
|
||||
return createContentProposal();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool QmlJSCompletionAssistProcessor::acceptsIdleEditor() const
|
||||
{
|
||||
const int cursorPos = m_interface->position();
|
||||
|
||||
bool maybeAccept = false;
|
||||
const QChar &charBeforeCursor = m_interface->document()->characterAt(cursorPos - 1);
|
||||
if (isActivationChar(charBeforeCursor)) {
|
||||
maybeAccept = true;
|
||||
} else {
|
||||
const QChar &charUnderCursor = m_interface->document()->characterAt(cursorPos);
|
||||
if (isIdentifierChar(charBeforeCursor)
|
||||
&& ((charUnderCursor.isSpace()
|
||||
|| charUnderCursor.isNull()
|
||||
|| isDelimiterChar(charUnderCursor))
|
||||
|| isIdentifierChar(charUnderCursor))) {
|
||||
|
||||
int startPos = cursorPos - 1;
|
||||
for (; startPos != -1; --startPos) {
|
||||
if (!isIdentifierChar(m_interface->document()->characterAt(startPos)))
|
||||
break;
|
||||
}
|
||||
++startPos;
|
||||
|
||||
const QString &word = m_interface->textAt(startPos, cursorPos - startPos);
|
||||
if (word.length() > 2 && isIdentifierChar(word.at(0), true)) {
|
||||
for (int i = 1; i < word.length(); ++i) {
|
||||
if (!isIdentifierChar(word.at(i)))
|
||||
return false;
|
||||
}
|
||||
maybeAccept = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maybeAccept) {
|
||||
QTextCursor tc(m_interface->document());
|
||||
tc.setPosition(m_interface->position());
|
||||
const QTextBlock &block = tc.block();
|
||||
const QString &blockText = block.text();
|
||||
const int blockState = qMax(0, block.previous().userState()) & 0xff;
|
||||
|
||||
Scanner scanner;
|
||||
const QList<Token> tokens = scanner(blockText, blockState);
|
||||
const int column = block.position() - m_interface->position();
|
||||
foreach (const Token &tk, tokens) {
|
||||
if (column >= tk.begin() && column <= tk.end()) {
|
||||
if (charBeforeCursor == QLatin1Char('/') && tk.is(Token::String))
|
||||
return true; // path completion inside string literals
|
||||
if (tk.is(Token::Comment) || tk.is(Token::String))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (charBeforeCursor != QLatin1Char('/'))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QmlJSCompletionAssistProcessor::completeFileName(const QString &relativeBasePath,
|
||||
const QString &fileName,
|
||||
const QStringList &patterns)
|
||||
{
|
||||
const QFileInfo fileInfo(fileName);
|
||||
QString directoryPrefix;
|
||||
if (fileInfo.isRelative()) {
|
||||
directoryPrefix = relativeBasePath;
|
||||
directoryPrefix += QDir::separator();
|
||||
directoryPrefix += fileInfo.path();
|
||||
} else {
|
||||
directoryPrefix = fileInfo.path();
|
||||
}
|
||||
if (!QFileInfo(directoryPrefix).exists())
|
||||
return false;
|
||||
|
||||
QDirIterator dirIterator(directoryPrefix,
|
||||
patterns,
|
||||
QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
|
||||
while (dirIterator.hasNext()) {
|
||||
dirIterator.next();
|
||||
const QString fileName = dirIterator.fileName();
|
||||
|
||||
BasicProposalItem *item = new QmlJSAssistProposalItem;
|
||||
item->setText(fileName);
|
||||
item->setIcon(m_interface->fileNameIcon());
|
||||
m_completions.append(item);
|
||||
}
|
||||
|
||||
return !m_completions.isEmpty();
|
||||
}
|
||||
|
||||
bool QmlJSCompletionAssistProcessor::completeUrl(const QString &relativeBasePath, const QString &urlString)
|
||||
{
|
||||
const QUrl url(urlString);
|
||||
QString fileName = url.toLocalFile();
|
||||
if (fileName.isEmpty())
|
||||
return false;
|
||||
|
||||
return completeFileName(relativeBasePath, fileName);
|
||||
}
|
||||
|
||||
void QmlJSCompletionAssistProcessor::addCompletionsPropertyLhs(const QHash<QString,
|
||||
const QmlJS::Interpreter::Value *> &newCompletions,
|
||||
const QIcon &icon,
|
||||
int order,
|
||||
bool afterOn)
|
||||
{
|
||||
QHashIterator<QString, const Interpreter::Value *> it(newCompletions);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
|
||||
QString itemText = it.key();
|
||||
QLatin1String postfix(": ");
|
||||
if (afterOn)
|
||||
postfix = QLatin1String(" {");
|
||||
if (const Interpreter::QmlObjectValue *qmlValue =
|
||||
dynamic_cast<const Interpreter::QmlObjectValue *>(it.value())) {
|
||||
// to distinguish "anchors." from "gradient:" we check if the right hand side
|
||||
// type is instantiatable or is the prototype of an instantiatable object
|
||||
if (qmlValue->hasChildInPackage())
|
||||
itemText.append(postfix);
|
||||
else
|
||||
itemText.append(QLatin1Char('.'));
|
||||
} else {
|
||||
itemText.append(postfix);
|
||||
}
|
||||
|
||||
addCompletion(itemText, icon, order);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSCompletionAssistProcessor::addCompletion(const QString &text,
|
||||
const QIcon &icon,
|
||||
int order,
|
||||
const QVariant &data)
|
||||
{
|
||||
if (text.isEmpty())
|
||||
return;
|
||||
|
||||
BasicProposalItem *item = new QmlJSAssistProposalItem;
|
||||
item->setText(text);
|
||||
item->setIcon(icon);
|
||||
item->setOrder(order);
|
||||
item->setData(data);
|
||||
m_completions.append(item);
|
||||
}
|
||||
|
||||
void QmlJSCompletionAssistProcessor::addCompletions(const QHash<QString,
|
||||
const QmlJS::Interpreter::Value *> &newCompletions,
|
||||
const QIcon &icon,
|
||||
int order)
|
||||
{
|
||||
QHashIterator<QString, const Interpreter::Value *> it(newCompletions);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
addCompletion(it.key(), icon, order);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSCompletionAssistProcessor::addCompletions(const QStringList &newCompletions,
|
||||
const QIcon &icon,
|
||||
int order)
|
||||
{
|
||||
foreach (const QString &text, newCompletions)
|
||||
addCompletion(text, icon, order);
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// QmlJSCompletionAssistInterface
|
||||
// ------------------------------
|
||||
QmlJSCompletionAssistInterface::QmlJSCompletionAssistInterface(QTextDocument *document,
|
||||
int position,
|
||||
Core::IFile *file,
|
||||
TextEditor::AssistReason reason,
|
||||
const SemanticInfo &info)
|
||||
: DefaultAssistInterface(document, position, file, reason)
|
||||
, m_semanticInfo(info)
|
||||
, m_darkBlueIcon(iconForColor(Qt::darkBlue))
|
||||
, m_darkYellowIcon(iconForColor(Qt::darkYellow))
|
||||
, m_darkCyanIcon(iconForColor(Qt::darkCyan))
|
||||
{}
|
||||
|
||||
const SemanticInfo &QmlJSCompletionAssistInterface::semanticInfo() const
|
||||
{
|
||||
return m_semanticInfo;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct QmlJSLessThan
|
||||
{
|
||||
bool operator() (const BasicProposalItem *a, const BasicProposalItem *b)
|
||||
{
|
||||
if (a->order() != b->order())
|
||||
return a->order() > b->order();
|
||||
else if (a->text().isEmpty())
|
||||
return true;
|
||||
else if (b->text().isEmpty())
|
||||
return false;
|
||||
else if (a->data().isValid() != b->data().isValid())
|
||||
return a->data().isValid();
|
||||
else if (a->text().at(0).isUpper() && b->text().at(0).isLower())
|
||||
return false;
|
||||
else if (a->text().at(0).isLower() && b->text().at(0).isUpper())
|
||||
return true;
|
||||
return a->text() < b->text();
|
||||
}
|
||||
};
|
||||
|
||||
} // Anonymous
|
||||
|
||||
// -------------------------
|
||||
// QmlJSAssistProposalModel
|
||||
// -------------------------
|
||||
void QmlJSAssistProposalModel::sort()
|
||||
{
|
||||
qSort(currentItems().first, currentItems().second, QmlJSLessThan());
|
||||
}
|
||||
158
src/plugins/qmljseditor/qmljscompletionassist.h
Normal file
158
src/plugins/qmljseditor/qmljscompletionassist.h
Normal file
@@ -0,0 +1,158 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSCOMPLETIONASSIST_H
|
||||
#define QMLJSCOMPLETIONASSIST_H
|
||||
|
||||
#include "qmljseditor.h"
|
||||
|
||||
#include <texteditor/codeassist/basicproposalitem.h>
|
||||
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
|
||||
#include <texteditor/codeassist/completionassistprovider.h>
|
||||
#include <texteditor/codeassist/iassistprocessor.h>
|
||||
#include <texteditor/snippets/snippetassistcollector.h>
|
||||
#include <texteditor/codeassist/defaultassistinterface.h>
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtGui/QIcon>
|
||||
|
||||
namespace QmlJS {
|
||||
namespace Interpreter {
|
||||
class Value;
|
||||
}
|
||||
}
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlJSCompletionAssistInterface;
|
||||
|
||||
class QmlJSAssistProposalItem : public TextEditor::BasicProposalItem
|
||||
{
|
||||
public:
|
||||
virtual bool prematurelyApplies(const QChar &c) const;
|
||||
virtual void applyContextualContent(TextEditor::BaseTextEditor *editor,
|
||||
int basePosition) const;
|
||||
};
|
||||
|
||||
|
||||
class QmlJSAssistProposalModel : public TextEditor::BasicProposalItemListModel
|
||||
{
|
||||
public:
|
||||
QmlJSAssistProposalModel(const QList<TextEditor::BasicProposalItem *> &items)
|
||||
: TextEditor::BasicProposalItemListModel(items)
|
||||
{}
|
||||
|
||||
virtual void sort();
|
||||
};
|
||||
|
||||
|
||||
class QmlJSCompletionAssistProvider : public TextEditor::CompletionAssistProvider
|
||||
{
|
||||
public:
|
||||
virtual bool supportsEditor(const QString &editorId) const;
|
||||
virtual TextEditor::IAssistProcessor *createProcessor() const;
|
||||
|
||||
virtual int activationCharSequenceLength() const;
|
||||
virtual bool isActivationCharSequence(const QString &sequence) const;
|
||||
virtual bool isContinuationChar(const QChar &c) const;
|
||||
};
|
||||
|
||||
|
||||
class QmlJSCompletionAssistProcessor : public TextEditor::IAssistProcessor
|
||||
{
|
||||
public:
|
||||
QmlJSCompletionAssistProcessor();
|
||||
virtual ~QmlJSCompletionAssistProcessor();
|
||||
|
||||
virtual TextEditor::IAssistProposal *perform(const TextEditor::IAssistInterface *interface);
|
||||
|
||||
private:
|
||||
TextEditor::IAssistProposal *createContentProposal() const;
|
||||
TextEditor::IAssistProposal *createHintProposal(const QString &functionName,
|
||||
const QStringList &signature) const;
|
||||
|
||||
bool acceptsIdleEditor() const;
|
||||
|
||||
bool completeUrl(const QString &relativeBasePath, const QString &urlString);
|
||||
bool completeFileName(const QString &relativeBasePath,
|
||||
const QString &fileName,
|
||||
const QStringList &patterns = QStringList());
|
||||
|
||||
void addCompletion(const QString &text,
|
||||
const QIcon &icon,
|
||||
int order,
|
||||
const QVariant &data = QVariant());
|
||||
void addCompletions(const QHash<QString, const QmlJS::Interpreter::Value *> &newCompletions,
|
||||
const QIcon &icon,
|
||||
int order);
|
||||
void addCompletions(const QStringList &newCompletions, const QIcon &icon, int order);
|
||||
void addCompletionsPropertyLhs(const QHash<QString,
|
||||
const QmlJS::Interpreter::Value *> &newCompletions,
|
||||
const QIcon &icon,
|
||||
int order,
|
||||
bool afterOn);
|
||||
|
||||
int m_startPosition;
|
||||
QScopedPointer<const QmlJSCompletionAssistInterface> m_interface;
|
||||
QList<TextEditor::BasicProposalItem *> m_completions;
|
||||
TextEditor::SnippetAssistCollector m_snippetCollector;
|
||||
const TextEditor::IAssistProvider *m_provider;
|
||||
};
|
||||
|
||||
|
||||
class QmlJSCompletionAssistInterface : public TextEditor::DefaultAssistInterface
|
||||
{
|
||||
public:
|
||||
QmlJSCompletionAssistInterface(QTextDocument *document,
|
||||
int position,
|
||||
Core::IFile *file,
|
||||
TextEditor::AssistReason reason,
|
||||
const SemanticInfo &info);
|
||||
const SemanticInfo &semanticInfo() const;
|
||||
const QIcon &fileNameIcon() const { return m_darkBlueIcon; }
|
||||
const QIcon &keywordIcon() const { return m_darkYellowIcon; }
|
||||
const QIcon &symbolIcon() const { return m_darkCyanIcon; }
|
||||
|
||||
private:
|
||||
SemanticInfo m_semanticInfo;
|
||||
QIcon m_darkBlueIcon;
|
||||
QIcon m_darkYellowIcon;
|
||||
QIcon m_darkCyanIcon;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
} // QmlJSEditor
|
||||
|
||||
#endif // QMLJSCOMPLETIONASSIST_H
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "qmljscomponentfromobjectdef.h"
|
||||
#include "qmljscomponentnamedialog.h"
|
||||
#include "qmljsquickfixassist.h"
|
||||
|
||||
#include <coreplugin/ifile.h>
|
||||
|
||||
@@ -93,8 +94,9 @@ class Operation: public QmlJSQuickFixOperation
|
||||
QString m_idName, m_componentName;
|
||||
|
||||
public:
|
||||
Operation(const QmlJSQuickFixState &state, UiObjectDefinition *objDef)
|
||||
: QmlJSQuickFixOperation(state, 0)
|
||||
Operation(const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface,
|
||||
UiObjectDefinition *objDef)
|
||||
: QmlJSQuickFixOperation(interface, 0)
|
||||
, m_objDef(objDef)
|
||||
{
|
||||
Q_ASSERT(m_objDef != 0);
|
||||
@@ -117,7 +119,7 @@ public:
|
||||
QString componentName = m_componentName;
|
||||
QString path = QFileInfo(fileName()).path();
|
||||
if (componentName.isEmpty()) {
|
||||
ComponentNameDialog::go(&componentName, &path, state().editor());
|
||||
ComponentNameDialog::go(&componentName, &path, assistInterface()->widget());
|
||||
}
|
||||
|
||||
if (componentName.isEmpty() || path.isEmpty())
|
||||
@@ -157,19 +159,21 @@ public:
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
QList<QmlJSQuickFixOperation::Ptr> ComponentFromObjectDef::match(const QmlJSQuickFixState &state)
|
||||
{
|
||||
const int pos = state.currentFile().cursor().position();
|
||||
|
||||
QList<Node *> path = state.semanticInfo().astPath(pos);
|
||||
QList<QmlJSQuickFixOperation::Ptr> ComponentFromObjectDef::match(
|
||||
const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface)
|
||||
{
|
||||
const int pos = interface->currentFile().cursor().position();
|
||||
|
||||
QList<Node *> path = interface->semanticInfo().astPath(pos);
|
||||
for (int i = path.size() - 1; i >= 0; --i) {
|
||||
Node *node = path.at(i);
|
||||
if (UiObjectDefinition *objDef = cast<UiObjectDefinition *>(node)) {
|
||||
if (!state.currentFile().isCursorOn(objDef->qualifiedTypeNameId))
|
||||
if (!interface->currentFile().isCursorOn(objDef->qualifiedTypeNameId))
|
||||
return noResult();
|
||||
// check that the node is not the root node
|
||||
if (i > 0 && !cast<UiProgram*>(path.at(i - 1))) {
|
||||
return singleResult(new Operation(state, objDef));
|
||||
return singleResult(new Operation(interface, objDef));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ namespace Internal {
|
||||
class ComponentFromObjectDef: public QmlJSQuickFixFactory
|
||||
{
|
||||
public:
|
||||
virtual QList<QmlJSQuickFixOperation::Ptr> match(const QmlJSQuickFixState &state);
|
||||
virtual QList<QmlJSQuickFixOperation::Ptr> match(
|
||||
const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -35,12 +35,13 @@
|
||||
#include "qmljseditorconstants.h"
|
||||
#include "qmljshighlighter.h"
|
||||
#include "qmljseditorplugin.h"
|
||||
#include "qmljsquickfix.h"
|
||||
#include "qmloutlinemodel.h"
|
||||
#include "qmljsfindreferences.h"
|
||||
#include "qmljssemantichighlighter.h"
|
||||
#include "qmljsindenter.h"
|
||||
#include "qmljsautocompleter.h"
|
||||
#include "qmljscompletionassist.h"
|
||||
#include "qmljsquickfixassist.h"
|
||||
|
||||
#include <qmljs/qmljsbind.h>
|
||||
#include <qmljs/qmljsevaluate.h>
|
||||
@@ -70,6 +71,8 @@
|
||||
#include <texteditor/syntaxhighlighter.h>
|
||||
#include <texteditor/refactoroverlay.h>
|
||||
#include <texteditor/tooltip/tooltip.h>
|
||||
#include <texteditor/codeassist/genericproposal.h>
|
||||
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
|
||||
#include <qmldesigner/qmldesignerconstants.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <utils/changeset.h>
|
||||
@@ -78,6 +81,7 @@
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QSignalMapper>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QScopedPointer>
|
||||
|
||||
#include <QtGui/QMenu>
|
||||
#include <QtGui/QComboBox>
|
||||
@@ -1347,20 +1351,29 @@ void QmlJSTextEditorWidget::contextMenuEvent(QContextMenuEvent *e)
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(renameIdUnderCursor()));
|
||||
}
|
||||
|
||||
// Add other refactoring actions:
|
||||
QmlJSQuickFixCollector *quickFixCollector = QmlJSEditorPlugin::instance()->quickFixCollector();
|
||||
QSignalMapper mapper;
|
||||
connect(&mapper, SIGNAL(mapped(int)), this, SLOT(performQuickFix(int)));
|
||||
|
||||
if (! isOutdated()) {
|
||||
if (quickFixCollector->startCompletion(editor()) != -1) {
|
||||
m_quickFixes = quickFixCollector->quickFixes();
|
||||
|
||||
for (int index = 0; index < m_quickFixes.size(); ++index) {
|
||||
TextEditor::QuickFixOperation::Ptr op = m_quickFixes.at(index);
|
||||
QAction *action = refactoringMenu->addAction(op->description());
|
||||
mapper.setMapping(action, index);
|
||||
connect(action, SIGNAL(triggered()), &mapper, SLOT(map()));
|
||||
TextEditor::IAssistInterface *interface =
|
||||
createAssistInterface(TextEditor::QuickFix, TextEditor::ExplicitlyInvoked);
|
||||
if (interface) {
|
||||
QScopedPointer<TextEditor::IAssistProcessor> processor(
|
||||
QmlJSEditorPlugin::instance()->quickFixAssistProvider()->createProcessor());
|
||||
QScopedPointer<TextEditor::IAssistProposal> proposal(processor->perform(interface));
|
||||
if (!proposal.isNull()) {
|
||||
TextEditor::BasicProposalItemListModel *model =
|
||||
static_cast<TextEditor::BasicProposalItemListModel *>(proposal->model());
|
||||
for (int index = 0; index < model->size(); ++index) {
|
||||
TextEditor::BasicProposalItem *item =
|
||||
static_cast<TextEditor::BasicProposalItem *>(model->proposalItem(index));
|
||||
TextEditor::QuickFixOperation::Ptr op =
|
||||
item->data().value<TextEditor::QuickFixOperation::Ptr>();
|
||||
m_quickFixes.append(op);
|
||||
QAction *action = refactoringMenu->addAction(op->description());
|
||||
mapper.setMapping(action, index);
|
||||
connect(action, SIGNAL(triggered()), &mapper, SLOT(map()));
|
||||
}
|
||||
delete model;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1380,7 +1393,6 @@ void QmlJSTextEditorWidget::contextMenuEvent(QContextMenuEvent *e)
|
||||
|
||||
menu->exec(e->globalPos());
|
||||
menu->deleteLater();
|
||||
quickFixCollector->cleanup();
|
||||
m_quickFixes.clear();
|
||||
}
|
||||
|
||||
@@ -1578,3 +1590,19 @@ SemanticHighlighterSource QmlJSTextEditorWidget::currentSource(bool force)
|
||||
source.force = force;
|
||||
return source;
|
||||
}
|
||||
|
||||
TextEditor::IAssistInterface *QmlJSTextEditorWidget::createAssistInterface(
|
||||
TextEditor::AssistKind assistKind,
|
||||
TextEditor::AssistReason reason) const
|
||||
{
|
||||
if (assistKind == TextEditor::Completion) {
|
||||
return new QmlJSCompletionAssistInterface(document(),
|
||||
position(),
|
||||
editor()->file(),
|
||||
reason,
|
||||
m_semanticInfo);
|
||||
} else if (assistKind == TextEditor::QuickFix) {
|
||||
return new QmlJSQuickFixAssistInterface(const_cast<QmlJSTextEditorWidget *>(this), reason);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -160,6 +160,9 @@ public:
|
||||
|
||||
static QVector<QString> highlighterFormatCategories();
|
||||
|
||||
TextEditor::IAssistInterface *createAssistInterface(TextEditor::AssistKind assistKind,
|
||||
TextEditor::AssistReason reason) const;
|
||||
|
||||
public slots:
|
||||
void forceSemanticRehighlight();
|
||||
void followSymbolUnderCursor();
|
||||
|
||||
@@ -8,7 +8,6 @@ DEFINES += \
|
||||
QT_CREATOR
|
||||
|
||||
HEADERS += \
|
||||
qmljscodecompletion.h \
|
||||
qmljseditor.h \
|
||||
qmljseditor_global.h \
|
||||
qmljseditoractionhandler.h \
|
||||
@@ -20,7 +19,6 @@ HEADERS += \
|
||||
qmljshighlighter.h \
|
||||
qmljshoverhandler.h \
|
||||
qmljspreviewrunner.h \
|
||||
qmljsquickfix.h \
|
||||
qmljscomponentfromobjectdef.h \
|
||||
qmljsoutline.h \
|
||||
qmloutlinemodel.h \
|
||||
@@ -35,10 +33,13 @@ HEADERS += \
|
||||
qmljsindenter.h \
|
||||
qmljsautocompleter.h \
|
||||
jsfilewizard.h \
|
||||
qmljssnippetprovider.h
|
||||
qmljssnippetprovider.h \
|
||||
qmljsreuse.h \
|
||||
qmljsquickfixassist.h \
|
||||
qmljscompletionassist.h \
|
||||
qmljsquickfix.h
|
||||
|
||||
SOURCES += \
|
||||
qmljscodecompletion.cpp \
|
||||
qmljseditor.cpp \
|
||||
qmljseditoractionhandler.cpp \
|
||||
qmljseditorfactory.cpp \
|
||||
@@ -48,7 +49,6 @@ SOURCES += \
|
||||
qmljshighlighter.cpp \
|
||||
qmljshoverhandler.cpp \
|
||||
qmljspreviewrunner.cpp \
|
||||
qmljsquickfix.cpp \
|
||||
qmljscomponentfromobjectdef.cpp \
|
||||
qmljsoutline.cpp \
|
||||
qmloutlinemodel.cpp \
|
||||
@@ -64,7 +64,11 @@ SOURCES += \
|
||||
qmljsindenter.cpp \
|
||||
qmljsautocompleter.cpp \
|
||||
jsfilewizard.cpp \
|
||||
qmljssnippetprovider.cpp
|
||||
qmljssnippetprovider.cpp \
|
||||
qmljsreuse.cpp \
|
||||
qmljsquickfixassist.cpp \
|
||||
qmljscompletionassist.cpp \
|
||||
qmljsquickfix.cpp
|
||||
|
||||
RESOURCES += qmljseditor.qrc
|
||||
OTHER_FILES += QmlJSEditor.mimetypes.xml
|
||||
|
||||
@@ -35,17 +35,17 @@
|
||||
#include "qmljseditor.h"
|
||||
#include "qmljseditorconstants.h"
|
||||
#include "qmljseditorfactory.h"
|
||||
#include "qmljscodecompletion.h"
|
||||
#include "qmljshoverhandler.h"
|
||||
#include "qmlfilewizard.h"
|
||||
#include "jsfilewizard.h"
|
||||
#include "qmljsoutline.h"
|
||||
#include "qmljspreviewrunner.h"
|
||||
#include "qmljsquickfix.h"
|
||||
#include "qmljssnippetprovider.h"
|
||||
#include "qmltaskmanager.h"
|
||||
#include "quicktoolbar.h"
|
||||
#include "quicktoolbarsettingspage.h"
|
||||
#include "qmljscompletionassist.h"
|
||||
#include "qmljsquickfixassist.h"
|
||||
|
||||
#include <qmljs/qmljsicons.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
@@ -69,7 +69,6 @@
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
#include <texteditor/textfilewizard.h>
|
||||
#include <texteditor/texteditoractionhandler.h>
|
||||
#include <texteditor/completionsupport.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QtPlugin>
|
||||
@@ -89,21 +88,18 @@ enum {
|
||||
QUICKFIX_INTERVAL = 20
|
||||
};
|
||||
|
||||
void registerQuickFixes(ExtensionSystem::IPlugin *plugIn);
|
||||
|
||||
QmlJSEditorPlugin *QmlJSEditorPlugin::m_instance = 0;
|
||||
|
||||
QmlJSEditorPlugin::QmlJSEditorPlugin() :
|
||||
m_modelManager(0),
|
||||
m_wizard(0),
|
||||
m_editor(0),
|
||||
m_actionHandler(0)
|
||||
m_actionHandler(0),
|
||||
m_quickFixAssistProvider(0)
|
||||
{
|
||||
m_instance = this;
|
||||
|
||||
m_quickFixCollector = 0;
|
||||
m_quickFixTimer = new QTimer(this);
|
||||
m_quickFixTimer->setInterval(20);
|
||||
m_quickFixTimer->setSingleShot(true);
|
||||
connect(m_quickFixTimer, SIGNAL(timeout()), this, SLOT(quickFixNow()));
|
||||
}
|
||||
|
||||
QmlJSEditorPlugin::~QmlJSEditorPlugin()
|
||||
@@ -211,25 +207,18 @@ bool QmlJSEditorPlugin::initialize(const QStringList & /*arguments*/, QString *e
|
||||
cmd = am->command(TextEditor::Constants::UN_COMMENT_SELECTION);
|
||||
contextMenu->addAction(cmd);
|
||||
|
||||
CodeCompletion *completion = new CodeCompletion(m_modelManager);
|
||||
addAutoReleasedObject(completion);
|
||||
m_quickFixAssistProvider = new QmlJSQuickFixAssistProvider;
|
||||
addAutoReleasedObject(m_quickFixAssistProvider);
|
||||
addAutoReleasedObject(new QmlJSCompletionAssistProvider);
|
||||
|
||||
addAutoReleasedObject(new HoverHandler);
|
||||
|
||||
// Set completion settings and keep them up to date
|
||||
TextEditor::TextEditorSettings *textEditorSettings = TextEditor::TextEditorSettings::instance();
|
||||
completion->setCompletionSettings(textEditorSettings->completionSettings());
|
||||
connect(textEditorSettings, SIGNAL(completionSettingsChanged(TextEditor::CompletionSettings)),
|
||||
completion, SLOT(setCompletionSettings(TextEditor::CompletionSettings)));
|
||||
|
||||
error_message->clear();
|
||||
|
||||
Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
|
||||
iconProvider->registerIconOverlayForSuffix(QIcon(QLatin1String(":/qmljseditor/images/qmlfile.png")), "qml");
|
||||
|
||||
m_quickFixCollector = new QmlJSQuickFixCollector;
|
||||
addAutoReleasedObject(m_quickFixCollector);
|
||||
QmlJSQuickFixCollector::registerQuickFixes(this);
|
||||
registerQuickFixes(this);
|
||||
|
||||
addAutoReleasedObject(new QmlJSOutlineWidgetFactory);
|
||||
|
||||
@@ -313,35 +302,9 @@ Core::Command *QmlJSEditorPlugin::addToolAction(QAction *a, Core::ActionManager
|
||||
return command;
|
||||
}
|
||||
|
||||
QmlJSQuickFixCollector *QmlJSEditorPlugin::quickFixCollector() const
|
||||
{ return m_quickFixCollector; }
|
||||
|
||||
void QmlJSEditorPlugin::quickFix(TextEditor::ITextEditor *editable)
|
||||
QmlJSQuickFixAssistProvider *QmlJSEditorPlugin::quickFixAssistProvider() const
|
||||
{
|
||||
m_currentTextEditable = editable;
|
||||
quickFixNow();
|
||||
}
|
||||
|
||||
void QmlJSEditorPlugin::quickFixNow()
|
||||
{
|
||||
if (! m_currentTextEditable)
|
||||
return;
|
||||
|
||||
Core::EditorManager *em = Core::EditorManager::instance();
|
||||
QmlJSTextEditorWidget *currentEditor = qobject_cast<QmlJSTextEditorWidget*>(em->currentEditor()->widget());
|
||||
|
||||
if (QmlJSTextEditorWidget *editor = qobject_cast<QmlJSTextEditorWidget*>(m_currentTextEditable->widget())) {
|
||||
if (currentEditor == editor) {
|
||||
if (editor->isOutdated()) {
|
||||
// qDebug() << "TODO: outdated document" << editor->editorRevision() << editor->semanticInfo().revision();
|
||||
// ### FIXME: m_quickFixTimer->start(QUICKFIX_INTERVAL);
|
||||
m_quickFixTimer->stop();
|
||||
} else {
|
||||
TextEditor::CompletionSupport::instance()
|
||||
->complete(m_currentTextEditable, TextEditor::QuickFixCompletion, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return m_quickFixAssistProvider;
|
||||
}
|
||||
|
||||
void QmlJSEditorPlugin::currentEditorChanged(Core::IEditor *editor)
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Internal {
|
||||
|
||||
class QmlJSEditorFactory;
|
||||
class QmlJSPreviewRunner;
|
||||
class QmlJSQuickFixCollector;
|
||||
class QmlJSQuickFixAssistProvider;
|
||||
class QmlTaskManager;
|
||||
|
||||
class QmlJSEditorPlugin : public ExtensionSystem::IPlugin
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
static QmlJSEditorPlugin *instance()
|
||||
{ return m_instance; }
|
||||
|
||||
QmlJSQuickFixCollector *quickFixCollector() const;
|
||||
QmlJSQuickFixAssistProvider *quickFixAssistProvider() const;
|
||||
|
||||
void initializeEditor(QmlJSEditor::QmlJSTextEditorWidget *editor);
|
||||
|
||||
@@ -97,8 +97,6 @@ public Q_SLOTS:
|
||||
void showContextPane();
|
||||
|
||||
private Q_SLOTS:
|
||||
void quickFix(TextEditor::ITextEditor *editable);
|
||||
void quickFixNow();
|
||||
void currentEditorChanged(Core::IEditor *editor);
|
||||
|
||||
private:
|
||||
@@ -115,9 +113,8 @@ private:
|
||||
QmlJSEditorFactory *m_editor;
|
||||
TextEditor::TextEditorActionHandler *m_actionHandler;
|
||||
|
||||
QmlJSQuickFixCollector *m_quickFixCollector;
|
||||
QmlJSQuickFixAssistProvider *m_quickFixAssistProvider;
|
||||
|
||||
QTimer *m_quickFixTimer;
|
||||
QPointer<TextEditor::ITextEditor> m_currentTextEditable;
|
||||
QmlTaskManager *m_qmlTaskManager;
|
||||
};
|
||||
|
||||
@@ -56,8 +56,6 @@ class QmlJSTextEditorWidget;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class SemanticInfo;
|
||||
|
||||
class HoverHandler : public TextEditor::BaseHoverHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "qmljscomponentfromobjectdef.h"
|
||||
#include "qmljseditor.h"
|
||||
#include "qmljs/parser/qmljsast_p.h"
|
||||
#include "qmljsquickfixassist.h"
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
@@ -50,34 +51,11 @@ using namespace QmlJSTools;
|
||||
using namespace TextEditor;
|
||||
using TextEditor::RefactoringChanges;
|
||||
|
||||
QmlJSQuickFixState::QmlJSQuickFixState(TextEditor::BaseTextEditorWidget *editor)
|
||||
: QuickFixState(editor)
|
||||
{
|
||||
}
|
||||
|
||||
SemanticInfo QmlJSQuickFixState::semanticInfo() const
|
||||
{
|
||||
return _semanticInfo;
|
||||
}
|
||||
|
||||
Snapshot QmlJSQuickFixState::snapshot() const
|
||||
{
|
||||
return _semanticInfo.snapshot;
|
||||
}
|
||||
|
||||
Document::Ptr QmlJSQuickFixState::document() const
|
||||
{
|
||||
return _semanticInfo.document;
|
||||
}
|
||||
|
||||
const QmlJSRefactoringFile QmlJSQuickFixState::currentFile() const
|
||||
{
|
||||
return QmlJSRefactoringFile(editor(), document());
|
||||
}
|
||||
|
||||
QmlJSQuickFixOperation::QmlJSQuickFixOperation(const QmlJSQuickFixState &state, int priority)
|
||||
QmlJSQuickFixOperation::QmlJSQuickFixOperation(
|
||||
const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface,
|
||||
int priority)
|
||||
: QuickFixOperation(priority)
|
||||
, _state(state)
|
||||
, m_interface(interface)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -88,20 +66,21 @@ QmlJSQuickFixOperation::~QmlJSQuickFixOperation()
|
||||
void QmlJSQuickFixOperation::perform()
|
||||
{
|
||||
QmlJSRefactoringChanges refactoring(ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>(),
|
||||
_state.snapshot());
|
||||
//_state.snapshot());
|
||||
m_interface->semanticInfo().snapshot);
|
||||
QmlJSRefactoringFile current = refactoring.file(fileName());
|
||||
|
||||
performChanges(¤t, &refactoring);
|
||||
}
|
||||
|
||||
const QmlJSQuickFixState &QmlJSQuickFixOperation::state() const
|
||||
const QmlJSQuickFixAssistInterface *QmlJSQuickFixOperation::assistInterface() const
|
||||
{
|
||||
return _state;
|
||||
return m_interface.data();
|
||||
}
|
||||
|
||||
QString QmlJSQuickFixOperation::fileName() const
|
||||
{
|
||||
return state().document()->fileName();
|
||||
return m_interface->semanticInfo().document->fileName();
|
||||
}
|
||||
|
||||
QmlJSQuickFixFactory::QmlJSQuickFixFactory()
|
||||
@@ -112,12 +91,10 @@ QmlJSQuickFixFactory::~QmlJSQuickFixFactory()
|
||||
{
|
||||
}
|
||||
|
||||
QList<QuickFixOperation::Ptr> QmlJSQuickFixFactory::matchingOperations(QuickFixState *state)
|
||||
QList<QuickFixOperation::Ptr> QmlJSQuickFixFactory::matchingOperations(
|
||||
const QSharedPointer<const TextEditor::IAssistInterface> &interface)
|
||||
{
|
||||
if (QmlJSQuickFixState *qmljsState = static_cast<QmlJSQuickFixState *>(state))
|
||||
return match(*qmljsState);
|
||||
else
|
||||
return QList<TextEditor::QuickFixOperation::Ptr>();
|
||||
return match(interface.staticCast<const QmlJSQuickFixAssistInterface>());
|
||||
}
|
||||
|
||||
QList<QmlJSQuickFixOperation::Ptr> QmlJSQuickFixFactory::noResult()
|
||||
@@ -131,49 +108,3 @@ QList<QmlJSQuickFixOperation::Ptr> QmlJSQuickFixFactory::singleResult(QmlJSQuick
|
||||
result.append(QmlJSQuickFixOperation::Ptr(operation));
|
||||
return result;
|
||||
}
|
||||
|
||||
QmlJSQuickFixCollector::QmlJSQuickFixCollector()
|
||||
{
|
||||
}
|
||||
|
||||
QmlJSQuickFixCollector::~QmlJSQuickFixCollector()
|
||||
{
|
||||
}
|
||||
|
||||
bool QmlJSQuickFixCollector::supportsEditor(TextEditor::ITextEditor *editable) const
|
||||
{
|
||||
return qobject_cast<QmlJSTextEditorWidget *>(editable->widget()) != 0;
|
||||
}
|
||||
|
||||
bool QmlJSQuickFixCollector::supportsPolicy(TextEditor::CompletionPolicy policy) const
|
||||
{
|
||||
return policy == TextEditor::QuickFixCompletion;
|
||||
}
|
||||
|
||||
TextEditor::QuickFixState *QmlJSQuickFixCollector::initializeCompletion(TextEditor::BaseTextEditorWidget *editor)
|
||||
{
|
||||
if (QmlJSTextEditorWidget *qmljsEditor = qobject_cast<QmlJSTextEditorWidget *>(editor)) {
|
||||
const SemanticInfo info = qmljsEditor->semanticInfo();
|
||||
|
||||
if (! info.isValid() || qmljsEditor->isOutdated()) {
|
||||
// outdated
|
||||
qWarning() << "TODO: outdated semantic info, force a reparse.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
QmlJSQuickFixState *state = new QmlJSQuickFixState(editor);
|
||||
state->_semanticInfo = info;
|
||||
return state;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<TextEditor::QuickFixFactory *> QmlJSQuickFixCollector::quickFixFactories() const
|
||||
{
|
||||
QList<TextEditor::QuickFixFactory *> results;
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
foreach (QmlJSQuickFixFactory *f, pm->getObjects<QmlJSEditor::QmlJSQuickFixFactory>())
|
||||
results.append(f);
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
#include <qmljstools/qmljsrefactoringchanges.h>
|
||||
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
namespace ExtensionSystem {
|
||||
class IPlugin;
|
||||
}
|
||||
@@ -51,40 +53,12 @@ namespace QmlJS {
|
||||
namespace QmlJSEditor {
|
||||
|
||||
namespace Internal {
|
||||
class QmlJSQuickFixCollector;
|
||||
class QmlJSQuickFixAssistInterface;
|
||||
} // namespace Internal
|
||||
|
||||
/*!
|
||||
Specialized QuickFixState for QML/JavaScript quick-fixes.
|
||||
|
||||
This specialized state for QML/JavaScript quick-fixes also holds the
|
||||
QmlJSEditor::Internal::SemanticInfo for the document in the editor.
|
||||
*/
|
||||
class QmlJSQuickFixState: public TextEditor::QuickFixState
|
||||
{
|
||||
friend class Internal::QmlJSQuickFixCollector;
|
||||
|
||||
public:
|
||||
/// Creates a new state for the given editor.
|
||||
QmlJSQuickFixState(TextEditor::BaseTextEditorWidget *editor);
|
||||
|
||||
SemanticInfo semanticInfo() const;
|
||||
|
||||
/// \returns the snapshot holding the document of the editor.
|
||||
QmlJS::Snapshot snapshot() const;
|
||||
|
||||
/// \returns the document of the editor
|
||||
QmlJS::Document::Ptr document() const;
|
||||
|
||||
const QmlJSTools::QmlJSRefactoringFile currentFile() const;
|
||||
|
||||
private:
|
||||
SemanticInfo _semanticInfo;
|
||||
};
|
||||
|
||||
/*!
|
||||
A quick-fix operation for the QML/JavaScript editor, which works on a
|
||||
QmlJSQuickFixState .
|
||||
A quick-fix operation for the QML/JavaScript editor.
|
||||
*/
|
||||
class QmlJSQuickFixOperation: public TextEditor::QuickFixOperation
|
||||
{
|
||||
@@ -94,13 +68,12 @@ public:
|
||||
/*!
|
||||
Creates a new QmlJSQuickFixOperation.
|
||||
|
||||
This operation will copy the complete state, in order to be able to perform
|
||||
its changes later on.
|
||||
|
||||
\param state The state for which this operation was created.
|
||||
\param interface The interface on which the operation is performed.
|
||||
\param priority The priority for this operation.
|
||||
*/
|
||||
explicit QmlJSQuickFixOperation(const QmlJSQuickFixState &state, int priority = -1);
|
||||
explicit QmlJSQuickFixOperation(
|
||||
const QSharedPointer<const Internal::QmlJSQuickFixAssistInterface> &interface,
|
||||
int priority = -1);
|
||||
virtual ~QmlJSQuickFixOperation();
|
||||
|
||||
virtual void perform();
|
||||
@@ -111,14 +84,13 @@ protected:
|
||||
virtual void performChanges(QmlJSTools::QmlJSRefactoringFile *currentFile,
|
||||
QmlJSTools::QmlJSRefactoringChanges *refactoring) = 0;
|
||||
|
||||
/// \returns A const-reference to the state of the operation.
|
||||
const QmlJSQuickFixState &state() const;
|
||||
const Internal::QmlJSQuickFixAssistInterface *assistInterface() const;
|
||||
|
||||
/// \returns The name of the file for for which this operation is invoked.
|
||||
QString fileName() const;
|
||||
|
||||
private:
|
||||
QmlJSQuickFixState _state;
|
||||
QSharedPointer<const Internal::QmlJSQuickFixAssistInterface> m_interface;
|
||||
};
|
||||
|
||||
class QmlJSQuickFixFactory: public TextEditor::QuickFixFactory
|
||||
@@ -129,39 +101,20 @@ public:
|
||||
QmlJSQuickFixFactory();
|
||||
virtual ~QmlJSQuickFixFactory();
|
||||
|
||||
virtual QList<TextEditor::QuickFixOperation::Ptr> matchingOperations(TextEditor::QuickFixState *state);
|
||||
virtual QList<TextEditor::QuickFixOperation::Ptr>
|
||||
matchingOperations(const QSharedPointer<const TextEditor::IAssistInterface> &interface);
|
||||
|
||||
/*!
|
||||
Implement this method to match and create the appropriate
|
||||
QmlJSQuickFixOperation objects.
|
||||
*/
|
||||
virtual QList<QmlJSQuickFixOperation::Ptr> match(const QmlJSQuickFixState &state) = 0;
|
||||
virtual QList<QmlJSQuickFixOperation::Ptr> match(
|
||||
const QSharedPointer<const Internal::QmlJSQuickFixAssistInterface> &interface) = 0;
|
||||
|
||||
static QList<QmlJSQuickFixOperation::Ptr> noResult();
|
||||
static QList<QmlJSQuickFixOperation::Ptr> singleResult(QmlJSQuickFixOperation *operation);
|
||||
};
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QmlJSQuickFixCollector: public TextEditor::QuickFixCollector
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlJSQuickFixCollector();
|
||||
virtual ~QmlJSQuickFixCollector();
|
||||
|
||||
virtual bool supportsEditor(TextEditor::ITextEditor *editor) const;
|
||||
virtual bool supportsPolicy(TextEditor::CompletionPolicy policy) const;
|
||||
virtual TextEditor::QuickFixState *initializeCompletion(TextEditor::BaseTextEditorWidget *editor);
|
||||
|
||||
virtual QList<TextEditor::QuickFixFactory *> quickFixFactories() const;
|
||||
|
||||
/// Registers all quick-fixes in this plug-in as auto-released objects.
|
||||
static void registerQuickFixes(ExtensionSystem::IPlugin *plugIn);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
#endif // QMLJSQUICKFIX_H
|
||||
|
||||
115
src/plugins/qmljseditor/qmljsquickfixassist.cpp
Normal file
115
src/plugins/qmljseditor/qmljsquickfixassist.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljsquickfixassist.h"
|
||||
#include "qmljseditorconstants.h"
|
||||
|
||||
//temp
|
||||
#include "qmljsquickfix.h"
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
using namespace QmlJSEditor;
|
||||
using namespace Internal;
|
||||
using namespace QmlJSTools;
|
||||
using namespace TextEditor;
|
||||
|
||||
// -----------------------
|
||||
// QuickFixAssistInterface
|
||||
// -----------------------
|
||||
QmlJSQuickFixAssistInterface::QmlJSQuickFixAssistInterface(QmlJSTextEditorWidget *editor,
|
||||
TextEditor::AssistReason reason)
|
||||
: DefaultAssistInterface(editor->document(), editor->position(), editor->file(), reason)
|
||||
, m_editor(editor)
|
||||
, m_semanticInfo(editor->semanticInfo())
|
||||
{}
|
||||
|
||||
QmlJSQuickFixAssistInterface::~QmlJSQuickFixAssistInterface()
|
||||
{}
|
||||
|
||||
const SemanticInfo &QmlJSQuickFixAssistInterface::semanticInfo() const
|
||||
{
|
||||
return m_semanticInfo;
|
||||
}
|
||||
|
||||
const QmlJSTools::QmlJSRefactoringFile QmlJSQuickFixAssistInterface::currentFile() const
|
||||
{
|
||||
return QmlJSRefactoringFile(m_editor, m_semanticInfo.document);
|
||||
}
|
||||
|
||||
QWidget *QmlJSQuickFixAssistInterface::widget() const
|
||||
{
|
||||
return m_editor;
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// QmlJSQuickFixProcessor
|
||||
// ----------------------
|
||||
QmlJSQuickFixProcessor::QmlJSQuickFixProcessor(const TextEditor::IAssistProvider *provider)
|
||||
: m_provider(provider)
|
||||
{}
|
||||
|
||||
QmlJSQuickFixProcessor::~QmlJSQuickFixProcessor()
|
||||
{}
|
||||
|
||||
const IAssistProvider *QmlJSQuickFixProcessor::provider() const
|
||||
{
|
||||
return m_provider;
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// QmlJSQuickFixAssistProvider
|
||||
// ---------------------------
|
||||
QmlJSQuickFixAssistProvider::QmlJSQuickFixAssistProvider()
|
||||
{}
|
||||
|
||||
QmlJSQuickFixAssistProvider::~QmlJSQuickFixAssistProvider()
|
||||
{}
|
||||
|
||||
bool QmlJSQuickFixAssistProvider::supportsEditor(const QString &editorId) const
|
||||
{
|
||||
return editorId == QLatin1String(Constants::C_QMLJSEDITOR_ID);
|
||||
}
|
||||
|
||||
IAssistProcessor *QmlJSQuickFixAssistProvider::createProcessor() const
|
||||
{
|
||||
return new QmlJSQuickFixProcessor(this);
|
||||
}
|
||||
|
||||
QList<QuickFixFactory *> QmlJSQuickFixAssistProvider::quickFixFactories() const
|
||||
{
|
||||
QList<TextEditor::QuickFixFactory *> results;
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
foreach (QmlJSQuickFixFactory *f, pm->getObjects<QmlJSEditor::QmlJSQuickFixFactory>())
|
||||
results.append(f);
|
||||
return results;
|
||||
}
|
||||
91
src/plugins/qmljseditor/qmljsquickfixassist.h
Normal file
91
src/plugins/qmljseditor/qmljsquickfixassist.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSQUICKFIXASSIST_H
|
||||
#define QMLJSQUICKFIXASSIST_H
|
||||
|
||||
#include "qmljseditor.h"
|
||||
|
||||
#include <qmljstools/qmljsrefactoringchanges.h>
|
||||
|
||||
#include <texteditor/codeassist/defaultassistinterface.h>
|
||||
#include <texteditor/codeassist/quickfixassistprovider.h>
|
||||
#include <texteditor/codeassist/quickfixassistprocessor.h>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlJSQuickFixAssistInterface : public TextEditor::DefaultAssistInterface
|
||||
{
|
||||
public:
|
||||
QmlJSQuickFixAssistInterface(QmlJSTextEditorWidget *editor, TextEditor::AssistReason reason);
|
||||
virtual ~QmlJSQuickFixAssistInterface();
|
||||
|
||||
const SemanticInfo &semanticInfo() const;
|
||||
const QmlJSTools::QmlJSRefactoringFile currentFile() const;
|
||||
QWidget *widget() const;
|
||||
|
||||
private:
|
||||
QmlJSTextEditorWidget *m_editor;
|
||||
SemanticInfo m_semanticInfo;
|
||||
};
|
||||
|
||||
|
||||
class QmlJSQuickFixProcessor : public TextEditor::QuickFixAssistProcessor
|
||||
{
|
||||
public:
|
||||
QmlJSQuickFixProcessor(const TextEditor::IAssistProvider *provider);
|
||||
virtual ~QmlJSQuickFixProcessor();
|
||||
|
||||
virtual const TextEditor::IAssistProvider *provider() const;
|
||||
|
||||
private:
|
||||
const TextEditor::IAssistProvider *m_provider;
|
||||
};
|
||||
|
||||
|
||||
class QmlJSQuickFixAssistProvider : public TextEditor::QuickFixAssistProvider
|
||||
{
|
||||
public:
|
||||
QmlJSQuickFixAssistProvider();
|
||||
virtual ~QmlJSQuickFixAssistProvider();
|
||||
|
||||
virtual bool supportsEditor(const QString &editorId) const;
|
||||
virtual TextEditor::IAssistProcessor *createProcessor() const;
|
||||
|
||||
virtual QList<TextEditor::QuickFixFactory *> quickFixFactories() const;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
} // QmlJSEditor
|
||||
|
||||
#endif // QMLJSQUICKFIXASSIST_H
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "qmljsquickfix.h"
|
||||
#include "qmljscomponentfromobjectdef.h"
|
||||
#include "qmljseditor.h"
|
||||
#include "qmljsquickfixassist.h"
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
@@ -64,13 +65,14 @@ namespace {
|
||||
class SplitInitializerOp: public QmlJSQuickFixFactory
|
||||
{
|
||||
public:
|
||||
virtual QList<QmlJSQuickFixOperation::Ptr> match(const QmlJSQuickFixState &state)
|
||||
virtual QList<QmlJSQuickFixOperation::Ptr> match(
|
||||
const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface)
|
||||
{
|
||||
UiObjectInitializer *objectInitializer = 0;
|
||||
|
||||
const int pos = state.currentFile().cursor().position();
|
||||
const int pos = interface->currentFile().cursor().position();
|
||||
|
||||
if (QmlJS::AST::Node *member = state.semanticInfo().declaringMember(pos)) {
|
||||
if (QmlJS::AST::Node *member = interface->semanticInfo().declaringMember(pos)) {
|
||||
if (QmlJS::AST::UiObjectBinding *b = QmlJS::AST::cast<QmlJS::AST::UiObjectBinding *>(member)) {
|
||||
if (b->initializer->lbraceToken.startLine == b->initializer->rbraceToken.startLine)
|
||||
objectInitializer = b->initializer;
|
||||
@@ -82,7 +84,7 @@ public:
|
||||
}
|
||||
|
||||
if (objectInitializer)
|
||||
return singleResult(new Operation(state, objectInitializer));
|
||||
return singleResult(new Operation(interface, objectInitializer));
|
||||
else
|
||||
return noResult();
|
||||
}
|
||||
@@ -93,8 +95,9 @@ private:
|
||||
UiObjectInitializer *_objectInitializer;
|
||||
|
||||
public:
|
||||
Operation(const QmlJSQuickFixState &state, UiObjectInitializer *objectInitializer)
|
||||
: QmlJSQuickFixOperation(state, 0)
|
||||
Operation(const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface,
|
||||
UiObjectInitializer *objectInitializer)
|
||||
: QmlJSQuickFixOperation(interface, 0)
|
||||
, _objectInitializer(objectInitializer)
|
||||
{
|
||||
setDescription(QApplication::translate("QmlJSEditor::QuickFix",
|
||||
@@ -129,7 +132,7 @@ private:
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
void QmlJSQuickFixCollector::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
|
||||
void registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
|
||||
{
|
||||
plugIn->addAutoReleasedObject(new SplitInitializerOp);
|
||||
plugIn->addAutoReleasedObject(new ComponentFromObjectDef);
|
||||
|
||||
122
src/plugins/qmljseditor/qmljsreuse.cpp
Normal file
122
src/plugins/qmljseditor/qmljsreuse.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljsreuse.h"
|
||||
|
||||
#include <QtCore/QChar>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
bool isIdentifierChar(const QChar &c, bool atStart, bool acceptDollar)
|
||||
{
|
||||
switch (c.unicode()) {
|
||||
case '_':
|
||||
return true;
|
||||
case '$':
|
||||
if (acceptDollar)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
default:
|
||||
if (atStart)
|
||||
return c.isLetter();
|
||||
else
|
||||
return c.isLetterOrNumber();
|
||||
}
|
||||
}
|
||||
|
||||
bool isDelimiterChar(const QChar &c)
|
||||
{
|
||||
switch (c.unicode()) {
|
||||
case '{':
|
||||
case '}':
|
||||
case '[':
|
||||
case ']':
|
||||
case ')':
|
||||
case '?':
|
||||
case '!':
|
||||
case ':':
|
||||
case ';':
|
||||
case ',':
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isActivationChar(const QChar &c)
|
||||
{
|
||||
if (c == QLatin1Char('(') || c == QLatin1Char('.') || c == QLatin1Char('/'))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
QIcon iconForColor(const QColor &color)
|
||||
{
|
||||
QPixmap pix(6, 6);
|
||||
|
||||
int pixSize = 20;
|
||||
QBrush br(color);
|
||||
|
||||
QPixmap pm(2 * pixSize, 2 * pixSize);
|
||||
QPainter pmp(&pm);
|
||||
pmp.fillRect(0, 0, pixSize, pixSize, Qt::lightGray);
|
||||
pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::lightGray);
|
||||
pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::darkGray);
|
||||
pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::darkGray);
|
||||
pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, color);
|
||||
br = QBrush(pm);
|
||||
|
||||
QPainter p(&pix);
|
||||
int corr = 1;
|
||||
QRect r = pix.rect().adjusted(corr, corr, -corr, -corr);
|
||||
p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr);
|
||||
p.fillRect(r, br);
|
||||
|
||||
p.fillRect(r.width() / 4 + corr, r.height() / 4 + corr,
|
||||
r.width() / 2, r.height() / 2,
|
||||
QColor(color.rgb()));
|
||||
p.drawRect(pix.rect().adjusted(0, 0, -1, -1));
|
||||
|
||||
return pix;
|
||||
}
|
||||
|
||||
|
||||
} // Internal
|
||||
} // QmlJSEditor
|
||||
55
src/plugins/qmljseditor/qmljsreuse.h
Normal file
55
src/plugins/qmljseditor/qmljsreuse.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSREUSE_H
|
||||
#define QMLJSREUSE_H
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include <QtGui/QIcon>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QChar;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
bool isIdentifierChar(const QChar &c, bool atStart = false, bool acceptDollar = true);
|
||||
bool isDelimiterChar(const QChar &c);
|
||||
bool isActivationChar(const QChar &c);
|
||||
|
||||
QIcon iconForColor(const QColor &color);
|
||||
|
||||
} // Internal
|
||||
} // QmlJSEditor
|
||||
|
||||
#endif // QMLJSREUSE_H
|
||||
Reference in New Issue
Block a user