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:
Leandro Melo
2011-04-15 16:19:23 +02:00
parent d835b769c7
commit bec4f02495
119 changed files with 9347 additions and 6595 deletions
+18 -13
View File
@@ -31,6 +31,7 @@
**************************************************************************/
#include "cppcompleteswitch.h"
#include "cppquickfixassistant.h"
#include <cplusplus/Overview.h>
#include <cplusplus/TypeOfExpression.h>
@@ -102,8 +103,11 @@ public:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, CompoundStatementAST *compoundStatement, const QStringList &values)
: CppQuickFixOperation(state, priority)
Operation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
int priority,
CompoundStatementAST *compoundStatement,
const QStringList &values)
: CppQuickFixOperation(interface, priority)
, compoundStatement(compoundStatement)
, values(values)
{
@@ -150,15 +154,15 @@ static Enum *findEnum(const QList<LookupItem> &results,
return 0;
}
static Enum *conditionEnum(const CppQuickFixState &state,
static Enum *conditionEnum(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
SwitchStatementAST *statement)
{
Block *block = statement->symbol;
Scope *scope = state.document()->scopeAt(block->line(), block->column());
Scope *scope = interface->semanticInfo().doc->scopeAt(block->line(), block->column());
TypeOfExpression typeOfExpression;
typeOfExpression.init(state.document(), state.snapshot());
typeOfExpression.init(interface->semanticInfo().doc, interface->snapshot());
const QList<LookupItem> results = typeOfExpression(statement->condition,
state.document(),
interface->semanticInfo().doc,
scope);
return findEnum(results, typeOfExpression.context());
@@ -166,9 +170,10 @@ static Enum *conditionEnum(const CppQuickFixState &state,
} // end of anonymous namespace
QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(const CppQuickFixState &state)
QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
const QList<AST *> &path = interface->path();
if (path.isEmpty())
return noResult(); // nothing to do
@@ -178,13 +183,13 @@ QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(const CppQui
AST *ast = path.at(depth);
SwitchStatementAST *switchStatement = ast->asSwitchStatement();
if (switchStatement) {
if (!state.isCursorOn(switchStatement->switch_token) || !switchStatement->statement)
if (!interface->isCursorOn(switchStatement->switch_token) || !switchStatement->statement)
return noResult();
CompoundStatementAST *compoundStatement = switchStatement->statement->asCompoundStatement();
if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;"
return noResult();
// look if the condition's type is an enum
if (Enum *e = conditionEnum(state, switchStatement)) {
if (Enum *e = conditionEnum(interface, switchStatement)) {
// check the possible enum values
QStringList values;
Overview prettyPrint;
@@ -195,8 +200,8 @@ QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(const CppQui
}
// Get the used values
Block *block = switchStatement->symbol;
CaseStatementCollector caseValues(state.document(), state.snapshot(),
state.document()->scopeAt(block->line(), block->column()));
CaseStatementCollector caseValues(interface->semanticInfo().doc, interface->snapshot(),
interface->semanticInfo().doc->scopeAt(block->line(), block->column()));
QStringList usedValues = caseValues(switchStatement);
// save the values that would be added
foreach (const QString &usedValue, usedValues)
@@ -204,7 +209,7 @@ QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(const CppQui
if (values.isEmpty())
return noResult();
else
return singleResult(new Operation(state, depth, compoundStatement, values));
return singleResult(new Operation(interface, depth, compoundStatement, values));
}
return noResult();
+2 -1
View File
@@ -46,7 +46,8 @@ namespace Internal {
class CompleteSwitchCaseStatement: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state);
virtual QList<CppQuickFixOperation::Ptr> match(
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface);
};
} // namespace Internal
+51 -13
View File
@@ -35,11 +35,10 @@
#include "cppplugin.h"
#include "cpphighlighter.h"
#include "cppchecksymbols.h"
#include "cppquickfix.h"
#include "cpplocalsymbols.h"
#include "cppquickfixcollector.h"
#include "cppqtstyleindenter.h"
#include "cppautocompleter.h"
#include "cppquickfixassistant.h"
#include <AST.h>
#include <Control.h>
@@ -66,6 +65,7 @@
#include <cpptools/cpptoolsplugin.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cppcodeformatter.h>
#include <cpptools/cppcompletionassist.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -83,6 +83,9 @@
#include <texteditor/fontsettings.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <texteditor/codeassist/basicproposalitem.h>
#include <texteditor/codeassist/genericproposal.h>
#include <QtCore/QDebug>
#include <QtCore/QTime>
@@ -1617,23 +1620,30 @@ void CPPEditorWidget::contextMenuEvent(QContextMenuEvent *e)
QMenu *quickFixMenu = new QMenu(tr("&Refactor"), menu);
quickFixMenu->addAction(am->command(Constants::RENAME_SYMBOL_UNDER_CURSOR)->action());
CppQuickFixCollector *quickFixCollector = CppPlugin::instance()->quickFixCollector();
QSignalMapper mapper;
connect(&mapper, SIGNAL(mapped(int)), this, SLOT(performQuickFix(int)));
if (! isOutdated()) {
if (quickFixCollector->startCompletion(editor()) != -1) {
m_quickFixes = quickFixCollector->quickFixes();
if (! m_quickFixes.isEmpty())
quickFixMenu->addSeparator();
for (int index = 0; index < m_quickFixes.size(); ++index) {
TextEditor::QuickFixOperation::Ptr op = m_quickFixes.at(index);
TextEditor::IAssistInterface *interface =
createAssistInterface(TextEditor::QuickFix, TextEditor::ExplicitlyInvoked);
if (interface) {
QScopedPointer<TextEditor::IAssistProcessor> processor(
CppPlugin::instance()->quickFixProvider()->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 = quickFixMenu->addAction(op->description());
mapper.setMapping(action, index);
connect(action, SIGNAL(triggered()), &mapper, SLOT(map()));
}
delete model;
}
}
}
@@ -1646,7 +1656,6 @@ void CPPEditorWidget::contextMenuEvent(QContextMenuEvent *e)
appendStandardContextMenuActions(menu);
menu->exec(e->globalPos());
quickFixCollector->cleanup();
m_quickFixes.clear();
delete menu;
}
@@ -1921,6 +1930,7 @@ void CPPEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo)
}
setExtraSelections(UnusedSymbolSelection, unusedSelections);
if (! m_renameSelections.isEmpty())
@@ -2205,4 +2215,32 @@ QVector<QString> CPPEditorWidget::highlighterFormatCategories()
return categories;
}
TextEditor::IAssistInterface *CPPEditorWidget::createAssistInterface(
TextEditor::AssistKind kind,
TextEditor::AssistReason reason) const
{
if (kind == TextEditor::Completion) {
QStringList includePaths;
QStringList frameworkPaths;
if (ProjectExplorer::Project *project =
ProjectExplorer::ProjectExplorerPlugin::instance()->currentProject()) {
includePaths = m_modelManager->projectInfo(project).includePaths;
frameworkPaths = m_modelManager->projectInfo(project).frameworkPaths;
}
return new CppTools::Internal::CppCompletionAssistInterface(
document(),
position(),
editor()->file(),
reason,
m_modelManager->snapshot(),
includePaths,
frameworkPaths);
} else if (kind == TextEditor::QuickFix) {
if (!semanticInfo().doc || semanticInfo().revision != editorRevision())
return 0;
return new CppQuickFixAssistInterface(const_cast<CPPEditorWidget *>(this), reason);
}
return 0;
}
#include "cppeditor.moc"
+4 -1
View File
@@ -34,13 +34,13 @@
#define CPPEDITOR_H
#include "cppeditorenums.h"
#include "cppquickfix.h"
#include "cppsemanticinfo.h"
#include <cplusplus/ModelManagerInterface.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/LookupContext.h>
#include <texteditor/basetexteditor.h>
#include <texteditor/quickfix.h>
#include <QtCore/QThread>
#include <QtCore/QMutex>
@@ -189,6 +189,9 @@ public:
static QVector<QString> highlighterFormatCategories();
virtual TextEditor::IAssistInterface *createAssistInterface(TextEditor::AssistKind kind,
TextEditor::AssistReason reason) const;
Q_SIGNALS:
void outlineModelIndexChanged(const QModelIndex &index);
+6 -6
View File
@@ -14,7 +14,6 @@ HEADERS += cppplugin.h \
cppeditorenums.h \
cppeditor_global.h \
cppclasswizard.h \
cppquickfix.h \
cppchecksymbols.h \
cppsemanticinfo.h \
cppoutline.h \
@@ -22,12 +21,13 @@ HEADERS += cppplugin.h \
cpplocalsymbols.h \
cpptypehierarchy.h \
cppelementevaluator.h \
cppquickfixcollector.h \
cppqtstyleindenter.h \
cppautocompleter.h \
cppcompleteswitch.h \
cppsnippetprovider.h \
cppinsertqtpropertymembers.h
cppinsertqtpropertymembers.h \
cppquickfixassistant.h \
cppquickfix.h
SOURCES += cppplugin.cpp \
cppeditor.cpp \
@@ -35,7 +35,6 @@ SOURCES += cppplugin.cpp \
cpphoverhandler.cpp \
cppfilewizard.cpp \
cppclasswizard.cpp \
cppquickfix.cpp \
cppquickfixes.cpp \
cppchecksymbols.cpp \
cppsemanticinfo.cpp \
@@ -44,12 +43,13 @@ SOURCES += cppplugin.cpp \
cpplocalsymbols.cpp \
cpptypehierarchy.cpp \
cppelementevaluator.cpp \
cppquickfixcollector.cpp \
cppqtstyleindenter.cpp \
cppautocompleter.cpp \
cppcompleteswitch.cpp \
cppsnippetprovider.cpp \
cppinsertqtpropertymembers.cpp
cppinsertqtpropertymembers.cpp \
cppquickfixassistant.cpp \
cppquickfix.cpp
RESOURCES += cppeditor.qrc
OTHER_FILES += CppEditor.mimetypes.xml
+22 -18
View File
@@ -31,6 +31,7 @@
**************************************************************************/
#include "cppinsertdecldef.h"
#include "cppquickfixassistant.h"
#include <CPlusPlus.h>
#include <cplusplus/ASTPath.h>
@@ -53,11 +54,12 @@ namespace {
class InsertDeclOperation: public CppQuickFixOperation
{
public:
InsertDeclOperation(const CppQuickFixState &state, int priority,
InsertDeclOperation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
int priority,
const QString &targetFileName, const Class *targetSymbol,
InsertionPointLocator::AccessSpec xsSpec,
const QString &decl)
: CppQuickFixOperation(state, priority)
: CppQuickFixOperation(interface, priority)
, m_targetFileName(targetFileName)
, m_targetSymbol(targetSymbol)
, m_xsSpec(xsSpec)
@@ -108,10 +110,11 @@ private:
} // anonymous namespace
QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &state)
QList<CppQuickFixOperation::Ptr> DeclFromDef::match(
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
const CppRefactoringFile &file = state.currentFile();
const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile();
FunctionDefinitionAST *funDef = 0;
int idx = 0;
@@ -158,7 +161,7 @@ QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &stat
if (!q->base())
return noResult();
if (ClassOrNamespace *binding = state.context().lookupType(q->base(), enclosingScope)) {
if (ClassOrNamespace *binding = interface->context().lookupType(q->base(), enclosingScope)) {
foreach (Symbol *s, binding->symbols()) {
if (Class *matchingClass = s->asClass()) {
for (Symbol *s = matchingClass->find(q->identifier()); s; s = s->next()) {
@@ -177,11 +180,11 @@ QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &stat
const QString fn = QString::fromUtf8(matchingClass->fileName(),
matchingClass->fileNameLength());
const QString decl = generateDeclaration(state,
const QString decl = generateDeclaration(interface,
method,
binding);
return singleResult(
new InsertDeclOperation(state, idx, fn, matchingClass,
new InsertDeclOperation(interface, idx, fn, matchingClass,
InsertionPointLocator::Public,
decl));
}
@@ -191,7 +194,7 @@ QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &stat
return noResult();
}
QString DeclFromDef::generateDeclaration(const CppQuickFixState &,
QString DeclFromDef::generateDeclaration(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &,
Function *method,
ClassOrNamespace *targetBinding)
{
@@ -214,9 +217,9 @@ namespace {
class InsertDefOperation: public CppQuickFixOperation
{
public:
InsertDefOperation(const CppQuickFixState &state, int priority,
InsertDefOperation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface, int priority,
Declaration *decl, const InsertionLocation &loc)
: CppQuickFixOperation(state, priority)
: CppQuickFixOperation(interface, priority)
, m_decl(decl)
, m_loc(loc)
{
@@ -241,12 +244,12 @@ public:
//--
SubstitutionEnvironment env;
env.setContext(state().context());
env.setContext(assistInterface()->context());
env.switchScope(m_decl->enclosingScope());
UseQualifiedNames q;
env.enter(&q);
Control *control = state().context().control().data();
Control *control = assistInterface()->context().control().data();
FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control);
QString name = oo(LookupContext::fullyQualifiedName(m_decl));
//--
@@ -274,10 +277,11 @@ private:
} // anonymous namespace
QList<CppQuickFixOperation::Ptr> DefFromDecl::match(const CppQuickFixState &state)
QList<CppQuickFixOperation::Ptr> DefFromDecl::match(
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
const CppRefactoringFile &file = state.currentFile();
const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile();
int idx = path.size() - 1;
for (; idx >= 0; --idx) {
@@ -292,12 +296,12 @@ QList<CppQuickFixOperation::Ptr> DefFromDecl::match(const CppQuickFixState &stat
&& decl->enclosingScope()->isClass()) {
DeclaratorAST *declarator = simpleDecl->declarator_list->value;
if (file.isCursorOn(declarator->core_declarator)) {
CppRefactoringChanges refactoring(state.snapshot());
CppRefactoringChanges refactoring(interface->snapshot());
InsertionPointLocator locator(&refactoring);
QList<CppQuickFixOperation::Ptr> results;
foreach (const InsertionLocation &loc, locator.methodDefinition(decl)) {
if (loc.isValid())
results.append(CppQuickFixOperation::Ptr(new InsertDefOperation(state, idx, decl, loc)));
results.append(CppQuickFixOperation::Ptr(new InsertDefOperation(interface, idx, decl, loc)));
}
return results;
}
+5 -3
View File
@@ -47,10 +47,11 @@ namespace Internal {
class DeclFromDef: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state);
virtual QList<CppQuickFixOperation::Ptr>
match(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface);
protected:
static QString generateDeclaration(const CppQuickFixState &state,
static QString generateDeclaration(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
CPlusPlus::Function *method,
CPlusPlus::ClassOrNamespace *targetBinding);
};
@@ -58,7 +59,8 @@ protected:
class DefFromDecl: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state);
virtual QList<CppQuickFixOperation::Ptr>
match(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface);
};
} // namespace Internal
@@ -31,6 +31,7 @@
**************************************************************************/
#include "cppinsertqtpropertymembers.h"
#include "cppquickfixassistant.h"
#include <AST.h>
#include <Token.h>
@@ -38,6 +39,7 @@
#include <cpptools/insertionpointlocator.h>
#include <cpptools/cpprefactoringchanges.h>
#include <cppeditor/cppquickfix.h>
#include <coreplugin/ifile.h>
using namespace CPlusPlus;
using namespace CppTools;
@@ -46,9 +48,10 @@ using namespace Utils;
using namespace CppEditor;
using namespace CppEditor::Internal;
QList<CppQuickFixOperation::Ptr> InsertQtPropertyMembers::match(const CppQuickFixState &state)
QList<CppQuickFixOperation::Ptr> InsertQtPropertyMembers::match(
const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
const QList<AST *> &path = interface->path();
if (path.isEmpty())
return noResult();
@@ -67,8 +70,8 @@ QList<CppQuickFixOperation::Ptr> InsertQtPropertyMembers::match(const CppQuickFi
if (!klass)
return noResult();
CppRefactoringChanges refactoring(state.snapshot());
const CppRefactoringFile &file = refactoring.file(state.document()->fileName());
CppRefactoringChanges refactoring(interface->snapshot());
const CppRefactoringFile &file = refactoring.file(interface->file()->fileName());
const QString propertyName = file.textOf(qtPropertyDeclaration->property_name);
QString getterName;
QString setterName;
@@ -116,16 +119,17 @@ QList<CppQuickFixOperation::Ptr> InsertQtPropertyMembers::match(const CppQuickFi
if (getterName.isEmpty() && setterName.isEmpty() && signalName.isEmpty())
return noResult();
return singleResult(new Operation(state, path.size() - 1, qtPropertyDeclaration, c,
return singleResult(new Operation(interface, path.size() - 1, qtPropertyDeclaration, c,
generateFlags,
getterName, setterName, signalName, storageName));
}
InsertQtPropertyMembers::Operation::Operation(
const CppQuickFixState &state, int priority, QtPropertyDeclarationAST *declaration, Class *klass,
const QSharedPointer<const CppQuickFixAssistInterface> &interface,
int priority, QtPropertyDeclarationAST *declaration, Class *klass,
int generateFlags, const QString &getterName, const QString &setterName, const QString &signalName,
const QString &storageName)
: CppQuickFixOperation(state, priority)
: CppQuickFixOperation(interface, priority)
, m_declaration(declaration)
, m_class(klass)
, m_generateFlags(generateFlags)
@@ -62,7 +62,8 @@ class InsertQtPropertyMembers : public CppQuickFixFactory
Q_OBJECT
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state);
virtual QList<CppQuickFixOperation::Ptr>
match(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface);
private:
enum GenerateFlag {
@@ -75,7 +76,8 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority,
Operation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
int priority,
CPlusPlus::QtPropertyDeclarationAST *declaration, CPlusPlus::Class *klass,
int generateFlags,
const QString &getterName, const QString &setterName, const QString &signalName,
+12 -40
View File
@@ -37,11 +37,10 @@
#include "cppeditorenums.h"
#include "cppfilewizard.h"
#include "cpphoverhandler.h"
#include "cppquickfix.h"
#include "cppoutline.h"
#include "cppquickfixcollector.h"
#include "cpptypehierarchy.h"
#include "cppsnippetprovider.h"
#include "cppquickfixassistant.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
@@ -54,7 +53,6 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/navigationwidget.h>
#include <texteditor/completionsupport.h>
#include <texteditor/fontsettings.h>
#include <texteditor/storagesettings.h>
#include <texteditor/texteditoractionhandler.h>
@@ -75,6 +73,8 @@
using namespace CppEditor;
using namespace CppEditor::Internal;
void registerQuickFixes(ExtensionSystem::IPlugin *plugIn);
enum { QUICKFIX_INTERVAL = 20 };
//////////////////////////// CppEditorFactory /////////////////////////////
@@ -149,15 +149,10 @@ CppPlugin::CppPlugin() :
m_renameSymbolUnderCursorAction(0),
m_findUsagesAction(0),
m_updateCodeModelAction(0),
m_openTypeHierarchyAction(0)
m_openTypeHierarchyAction(0),
m_quickFixProvider(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()));
}
CppPlugin::~CppPlugin()
@@ -193,8 +188,10 @@ bool CppPlugin::sortedOutline() const
return m_sortedOutline;
}
CppQuickFixCollector *CppPlugin::quickFixCollector() const
{ return m_quickFixCollector; }
CppQuickFixAssistProvider *CppPlugin::quickFixProvider() const
{
return m_quickFixProvider;
}
bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
{
@@ -209,9 +206,9 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
addAutoReleasedObject(new CppTypeHierarchyFactory);
addAutoReleasedObject(new CppSnippetProvider);
m_quickFixCollector = new CppQuickFixCollector;
addAutoReleasedObject(m_quickFixCollector);
CppQuickFixCollector::registerQuickFixes(this);
m_quickFixProvider = new CppQuickFixAssistProvider;
addAutoReleasedObject(m_quickFixProvider);
registerQuickFixes(this);
CppFileWizard::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
@@ -380,31 +377,6 @@ void CppPlugin::findUsages()
editor->findUsages();
}
void CppPlugin::quickFix(TextEditor::ITextEditor *editor)
{
m_currentEditor = editor;
quickFixNow();
}
void CppPlugin::quickFixNow()
{
if (! m_currentEditor)
return;
Core::EditorManager *em = Core::EditorManager::instance();
CPPEditorWidget *currentEditor = qobject_cast<CPPEditorWidget*>(em->currentEditor()->widget());
if (CPPEditorWidget *editor = qobject_cast<CPPEditorWidget*>(m_currentEditor->widget())) {
if (currentEditor == editor) {
if (editor->isOutdated())
m_quickFixTimer->start(QUICKFIX_INTERVAL);
else
TextEditor::CompletionSupport::instance()->
complete(m_currentEditor, TextEditor::QuickFixCompletion, true);
}
}
}
void CppPlugin::onTaskStarted(const QString &type)
{
if (type == CppTools::Constants::TASK_INDEX) {
+3 -5
View File
@@ -50,6 +50,7 @@ namespace Internal {
class CPPEditorWidget;
class CppQuickFixCollector;
class CppQuickFixAssistProvider;
class CppPlugin : public ExtensionSystem::IPlugin
{
@@ -70,7 +71,7 @@ public:
bool sortedOutline() const;
CppQuickFixCollector *quickFixCollector() const;
CppQuickFixAssistProvider *quickFixProvider() const;
signals:
void outlineSortingChanged(bool sort);
@@ -86,8 +87,6 @@ private slots:
void onTaskStarted(const QString &type);
void onAllTasksFinished(const QString &type);
void findUsages();
void quickFix(TextEditor::ITextEditor *editable);
void quickFixNow();
void currentEditorChanged(Core::IEditor *editor);
void openTypeHierarchy();
@@ -105,9 +104,8 @@ private:
QAction *m_updateCodeModelAction;
QAction *m_openTypeHierarchyAction;
CppQuickFixCollector *m_quickFixCollector;
CppQuickFixAssistProvider *m_quickFixProvider;
QTimer *m_quickFixTimer;
QPointer<TextEditor::ITextEditor> m_currentEditor;
};
+17 -56
View File
@@ -32,7 +32,7 @@
#include "cppquickfix.h"
#include "cppeditor.h"
#include "cppquickfixcollector.h"
#include "cppquickfixassistant.h"
#include <AST.h>
#include <TranslationUnit.h>
@@ -58,53 +58,10 @@ using namespace TextEditor;
using namespace CPlusPlus;
using namespace Utils;
CppQuickFixState::CppQuickFixState(TextEditor::BaseTextEditorWidget *editor)
: QuickFixState(editor)
{}
const QList<AST *> &CppQuickFixState::path() const
{
return _path;
}
Snapshot CppQuickFixState::snapshot() const
{
return _snapshot;
}
Document::Ptr CppQuickFixState::document() const
{
return _semanticInfo.doc;
}
SemanticInfo CppQuickFixState::semanticInfo() const
{
return _semanticInfo;
}
const LookupContext &CppQuickFixState::context() const
{
return _context;
}
const CppRefactoringFile CppQuickFixState::currentFile() const
{
return CppRefactoringFile(editor(), document());
}
bool CppQuickFixState::isCursorOn(unsigned tokenIndex) const
{
return currentFile().isCursorOn(tokenIndex);
}
bool CppQuickFixState::isCursorOn(const CPlusPlus::AST *ast) const
{
return currentFile().isCursorOn(ast);
}
CppQuickFixOperation::CppQuickFixOperation(const CppQuickFixState &state, int priority)
CppQuickFixOperation::CppQuickFixOperation(
const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority)
: QuickFixOperation(priority)
, _state(state)
, m_interface(interface)
{}
CppQuickFixOperation::~CppQuickFixOperation()
@@ -112,19 +69,21 @@ CppQuickFixOperation::~CppQuickFixOperation()
void CppQuickFixOperation::perform()
{
CppRefactoringChanges refactoring(_state.snapshot());
CppRefactoringChanges refactoring(m_interface->snapshot());
CppRefactoringFile current = refactoring.file(fileName());
performChanges(&current, &refactoring);
}
const CppQuickFixState &CppQuickFixOperation::state() const
const CppQuickFixAssistInterface *CppQuickFixOperation::assistInterface() const
{
return _state;
return m_interface.data();
}
QString CppQuickFixOperation::fileName() const
{ return state().document()->fileName(); }
{
return m_interface->file()->fileName();
}
CppQuickFixFactory::CppQuickFixFactory()
{
@@ -134,12 +93,14 @@ CppQuickFixFactory::~CppQuickFixFactory()
{
}
QList<QuickFixOperation::Ptr> CppQuickFixFactory::matchingOperations(QuickFixState *state)
QList<QuickFixOperation::Ptr> CppQuickFixFactory::matchingOperations(
const QSharedPointer<const TextEditor::IAssistInterface> &interface)
{
if (CppQuickFixState *cppState = static_cast<CppQuickFixState *>(state))
return match(*cppState);
else
return QList<TextEditor::QuickFixOperation::Ptr>();
QSharedPointer<const CppQuickFixAssistInterface> cppInterface =
interface.staticCast<const CppQuickFixAssistInterface>();
if (cppInterface->path().isEmpty())
return QList<QuickFixOperation::Ptr>();
return match(cppInterface);
}
QList<CppQuickFixOperation::Ptr> CppQuickFixFactory::singleResult(CppQuickFixOperation *operation)
+12 -32
View File
@@ -53,40 +53,17 @@ class IPlugin;
namespace CppEditor {
namespace Internal {
class CppQuickFixCollector;
} // namespace Internal
class CPPEDITOR_EXPORT CppQuickFixState: public TextEditor::QuickFixState
{
friend class Internal::CppQuickFixCollector;
public:
CppQuickFixState(TextEditor::BaseTextEditorWidget *editor);
const QList<CPlusPlus::AST *> &path() const;
CPlusPlus::Snapshot snapshot() const;
CPlusPlus::Document::Ptr document() const;
CppEditor::Internal::SemanticInfo semanticInfo() const;
const CPlusPlus::LookupContext &context() const;
const CppTools::CppRefactoringFile currentFile() const;
bool isCursorOn(unsigned tokenIndex) const;
bool isCursorOn(const CPlusPlus::AST *ast) const;
private:
QList<CPlusPlus::AST *> _path;
CPlusPlus::Snapshot _snapshot;
CppEditor::Internal::SemanticInfo _semanticInfo;
CPlusPlus::LookupContext _context;
};
class CppQuickFixAssistInterface;
}
class CPPEDITOR_EXPORT CppQuickFixOperation: public TextEditor::QuickFixOperation
{
Q_DISABLE_COPY(CppQuickFixOperation)
public:
explicit CppQuickFixOperation(const CppQuickFixState &state, int priority = -1);
explicit CppQuickFixOperation(
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
int priority = -1);
virtual ~CppQuickFixOperation();
virtual void perform();
@@ -97,10 +74,10 @@ protected:
QString fileName() const;
const CppQuickFixState &state() const;
const Internal::CppQuickFixAssistInterface *assistInterface() const;
private:
CppQuickFixState _state;
QSharedPointer<const Internal::CppQuickFixAssistInterface> m_interface;
};
class CPPEDITOR_EXPORT CppQuickFixFactory: public TextEditor::QuickFixFactory
@@ -111,12 +88,15 @@ public:
CppQuickFixFactory();
virtual ~CppQuickFixFactory();
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
CppQuickFixOperation objects.
*/
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state) = 0;
virtual QList<CppQuickFixOperation::Ptr> match(
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface) = 0;
protected:
/*!
@@ -0,0 +1,152 @@
/**************************************************************************
**
** 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 "cppquickfixassistant.h"
#include "cppeditorconstants.h"
#include "cppeditor.h"
// @TODO: temp
#include "cppquickfix.h"
#include <AST.h>
#include <TranslationUnit.h>
#include <Token.h>
#include <cplusplus/ASTPath.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/ResolveExpression.h>
#include <cplusplus/Overview.h>
#include <cplusplus/TypeOfExpression.h>
#include <cplusplus/DependencyTable.h>
#include <cplusplus/CppRewriter.h>
#include <cpptools/cpprefactoringchanges.h>
#include <extensionsystem/pluginmanager.h>
#include <QtCore/QFileInfo>
#include <QtGui/QTextBlock>
using namespace CppEditor;
using namespace CppEditor::Internal;
using namespace TextEditor;
using namespace CppTools;
using namespace CPlusPlus;
// -------------------------
// CppQuickFixAssistProvider
// -------------------------
bool CppQuickFixAssistProvider::supportsEditor(const QString &editorId) const
{
return editorId == QLatin1String(CppEditor::Constants::CPPEDITOR_ID);
}
IAssistProcessor *CppQuickFixAssistProvider::createProcessor() const
{
return new CppQuickFixAssistProcessor(this);
}
QList<TextEditor::QuickFixFactory *> CppQuickFixAssistProvider::quickFixFactories() const
{
QList<TextEditor::QuickFixFactory *> results;
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
foreach (CppQuickFixFactory *f, pm->getObjects<CppEditor::CppQuickFixFactory>())
results.append(f);
return results;
}
// --------------------------
// CppQuickFixAssistProcessor
// --------------------------
CppQuickFixAssistProcessor::CppQuickFixAssistProcessor(const IAssistProvider *provider)
: m_provider(provider)
{}
const IAssistProvider *CppQuickFixAssistProcessor::provider() const
{
return m_provider;
}
// --------------------------
// CppQuickFixAssistInterface
// --------------------------
CppQuickFixAssistInterface::CppQuickFixAssistInterface(CPPEditorWidget *editor,
TextEditor::AssistReason reason)
: DefaultAssistInterface(editor->document(), editor->position(), editor->file(), reason)
, m_editor(editor)
, m_semanticInfo(editor->semanticInfo())
, m_snapshot(CPlusPlus::CppModelManagerInterface::instance()->snapshot())
, m_context(m_semanticInfo.doc, m_snapshot)
{
CPlusPlus::ASTPath astPath(m_semanticInfo.doc);
m_path = astPath(editor->textCursor());
}
const QList<AST *> &CppQuickFixAssistInterface::path() const
{
return m_path;
}
Snapshot CppQuickFixAssistInterface::snapshot() const
{
return m_snapshot;
}
SemanticInfo CppQuickFixAssistInterface::semanticInfo() const
{
return m_semanticInfo;
}
const LookupContext &CppQuickFixAssistInterface::context() const
{
return m_context;
}
CPPEditorWidget *CppQuickFixAssistInterface::editor() const
{
return m_editor;
}
const CppRefactoringFile CppQuickFixAssistInterface::currentFile() const
{
return CppRefactoringFile(m_editor, m_semanticInfo.doc);
}
bool CppQuickFixAssistInterface::isCursorOn(unsigned tokenIndex) const
{
return currentFile().isCursorOn(tokenIndex);
}
bool CppQuickFixAssistInterface::isCursorOn(const CPlusPlus::AST *ast) const
{
return currentFile().isCursorOn(ast);
}
@@ -0,0 +1,101 @@
/**************************************************************************
**
** 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 CPPQUICKFIXASSISTANT_H
#define CPPQUICKFIXASSISTANT_H
#include "cppsemanticinfo.h"
#include <ASTfwd.h>
#include <cplusplus/CppDocument.h>
#include <texteditor/codeassist/defaultassistinterface.h>
#include <texteditor/codeassist/quickfixassistprovider.h>
#include <texteditor/codeassist/quickfixassistprocessor.h>
namespace CppTools {
class CppRefactoringFile;
}
namespace CppEditor {
namespace Internal {
class CPPEditorWidget;
class CppQuickFixAssistInterface : public TextEditor::DefaultAssistInterface
{
public:
CppQuickFixAssistInterface(CPPEditorWidget *editor, TextEditor::AssistReason reason);
const QList<CPlusPlus::AST *> &path() const;
CPlusPlus::Snapshot snapshot() const;
CppEditor::Internal::SemanticInfo semanticInfo() const;
const CPlusPlus::LookupContext &context() const;
CPPEditorWidget *editor() const;
const CppTools::CppRefactoringFile currentFile() const;
bool isCursorOn(unsigned tokenIndex) const;
bool isCursorOn(const CPlusPlus::AST *ast) const;
private:
CPPEditorWidget *m_editor;
CppEditor::Internal::SemanticInfo m_semanticInfo;
CPlusPlus::Snapshot m_snapshot;
CPlusPlus::LookupContext m_context;
QList<CPlusPlus::AST *> m_path;
};
class CppQuickFixAssistProcessor : public TextEditor::QuickFixAssistProcessor
{
public:
CppQuickFixAssistProcessor(const TextEditor::IAssistProvider *provider);
virtual const TextEditor::IAssistProvider *provider() const;
private:
const TextEditor::IAssistProvider *m_provider;
};
class CppQuickFixAssistProvider : public TextEditor::QuickFixAssistProvider
{
public:
virtual bool supportsEditor(const QString &editorId) const;
virtual TextEditor::IAssistProcessor *createProcessor() const;
virtual QList<TextEditor::QuickFixFactory *> quickFixFactories() const;
};
} // Internal
} // CppEditor
#endif // CPPQUICKFIXASSISTANT_H
@@ -1,100 +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.
**
**************************************************************************/
#include "cppquickfixcollector.h"
#include "cppeditor.h"
#include <extensionsystem/pluginmanager.h>
#include <cplusplus/ModelManagerInterface.h>
#include <cpptools/cpprefactoringchanges.h>
#include <cpptools/cpptoolsconstants.h>
#include <AST.h>
#include <cplusplus/ASTPath.h>
namespace CppEditor {
namespace Internal {
CppQuickFixCollector::CppQuickFixCollector()
{
}
CppQuickFixCollector::~CppQuickFixCollector()
{
}
bool CppQuickFixCollector::supportsEditor(TextEditor::ITextEditor *editor) const
{
return CPlusPlus::CppModelManagerInterface::instance()->isCppEditor(editor);
}
TextEditor::QuickFixState *CppQuickFixCollector::initializeCompletion(TextEditor::BaseTextEditorWidget *editor)
{
if (CPPEditorWidget *cppEditor = qobject_cast<CPPEditorWidget *>(editor)) {
const SemanticInfo info = cppEditor->semanticInfo();
if (info.revision != cppEditor->editorRevision()) {
// outdated
qWarning() << "TODO: outdated semantic info, force a reparse.";
return 0;
}
if (info.doc) {
CPlusPlus::ASTPath astPath(info.doc);
const QList<CPlusPlus::AST *> path = astPath(cppEditor->textCursor());
if (! path.isEmpty()) {
CppQuickFixState *state = new CppQuickFixState(editor);
state->_path = path;
state->_semanticInfo = info;
state->_snapshot = CPlusPlus::CppModelManagerInterface::instance()->snapshot();
state->_context = CPlusPlus::LookupContext(info.doc, state->snapshot());
return state;
}
}
}
return 0;
}
QList<TextEditor::QuickFixFactory *> CppQuickFixCollector::quickFixFactories() const
{
QList<TextEditor::QuickFixFactory *> results;
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
foreach (CppQuickFixFactory *f, pm->getObjects<CppEditor::CppQuickFixFactory>())
results.append(f);
return results;
}
} // namespace Internal
} // namespace CppEditor
+137 -130
View File
@@ -35,7 +35,8 @@
#include "cppquickfix.h"
#include "cppinsertdecldef.h"
#include "cppinsertqtpropertymembers.h"
#include "cppquickfixcollector.h"
#include "cppquickfixassistant.h"
#include "cppcompleteswitch.h"
#include <ASTVisitor.h>
#include <AST.h>
@@ -85,17 +86,17 @@ namespace {
class UseInverseOp: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
QList<CppQuickFixOperation::Ptr> result;
const CppRefactoringFile &file = state.currentFile();
const CppRefactoringFile &file = interface->currentFile();
const QList<AST *> &path = state.path();
const QList<AST *> &path = interface->path();
int index = path.size() - 1;
BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
if (! binary)
return result;
if (! state.isCursorOn(binary->binary_op_token))
if (! interface->isCursorOn(binary->binary_op_token))
return result;
Kind invertToken;
@@ -122,7 +123,7 @@ public:
return result;
}
result.append(CppQuickFixOperation::Ptr(new Operation(state, index, binary, invertToken)));
result.append(CppQuickFixOperation::Ptr(new Operation(interface, index, binary, invertToken)));
return result;
}
@@ -136,8 +137,9 @@ private:
QString replacement;
public:
Operation(const CppQuickFixState &state, int priority, BinaryExpressionAST *binary, Kind invertToken)
: CppQuickFixOperation(state, priority)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
int priority, BinaryExpressionAST *binary, Kind invertToken)
: CppQuickFixOperation(interface, priority)
, binary(binary), nested(0), negation(0)
{
Token tok;
@@ -146,12 +148,12 @@ private:
// check for enclosing nested expression
if (priority - 1 >= 0)
nested = state.path()[priority - 1]->asNestedExpression();
nested = interface->path()[priority - 1]->asNestedExpression();
// check for ! before parentheses
if (nested && priority - 2 >= 0) {
negation = state.path()[priority - 2]->asUnaryExpression();
if (negation && ! state.currentFile().tokenAt(negation->unary_op_token).is(T_EXCLAIM))
negation = interface->path()[priority - 2]->asUnaryExpression();
if (negation && ! interface->currentFile().tokenAt(negation->unary_op_token).is(T_EXCLAIM))
negation = 0;
}
}
@@ -191,17 +193,17 @@ private:
class FlipBinaryOp: public CppQuickFixFactory
{
public:
virtual QList<QuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<QuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
QList<QuickFixOperation::Ptr> result;
const QList<AST *> &path = state.path();
const CppRefactoringFile &file = state.currentFile();
const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile();
int index = path.size() - 1;
BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
if (! binary)
return result;
if (! state.isCursorOn(binary->binary_op_token))
if (! interface->isCursorOn(binary->binary_op_token))
return result;
Kind flipToken;
@@ -235,7 +237,7 @@ public:
replacement = QLatin1String(tok.spell());
}
result.append(QuickFixOperation::Ptr(new Operation(state, index, binary, replacement)));
result.append(QuickFixOperation::Ptr(new Operation(interface, index, binary, replacement)));
return result;
}
@@ -243,8 +245,9 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, BinaryExpressionAST *binary, QString replacement)
: CppQuickFixOperation(state)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
int priority, BinaryExpressionAST *binary, QString replacement)
: CppQuickFixOperation(interface)
, binary(binary)
, replacement(replacement)
{
@@ -288,12 +291,12 @@ private:
class RewriteLogicalAndOp: public CppQuickFixFactory
{
public:
virtual QList<QuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<QuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
QList<QuickFixOperation::Ptr> result;
BinaryExpressionAST *expression = 0;
const QList<AST *> &path = state.path();
const CppRefactoringFile &file = state.currentFile();
const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile();
int index = path.size() - 1;
for (; index != -1; --index) {
@@ -305,10 +308,10 @@ public:
if (! expression)
return result;
if (! state.isCursorOn(expression->binary_op_token))
if (! interface->isCursorOn(expression->binary_op_token))
return result;
QSharedPointer<Operation> op(new Operation(state));
QSharedPointer<Operation> op(new Operation(interface));
if (expression->match(op->pattern, &matcher) &&
file.tokenAt(op->pattern->binary_op_token).is(T_AMPER_AMPER) &&
@@ -331,8 +334,8 @@ private:
UnaryExpressionAST *right;
BinaryExpressionAST *pattern;
Operation(const CppQuickFixState &state)
: CppQuickFixOperation(state)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
: CppQuickFixOperation(interface)
, mk(new ASTPatternBuilder)
{
left = mk->UnaryExpression();
@@ -400,12 +403,12 @@ class SplitSimpleDeclarationOp: public CppQuickFixFactory
}
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
QList<CppQuickFixOperation::Ptr> result;
CoreDeclaratorAST *core_declarator = 0;
const QList<AST *> &path = state.path();
const CppRefactoringFile &file = state.currentFile();
const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile();
for (int index = path.size() - 1; index != -1; --index) {
AST *node = path.at(index);
@@ -424,12 +427,12 @@ public:
if (cursorPosition >= startOfDeclSpecifier && cursorPosition <= endOfDeclSpecifier) {
// the AST node under cursor is a specifier.
return singleResult(new Operation(state, index, declaration));
return singleResult(new Operation(interface, index, declaration));
}
if (core_declarator && state.isCursorOn(core_declarator)) {
if (core_declarator && interface->isCursorOn(core_declarator)) {
// got a core-declarator under the text cursor.
return singleResult(new Operation(state, index, declaration));
return singleResult(new Operation(interface, index, declaration));
}
}
@@ -444,8 +447,8 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, SimpleDeclarationAST *decl)
: CppQuickFixOperation(state, priority)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, SimpleDeclarationAST *decl)
: CppQuickFixOperation(interface, priority)
, declaration(decl)
{
setDescription(QApplication::translate("CppTools::QuickFix",
@@ -503,16 +506,16 @@ private:
class AddBracesToIfOp: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
const QList<AST *> &path = interface->path();
// show when we're on the 'if' of an if statement
int index = path.size() - 1;
IfStatementAST *ifStatement = path.at(index)->asIfStatement();
if (ifStatement && state.isCursorOn(ifStatement->if_token) && ifStatement->statement
if (ifStatement && interface->isCursorOn(ifStatement->if_token) && ifStatement->statement
&& ! ifStatement->statement->asCompoundStatement()) {
return singleResult(new Operation(state, index, ifStatement->statement));
return singleResult(new Operation(interface, index, ifStatement->statement));
}
// or if we're on the statement contained in the if
@@ -520,9 +523,9 @@ public:
for (; index != -1; --index) {
IfStatementAST *ifStatement = path.at(index)->asIfStatement();
if (ifStatement && ifStatement->statement
&& state.isCursorOn(ifStatement->statement)
&& interface->isCursorOn(ifStatement->statement)
&& ! ifStatement->statement->asCompoundStatement()) {
return singleResult(new Operation(state, index, ifStatement->statement));
return singleResult(new Operation(interface, index, ifStatement->statement));
}
}
@@ -536,8 +539,8 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, StatementAST *statement)
: CppQuickFixOperation(state, priority)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, StatementAST *statement)
: CppQuickFixOperation(interface, priority)
, _statement(statement)
{
setDescription(QApplication::translate("CppTools::QuickFix",
@@ -576,10 +579,10 @@ private:
class MoveDeclarationOutOfIfOp: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
QSharedPointer<Operation> op(new Operation(state));
const QList<AST *> &path = interface->path();
QSharedPointer<Operation> op(new Operation(interface));
int index = path.size() - 1;
for (; index != -1; --index) {
@@ -590,7 +593,7 @@ public:
if (! op->core)
return noResult();
if (state.isCursorOn(op->core)) {
if (interface->isCursorOn(op->core)) {
QList<CppQuickFixOperation::Ptr> result;
op->setPriority(index);
result.append(op);
@@ -607,8 +610,8 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state)
: CppQuickFixOperation(state)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
: CppQuickFixOperation(interface)
{
setDescription(QApplication::translate("CppTools::QuickFix",
"Move Declaration out of Condition"));
@@ -653,10 +656,10 @@ private:
class MoveDeclarationOutOfWhileOp: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
QSharedPointer<Operation> op(new Operation(state));
const QList<AST *> &path = interface->path();
QSharedPointer<Operation> op(new Operation(interface));
int index = path.size() - 1;
for (; index != -1; --index) {
@@ -674,7 +677,7 @@ public:
else if (! declarator->initializer)
return noResult();
if (state.isCursorOn(op->core)) {
if (interface->isCursorOn(op->core)) {
QList<CppQuickFixOperation::Ptr> result;
op->setPriority(index);
result.append(op);
@@ -691,8 +694,8 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state)
: CppQuickFixOperation(state)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
: CppQuickFixOperation(interface)
{
setDescription(QApplication::translate("CppTools::QuickFix",
"Move Declaration out of Condition"));
@@ -753,10 +756,10 @@ private:
class SplitIfStatementOp: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
IfStatementAST *pattern = 0;
const QList<AST *> &path = state.path();
const QList<AST *> &path = interface->path();
int index = path.size() - 1;
for (; index != -1; --index) {
@@ -777,7 +780,7 @@ public:
if (! condition)
return noResult();
Token binaryToken = state.currentFile().tokenAt(condition->binary_op_token);
Token binaryToken = interface->currentFile().tokenAt(condition->binary_op_token);
// only accept a chain of ||s or &&s - no mixing
if (! splitKind) {
@@ -791,8 +794,8 @@ public:
return noResult();
}
if (state.isCursorOn(condition->binary_op_token))
return singleResult(new Operation(state, index, pattern, condition));
if (interface->isCursorOn(condition->binary_op_token))
return singleResult(new Operation(interface, index, pattern, condition));
}
return noResult();
@@ -802,9 +805,9 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority,
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority,
IfStatementAST *pattern, BinaryExpressionAST *condition)
: CppQuickFixOperation(state, priority)
: CppQuickFixOperation(interface, priority)
, pattern(pattern)
, condition(condition)
{
@@ -889,12 +892,12 @@ class WrapStringLiteral: public CppQuickFixFactory
public:
enum Type { TypeString, TypeObjCString, TypeChar, TypeNone };
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
ExpressionAST *literal = 0;
Type type = TypeNone;
const QList<AST *> &path = state.path();
const CppRefactoringFile &file = state.currentFile();
const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile();
if (path.isEmpty())
return noResult(); // nothing to do
@@ -932,7 +935,7 @@ public:
if (file.charAt(file.startOf(literal)) == QLatin1Char('@'))
type = TypeObjCString;
}
return singleResult(new Operation(state,
return singleResult(new Operation(interface,
path.size() - 1, // very high priority
type,
literal));
@@ -942,9 +945,9 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, Type type,
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, Type type,
ExpressionAST *literal)
: CppQuickFixOperation(state, priority)
: CppQuickFixOperation(interface, priority)
, type(type)
, literal(literal)
{
@@ -996,9 +999,9 @@ class TranslateStringLiteral: public CppQuickFixFactory
public:
enum TranslationOption { unknown, useTr, useQCoreApplicationTranslate, useMacro };
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
const QList<AST *> &path = interface->path();
// Initialize
ExpressionAST *literal = 0;
QString trContext;
@@ -1016,7 +1019,7 @@ public:
if (call->base_expression) {
if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
const QByteArray id(state.currentFile().tokenAt(functionName->identifier_token).identifier->chars());
const QByteArray id(interface->currentFile().tokenAt(functionName->identifier_token).identifier->chars());
if (id == "tr" || id == "trUtf8"
|| id == "translate"
@@ -1029,7 +1032,7 @@ public:
}
}
QSharedPointer<Control> control = state.context().control();
QSharedPointer<Control> control = interface->context().control();
const Name *trName = control->identifier("tr");
// Check whether we are in a method:
@@ -1037,14 +1040,14 @@ public:
{
if (FunctionDefinitionAST *definition = path.at(i)->asFunctionDefinition()) {
Function *function = definition->symbol;
ClassOrNamespace *b = state.context().lookupType(function);
ClassOrNamespace *b = interface->context().lookupType(function);
if (b) {
// Do we have a tr method?
foreach(const LookupItem &r, b->find(trName)) {
Symbol *s = r.declaration();
if (s->type()->isFunctionType()) {
// no context required for tr
return singleResult(new Operation(state, path.size() - 1, literal, useTr, trContext));
return singleResult(new Operation(interface, path.size() - 1, literal, useTr, trContext));
}
}
}
@@ -1059,20 +1062,20 @@ public:
// ... or global if none available!
if (trContext.isEmpty())
trContext = QLatin1String("GLOBAL");
return singleResult(new Operation(state, path.size() - 1, literal, useQCoreApplicationTranslate, trContext));
return singleResult(new Operation(interface, path.size() - 1, literal, useQCoreApplicationTranslate, trContext));
}
}
// We need to use Q_TRANSLATE_NOOP
return singleResult(new Operation(state, path.size() - 1, literal, useMacro, QLatin1String("GLOBAL")));
return singleResult(new Operation(interface, path.size() - 1, literal, useMacro, QLatin1String("GLOBAL")));
}
private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, ExpressionAST *literal, TranslationOption option, const QString &context)
: CppQuickFixOperation(state, priority)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, ExpressionAST *literal, TranslationOption option, const QString &context)
: CppQuickFixOperation(interface, priority)
, m_literal(literal)
, m_option(option)
, m_context(context)
@@ -1120,16 +1123,16 @@ private:
class CStringToNSString: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
const CppRefactoringFile &file = state.currentFile();
const CppRefactoringFile &file = interface->currentFile();
if (state.editor()->mimeType() != CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
if (interface->editor()->mimeType() != CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
return noResult();
StringLiteralAST *stringLiteral = 0;
CallAST *qlatin1Call = 0;
const QList<AST *> &path = state.path();
const QList<AST *> &path = interface->path();
if (path.isEmpty())
return noResult(); // nothing to do
@@ -1147,7 +1150,7 @@ public:
if (call->base_expression) {
if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
const QByteArray id(state.currentFile().tokenAt(functionName->identifier_token).identifier->chars());
const QByteArray id(interface->currentFile().tokenAt(functionName->identifier_token).identifier->chars());
if (id == "QLatin1String" || id == "QLatin1Literal")
qlatin1Call = call;
@@ -1157,15 +1160,15 @@ public:
}
}
return singleResult(new Operation(state, path.size() - 1, stringLiteral, qlatin1Call));
return singleResult(new Operation(interface, path.size() - 1, stringLiteral, qlatin1Call));
}
private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, StringLiteralAST *stringLiteral, CallAST *qlatin1Call)
: CppQuickFixOperation(state, priority)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, StringLiteralAST *stringLiteral, CallAST *qlatin1Call)
: CppQuickFixOperation(interface, priority)
, stringLiteral(stringLiteral)
, qlatin1Call(qlatin1Call)
{
@@ -1214,12 +1217,12 @@ private:
class ConvertNumericLiteral: public CppQuickFixFactory
{
public:
virtual QList<QuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<QuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
QList<QuickFixOperation::Ptr> result;
const QList<AST *> &path = state.path();
const CppRefactoringFile &file = state.currentFile();
const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile();
if (path.isEmpty())
return result; // nothing to do
@@ -1266,7 +1269,7 @@ public:
*/
QString replacement;
replacement.sprintf("0x%lX", value);
QuickFixOperation::Ptr op(new ConvertNumeric(state, start, start + numberLength, replacement));
QuickFixOperation::Ptr op(new ConvertNumeric(interface, start, start + numberLength, replacement));
op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Hexadecimal"));
op->setPriority(priority);
result.append(op);
@@ -1284,7 +1287,7 @@ public:
*/
QString replacement;
replacement.sprintf("0%lo", value);
QuickFixOperation::Ptr op(new ConvertNumeric(state, start, start + numberLength, replacement));
QuickFixOperation::Ptr op(new ConvertNumeric(interface, start, start + numberLength, replacement));
op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Octal"));
op->setPriority(priority);
result.append(op);
@@ -1303,7 +1306,7 @@ public:
*/
QString replacement;
replacement.sprintf("%lu", value);
QuickFixOperation::Ptr op(new ConvertNumeric(state, start, start + numberLength, replacement));
QuickFixOperation::Ptr op(new ConvertNumeric(interface, start, start + numberLength, replacement));
op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Decimal"));
op->setPriority(priority);
result.append(op);
@@ -1317,8 +1320,9 @@ private:
class ConvertNumeric: public CppQuickFixOperation
{
public:
ConvertNumeric(const CppQuickFixState &state, int start, int end, const QString &replacement)
: CppQuickFixOperation(state)
ConvertNumeric(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
int start, int end, const QString &replacement)
: CppQuickFixOperation(interface)
, start(start)
, end(end)
, replacement(replacement)
@@ -1345,18 +1349,18 @@ private:
class FixForwardDeclarationOp: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
const QList<AST *> &path = interface->path();
for (int index = path.size() - 1; index != -1; --index) {
AST *ast = path.at(index);
if (NamedTypeSpecifierAST *namedTy = ast->asNamedTypeSpecifier()) {
if (Symbol *fwdClass = checkName(state, namedTy->name))
return singleResult(new Operation(state, index, fwdClass));
if (Symbol *fwdClass = checkName(interface, namedTy->name))
return singleResult(new Operation(interface, index, fwdClass));
} else if (ElaboratedTypeSpecifierAST *eTy = ast->asElaboratedTypeSpecifier()) {
if (Symbol *fwdClass = checkName(state, eTy->name))
return singleResult(new Operation(state, index, fwdClass));
if (Symbol *fwdClass = checkName(interface, eTy->name))
return singleResult(new Operation(interface, index, fwdClass));
}
}
@@ -1364,16 +1368,18 @@ public:
}
protected:
static Symbol *checkName(const CppQuickFixState &state, NameAST *ast)
static Symbol *checkName(const QSharedPointer<const CppQuickFixAssistInterface> &interface, NameAST *ast)
{
if (ast && state.isCursorOn(ast)) {
if (ast && interface->isCursorOn(ast)) {
if (const Name *name = ast->name) {
unsigned line, column;
state.document()->translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column);
interface->semanticInfo().doc->translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column);
Symbol *fwdClass = 0;
foreach (const LookupItem &r, state.context().lookup(name, state.document()->scopeAt(line, column))) {
foreach (const LookupItem &r,
interface->context().lookup(name,
interface->semanticInfo().doc->scopeAt(line, column))) {
if (! r.declaration())
continue;
else if (ForwardClassDeclaration *fwd = r.declaration()->asForwardClassDeclaration())
@@ -1393,8 +1399,8 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, Symbol *fwdClass)
: CppQuickFixOperation(state, priority)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, Symbol *fwdClass)
: CppQuickFixOperation(interface, priority)
, fwdClass(fwdClass)
{
setDescription(QApplication::translate("CppTools::QuickFix",
@@ -1405,13 +1411,13 @@ private:
{
Q_ASSERT(fwdClass != 0);
if (Class *k = state().snapshot().findMatchingClassDeclaration(fwdClass)) {
if (Class *k = assistInterface()->snapshot().findMatchingClassDeclaration(fwdClass)) {
const QString headerFile = QString::fromUtf8(k->fileName(), k->fileNameLength());
// collect the fwd headers
Snapshot fwdHeaders;
fwdHeaders.insert(state().snapshot().document(headerFile));
foreach (Document::Ptr doc, state().snapshot()) {
fwdHeaders.insert(assistInterface()->snapshot().document(headerFile));
foreach (Document::Ptr doc, assistInterface()->snapshot()) {
QFileInfo headerFileInfo(doc->fileName());
if (doc->globalSymbolCount() == 0 && doc->includes().size() == 1)
fwdHeaders.insert(doc);
@@ -1448,7 +1454,7 @@ private:
unsigned currentLine = currentFile->cursor().blockNumber() + 1;
unsigned bestLine = 0;
foreach (const Document::Include &incl, state().document()->includes()) {
foreach (const Document::Include &incl, assistInterface()->semanticInfo().doc->includes()) {
if (incl.line() < currentLine)
bestLine = incl.line();
}
@@ -1479,18 +1485,18 @@ private:
class AddLocalDeclarationOp: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
const CppRefactoringFile &file = state.currentFile();
const QList<AST *> &path = interface->path();
const CppRefactoringFile &file = interface->currentFile();
for (int index = path.size() - 1; index != -1; --index) {
if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) {
if (binary->left_expression && binary->right_expression && file.tokenAt(binary->binary_op_token).is(T_EQUAL)) {
IdExpressionAST *idExpr = binary->left_expression->asIdExpression();
if (state.isCursorOn(binary->left_expression) && idExpr && idExpr->name->asSimpleName() != 0) {
if (interface->isCursorOn(binary->left_expression) && idExpr && idExpr->name->asSimpleName() != 0) {
SimpleNameAST *nameAST = idExpr->name->asSimpleName();
const QList<LookupItem> results = state.context().lookup(nameAST->name, file.scopeAt(nameAST->firstToken()));
const QList<LookupItem> results = interface->context().lookup(nameAST->name, file.scopeAt(nameAST->firstToken()));
Declaration *decl = 0;
foreach (const LookupItem &r, results) {
if (! r.declaration())
@@ -1504,7 +1510,7 @@ public:
}
if (! decl) {
return singleResult(new Operation(state, index, binary));
return singleResult(new Operation(interface, index, binary));
}
}
}
@@ -1518,8 +1524,8 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, BinaryExpressionAST *binaryAST)
: CppQuickFixOperation(state, priority)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, BinaryExpressionAST *binaryAST)
: CppQuickFixOperation(interface, priority)
, binaryAST(binaryAST)
{
setDescription(QApplication::translate("CppTools::QuickFix", "Add Local Declaration"));
@@ -1528,7 +1534,8 @@ private:
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
{
TypeOfExpression typeOfExpression;
typeOfExpression.init(state().document(), state().snapshot(), state().context().bindings());
typeOfExpression.init(assistInterface()->semanticInfo().doc,
assistInterface()->snapshot(), assistInterface()->context().bindings());
const QList<LookupItem> result = typeOfExpression(currentFile->textOf(binaryAST->right_expression),
currentFile->scopeAt(binaryAST->firstToken()),
TypeOfExpression::Preprocess);
@@ -1536,12 +1543,12 @@ private:
if (! result.isEmpty()) {
SubstitutionEnvironment env;
env.setContext(state().context());
env.setContext(assistInterface()->context());
env.switchScope(result.first().scope());
UseQualifiedNames q;
env.enter(&q);
Control *control = state().context().control().data();
Control *control = assistInterface()->context().control().data();
FullySpecifiedType tn = rewriteType(result.first().type(), &env, control);
Overview oo;
@@ -1573,9 +1580,9 @@ private:
class ToCamelCaseConverter : public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
const QList<AST *> &path = state.path();
const QList<AST *> &path = interface->path();
if (path.isEmpty())
return noResult();
@@ -1597,7 +1604,7 @@ public:
return noResult();
for (int i = 1; i < newName.length() - 1; ++i) {
if (Operation::isConvertibleUnderscore(newName, i))
return singleResult(new Operation(state, path.size() - 1, newName));
return singleResult(new Operation(interface, path.size() - 1, newName));
}
return noResult();
@@ -1607,8 +1614,8 @@ private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority, const QString &newName)
: CppQuickFixOperation(state, priority)
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, const QString &newName)
: CppQuickFixOperation(interface, priority)
, m_name(newName)
{
setDescription(QApplication::translate("CppTools::QuickFix",
@@ -1627,7 +1634,7 @@ private:
m_name[i] = m_name.at(i).toUpper();
}
}
static_cast<CppEditor::Internal::CPPEditorWidget*>(state().editor())->renameUsagesNow(m_name);
static_cast<CppEditor::Internal::CPPEditorWidget*>(assistInterface()->editor())->renameUsagesNow(m_name);
}
static bool isConvertibleUnderscore(const QString &name, int pos)
@@ -1643,7 +1650,7 @@ private:
} // end of anonymous namespace
void CppQuickFixCollector::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
void registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
{
plugIn->addAutoReleasedObject(new UseInverseOp);
plugIn->addAutoReleasedObject(new FlipBinaryOp);
@@ -1657,11 +1664,11 @@ void CppQuickFixCollector::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
plugIn->addAutoReleasedObject(new TranslateStringLiteral);
plugIn->addAutoReleasedObject(new CStringToNSString);
plugIn->addAutoReleasedObject(new ConvertNumericLiteral);
plugIn->addAutoReleasedObject(new Internal::CompleteSwitchCaseStatement);
plugIn->addAutoReleasedObject(new CompleteSwitchCaseStatement);
plugIn->addAutoReleasedObject(new FixForwardDeclarationOp);
plugIn->addAutoReleasedObject(new AddLocalDeclarationOp);
plugIn->addAutoReleasedObject(new ToCamelCaseConverter);
plugIn->addAutoReleasedObject(new Internal::InsertQtPropertyMembers);
plugIn->addAutoReleasedObject(new Internal::DeclFromDef);
plugIn->addAutoReleasedObject(new Internal::DefFromDecl);
plugIn->addAutoReleasedObject(new InsertQtPropertyMembers);
plugIn->addAutoReleasedObject(new DeclFromDef);
plugIn->addAutoReleasedObject(new DefFromDecl);
}
-175
View File
@@ -1,175 +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 CPPCODECOMPLETION_H
#define CPPCODECOMPLETION_H
#include <ASTfwd.h>
#include <FullySpecifiedType.h>
#include <cplusplus/Icons.h>
#include <cplusplus/Overview.h>
#include <cplusplus/TypeOfExpression.h>
#include <texteditor/icompletioncollector.h>
#include <texteditor/snippets/snippetcollector.h>
#include <QtCore/QObject>
#include <QtCore/QPointer>
QT_BEGIN_NAMESPACE
class QTextCursor;
QT_END_NAMESPACE
namespace TextEditor {
class ITextEditor;
class BaseTextEditorWidget;
}
namespace CPlusPlus {
class LookupItem;
class ClassOrNamespace;
}
namespace CppTools {
namespace Internal {
class CppModelManager;
class FunctionArgumentWidget;
class CppCodeCompletion : public TextEditor::ICompletionCollector
{
Q_OBJECT
public:
explicit CppCodeCompletion(CppModelManager *manager);
void setObjcEnabled(bool objcEnabled)
{ m_objcEnabled = objcEnabled; }
TextEditor::ITextEditor *editor() const;
int startPosition() const;
bool shouldRestartCompletion();
QList<TextEditor::CompletionItem> getCompletions();
bool supportsEditor(TextEditor::ITextEditor *editor) const;
bool supportsPolicy(TextEditor::CompletionPolicy policy) const;
bool triggersCompletion(TextEditor::ITextEditor *editor);
int startCompletion(TextEditor::ITextEditor *editor);
void completions(QList<TextEditor::CompletionItem> *completions);
bool typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar);
void complete(const TextEditor::CompletionItem &item, QChar typedChar);
bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
void cleanup();
QIcon iconForSymbol(CPlusPlus::Symbol *symbol) const;
private:
void addSnippets();
void addKeywords();
void addMacros(const QString &fileName, const CPlusPlus::Snapshot &snapshot);
void addMacros_helper(const CPlusPlus::Snapshot &snapshot,
const QString &fileName,
QSet<QString> *processed,
QSet<QString> *definedMacros);
void addCompletionItem(CPlusPlus::Symbol *symbol);
bool completeInclude(const QTextCursor &cursor);
void completePreprocessor();
void globalCompletion(CPlusPlus::Scope *scope);
bool completeConstructorOrFunction(const QList<CPlusPlus::LookupItem> &results,
int endOfExpression, bool toolTipOnly);
bool completeMember(const QList<CPlusPlus::LookupItem> &results);
bool completeScope(const QList<CPlusPlus::LookupItem> &results);
void completeNamespace(CPlusPlus::ClassOrNamespace *binding);
void completeClass(CPlusPlus::ClassOrNamespace *b,
bool staticLookup = true);
bool completeConstructors(CPlusPlus::Class *klass);
bool completeQtMethod(const QList<CPlusPlus::LookupItem> &results,
bool wantSignals);
bool completeSignal(const QList<CPlusPlus::LookupItem> &results)
{ return completeQtMethod(results, true); }
bool completeSlot(const QList<CPlusPlus::LookupItem> &results)
{ return completeQtMethod(results, false); }
int findStartOfName(int pos = -1) const;
int startCompletionHelper(TextEditor::ITextEditor *editor);
int startCompletionInternal(TextEditor::BaseTextEditorWidget *edit,
const QString fileName,
unsigned line, unsigned column,
const QString &expression,
int endOfExpression);
QList<TextEditor::CompletionItem> removeDuplicates(const QList<TextEditor::CompletionItem> &items);
private:
void completeObjCMsgSend(CPlusPlus::ClassOrNamespace *binding,
bool staticClassAccess);
bool tryObjCCompletion(TextEditor::BaseTextEditorWidget *edit);
bool objcKeywordsWanted() const;
static QStringList preprocessorCompletions;
CppModelManager *m_manager;
TextEditor::ITextEditor *m_editor;
int m_startPosition; // Position of the cursor from which completion started
bool m_shouldRestartCompletion;
bool m_automaticCompletion;
unsigned m_completionOperator;
bool m_objcEnabled;
TextEditor::SnippetCollector m_snippetProvider;
CPlusPlus::Icons m_icons;
CPlusPlus::Overview overview;
CPlusPlus::TypeOfExpression typeOfExpression;
QPointer<FunctionArgumentWidget> m_functionArgumentWidget;
QList<TextEditor::CompletionItem> m_completions;
};
} // namespace Internal
} // namespace CppTools
Q_DECLARE_METATYPE(CPlusPlus::Symbol *)
#endif // CPPCODECOMPLETION_H
+172
View File
@@ -0,0 +1,172 @@
/**************************************************************************
**
** 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 CPPCOMPLETIONASSIST_H
#define CPPCOMPLETIONASSIST_H
#include <cplusplus/Icons.h>
#include <cplusplus/Overview.h>
#include <cplusplus/TypeOfExpression.h>
#include <cplusplus/CppDocument.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/QVariant>
QT_BEGIN_NAMESPACE
class QTextCursor;
QT_END_NAMESPACE
namespace CPlusPlus {
class LookupItem;
class ClassOrNamespace;
class Function;
class LookupContext;
}
namespace CppTools {
namespace Internal {
class CppCompletionAssistInterface;
class CppAssistProposalModel;
class CppCompletionAssistProvider : public TextEditor::CompletionAssistProvider
{
public:
virtual bool supportsEditor(const QString &editorId) const;
virtual int activationCharSequenceLength() const;
virtual bool isActivationCharSequence(const QString &sequence) const;
virtual TextEditor::IAssistProcessor *createProcessor() const;
};
class CppCompletionAssistProcessor : public TextEditor::IAssistProcessor
{
public:
CppCompletionAssistProcessor();
virtual ~CppCompletionAssistProcessor();
virtual TextEditor::IAssistProposal *perform(const TextEditor::IAssistInterface *interface);
private:
TextEditor::IAssistProposal *createContentProposal();
TextEditor::IAssistProposal *createHintProposal(QList<CPlusPlus::Function *> symbols) const;
bool accepts() const;
int startOfOperator(int pos, unsigned *kind, bool wantFunctionCall) const;
int findStartOfName(int pos = -1) const;
int startCompletionHelper();
bool tryObjCCompletion();
bool objcKeywordsWanted() const;
int startCompletionInternal(const QString fileName,
unsigned line, unsigned column,
const QString &expression,
int endOfExpression);
void completeObjCMsgSend(CPlusPlus::ClassOrNamespace *binding, bool staticClassAccess);
bool completeInclude(const QTextCursor &cursor);
void completePreprocessor();
bool completeConstructorOrFunction(const QList<CPlusPlus::LookupItem> &results,
int endOfExpression,
bool toolTipOnly);
bool completeMember(const QList<CPlusPlus::LookupItem> &results);
bool completeScope(const QList<CPlusPlus::LookupItem> &results);
void completeNamespace(CPlusPlus::ClassOrNamespace *binding);
void completeClass(CPlusPlus::ClassOrNamespace *b, bool staticLookup = true);
bool completeQtMethod(const QList<CPlusPlus::LookupItem> &results, bool wantSignals);
bool completeSignal(const QList<CPlusPlus::LookupItem> &results)
{ return completeQtMethod(results, true); }
bool completeSlot(const QList<CPlusPlus::LookupItem> &results)
{ return completeQtMethod(results, false); }
void globalCompletion(CPlusPlus::Scope *scope);
void addCompletionItem(const QString &text,
const QIcon &icon = QIcon(),
int order = 0,
const QVariant &data = QVariant());
void addCompletionItem(CPlusPlus::Symbol *symbol);
void addSnippets();
void addKeywords();
void addMacros(const QString &fileName, const CPlusPlus::Snapshot &snapshot);
void addMacros_helper(const CPlusPlus::Snapshot &snapshot,
const QString &fileName,
QSet<QString> *processed,
QSet<QString> *definedMacros);
int m_startPosition;
bool m_objcEnabled;
QScopedPointer<const CppCompletionAssistInterface> m_interface;
QList<TextEditor::BasicProposalItem *> m_completions;
TextEditor::SnippetAssistCollector m_snippetCollector;
const CppCompletionAssistProvider *m_provider;
CPlusPlus::Icons m_icons;
CPlusPlus::TypeOfExpression typeOfExpression;
QStringList preprocessorCompletions;
QScopedPointer<CppAssistProposalModel> m_model;
TextEditor::IAssistProposal *m_hintProposal;
};
class CppCompletionAssistInterface : public TextEditor::DefaultAssistInterface
{
public:
CppCompletionAssistInterface(QTextDocument *document,
int position,
Core::IFile *file,
TextEditor::AssistReason reason,
const CPlusPlus::Snapshot &snapshot,
const QStringList &includePaths,
const QStringList &frameworkPaths)
: TextEditor::DefaultAssistInterface(document, position, file, reason)
, m_snapshot(snapshot)
, m_includePaths(includePaths)
, m_frameworkPaths(frameworkPaths)
{}
const CPlusPlus::Snapshot &snapshot() const { return m_snapshot; }
const QStringList &includePaths() const { return m_includePaths; }
const QStringList &frameworkPaths() const { return m_frameworkPaths; }
private:
CPlusPlus::Snapshot m_snapshot;
QStringList m_includePaths;
QStringList m_frameworkPaths;
};
} // Internal
} // CppTools
Q_DECLARE_METATYPE(CPlusPlus::Symbol *)
#endif // CPPCOMPLETIONASSIST_H
+4 -4
View File
@@ -10,7 +10,6 @@ INCLUDEPATH += .
DEFINES += CPPTOOLS_LIBRARY
HEADERS += completionsettingspage.h \
cppclassesfilter.h \
cppcodecompletion.h \
cppcurrentdocumentfilter.h \
cppfunctionsfilter.h \
cppmodelmanager.h \
@@ -28,11 +27,11 @@ HEADERS += completionsettingspage.h \
uicodecompletionsupport.h \
insertionpointlocator.h \
cpprefactoringchanges.h \
abstracteditorsupport.h
abstracteditorsupport.h \
cppcompletionassist.h
SOURCES += completionsettingspage.cpp \
cppclassesfilter.cpp \
cppcodecompletion.cpp \
cppcurrentdocumentfilter.cpp \
cppfunctionsfilter.cpp \
cppmodelmanager.cpp \
@@ -48,7 +47,8 @@ SOURCES += completionsettingspage.cpp \
symbolsfindfilter.cpp \
uicodecompletionsupport.cpp \
insertionpointlocator.cpp \
cpprefactoringchanges.cpp
cpprefactoringchanges.cpp \
cppcompletionassist.cpp
FORMS += completionsettingspage.ui \
cppfilesettingspage.ui
+2 -10
View File
@@ -34,13 +34,13 @@
#include "completionsettingspage.h"
#include "cppfilesettingspage.h"
#include "cppclassesfilter.h"
#include "cppcodecompletion.h"
#include "cppfunctionsfilter.h"
#include "cppcurrentdocumentfilter.h"
#include "cppmodelmanager.h"
#include "cpptoolsconstants.h"
#include "cpplocatorfilter.h"
#include "symbolsfindfilter.h"
#include "cppcompletionassist.h"
#include <extensionsystem/pluginmanager.h>
@@ -113,9 +113,7 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
m_modelManager, SLOT(updateSourceFiles(QStringList)));
addAutoReleasedObject(m_modelManager);
CppCodeCompletion *completion = new CppCodeCompletion(m_modelManager);
addAutoReleasedObject(completion);
addAutoReleasedObject(new CppCompletionAssistProvider);
addAutoReleasedObject(new CppLocatorFilter(m_modelManager));
addAutoReleasedObject(new CppClassesFilter(m_modelManager));
addAutoReleasedObject(new CppFunctionsFilter(m_modelManager));
@@ -141,12 +139,6 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
mcpptools->addAction(command);
connect(switchAction, SIGNAL(triggered()), this, SLOT(switchHeaderSource()));
// 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)));
return true;
}
+117 -111
View File
@@ -57,12 +57,16 @@
#include <texteditor/basetextdocumentlayout.h>
#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
#include <texteditor/completionsupport.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/indenter.h>
#include <texteditor/icompletioncollector.h>
#include <texteditor/codeassist/basicproposalitem.h>
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <texteditor/codeassist/completionassistprovider.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/codeassist/iassistinterface.h>
#include <texteditor/codeassist/genericproposal.h>
#include <find/findplugin.h>
#include <find/textfindconstants.h>
@@ -581,58 +585,15 @@ void FakeVimUserCommandsPage::apply()
//
///////////////////////////////////////////////////////////////////////
class WordCompletion : public ICompletionCollector
class FakeVimCompletionAssistProvider : public TextEditor::CompletionAssistProvider
{
Q_OBJECT
public:
WordCompletion()
virtual bool supportsEditor(const QString &) const
{
m_editable = 0;
m_editor = 0;
}
virtual bool shouldRestartCompletion()
{
//qDebug() << "SHOULD RESTART COMPLETION?";
return false;
}
virtual ITextEditor *editor() const
{
//qDebug() << "NO EDITOR?";
return m_editable;
}
virtual int startPosition() const
{
return m_startPosition;
}
virtual bool supportsEditor(ITextEditor *) const
{
return true;
}
virtual bool supportsPolicy(CompletionPolicy policy) const
{
return policy == TextCompletion;
}
virtual bool triggersCompletion(ITextEditor *editable)
{
//qDebug() << "TRIGGERS?";
QTC_ASSERT(m_editable == editable, /**/);
return true;
}
virtual int startCompletion(ITextEditor *editable)
{
//qDebug() << "START COMPLETION";
QTC_ASSERT(m_editor, return -1);
QTC_ASSERT(m_editable == editable, return -1);
return m_editor->textCursor().position();
}
virtual TextEditor::IAssistProcessor *createProcessor() const;
void setActive(const QString &needle, bool forward, FakeVimHandler *handler)
{
@@ -640,96 +601,138 @@ public:
m_handler = handler;
if (!m_handler)
return;
m_editor = qobject_cast<BaseTextEditorWidget *>(handler->widget());
if (!m_editor)
BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(handler->widget());
if (!editor)
return;
//qDebug() << "ACTIVATE: " << needle << forward;
m_needle = needle;
m_editable = m_editor->editor();
m_startPosition = m_editor->textCursor().position() - needle.size();
CompletionSupport::instance()->complete(m_editable, TextCompletion, false);
editor->invokeAssist(Completion, this);
}
void setInactive()
{
m_needle.clear();
m_editable = 0;
m_editor = 0;
m_handler = 0;
m_startPosition = -1;
}
virtual void completions(QList<CompletionItem> *completions)
const QString &needle() const
{
QTC_ASSERT(m_editor, return);
QTC_ASSERT(completions, return);
QTextCursor tc = m_editor->textCursor();
return m_needle;
}
void appendNeedle(const QChar &c)
{
m_needle.append(c);
}
FakeVimHandler *handler() const
{
return m_handler;
}
private:
FakeVimHandler *m_handler;
QString m_needle;
};
class FakeVimAssistProposalItem : public BasicProposalItem
{
public:
FakeVimAssistProposalItem(const FakeVimCompletionAssistProvider *provider)
: m_provider(const_cast<FakeVimCompletionAssistProvider *>(provider))
{}
virtual bool implicitlyApplies() const
{
return false;
}
virtual bool prematurelyApplies(const QChar &c) const
{
m_provider->appendNeedle(c);
return text() == m_provider->needle();
}
virtual void applyContextualContent(BaseTextEditor *, int) const
{
QTC_ASSERT(m_provider->handler(), return);
m_provider->handler()->handleReplay(text().mid(m_provider->needle().size()));
const_cast<FakeVimCompletionAssistProvider *>(m_provider)->setInactive();
}
private:
FakeVimCompletionAssistProvider *m_provider;
};
class FakeVimAssistProposalModel : public BasicProposalItemListModel
{
public:
FakeVimAssistProposalModel(const QList<BasicProposalItem *> &items)
: BasicProposalItemListModel(items)
{}
virtual bool supportsPrefixExpansion() const
{
return false;
}
};
class FakeVimCompletionAssistProcessor : public IAssistProcessor
{
public:
FakeVimCompletionAssistProcessor(const TextEditor::IAssistProvider *provider)
: m_provider(static_cast<const FakeVimCompletionAssistProvider *>(provider))
{}
virtual TextEditor::IAssistProposal *perform(const IAssistInterface *interface)
{
const QString &needle = m_provider->needle();
const int basePosition = interface->position() - needle.size();
QTextCursor tc(interface->document());
tc.setPosition(interface->position());
tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
QList<BasicProposalItem *> items;
QSet<QString> seen;
QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
while (1) {
tc = tc.document()->find(m_needle, tc.position(), flags);
tc = tc.document()->find(needle, tc.position(), flags);
if (tc.isNull())
break;
QTextCursor sel = tc;
sel.select(QTextCursor::WordUnderCursor);
QString found = sel.selectedText();
// Only add "real" completions.
if (found.startsWith(m_needle)
if (found.startsWith(needle)
&& !seen.contains(found)
&& sel.anchor() != m_startPosition) {
&& sel.anchor() != basePosition) {
seen.insert(found);
CompletionItem item;
item.collector = this;
item.text = found;
completions->append(item);
BasicProposalItem *item = new FakeVimAssistProposalItem(m_provider);
item->setText(found);
items.append(item);
}
tc.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor);
}
//qDebug() << "COMPLETIONS" << completions->size();
}
virtual bool typedCharCompletes(const CompletionItem &item, QChar typedChar)
{
m_needle += typedChar;
//qDebug() << "COMPLETE? " << typedChar << item.text << m_needle;
return item.text == m_needle;
delete interface;
return new GenericProposal(basePosition, new FakeVimAssistProposalModel(items));
}
virtual void complete(const CompletionItem &item, QChar typedChar)
{
Q_UNUSED(typedChar);
//qDebug() << "COMPLETE: " << item.text;
QTC_ASSERT(m_handler, return);
m_handler->handleReplay(item.text.mid(m_needle.size()));
setInactive();
}
virtual bool partiallyComplete(const QList<CompletionItem> &completionItems)
{
//qDebug() << "PARTIALLY";
Q_UNUSED(completionItems);
return false;
}
virtual void cleanup() {}
private:
int findStartOfName(int pos = -1) const;
bool isInComment() const;
FakeVimHandler *m_handler;
BaseTextEditorWidget *m_editor;
ITextEditor *m_editable;
QString m_needle;
QString m_currentPrefix;
QList<CompletionItem> m_items;
int m_startPosition;
const FakeVimCompletionAssistProvider *m_provider;
};
IAssistProcessor *FakeVimCompletionAssistProvider::createProcessor() const
{
return new FakeVimCompletionAssistProcessor(this);
}
///////////////////////////////////////////////////////////////////////
//
@@ -822,7 +825,9 @@ private:
UserCommandMap m_defaultUserCommandMap;
Core::StatusBarWidget *m_statusBar;
WordCompletion *m_wordCompletion;
// @TODO: Delete
//WordCompletion *m_wordCompletion;
FakeVimCompletionAssistProvider *m_wordProvider;
};
QVariant FakeVimUserCommandsModel::data(const QModelIndex &index, int role) const
@@ -912,8 +917,10 @@ bool FakeVimPluginPrivate::initialize()
m_actionManager = core()->actionManager();
QTC_ASSERT(actionManager(), return false);
m_wordCompletion = new WordCompletion;
q->addAutoReleasedObject(m_wordCompletion);
//m_wordCompletion = new WordCompletion;
//q->addAutoReleasedObject(m_wordCompletion);
m_wordProvider = new FakeVimCompletionAssistProvider;
/*
// Set completion settings and keep them up to date.
TextEditorSettings *textEditorSettings = TextEditorSettings::instance();
@@ -1407,16 +1414,15 @@ void FakeVimPluginPrivate::triggerCompletions()
if (!handler)
return;
if (BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
CompletionSupport::instance()->
complete(editor->editor(), TextCompletion, false);
// editor->triggerCompletions();
editor->invokeAssist(Completion, m_wordProvider);
// CompletionSupport::instance()->complete(editor->editor(), TextCompletion, false);
}
void FakeVimPluginPrivate::triggerSimpleCompletions(const QString &needle,
bool forward)
{
m_wordCompletion->setActive(needle, forward,
qobject_cast<FakeVimHandler *>(sender()));
// m_wordCompletion->setActive(needle, forward, qobject_cast<FakeVimHandler *>(sender()));
m_wordProvider->setActive(needle, forward, qobject_cast<FakeVimHandler *>(sender()));
}
void FakeVimPluginPrivate::setBlockSelection(bool on)
@@ -1,731 +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.
**
**************************************************************************/
#include "glslcodecompletion.h"
#include "glsleditor.h"
#include "glsleditorplugin.h"
#include <glsl/glslengine.h>
#include <glsl/glslengine.h>
#include <glsl/glsllexer.h>
#include <glsl/glslparser.h>
#include <glsl/glslsemantic.h>
#include <glsl/glslsymbols.h>
#include <glsl/glslastdump.h>
#include <cplusplus/ExpressionUnderCursor.h>
#include <texteditor/completionsettings.h>
#include <utils/faketooltip.h>
#include <QtGui/QIcon>
#include <QtGui/QPainter>
#include <QtGui/QLabel>
#include <QtGui/QToolButton>
#include <QtGui/QHBoxLayout>
#include <QtGui/QApplication>
#include <QtGui/QDesktopWidget>
#include <QtCore/QDebug>
using namespace GLSLEditor;
using namespace GLSLEditor::Internal;
enum CompletionOrder {
SpecialMemberOrder = -5
};
static bool isIdentifierChar(QChar ch)
{
return ch.isLetterOrNumber() || ch == QLatin1Char('_');
}
static bool isDelimiter(QChar ch)
{
switch (ch.unicode()) {
case '{':
case '}':
case '[':
case ']':
case ')':
case '?':
case '!':
case ':':
case ';':
case ',':
case '+':
case '-':
case '*':
case '/':
return true;
default:
return false;
}
}
static bool checkStartOfIdentifier(const QString &word)
{
if (! word.isEmpty()) {
const QChar ch = word.at(0);
if (ch.isLetter() || ch == QLatin1Char('_'))
return true;
}
return false;
}
namespace GLSLEditor {
namespace Internal {
class FunctionArgumentWidget : public QLabel
{
Q_OBJECT
public:
FunctionArgumentWidget();
void showFunctionHint(QVector<GLSL::Function *> functionSymbols,
int startPosition);
protected:
bool eventFilter(QObject *obj, QEvent *e);
private slots:
void nextPage();
void previousPage();
private:
void updateArgumentHighlight();
void updateHintText();
void placeInsideScreen();
GLSL::Function *currentFunction() const
{ return m_items.at(m_current); }
int m_startpos;
int m_currentarg;
int m_current;
bool m_escapePressed;
TextEditor::ITextEditor *m_editor;
QWidget *m_pager;
QLabel *m_numberLabel;
Utils::FakeToolTip *m_popupFrame;
QVector<GLSL::Function *> m_items;
};
FunctionArgumentWidget::FunctionArgumentWidget():
m_startpos(-1),
m_current(0),
m_escapePressed(false)
{
QObject *editorObject = Core::EditorManager::instance()->currentEditor();
m_editor = qobject_cast<TextEditor::ITextEditor *>(editorObject);
m_popupFrame = new Utils::FakeToolTip(m_editor->widget());
QToolButton *downArrow = new QToolButton;
downArrow->setArrowType(Qt::DownArrow);
downArrow->setFixedSize(16, 16);
downArrow->setAutoRaise(true);
QToolButton *upArrow = new QToolButton;
upArrow->setArrowType(Qt::UpArrow);
upArrow->setFixedSize(16, 16);
upArrow->setAutoRaise(true);
setParent(m_popupFrame);
setFocusPolicy(Qt::NoFocus);
m_pager = new QWidget;
QHBoxLayout *hbox = new QHBoxLayout(m_pager);
hbox->setMargin(0);
hbox->setSpacing(0);
hbox->addWidget(upArrow);
m_numberLabel = new QLabel;
hbox->addWidget(m_numberLabel);
hbox->addWidget(downArrow);
QHBoxLayout *layout = new QHBoxLayout;
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(m_pager);
layout->addWidget(this);
m_popupFrame->setLayout(layout);
connect(upArrow, SIGNAL(clicked()), SLOT(previousPage()));
connect(downArrow, SIGNAL(clicked()), SLOT(nextPage()));
setTextFormat(Qt::RichText);
qApp->installEventFilter(this);
}
void FunctionArgumentWidget::showFunctionHint(QVector<GLSL::Function *> functionSymbols,
int startPosition)
{
Q_ASSERT(!functionSymbols.isEmpty());
if (m_startpos == startPosition)
return;
m_pager->setVisible(functionSymbols.size() > 1);
m_items = functionSymbols;
m_startpos = startPosition;
m_current = 0;
m_escapePressed = false;
// update the text
m_currentarg = -1;
updateArgumentHighlight();
m_popupFrame->show();
}
void FunctionArgumentWidget::nextPage()
{
m_current = (m_current + 1) % m_items.size();
updateHintText();
}
void FunctionArgumentWidget::previousPage()
{
if (m_current == 0)
m_current = m_items.size() - 1;
else
--m_current;
updateHintText();
}
void FunctionArgumentWidget::updateArgumentHighlight()
{
int curpos = m_editor->position();
if (curpos < m_startpos) {
m_popupFrame->close();
return;
}
const QByteArray str = m_editor->textAt(m_startpos, curpos - m_startpos).toLatin1();
int argnr = 0;
int parcount = 0;
GLSL::Lexer lexer(0, str.constData(), str.length());
GLSL::Token tk;
QList<GLSL::Token> tokens;
do {
lexer.yylex(&tk);
tokens.append(tk);
} while (tk.isNot(GLSL::Parser::EOF_SYMBOL));
for (int i = 0; i < tokens.count(); ++i) {
const GLSL::Token &tk = tokens.at(i);
if (tk.is(GLSL::Parser::T_LEFT_PAREN))
++parcount;
else if (tk.is(GLSL::Parser::T_RIGHT_PAREN))
--parcount;
else if (! parcount && tk.is(GLSL::Parser::T_COMMA))
++argnr;
}
if (m_currentarg != argnr) {
m_currentarg = argnr;
updateHintText();
}
if (parcount < 0)
m_popupFrame->close();
}
bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e)
{
switch (e->type()) {
case QEvent::ShortcutOverride:
if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
m_escapePressed = true;
}
break;
case QEvent::KeyPress:
if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
m_escapePressed = true;
}
if (m_items.size() > 1) {
QKeyEvent *ke = static_cast<QKeyEvent*>(e);
if (ke->key() == Qt::Key_Up) {
previousPage();
return true;
} else if (ke->key() == Qt::Key_Down) {
nextPage();
return true;
}
return false;
}
break;
case QEvent::KeyRelease:
if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && m_escapePressed) {
m_popupFrame->close();
return false;
}
updateArgumentHighlight();
break;
case QEvent::WindowDeactivate:
case QEvent::FocusOut:
if (obj != m_editor->widget())
break;
m_popupFrame->close();
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::Wheel: {
QWidget *widget = qobject_cast<QWidget *>(obj);
if (! (widget == this || m_popupFrame->isAncestorOf(widget))) {
m_popupFrame->close();
}
}
break;
default:
break;
}
return false;
}
void FunctionArgumentWidget::updateHintText()
{
setText(currentFunction()->prettyPrint(m_currentarg));
m_numberLabel->setText(tr("%1 of %2").arg(m_current + 1).arg(m_items.size()));
placeInsideScreen();
}
void FunctionArgumentWidget::placeInsideScreen()
{
const QDesktopWidget *desktop = QApplication::desktop();
#ifdef Q_WS_MAC
const QRect screen = desktop->availableGeometry(desktop->screenNumber(m_editor->widget()));
#else
const QRect screen = desktop->screenGeometry(desktop->screenNumber(m_editor->widget()));
#endif
m_pager->setFixedWidth(m_pager->minimumSizeHint().width());
setWordWrap(false);
const int maxDesiredWidth = screen.width() - 10;
const QSize minHint = m_popupFrame->minimumSizeHint();
if (minHint.width() > maxDesiredWidth) {
setWordWrap(true);
m_popupFrame->setFixedWidth(maxDesiredWidth);
const int extra =
m_popupFrame->contentsMargins().bottom() + m_popupFrame->contentsMargins().top();
m_popupFrame->setFixedHeight(heightForWidth(maxDesiredWidth - m_pager->width()) + extra);
} else {
m_popupFrame->setFixedSize(minHint);
}
const QSize sz = m_popupFrame->size();
QPoint pos = m_editor->cursorRect(m_startpos).topLeft();
pos.setY(pos.y() - sz.height() - 1);
if (pos.x() + sz.width() > screen.right())
pos.setX(screen.right() - sz.width());
m_popupFrame->move(pos);
}
} // Internal
} // GLSLEditor
CodeCompletion::CodeCompletion(QObject *parent)
: ICompletionCollector(parent),
m_editor(0),
m_startPosition(-1),
m_restartCompletion(false),
m_keywordVariant(-1),
m_keywordIcon(":/glsleditor/images/keyword.png"),
m_varIcon(":/glsleditor/images/var.png"),
m_functionIcon(":/glsleditor/images/func.png"),
m_typeIcon(":/glsleditor/images/type.png"),
m_constIcon(":/glsleditor/images/const.png"),
m_attributeIcon(":/glsleditor/images/attribute.png"),
m_uniformIcon(":/glsleditor/images/uniform.png"),
m_varyingIcon(":/glsleditor/images/varying.png"),
m_otherIcon(":/glsleditor/images/other.png")
{
}
CodeCompletion::~CodeCompletion()
{
}
TextEditor::ITextEditor *CodeCompletion::editor() const
{
return m_editor;
}
int CodeCompletion::startPosition() const
{
return m_startPosition;
}
bool CodeCompletion::supportsEditor(TextEditor::ITextEditor *editor) const
{
return qobject_cast<GLSLTextEditorWidget *>(editor->widget()) != 0;
}
bool CodeCompletion::supportsPolicy(TextEditor::CompletionPolicy policy) const
{
return policy == TextEditor::SemanticCompletion;
}
bool CodeCompletion::triggersCompletion(TextEditor::ITextEditor *editor)
{
const int cursorPosition = editor->position();
const QChar ch = editor->characterAt(cursorPosition - 1);
if (completionSettings().m_completionTrigger == TextEditor::AutomaticCompletion) {
const QChar characterUnderCursor = editor->characterAt(cursorPosition);
if (isIdentifierChar(ch) && (characterUnderCursor.isSpace() ||
characterUnderCursor.isNull() ||
isDelimiter(characterUnderCursor))) {
int pos = editor->position() - 1;
for (; pos != -1; --pos) {
if (! isIdentifierChar(editor->characterAt(pos)))
break;
}
++pos;
const QString word = editor->textAt(pos, cursorPosition - pos);
if (word.length() > 2 && checkStartOfIdentifier(word)) {
for (int i = 0; i < word.length(); ++i) {
if (! isIdentifierChar(word.at(i)))
return false;
}
return true;
}
}
}
if (ch == QLatin1Char('(') || ch == QLatin1Char('.') || ch == QLatin1Char(','))
return true;
return false;
}
int CodeCompletion::startCompletion(TextEditor::ITextEditor *editor)
{
m_editor = editor;
int pos = editor->position() - 1;
QChar ch = editor->characterAt(pos);
while (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
ch = editor->characterAt(--pos);
CPlusPlus::ExpressionUnderCursor expressionUnderCursor;
GLSLTextEditorWidget *edit = qobject_cast<GLSLTextEditorWidget *>(editor->widget());
QList<GLSL::Symbol *> members;
QStringList specialMembers;
bool functionCall = (ch == QLatin1Char('(') && pos == editor->position() - 1);
if (ch == QLatin1Char(',')) {
QTextCursor tc(edit->document());
tc.setPosition(pos);
const int start = expressionUnderCursor.startOfFunctionCall(tc);
if (start == -1)
return -1;
if (edit->characterAt(start) == QLatin1Char('(')) {
pos = start;
ch = QLatin1Char('(');
functionCall = true;
}
}
if (ch == QLatin1Char('.') || functionCall) {
const bool memberCompletion = ! functionCall;
QTextCursor tc(edit->document());
tc.setPosition(pos);
// get the expression under cursor
const QByteArray code = expressionUnderCursor(tc).toLatin1();
//qDebug() << endl << "expression:" << code;
// parse the expression
GLSL::Engine engine;
GLSL::Parser parser(&engine, code, code.size(), edit->languageVariant());
GLSL::ExpressionAST *expr = parser.parseExpression();
#if 0
// dump it!
QTextStream qout(stdout, QIODevice::WriteOnly);
GLSL::ASTDump dump(qout);
dump(expr);
#endif
if (Document::Ptr doc = edit->glslDocument()) {
GLSL::Scope *currentScope = doc->scopeAt(pos);
GLSL::Semantic sem;
GLSL::Semantic::ExprResult exprTy = sem.expression(expr, currentScope, doc->engine());
if (exprTy.type) {
if (memberCompletion) {
if (const GLSL::VectorType *vecTy = exprTy.type->asVectorType()) {
members = vecTy->members();
// Sort the most relevant swizzle orderings to the top.
specialMembers += QLatin1String("xy");
specialMembers += QLatin1String("xyz");
specialMembers += QLatin1String("xyzw");
specialMembers += QLatin1String("rgb");
specialMembers += QLatin1String("rgba");
specialMembers += QLatin1String("st");
specialMembers += QLatin1String("stp");
specialMembers += QLatin1String("stpq");
} else if (const GLSL::Struct *structTy = exprTy.type->asStructType()) {
members = structTy->members();
} else {
// some other type
}
} else { // function completion
QVector<GLSL::Function *> signatures;
if (const GLSL::Function *funTy = exprTy.type->asFunctionType())
signatures.append(const_cast<GLSL::Function *>(funTy)); // ### get rid of the const_cast
else if (const GLSL::OverloadSet *overload = exprTy.type->asOverloadSetType())
signatures = overload->functions();
if (! signatures.isEmpty()) {
// Recreate if necessary
if (!m_functionArgumentWidget)
m_functionArgumentWidget = new FunctionArgumentWidget;
m_functionArgumentWidget->showFunctionHint(signatures, pos + 1);
return false;
}
}
} else {
// undefined
}
} else {
// sorry, there's no document
}
} else {
// it's a global completion
if (Document::Ptr doc = edit->glslDocument()) {
GLSL::Scope *currentScope = doc->scopeAt(pos);
bool isGlobal = !currentScope || !currentScope->scope();
// add the members from the scope chain
for (; currentScope; currentScope = currentScope->scope())
members += currentScope->members();
// if this is the global scope, then add some standard Qt attribute
// and uniform names for autocompleting variable declarations
// this isn't a complete list, just the most common
if (isGlobal) {
static const char * const attributeNames[] = {
"qt_Vertex",
"qt_Normal",
"qt_MultiTexCoord0",
"qt_MultiTexCoord1",
"qt_MultiTexCoord2",
0
};
static const char * const uniformNames[] = {
"qt_ModelViewProjectionMatrix",
"qt_ModelViewMatrix",
"qt_ProjectionMatrix",
"qt_NormalMatrix",
"qt_Texture0",
"qt_Texture1",
"qt_Texture2",
"qt_Color",
"qt_Opacity",
0
};
for (int index = 0; attributeNames[index]; ++index) {
TextEditor::CompletionItem item(this);
item.text = QString::fromLatin1(attributeNames[index]);
item.icon = m_attributeIcon;
m_completions.append(item);
}
for (int index = 0; uniformNames[index]; ++index) {
TextEditor::CompletionItem item(this);
item.text = QString::fromLatin1(uniformNames[index]);
item.icon = m_uniformIcon;
m_completions.append(item);
}
}
}
if (m_keywordVariant != edit->languageVariant()) {
QStringList keywords = GLSL::Lexer::keywords(edit->languageVariant());
m_keywordCompletions.clear();
for (int index = 0; index < keywords.size(); ++index) {
TextEditor::CompletionItem item(this);
item.text = keywords.at(index);
item.icon = m_keywordIcon;
m_keywordCompletions.append(item);
}
m_keywordVariant = edit->languageVariant();
}
m_completions += m_keywordCompletions;
}
foreach (GLSL::Symbol *s, members) {
TextEditor::CompletionItem item(this);
GLSL::Variable *var = s->asVariable();
if (var) {
int storageType = var->qualifiers() & GLSL::QualifiedTypeAST::StorageMask;
if (storageType == GLSL::QualifiedTypeAST::Attribute)
item.icon = m_attributeIcon;
else if (storageType == GLSL::QualifiedTypeAST::Uniform)
item.icon = m_uniformIcon;
else if (storageType == GLSL::QualifiedTypeAST::Varying)
item.icon = m_varyingIcon;
else if (storageType == GLSL::QualifiedTypeAST::Const)
item.icon = m_constIcon;
else
item.icon = m_varIcon;
} else if (s->asArgument()) {
item.icon = m_varIcon;
} else if (s->asFunction() || s->asOverloadSet()) {
item.icon = m_functionIcon;
} else if (s->asStruct()) {
item.icon = m_typeIcon;
} else {
item.icon = m_otherIcon;
}
item.text = s->name();
if (specialMembers.contains(item.text))
item.order = SpecialMemberOrder;
m_completions.append(item);
}
m_startPosition = pos + 1;
return m_startPosition;
}
void CodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)
{
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);
filter(m_completions, completions, key);
if (completions->size() == 1) {
if (key == completions->first().text)
completions->clear();
}
}
}
bool CodeCompletion::typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar)
{
Q_UNUSED(item);
Q_UNUSED(typedChar);
return false;
}
void CodeCompletion::complete(const TextEditor::CompletionItem &item, QChar typedChar)
{
Q_UNUSED(typedChar);
QString toInsert = item.text;
const int length = m_editor->position() - m_startPosition;
m_editor->setCursorPosition(m_startPosition);
m_editor->replace(length, toInsert);
if (toInsert.endsWith(QLatin1Char('.')) || toInsert.endsWith(QLatin1Char('(')))
m_restartCompletion = true;
}
bool CodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)
{
return ICompletionCollector::partiallyComplete(completionItems);
}
bool CodeCompletion::glslCompletionItemLessThan(const TextEditor::CompletionItem &l, const TextEditor::CompletionItem &r)
{
if (l.order != r.order)
return l.order < r.order;
return completionItemLessThan(l, r);
}
QList<TextEditor::CompletionItem> CodeCompletion::getCompletions()
{
QList<TextEditor::CompletionItem> completionItems;
completions(&completionItems);
qStableSort(completionItems.begin(), completionItems.end(), glslCompletionItemLessThan);
// Remove duplicates
QString lastKey;
QVariant lastData;
QList<TextEditor::CompletionItem> uniquelist;
foreach (const TextEditor::CompletionItem &item, completionItems) {
if (item.text != lastKey || item.data.type() != lastData.type()) {
uniquelist.append(item);
lastKey = item.text;
lastData = item.data;
}
}
return uniquelist;
}
bool CodeCompletion::shouldRestartCompletion()
{
return m_restartCompletion;
}
void CodeCompletion::cleanup()
{
m_editor = 0;
m_completions.clear();
m_restartCompletion = false;
m_startPosition = -1;
}
#include "glslcodecompletion.moc"
-134
View File
@@ -1,134 +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 GLSLCODECOMPLETION_H
#define GLSLCODECOMPLETION_H
#include <texteditor/icompletioncollector.h>
#include <QtCore/QPointer>
namespace GLSLEditor {
namespace Internal {
class FunctionArgumentWidget;
class CodeCompletion: public TextEditor::ICompletionCollector
{
Q_OBJECT
public:
CodeCompletion(QObject *parent = 0);
virtual ~CodeCompletion();
/* Returns the current active ITextEditor */
virtual TextEditor::ITextEditor *editor() const;
virtual int startPosition() const;
/*
* Returns true if this completion collector can be used with the given editor.
*/
virtual bool supportsEditor(TextEditor::ITextEditor *editor) const;
/*
* Returns true if this completion collector supports the given completion policy.
*/
virtual bool supportsPolicy(TextEditor::CompletionPolicy policy) const;
/* This method should return whether the cursor is at a position which could
* trigger an autocomplete. It will be called each time a character is typed in
* the text editor.
*/
virtual bool triggersCompletion(TextEditor::ITextEditor *editor);
// returns starting position
virtual int startCompletion(TextEditor::ITextEditor *editor);
/* This method should add all the completions it wants to show into the list,
* based on the given cursor position.
*/
virtual void completions(QList<TextEditor::CompletionItem> *completions);
/**
* This method should return true when the given typed character should cause
* the selected completion item to be completed.
*/
virtual bool typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar);
/**
* This method should complete the given completion item.
*
* \param typedChar Non-null when completion was triggered by typing a
* character. Possible values depend on typedCharCompletes()
*/
virtual void complete(const TextEditor::CompletionItem &item, QChar typedChar);
/* This method gives the completion collector a chance to partially complete
* based on a set of items. The general use case is to complete the common
* prefix shared by all possible completion items.
*
* Returns whether the completion popup should be closed.
*/
virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
virtual QList<TextEditor::CompletionItem> getCompletions();
virtual bool shouldRestartCompletion();
/* Called when it's safe to clean up the completion items.
*/
virtual void cleanup();
private:
QList<TextEditor::CompletionItem> m_completions;
QList<TextEditor::CompletionItem> m_keywordCompletions;
TextEditor::ITextEditor *m_editor;
int m_startPosition;
bool m_restartCompletion;
QPointer<FunctionArgumentWidget> m_functionArgumentWidget;
static bool glslCompletionItemLessThan(const TextEditor::CompletionItem &l, const TextEditor::CompletionItem &r);
int m_keywordVariant;
QIcon m_keywordIcon;
QIcon m_varIcon;
QIcon m_functionIcon;
QIcon m_typeIcon;
QIcon m_constIcon;
QIcon m_attributeIcon;
QIcon m_uniformIcon;
QIcon m_varyingIcon;
QIcon m_otherIcon;
};
} // namespace Internal
} // namespace GLSLEditor
#endif // GLSLCODECOMPLETION_H
@@ -0,0 +1,478 @@
/**************************************************************************
**
** 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 "glslcompletionassist.h"
#include "glsleditorconstants.h"
#include "glsleditorplugin.h"
#include "reuse.h"
#include <glsl/glslengine.h>
#include <glsl/glslengine.h>
#include <glsl/glsllexer.h>
#include <glsl/glslparser.h>
#include <glsl/glslsemantic.h>
#include <glsl/glslsymbols.h>
#include <glsl/glslastdump.h>
#include <coreplugin/ifile.h>
#include <texteditor/completionsettings.h>
#include <texteditor/codeassist/basicproposalitem.h>
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <texteditor/codeassist/genericproposal.h>
#include <texteditor/codeassist/functionhintproposal.h>
#include <cplusplus/ExpressionUnderCursor.h>
#include <utils/faketooltip.h>
#include <QtGui/QIcon>
#include <QtGui/QPainter>
#include <QtGui/QLabel>
#include <QtGui/QToolButton>
#include <QtGui/QHBoxLayout>
#include <QtGui/QApplication>
#include <QtGui/QDesktopWidget>
#include <QtCore/QDebug>
using namespace GLSLEditor;
using namespace Internal;
using namespace TextEditor;
namespace {
enum CompletionOrder {
SpecialMemberOrder = -5
};
bool isActivationChar(const QChar &ch)
{
return ch == QLatin1Char('(') || ch == QLatin1Char('.') || ch == QLatin1Char(',');
}
bool isIdentifierChar(QChar ch)
{
return ch.isLetterOrNumber() || ch == QLatin1Char('_');
}
bool isDelimiter(QChar ch)
{
switch (ch.unicode()) {
case '{':
case '}':
case '[':
case ']':
case ')':
case '?':
case '!':
case ':':
case ';':
case ',':
case '+':
case '-':
case '*':
case '/':
return true;
default:
return false;
}
}
bool checkStartOfIdentifier(const QString &word)
{
if (! word.isEmpty()) {
const QChar ch = word.at(0);
if (ch.isLetter() || ch == QLatin1Char('_'))
return true;
}
return false;
}
} // Anonymous
// ----------------------------
// GLSLCompletionAssistProvider
// ----------------------------
bool GLSLCompletionAssistProvider::supportsEditor(const QString &editorId) const
{
return editorId == QLatin1String(Constants::C_GLSLEDITOR_ID);
}
IAssistProcessor *GLSLCompletionAssistProvider::createProcessor() const
{
return new GLSLCompletionAssistProcessor;
}
int GLSLCompletionAssistProvider::activationCharSequenceLength() const
{
return 1;
}
bool GLSLCompletionAssistProvider::isActivationCharSequence(const QString &sequence) const
{
return isActivationChar(sequence.at(0));
}
// -----------------------------
// GLSLFunctionHintProposalModel
// -----------------------------
class GLSLFunctionHintProposalModel : public TextEditor::IFunctionHintProposalModel
{
public:
GLSLFunctionHintProposalModel(QVector<GLSL::Function *> functionSymbols)
: m_items(functionSymbols)
, m_currentArg(-1)
{}
virtual void reset() {}
virtual int size() const { return m_items.size(); }
virtual QString text(int index) const;
virtual int activeArgument(const QString &prefix) const;
private:
QVector<GLSL::Function *> m_items;
mutable int m_currentArg;
};
QString GLSLFunctionHintProposalModel::text(int index) const
{
return m_items.at(index)->prettyPrint(m_currentArg);
}
int GLSLFunctionHintProposalModel::activeArgument(const QString &prefix) const
{
const QByteArray &str = prefix.toLatin1();
int argnr = 0;
int parcount = 0;
GLSL::Lexer lexer(0, str.constData(), str.length());
GLSL::Token tk;
QList<GLSL::Token> tokens;
do {
lexer.yylex(&tk);
tokens.append(tk);
} while (tk.isNot(GLSL::Parser::EOF_SYMBOL));
for (int i = 0; i < tokens.count(); ++i) {
const GLSL::Token &tk = tokens.at(i);
if (tk.is(GLSL::Parser::T_LEFT_PAREN))
++parcount;
else if (tk.is(GLSL::Parser::T_RIGHT_PAREN))
--parcount;
else if (! parcount && tk.is(GLSL::Parser::T_COMMA))
++argnr;
}
if (parcount < 0)
return -1;
if (argnr != m_currentArg)
m_currentArg = argnr;
return argnr;
}
// -----------------------------
// GLSLCompletionAssistProcessor
// -----------------------------
GLSLCompletionAssistProcessor::GLSLCompletionAssistProcessor()
: m_startPosition(0)
, m_keywordIcon(":/glsleditor/images/keyword.png")
, m_varIcon(":/glsleditor/images/var.png")
, m_functionIcon(":/glsleditor/images/func.png")
, m_typeIcon(":/glsleditor/images/type.png")
, m_constIcon(":/glsleditor/images/const.png")
, m_attributeIcon(":/glsleditor/images/attribute.png")
, m_uniformIcon(":/glsleditor/images/uniform.png")
, m_varyingIcon(":/glsleditor/images/varying.png")
, m_otherIcon(":/glsleditor/images/other.png")
{}
GLSLCompletionAssistProcessor::~GLSLCompletionAssistProcessor()
{}
IAssistProposal *GLSLCompletionAssistProcessor::perform(const IAssistInterface *interface)
{
m_interface.reset(static_cast<const GLSLCompletionAssistInterface *>(interface));
if (interface->reason() == IdleEditor && !acceptsIdleEditor())
return 0;
int pos = m_interface->position() - 1;
QChar ch = m_interface->characterAt(pos);
while (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
ch = m_interface->characterAt(--pos);
CPlusPlus::ExpressionUnderCursor expressionUnderCursor;
//GLSLTextEditorWidget *edit = qobject_cast<GLSLTextEditorWidget *>(editor->widget());
QList<GLSL::Symbol *> members;
QStringList specialMembers;
bool functionCall = (ch == QLatin1Char('(') && pos == m_interface->position() - 1);
if (ch == QLatin1Char(',')) {
QTextCursor tc(m_interface->document());
tc.setPosition(pos);
const int start = expressionUnderCursor.startOfFunctionCall(tc);
if (start == -1)
return 0;
if (m_interface->characterAt(start) == QLatin1Char('(')) {
pos = start;
ch = QLatin1Char('(');
functionCall = true;
}
}
if (ch == QLatin1Char('.') || functionCall) {
const bool memberCompletion = ! functionCall;
QTextCursor tc(m_interface->document());
tc.setPosition(pos);
// get the expression under cursor
const QByteArray code = expressionUnderCursor(tc).toLatin1();
//qDebug() << endl << "expression:" << code;
// parse the expression
GLSL::Engine engine;
GLSL::Parser parser(&engine, code, code.size(), languageVariant(m_interface->mimeType()));
GLSL::ExpressionAST *expr = parser.parseExpression();
#if 0
// dump it!
QTextStream qout(stdout, QIODevice::WriteOnly);
GLSL::ASTDump dump(qout);
dump(expr);
#endif
if (Document::Ptr doc = m_interface->glslDocument()) {
GLSL::Scope *currentScope = doc->scopeAt(pos);
GLSL::Semantic sem;
GLSL::Semantic::ExprResult exprTy = sem.expression(expr, currentScope, doc->engine());
if (exprTy.type) {
if (memberCompletion) {
if (const GLSL::VectorType *vecTy = exprTy.type->asVectorType()) {
members = vecTy->members();
// Sort the most relevant swizzle orderings to the top.
specialMembers += QLatin1String("xy");
specialMembers += QLatin1String("xyz");
specialMembers += QLatin1String("xyzw");
specialMembers += QLatin1String("rgb");
specialMembers += QLatin1String("rgba");
specialMembers += QLatin1String("st");
specialMembers += QLatin1String("stp");
specialMembers += QLatin1String("stpq");
} else if (const GLSL::Struct *structTy = exprTy.type->asStructType()) {
members = structTy->members();
} else {
// some other type
}
} else { // function completion
QVector<GLSL::Function *> signatures;
if (const GLSL::Function *funTy = exprTy.type->asFunctionType())
signatures.append(const_cast<GLSL::Function *>(funTy)); // ### get rid of the const_cast
else if (const GLSL::OverloadSet *overload = exprTy.type->asOverloadSetType())
signatures = overload->functions();
if (! signatures.isEmpty()) {
m_startPosition = pos + 1;
return createHintProposal(signatures);
}
}
} else {
// undefined
}
} else {
// sorry, there's no document
}
} else {
// it's a global completion
if (Document::Ptr doc = m_interface->glslDocument()) {
GLSL::Scope *currentScope = doc->scopeAt(pos);
bool isGlobal = !currentScope || !currentScope->scope();
// add the members from the scope chain
for (; currentScope; currentScope = currentScope->scope())
members += currentScope->members();
// if this is the global scope, then add some standard Qt attribute
// and uniform names for autocompleting variable declarations
// this isn't a complete list, just the most common
if (isGlobal) {
static const char * const attributeNames[] = {
"qt_Vertex",
"qt_Normal",
"qt_MultiTexCoord0",
"qt_MultiTexCoord1",
"qt_MultiTexCoord2",
0
};
static const char * const uniformNames[] = {
"qt_ModelViewProjectionMatrix",
"qt_ModelViewMatrix",
"qt_ProjectionMatrix",
"qt_NormalMatrix",
"qt_Texture0",
"qt_Texture1",
"qt_Texture2",
"qt_Color",
"qt_Opacity",
0
};
for (int index = 0; attributeNames[index]; ++index)
addCompletion(QString::fromLatin1(attributeNames[index]), m_attributeIcon);
for (int index = 0; uniformNames[index]; ++index)
addCompletion(QString::fromLatin1(uniformNames[index]), m_uniformIcon);
}
}
// if (m_keywordVariant != languageVariant(m_interface->mimeType())) {
QStringList keywords = GLSL::Lexer::keywords(languageVariant(m_interface->mimeType()));
// m_keywordCompletions.clear();
for (int index = 0; index < keywords.size(); ++index)
addCompletion(keywords.at(index), m_keywordIcon);
// m_keywordVariant = languageVariant(m_interface->mimeType());
// }
// m_completions += m_keywordCompletions;
}
foreach (GLSL::Symbol *s, members) {
QIcon icon;
GLSL::Variable *var = s->asVariable();
if (var) {
int storageType = var->qualifiers() & GLSL::QualifiedTypeAST::StorageMask;
if (storageType == GLSL::QualifiedTypeAST::Attribute)
icon = m_attributeIcon;
else if (storageType == GLSL::QualifiedTypeAST::Uniform)
icon = m_uniformIcon;
else if (storageType == GLSL::QualifiedTypeAST::Varying)
icon = m_varyingIcon;
else if (storageType == GLSL::QualifiedTypeAST::Const)
icon = m_constIcon;
else
icon = m_varIcon;
} else if (s->asArgument()) {
icon = m_varIcon;
} else if (s->asFunction() || s->asOverloadSet()) {
icon = m_functionIcon;
} else if (s->asStruct()) {
icon = m_typeIcon;
} else {
icon = m_otherIcon;
}
if (specialMembers.contains(s->name()))
addCompletion(s->name(), icon, SpecialMemberOrder);
else
addCompletion(s->name(), icon);
}
m_startPosition = pos + 1;
return createContentProposal();
}
IAssistProposal *GLSLCompletionAssistProcessor::createContentProposal() const
{
IGenericProposalModel *model = new BasicProposalItemListModel(m_completions);
IAssistProposal *proposal = new GenericProposal(m_startPosition, model);
return proposal;
}
IAssistProposal *GLSLCompletionAssistProcessor::createHintProposal(
const QVector<GLSL::Function *> &symbols)
{
IFunctionHintProposalModel *model = new GLSLFunctionHintProposalModel(symbols);
IAssistProposal *proposal = new FunctionHintProposal(m_startPosition, model);
return proposal;
}
bool GLSLCompletionAssistProcessor::acceptsIdleEditor() const
{
const int cursorPosition = m_interface->position();
const QChar ch = m_interface->characterAt(cursorPosition - 1);
const QChar characterUnderCursor = m_interface->characterAt(cursorPosition);
if (isIdentifierChar(ch) && (characterUnderCursor.isSpace() ||
characterUnderCursor.isNull() ||
isDelimiter(characterUnderCursor))) {
int pos = m_interface->position() - 1;
for (; pos != -1; --pos) {
if (! isIdentifierChar(m_interface->characterAt(pos)))
break;
}
++pos;
const QString word = m_interface->textAt(pos, cursorPosition - pos);
if (word.length() > 2 && checkStartOfIdentifier(word)) {
for (int i = 0; i < word.length(); ++i) {
if (! isIdentifierChar(word.at(i)))
return false;
}
return true;
}
}
return isActivationChar(ch);
}
void GLSLCompletionAssistProcessor::addCompletion(const QString &text,
const QIcon &icon,
int order)
{
BasicProposalItem *item = new BasicProposalItem;
item->setText(text);
item->setIcon(icon);
item->setOrder(order);
m_completions.append(item);
}
// -----------------------------
// GLSLCompletionAssistInterface
// -----------------------------
GLSLCompletionAssistInterface::GLSLCompletionAssistInterface(QTextDocument *document,
int position,
Core::IFile *file,
TextEditor::AssistReason reason,
const QString &mimeType,
const Document::Ptr &glslDoc)
: DefaultAssistInterface(document, position, file, reason)
, m_mimeType(mimeType)
, m_glslDoc(glslDoc)
{
}
@@ -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.
**
**************************************************************************/
#ifndef GLSLCOMPLETIONASSIST_H
#define GLSLCOMPLETIONASSIST_H
#include "glsleditor.h"
#include <texteditor/codeassist/completionassistprovider.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <texteditor/codeassist/defaultassistinterface.h>
#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
#include <QtCore/QScopedPointer>
#include <QtGui/QIcon>
namespace TextEditor {
class BasicProposalItem;
}
namespace GLSLEditor {
namespace Internal {
class GLSLCompletionAssistInterface;
class GLSLCompletionAssistProvider : 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;
};
class GLSLCompletionAssistProcessor : public TextEditor::IAssistProcessor
{
public:
GLSLCompletionAssistProcessor();
virtual ~GLSLCompletionAssistProcessor();
virtual TextEditor::IAssistProposal *perform(const TextEditor::IAssistInterface *interface);
private:
TextEditor::IAssistProposal *createContentProposal() const;
TextEditor::IAssistProposal *createHintProposal(const QVector<GLSL::Function *> &symbols);
bool acceptsIdleEditor() const;
void addCompletion(const QString &text, const QIcon &icon, int order = 0);
int m_startPosition;
QScopedPointer<const GLSLCompletionAssistInterface> m_interface;
QList<TextEditor::BasicProposalItem *> m_completions;
QIcon m_keywordIcon;
QIcon m_varIcon;
QIcon m_functionIcon;
QIcon m_typeIcon;
QIcon m_constIcon;
QIcon m_attributeIcon;
QIcon m_uniformIcon;
QIcon m_varyingIcon;
QIcon m_otherIcon;
};
class GLSLCompletionAssistInterface : public TextEditor::DefaultAssistInterface
{
public:
GLSLCompletionAssistInterface(QTextDocument *document,
int position,
Core::IFile *file,
TextEditor::AssistReason reason,
const QString &mimeType,
const Document::Ptr &glslDoc);
const QString &mimeType() const { return m_mimeType; }
const Document::Ptr &glslDocument() const { return m_glslDoc; }
private:
QString m_mimeType;
Document::Ptr m_glslDoc;
};
} // Internal
} // GLSLEditor
#endif // GLSLCOMPLETIONASSIST_H
+15
View File
@@ -37,6 +37,7 @@
#include "glslhighlighter.h"
#include "glslautocompleter.h"
#include "glslindenter.h"
#include "glslcompletionassist.h"
#include <glsl/glsllexer.h>
#include <glsl/glslparser.h>
@@ -412,3 +413,17 @@ Document::Ptr GLSLTextEditorWidget::glslDocument() const
{
return m_glslDocument;
}
TextEditor::IAssistInterface *GLSLTextEditorWidget::createAssistInterface(
TextEditor::AssistKind kind,
TextEditor::AssistReason reason) const
{
if (kind == TextEditor::Completion)
return new GLSLCompletionAssistInterface(document(),
position(),
editor()->file(),
reason,
mimeType(),
glslDocument());
return BaseTextEditorWidget::createAssistInterface(kind, reason);
}
+3
View File
@@ -104,6 +104,9 @@ public:
Document::Ptr glslDocument() const;
TextEditor::IAssistInterface *createAssistInterface(TextEditor::AssistKind assistKind,
TextEditor::AssistReason reason) const;
public slots:
virtual void setFontSettings(const TextEditor::FontSettings &);
+6 -4
View File
@@ -17,10 +17,11 @@ glsleditorfactory.h \
glsleditorplugin.h \
glslfilewizard.h \
glslhighlighter.h \
glslcodecompletion.h \
glslautocompleter.h \
glslindenter.h \
glslhoverhandler.h
glslhoverhandler.h \
glslcompletionassist.h \
reuse.h
SOURCES += \
glsleditor.cpp \
@@ -30,10 +31,11 @@ glsleditorfactory.cpp \
glsleditorplugin.cpp \
glslfilewizard.cpp \
glslhighlighter.cpp \
glslcodecompletion.cpp \
glslautocompleter.cpp \
glslindenter.cpp \
glslhoverhandler.cpp
glslhoverhandler.cpp \
glslcompletionassist.cpp \
reuse.cpp
OTHER_FILES += GLSLEditor.mimetypes.xml
RESOURCES += glsleditor.qrc
+2 -10
View File
@@ -34,9 +34,9 @@
#include "glsleditor.h"
#include "glsleditorconstants.h"
#include "glsleditorfactory.h"
#include "glslcodecompletion.h"
#include "glslfilewizard.h"
#include "glslhoverhandler.h"
#include "glslcompletionassist.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
@@ -55,7 +55,6 @@
#include <texteditor/texteditorsettings.h>
#include <texteditor/textfilewizard.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/completionsupport.h>
#include <utils/qtcassert.h>
#include <glsl/glslengine.h>
@@ -132,8 +131,7 @@ bool GLSLEditorPlugin::initialize(const QStringList & /*arguments*/, QString *er
m_editor = new GLSLEditorFactory(this);
addObject(m_editor);
CodeCompletion *completion = new CodeCompletion(this);
addAutoReleasedObject(completion);
addAutoReleasedObject(new GLSLCompletionAssistProvider);
m_actionHandler = new TextEditor::TextEditorActionHandler(GLSLEditor::Constants::C_GLSLEDITOR_ID,
TextEditor::TextEditorActionHandler::Format
@@ -164,12 +162,6 @@ bool GLSLEditorPlugin::initialize(const QStringList & /*arguments*/, QString *er
cmd = am->command(TextEditor::Constants::UN_COMMENT_SELECTION);
contextMenu->addAction(cmd);
// 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();
+83
View File
@@ -0,0 +1,83 @@
/**************************************************************************
**
** 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 "reuse.h"
#include <QtCore/QLatin1String>
#include <glsl/glsllexer.h>
using namespace GLSL;
namespace GLSLEditor {
namespace Internal {
int languageVariant(const QString &mimeType)
{
int variant = 0;
bool isVertex = false;
bool isFragment = false;
bool isDesktop = false;
if (mimeType.isEmpty()) {
// ### Before file has been opened, so don't know the mime type.
isVertex = true;
isFragment = true;
} else if (mimeType == QLatin1String("text/x-glsl") ||
mimeType == QLatin1String("application/x-glsl")) {
isVertex = true;
isFragment = true;
isDesktop = true;
} else if (mimeType == QLatin1String("text/x-glsl-vert")) {
isVertex = true;
isDesktop = true;
} else if (mimeType == QLatin1String("text/x-glsl-frag")) {
isFragment = true;
isDesktop = true;
} else if (mimeType == QLatin1String("text/x-glsl-es-vert")) {
isVertex = true;
} else if (mimeType == QLatin1String("text/x-glsl-es-frag")) {
isFragment = true;
}
if (isDesktop)
variant |= Lexer::Variant_GLSL_120;
else
variant |= Lexer::Variant_GLSL_ES_100;
if (isVertex)
variant |= Lexer::Variant_VertexShader;
if (isFragment)
variant |= Lexer::Variant_FragmentShader;
return variant;
}
} // Internal
} // GLSLEditor
+46
View File
@@ -0,0 +1,46 @@
/**************************************************************************
**
** 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 REUSE_H
#define REUSE_H
#include <QtCore/QtGlobal>
namespace GLSLEditor {
namespace Internal {
int languageVariant(const QString &mimeType);
} // Internal
} // GLSLEditor
#endif // REUSE_H
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
@@ -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());
}
@@ -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
+38 -10
View File
@@ -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,21 +1351,30 @@ 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);
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;
}
+3
View File
@@ -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();
+10 -6
View File
@@ -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
+12 -49
View File
@@ -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)
+3 -6
View File
@@ -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
+13 -82
View File
@@ -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(&current, &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;
}
+14 -61
View File
@@ -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
@@ -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;
}
@@ -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
+10 -7
View File
@@ -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
View 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
View 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
@@ -1,224 +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.
**
**************************************************************************/
#include "profilecompletion.h"
#include "profileeditor.h"
#include "profilekeywords.h"
#include <texteditor/itexteditor.h>
#include <texteditor/completionsettings.h>
#include <cplusplus/Icons.h>
#include <QtCore/QDebug>
using namespace Qt4ProjectManager::Internal;
ProFileCompletion::ProFileCompletion(QObject *parent) :
TextEditor::ICompletionCollector(parent),
m_editor(0),
m_startPosition(-1),
m_variableIcon(CPlusPlus::Icons().iconForType(CPlusPlus::Icons::VarPublicIconType)),
m_functionIcon(CPlusPlus::Icons().iconForType(CPlusPlus::Icons::FuncPublicIconType))
{
}
ProFileCompletion::~ProFileCompletion()
{
}
QList<TextEditor::CompletionItem> ProFileCompletion::getCompletions()
{
QList<TextEditor::CompletionItem> completionItems;
completions(&completionItems);
return completionItems;
}
bool ProFileCompletion::shouldRestartCompletion()
{
return false;
}
TextEditor::ITextEditor *ProFileCompletion::editor() const
{
return m_editor;
}
int ProFileCompletion::startPosition() const
{
return m_startPosition;
}
bool ProFileCompletion::supportsEditor(TextEditor::ITextEditor *editor) const
{
return qobject_cast<ProFileEditor *>(editor) != 0;
}
bool ProFileCompletion::supportsPolicy(TextEditor::CompletionPolicy policy) const
{
return policy == TextEditor::SemanticCompletion;
}
bool ProFileCompletion::triggersCompletion(TextEditor::ITextEditor *editor)
{
m_editor = editor;
const int pos = editor->position();
if (completionSettings().m_completionTrigger == TextEditor::AutomaticCompletion) {
QChar characterUnderCursor = editor->characterAt(pos);
if (!characterUnderCursor.isLetterOrNumber()) {
m_startPosition = findStartOfName();
if (pos - m_startPosition >= 3 && !isInComment())
return true;
}
}
return false;
}
int ProFileCompletion::findStartOfName(int pos) const
{
if (pos == -1)
pos = m_editor->position();
QChar chr;
// Skip to the start of a name
do {
chr = m_editor->characterAt(--pos);
} while (chr.isLetterOrNumber() || chr == QLatin1Char('_'));
return pos + 1;
}
bool ProFileCompletion::isInComment() const
{
const int beginOfLinePosition = m_editor->position(TextEditor::ITextEditor::StartOfLine);
const QString lineBeginning = m_editor->textAt(beginOfLinePosition,
m_startPosition - beginOfLinePosition);
if (lineBeginning.contains(QLatin1Char('#')))
return true;
return false;
}
int ProFileCompletion::startCompletion(TextEditor::ITextEditor *editor)
{
m_editor = editor;
m_startPosition = findStartOfName();
return m_startPosition;
}
void ProFileCompletion::completions(QList<TextEditor::CompletionItem> *completions)
{
const int length = m_editor->position() - m_startPosition;
if (length < 0)
return;
if (isInComment())
return;
const QString key = m_editor->textAt(m_startPosition, length);
QList<TextEditor::CompletionItem> items;
QStringList keywords = ProFileKeywords::variables()
+ ProFileKeywords::functions();
// qSort(keywords);
for (int i = 0; i < keywords.count(); i++) {
TextEditor::CompletionItem item(this);
item.text = keywords[i];
item.data = QVariant::fromValue(item.text);
item.icon = ProFileKeywords::isFunction(item.text)
? m_functionIcon : m_variableIcon;
items.append(item);
}
filter(items, completions, key);
}
bool ProFileCompletion::typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar)
{
// only '(' in case of a function
if (typedChar == QLatin1Char('(') && ProFileKeywords::isFunction(item.text))
return true;
return false;
}
void ProFileCompletion::complete(const TextEditor::CompletionItem &item, QChar typedChar)
{
Q_UNUSED(typedChar)
int replaceLength = m_editor->position() - m_startPosition;
if (replaceLength < 0)
return;
QString toInsert = item.text;
int cursorOffset = 0;
if (ProFileKeywords::isFunction(toInsert)
&& completionSettings().m_autoInsertBrackets) {
if (completionSettings().m_spaceAfterFunctionName) {
if (m_editor->textAt(m_editor->position(), 2) == QLatin1String(" (")) {
cursorOffset = 2;
} else if (m_editor->characterAt(m_editor->position()) == QLatin1Char('(')
|| m_editor->characterAt(m_editor->position()) == QLatin1Char(' ')) {
replaceLength += 1;
toInsert += QLatin1String(" (");
} else {
toInsert += QLatin1String(" ()");
cursorOffset = -1;
}
} else {
if (m_editor->characterAt(m_editor->position()) == QLatin1Char('(')) {
cursorOffset = 1;
} else {
toInsert += QLatin1String("()");
cursorOffset = -1;
}
}
}
m_editor->setCursorPosition(m_startPosition);
m_editor->replace(replaceLength, toInsert);
if (cursorOffset)
m_editor->setCursorPosition(m_editor->position() + cursorOffset);
}
bool ProFileCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)
{
if (completionItems.count() == 1) {
complete(completionItems.first(), QChar());
return true;
}
return TextEditor::ICompletionCollector::partiallyComplete(completionItems);
}
void ProFileCompletion::cleanup()
{
}
@@ -1,78 +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 PROFILECOMPLETION_H
#define PROFILECOMPLETION_H
#include <texteditor/icompletioncollector.h>
namespace Qt4ProjectManager {
namespace Internal {
class ProFileCompletion : public TextEditor::ICompletionCollector
{
Q_OBJECT
public:
ProFileCompletion(QObject *parent = 0);
virtual ~ProFileCompletion();
virtual QList<TextEditor::CompletionItem> getCompletions();
virtual bool shouldRestartCompletion();
virtual TextEditor::ITextEditor *editor() const;
virtual int startPosition() const;
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 void cleanup();
private:
int findStartOfName(int pos = -1) const;
bool isInComment() const;
TextEditor::ITextEditor *m_editor;
int m_startPosition;
const QIcon m_variableIcon;
const QIcon m_functionIcon;
};
} // namespace Internal
} // namespace Qt4ProjectManager
#endif // PROFILECOMPLETION_H
@@ -0,0 +1,231 @@
/**************************************************************************
**
** 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 "profilecompletionassist.h"
#include "qt4projectmanagerconstants.h"
#include "profilekeywords.h"
#include <texteditor/codeassist/iassistinterface.h>
#include <texteditor/codeassist/genericproposal.h>
#include <texteditor/completionsettings.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/basetexteditor.h>
#include <cplusplus/Icons.h>
#include <QtGui/QTextCursor>
using namespace Qt4ProjectManager::Internal;
using namespace TextEditor;
// -------------------------
// ProFileAssistProposalItem
// -------------------------
ProFileAssistProposalItem::ProFileAssistProposalItem()
{}
ProFileAssistProposalItem::~ProFileAssistProposalItem()
{}
bool ProFileAssistProposalItem::prematurelyApplies(const QChar &c) const
{
// only '(' in case of a function
if (c == QLatin1Char('(') && ProFileKeywords::isFunction(text()))
return true;
return false;
}
void ProFileAssistProposalItem::applyContextualContent(TextEditor::BaseTextEditor *editor,
int basePosition) const
{
const CompletionSettings &settings = TextEditorSettings::instance()->completionSettings();
int replaceLength = editor->position() - basePosition;
QString toInsert = text();
int cursorOffset = 0;
if (ProFileKeywords::isFunction(toInsert) && settings.m_autoInsertBrackets) {
if (settings.m_spaceAfterFunctionName) {
if (editor->textAt(editor->position(), 2) == QLatin1String(" (")) {
cursorOffset = 2;
} else if (editor->characterAt(editor->position()) == QLatin1Char('(')
|| editor->characterAt(editor->position()) == QLatin1Char(' ')) {
replaceLength += 1;
toInsert += QLatin1String(" (");
} else {
toInsert += QLatin1String(" ()");
cursorOffset = -1;
}
} else {
if (editor->characterAt(editor->position()) == QLatin1Char('(')) {
cursorOffset = 1;
} else {
toInsert += QLatin1String("()");
cursorOffset = -1;
}
}
}
editor->setCursorPosition(basePosition);
editor->replace(replaceLength, toInsert);
if (cursorOffset)
editor->setCursorPosition(editor->position() + cursorOffset);
}
// -------------------------------
// ProFileCompletionAssistProvider
// -------------------------------
ProFileCompletionAssistProvider::ProFileCompletionAssistProvider()
{}
ProFileCompletionAssistProvider::~ProFileCompletionAssistProvider()
{}
bool ProFileCompletionAssistProvider::supportsEditor(const QString &editorId) const
{
return editorId == QLatin1String(Qt4ProjectManager::Constants::PROFILE_EDITOR_ID);
}
bool ProFileCompletionAssistProvider::isAsynchronous() const
{
return false;
}
int ProFileCompletionAssistProvider::activationCharSequenceLength() const
{
return 0;
}
bool ProFileCompletionAssistProvider::isActivationCharSequence(const QString &sequence) const
{
Q_UNUSED(sequence);
return false;
}
bool ProFileCompletionAssistProvider::isContinuationChar(const QChar &c) const
{
return c.isLetterOrNumber() || c == QLatin1Char('_');
}
IAssistProcessor *ProFileCompletionAssistProvider::createProcessor() const
{
return new ProFileCompletionAssistProcessor;
}
// --------------------------------
// ProFileCompletionAssistProcessor
// --------------------------------
ProFileCompletionAssistProcessor::ProFileCompletionAssistProcessor()
: m_startPosition(-1)
, m_variableIcon(CPlusPlus::Icons().iconForType(CPlusPlus::Icons::VarPublicIconType))
, m_functionIcon(CPlusPlus::Icons().iconForType(CPlusPlus::Icons::FuncPublicIconType))
{}
ProFileCompletionAssistProcessor::~ProFileCompletionAssistProcessor()
{}
IAssistProposal *ProFileCompletionAssistProcessor::perform(const IAssistInterface *interface)
{
m_interface.reset(interface);
if (isInComment())
return 0;
if (interface->reason() == IdleEditor && !acceptsIdleEditor())
return 0;
if (m_startPosition == -1)
m_startPosition = findStartOfName();
QList<TextEditor::BasicProposalItem *> items;
QStringList keywords = ProFileKeywords::variables() + ProFileKeywords::functions();
for (int i = 0; i < keywords.count(); i++) {
BasicProposalItem *item = new ProFileAssistProposalItem;
item->setText(keywords[i]);
item->setIcon(ProFileKeywords::isFunction(item->text()) ? m_functionIcon : m_variableIcon);
items.append(item);
}
return new GenericProposal(m_startPosition, new ProFileAssistProposalModel(items));
}
bool ProFileCompletionAssistProcessor::acceptsIdleEditor()
{
const int pos = m_interface->position();
QChar characterUnderCursor = m_interface->characterAt(pos);
if (!characterUnderCursor.isLetterOrNumber()) {
m_startPosition = findStartOfName();
if (pos - m_startPosition >= 3 && !isInComment())
return true;
}
return false;
}
int ProFileCompletionAssistProcessor::findStartOfName(int pos) const
{
if (pos == -1)
pos = m_interface->position();
QChar chr;
// Skip to the start of a name
do {
chr = m_interface->characterAt(--pos);
} while (chr.isLetterOrNumber() || chr == QLatin1Char('_'));
return pos + 1;
}
bool ProFileCompletionAssistProcessor::isInComment() const
{
QTextCursor tc(m_interface->document());
tc.setPosition(m_interface->position());
tc.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
const QString &lineBeginning = tc.selectedText();
if (lineBeginning.contains(QLatin1Char('#')))
return true;
return false;
}
// --------------------------
// ProFileAssistProposalModel
// --------------------------
ProFileAssistProposalModel::ProFileAssistProposalModel(
const QList<BasicProposalItem *> &items)
: BasicProposalItemListModel(items)
{}
ProFileAssistProposalModel::~ProFileAssistProposalModel()
{}
bool ProFileAssistProposalModel::isSortable() const
{
return false;
}
@@ -0,0 +1,106 @@
/**************************************************************************
**
** 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 PROFILECOMPLETIONASSIST_H
#define PROFILECOMPLETIONASSIST_H
#include <texteditor/codeassist/basicproposalitem.h>
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <texteditor/codeassist/completionassistprovider.h>
#include <texteditor/codeassist/iassistprocessor.h>
#include <QtGui/QIcon>
namespace Qt4ProjectManager {
namespace Internal {
class ProFileAssistProposalItem : public TextEditor::BasicProposalItem
{
public:
ProFileAssistProposalItem();
virtual ~ProFileAssistProposalItem();
virtual bool prematurelyApplies(const QChar &c) const;
virtual void applyContextualContent(TextEditor::BaseTextEditor *editor,
int basePosition) const;
};
class ProFileCompletionAssistProvider : public TextEditor::CompletionAssistProvider
{
public:
ProFileCompletionAssistProvider();
virtual ~ProFileCompletionAssistProvider();
virtual bool supportsEditor(const QString &editorId) const;
virtual TextEditor::IAssistProcessor *createProcessor() const;
virtual bool isAsynchronous() const;
virtual int activationCharSequenceLength() const;
virtual bool isActivationCharSequence(const QString &sequence) const;
virtual bool isContinuationChar(const QChar &c) const;
};
class ProFileCompletionAssistProcessor : public TextEditor::IAssistProcessor
{
public:
ProFileCompletionAssistProcessor();
virtual ~ProFileCompletionAssistProcessor();
virtual TextEditor::IAssistProposal *perform(const TextEditor::IAssistInterface *interface);
private:
bool acceptsIdleEditor();
int findStartOfName(int pos = -1) const;
bool isInComment() const;
int m_startPosition;
QScopedPointer<const TextEditor::IAssistInterface> m_interface;
const QIcon m_variableIcon;
const QIcon m_functionIcon;
};
class ProFileAssistProposalModel : public TextEditor::BasicProposalItemListModel
{
public:
ProFileAssistProposalModel(const QList<TextEditor::BasicProposalItem *> &items);
virtual ~ProFileAssistProposalModel();
virtual bool isSortable() const;
};
} // Internal
} // Qt4ProjectManager
#endif // PROFILECOMPLETIONASSIST_H
@@ -40,7 +40,6 @@
#include <coreplugin/editormanager/editormanager.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/completionsupport.h>
#include <QtCore/QFileInfo>
#include <QtGui/QAction>
@@ -69,7 +69,6 @@ HEADERS += \
qmldumptool.h \
qmlobservertool.h \
qmldebugginglibrary.h \
profilecompletion.h \
profilekeywords.h \
debugginghelperbuildtask.h \
qt4targetsetupwidget.h \
@@ -78,7 +77,8 @@ HEADERS += \
qtversionfactory.h \
winceqtversionfactory.h \
baseqtversion.h \
winceqtversion.h
winceqtversion.h \
profilecompletionassist.h
SOURCES += qt4projectmanagerplugin.cpp \
qtparser.cpp \
@@ -142,13 +142,14 @@ SOURCES += qt4projectmanagerplugin.cpp \
qmldumptool.cpp \
qmlobservertool.cpp \
qmldebugginglibrary.cpp \
profilecompletion.cpp \
profilekeywords.cpp \
debugginghelperbuildtask.cpp \
qtversionfactory.cpp \
winceqtversionfactory.cpp \
baseqtversion.cpp \
winceqtversion.cpp
winceqtversion.cpp \
profilecompletionassist.cpp
FORMS += makestep.ui \
qmakestep.ui \
qt4projectconfigwidget.ui \
@@ -54,7 +54,7 @@
#include "qtoptionspage.h"
#include "externaleditors.h"
#include "gettingstartedwelcomepage.h"
#include "profilecompletion.h"
#include "profilecompletionassist.h"
#include "qt-maemo/maemomanager.h"
#include "qt-s60/s60manager.h"
@@ -180,13 +180,7 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString *
addAutoReleasedObject(new SimulatorQtVersionFactory);
addAutoReleasedObject(new WinCeQtVersionFactory);
ProFileCompletion *completion = new ProFileCompletion;
addAutoReleasedObject(completion);
// 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)));
addAutoReleasedObject(new ProFileCompletionAssistProvider);
// TODO reenable
//m_embeddedPropertiesPage = new EmbeddedPropertiesPage;
+36 -72
View File
@@ -38,7 +38,6 @@
#include "behaviorsettings.h"
#include "codecselector.h"
#include "completionsettings.h"
#include "completionsupport.h"
#include "tabsettings.h"
#include "texteditorconstants.h"
#include "texteditorplugin.h"
@@ -48,6 +47,9 @@
#include "indenter.h"
#include "autocompleter.h"
#include "snippet.h"
#include "codeassistant.h"
#include "defaultassistinterface.h"
#include "convenience.h"
#include <aggregation/aggregate.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -236,11 +238,6 @@ BaseTextEditorWidget::BaseTextEditorWidget(QWidget *parent)
d->m_highlightBlocksTimer->setSingleShot(true);
connect(d->m_highlightBlocksTimer, SIGNAL(timeout()), this, SLOT(_q_highlightBlocks()));
d->m_requestAutoCompletionTimer = new QTimer(this);
d->m_requestAutoCompletionTimer->setSingleShot(true);
d->m_requestAutoCompletionTimer->setInterval(500);
connect(d->m_requestAutoCompletionTimer, SIGNAL(timeout()), this, SLOT(_q_requestAutoCompletion()));
d->m_animator = 0;
d->m_searchResultFormat.setBackground(QColor(0xffef0b));
@@ -490,7 +487,8 @@ ITextMarkable *BaseTextEditorWidget::markableInterface() const
BaseTextEditor *BaseTextEditorWidget::editor() const
{
if (!d->m_editor) {
d->m_editor = const_cast<BaseTextEditorWidget*>(this)->createEditor();
d->m_editor = const_cast<BaseTextEditorWidget *>(this)->createEditor();
d->m_codeAssistant->configure(d->m_editor);
connect(this, SIGNAL(textChanged()),
d->m_editor, SIGNAL(contentsChanged()));
connect(this, SIGNAL(changed()),
@@ -668,6 +666,9 @@ void BaseTextEditorWidget::editorContentsChange(int position, int charsRemoved,
if (doc->isRedoAvailable())
emit editor()->contentsChangedBecauseOfUndo();
if (charsAdded != 0 && characterAt(position + charsAdded - 1).isPrint())
d->m_assistRelevantContentAdded = true;
}
void BaseTextEditorWidget::slotSelectionChanged()
@@ -1535,9 +1536,7 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
if (!ro
&& (e == QKeySequence::InsertParagraphSeparator
|| (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))
) {
|| (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))) {
if (d->m_snippetOverlay->isVisible()) {
e->accept();
d->m_snippetOverlay->hide();
@@ -1548,7 +1547,6 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
return;
}
QTextCursor cursor = textCursor();
if (d->m_inBlockSelectionMode)
cursor.clearSelection();
@@ -1702,7 +1700,8 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
case Qt::Key_Right:
case Qt::Key_Left:
#ifndef Q_WS_MAC
if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) {
if ((e->modifiers()
& (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) {
int diff_row = 0;
int diff_col = 0;
if (e->key() == Qt::Key_Up)
@@ -1833,39 +1832,8 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
if (!ro && e->key() == Qt::Key_Delete && d->m_parenthesesMatchingEnabled)
d->m_parenthesesMatchingTimer->start(50);
if (!ro && d->m_contentsChanged && !e->text().isEmpty() && e->text().at(0).isPrint()) {
maybeRequestAutoCompletion(e->text().at(0));
}
}
void BaseTextEditorWidget::maybeRequestAutoCompletion(const QChar &ch)
{
if (ch.isLetterOrNumber() || ch == QLatin1Char('_')) {
if (CompletionSupport::instance()->isActive())
d->m_requestAutoCompletionTimer->stop();
else {
d->m_requestAutoCompletionRevision = document()->revision();
d->m_requestAutoCompletionPosition = position();
d->m_requestAutoCompletionTimer->start();
}
} else {
d->m_requestAutoCompletionTimer->stop();
CompletionSupport::instance()->complete(editor(), SemanticCompletion, false);
}
}
void BaseTextEditorWidget::_q_requestAutoCompletion()
{
d->m_requestAutoCompletionTimer->stop();
if (CompletionSupport::instance()->isActive())
return;
if (d->m_requestAutoCompletionRevision == document()->revision()
&& d->m_requestAutoCompletionPosition == position())
CompletionSupport::instance()->complete(editor(), SemanticCompletion, false);
if (!ro && d->m_contentsChanged && !e->text().isEmpty() && e->text().at(0).isPrint())
d->m_codeAssistant->process();
}
void BaseTextEditorWidget::insertCodeSnippet(const QTextCursor &cursor_arg, const QString &snippet)
@@ -2025,14 +1993,7 @@ int BaseTextEditorWidget::position(ITextEditor::PositionOperation posOp, int at)
void BaseTextEditorWidget::convertPosition(int pos, int *line, int *column) const
{
QTextBlock block = document()->findBlock(pos);
if (!block.isValid()) {
(*line) = -1;
(*column) = -1;
} else {
(*line) = block.blockNumber() + 1;
(*column) = pos - block.position();
}
Convenience::convertPosition(document(), pos, line, column);
}
QChar BaseTextEditorWidget::characterAt(int pos) const
@@ -2087,6 +2048,7 @@ BaseTextDocument *BaseTextEditorWidget::baseTextDocument() const
return d->m_document;
}
void BaseTextEditorWidget::setBaseTextDocument(BaseTextDocument *doc)
{
if (doc) {
@@ -2403,9 +2365,8 @@ BaseTextEditorPrivate::BaseTextEditorPrivate()
m_findScopeVerticalBlockSelectionFirstColumn(-1),
m_findScopeVerticalBlockSelectionLastColumn(-1),
m_highlightBlocksTimer(0),
m_requestAutoCompletionRevision(0),
m_requestAutoCompletionPosition(0),
m_requestAutoCompletionTimer(0),
m_codeAssistant(new CodeAssistant),
m_assistRelevantContentAdded(false),
m_cursorBlockNumber(-1),
m_autoCompleter(new AutoCompleter),
m_indenter(new Indenter)
@@ -3787,6 +3748,7 @@ void BaseTextEditorWidget::extraAreaPaintEvent(QPaintEvent *e)
const QString &number = QString::number(blockNumber + 1);
bool selected = (
(selStart < block.position() + block.length()
&& selEnd > block.position())
|| (selStart == selEnd && selStart == block.position())
);
@@ -3961,6 +3923,7 @@ void BaseTextEditorWidget::slotCursorPositionChanged()
} else if (d->m_contentsChanged) {
saveCurrentCursorPositionForNavigation();
}
updateHighlights();
}
@@ -5650,8 +5613,8 @@ void BaseTextEditorWidget::insertFromMimeData(const QMimeData *source)
if (text.isEmpty())
return;
if (CompletionSupport::instance()->isActive())
setFocus();
if (d->m_codeAssistant->hasContext())
d->m_codeAssistant->destroyContext();
QStringList lines = text.split(QLatin1Char('\n'));
QTextCursor cursor = textCursor();
@@ -5696,8 +5659,8 @@ void BaseTextEditorWidget::insertFromMimeData(const QMimeData *source)
if (text.isEmpty())
return;
if (CompletionSupport::instance()->isActive())
setFocus();
if (d->m_codeAssistant->hasContext())
d->m_codeAssistant->destroyContext();
if (d->m_snippetOverlay->isVisible() && (text.contains(QLatin1Char('\n'))
|| text.contains(QLatin1Char('\t')))) {
@@ -5882,18 +5845,7 @@ QString BaseTextEditor::selectedText() const
QString BaseTextEditor::textAt(int pos, int length) const
{
QTextCursor c = e->textCursor();
if (pos < 0)
pos = 0;
c.movePosition(QTextCursor::End);
if (pos + length > c.position())
length = c.position() - pos;
c.setPosition(pos);
c.setPosition(pos + length, QTextCursor::KeepAnchor);
return c.selectedText();
return Convenience::textAt(e->textCursor(), pos, length);
}
void BaseTextEditor::remove(int length)
@@ -6166,3 +6118,15 @@ void BaseTextEditorWidget::inSnippetMode(bool *active)
{
*active = d->m_snippetOverlay->isVisible();
}
void BaseTextEditorWidget::invokeAssist(AssistKind kind, IAssistProvider *provider)
{
d->m_codeAssistant->invoke(kind, provider);
}
IAssistInterface *BaseTextEditorWidget::createAssistInterface(AssistKind kind,
AssistReason reason) const
{
Q_UNUSED(kind);
return new DefaultAssistInterface(document(), position(), d->m_document, reason);
}
+9 -5
View File
@@ -34,7 +34,7 @@
#define BASETEXTEDITOR_H
#include "itexteditor.h"
#include "icompletioncollector.h"
#include "codeassist/assistenums.h"
#include <find/ifindsupport.h>
@@ -56,6 +56,9 @@ namespace TextEditor {
class TabSettings;
class RefactorOverlay;
struct RefactorMarker;
class IAssistMonitorInterface;
class IAssistInterface;
class IAssistProvider;
namespace Internal {
class BaseTextEditorPrivate;
@@ -235,6 +238,11 @@ public:
QPoint toolTipPosition(const QTextCursor &c) const;
void invokeAssist(AssistKind assistKind, IAssistProvider *provider = 0);
virtual IAssistInterface *createAssistInterface(AssistKind assistKind,
AssistReason assistReason) const;
public slots:
void setDisplayName(const QString &title);
@@ -492,7 +500,6 @@ signals:
void requestBlockUpdate(const QTextBlock &);
private:
void maybeRequestAutoCompletion(const QChar &ch);
void indentOrUnindent(bool doIndent);
void handleHomeKey(bool anchor);
void handleBackspaceKey();
@@ -531,9 +538,6 @@ private:
void transformSelection(Internal::TransformationMethod method);
private slots:
// auto completion
void _q_requestAutoCompletion();
void handleBlockSelection(int diff_row, int diff_col);
// parentheses matcher
+3 -3
View File
@@ -54,6 +54,7 @@ namespace TextEditor {
class BaseTextDocument;
class TextEditorActionHandler;
class CodeAssistant;
namespace Internal {
@@ -288,9 +289,8 @@ public:
BaseTextEditorPrivateHighlightBlocks m_highlightBlocksInfo;
QTimer *m_highlightBlocksTimer;
int m_requestAutoCompletionRevision;
int m_requestAutoCompletionPosition;
QTimer *m_requestAutoCompletionTimer;
QScopedPointer<CodeAssistant> m_codeAssistant;
bool m_assistRelevantContentAdded;
QPointer<BaseTextEditorAnimator> m_animator;
int m_cursorBlockNumber;
@@ -0,0 +1,53 @@
/**************************************************************************
**
** 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 ASSISTENUMS_H
#define ASSISTENUMS_H
namespace TextEditor {
enum AssistKind
{
Completion,
QuickFix
};
enum AssistReason
{
IdleEditor,
ActivationCharacter,
ExplicitlyInvoked
};
} // TextEditor
#endif // ASSISTENUMS_H
@@ -0,0 +1,142 @@
/**************************************************************************
**
** 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 "basicproposalitem.h"
#include <texteditor/basetexteditor.h>
#include <texteditor/quickfix.h>
#include <QtGui/QTextCursor>
using namespace TextEditor;
BasicProposalItem::BasicProposalItem()
: m_order(0)
{}
BasicProposalItem::~BasicProposalItem()
{}
void BasicProposalItem::setIcon(const QIcon &icon)
{
m_icon = icon;
}
const QIcon &BasicProposalItem::icon() const
{
return m_icon;
}
void BasicProposalItem::setText(const QString &text)
{
m_text = text;
}
const QString &BasicProposalItem::text() const
{
return m_text;
}
void BasicProposalItem::setDetail(const QString &detail)
{
m_detail = detail;
}
const QString &BasicProposalItem::detail() const
{
return m_detail;
}
void BasicProposalItem::setData(const QVariant &var)
{
m_data = var;
}
const QVariant &BasicProposalItem::data() const
{
return m_data;
}
int BasicProposalItem::order() const
{
return m_order;
}
void BasicProposalItem::setOrder(int order)
{
m_order = order;
}
bool BasicProposalItem::implicitlyApplies() const
{
return !data().canConvert<QString>() && !data().canConvert<QuickFixOperation::Ptr>();
}
bool BasicProposalItem::prematurelyApplies(const QChar &c) const
{
Q_UNUSED(c);
return false;
}
void BasicProposalItem::apply(BaseTextEditor *editor, int basePosition) const
{
if (data().canConvert<QString>())
applySnippet(editor, basePosition);
else if (data().canConvert<QuickFixOperation::Ptr>())
applyQuickFix(editor, basePosition);
else
applyContextualContent(editor, basePosition);
}
void BasicProposalItem::applyContextualContent(BaseTextEditor *editor, int basePosition) const
{
const int currentPosition = editor->position();
editor->setCursorPosition(basePosition);
editor->replace(currentPosition - basePosition, text());
}
void BasicProposalItem::applySnippet(BaseTextEditor *editor, int basePosition) const
{
BaseTextEditorWidget *editorWidget = static_cast<BaseTextEditorWidget *>(editor->widget());
QTextCursor tc = editorWidget->textCursor();
tc.setPosition(basePosition, QTextCursor::KeepAnchor);
editorWidget->insertCodeSnippet(tc, data().toString());
}
void BasicProposalItem::applyQuickFix(BaseTextEditor *editor, int basePosition) const
{
Q_UNUSED(editor)
Q_UNUSED(basePosition)
QuickFixOperation::Ptr op = data().value<QuickFixOperation::Ptr>();
op->perform();
}
@@ -0,0 +1,83 @@
/**************************************************************************
**
** 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 BASICPROPOSALITEM_H
#define BASICPROPOSALITEM_H
#include "iassistproposalitem.h"
#include <texteditor/texteditor_global.h>
#include <QtCore/QVariant>
#include <QtGui/QIcon>
namespace TextEditor {
class TEXTEDITOR_EXPORT BasicProposalItem : public IAssistProposalItem
{
public:
BasicProposalItem();
virtual ~BasicProposalItem();
void setIcon(const QIcon &icon);
const QIcon &icon() const;
void setText(const QString &text);
const QString &text() const;
void setDetail(const QString &detail);
const QString &detail() const;
void setData(const QVariant &var);
const QVariant &data() const;
int order() const;
void setOrder(int order);
virtual bool implicitlyApplies() const;
virtual bool prematurelyApplies(const QChar &c) const;
virtual void apply(BaseTextEditor *editor, int basePosition) const;
virtual void applyContextualContent(BaseTextEditor *editor, int basePosition) const;
virtual void applySnippet(BaseTextEditor *editor, int basePosition) const;
virtual void applyQuickFix(BaseTextEditor *editor, int basePosition) const;
private:
QIcon m_icon;
QString m_text;
QString m_detail;
QVariant m_data;
int m_order;
};
} // TextEditor
#endif // BASICPROPOSALITEM_H
@@ -0,0 +1,267 @@
/**************************************************************************
**
** 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 "basicproposalitemlistmodel.h"
#include "basicproposalitem.h"
#include "texteditorsettings.h"
#include "completionsettings.h"
#include <QtCore/QDebug>
#include <QtCore/QRegExp>
#include <QtCore/QtAlgorithms>
#include <QtCore/QHash>
#include <algorithm>
using namespace TextEditor;
uint qHash(const BasicProposalItem &item)
{
return qHash(item.text());
}
namespace {
const int kMaxSort = 1000;
const int kMaxPrefixFilter = 100;
struct ContentLessThan
{
bool operator()(const BasicProposalItem *a, const BasicProposalItem *b)
{
// The order is case-insensitive in principle, but case-sensitive when this
// would otherwise mean equality
const QString &lowera = a->text().toLower();
const QString &lowerb = b->text().toLower();
if (lowera == lowerb)
return lessThan(a->text(), b->text());
else
return lessThan(lowera, lowerb);
}
bool lessThan(const QString &a, const QString &b)
{
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), CharLessThan());
}
struct CharLessThan
{
bool operator()(const QChar &a, const QChar &b)
{
if (a == QLatin1Char('_'))
return false;
else if (b == QLatin1Char('_'))
return true;
else
return a < b;
}
};
};
} // Anonymous
BasicProposalItemListModel::BasicProposalItemListModel()
{}
BasicProposalItemListModel::BasicProposalItemListModel(const QList<BasicProposalItem *> &items)
: m_originalItems(items)
, m_currentItems(items)
{
mapPersistentIds();
}
BasicProposalItemListModel::~BasicProposalItemListModel()
{
qDeleteAll(m_originalItems);
}
void BasicProposalItemListModel::loadContent(const QList<BasicProposalItem *> &items)
{
m_originalItems = items;
m_currentItems = items;
mapPersistentIds();
}
void BasicProposalItemListModel::mapPersistentIds()
{
for (int i = 0; i < m_originalItems.size(); ++i)
m_idByText.insert(m_originalItems.at(i)->text(), i);
}
void BasicProposalItemListModel::reset()
{
m_currentItems = m_originalItems;
}
int BasicProposalItemListModel::size() const
{
return m_currentItems.size();
}
QString BasicProposalItemListModel::text(int index) const
{
return m_currentItems.at(index)->text();
}
QIcon BasicProposalItemListModel::icon(int index) const
{
return m_currentItems.at(index)->icon();
}
QString BasicProposalItemListModel::detail(int index) const
{
return m_currentItems.at(index)->detail();
}
void BasicProposalItemListModel::removeDuplicates()
{
QHash<QString, QVariant> unique;
QList<BasicProposalItem *>::iterator it = m_originalItems.begin();
while (it != m_originalItems.end()) {
const BasicProposalItem *item = *it;
if (unique.contains(item->text())
&& unique.value(item->text(), QVariant()) == item->data()) {
it = m_originalItems.erase(it);
} else {
unique.insert(item->text(), item->data());
++it;
}
}
}
void BasicProposalItemListModel::filter(const QString &prefix)
{
if (prefix.isEmpty())
return;
/*
* 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.
*
* It also implements the first-letter-only case sensitivity.
*/
const TextEditor::CaseSensitivity caseSensitivity =
TextEditorSettings::instance()->completionSettings().m_caseSensitivity;
QString keyRegExp;
keyRegExp += QLatin1Char('^');
bool first = true;
const QLatin1String wordContinuation("[a-z0-9_]*");
foreach (const QChar &c, prefix) {
if (caseSensitivity == TextEditor::CaseInsensitive ||
(caseSensitivity == TextEditor::FirstLetterCaseSensitive && !first)) {
keyRegExp += QLatin1String("(?:");
if (c.isUpper() && !first)
keyRegExp += wordContinuation;
keyRegExp += QRegExp::escape(c.toUpper());
keyRegExp += QLatin1Char('|');
keyRegExp += QRegExp::escape(c.toLower());
keyRegExp += QLatin1Char(')');
} else {
if (c.isUpper() && !first)
keyRegExp += wordContinuation;
keyRegExp += QRegExp::escape(c);
}
first = false;
}
const QRegExp regExp(keyRegExp);
m_currentItems.clear();
for (QList<BasicProposalItem *>::const_iterator it = m_originalItems.begin();
it != m_originalItems.end();
++it) {
BasicProposalItem *item = *it;
if (regExp.indexIn(item->text()) == 0)
m_currentItems.append(item);
}
}
bool BasicProposalItemListModel::isSortable() const
{
if (m_currentItems.size() < kMaxSort)
return true;
return false;
}
void BasicProposalItemListModel::sort()
{
qStableSort(m_currentItems.begin(), m_currentItems.end(), ContentLessThan());
}
int BasicProposalItemListModel::persistentId(int index) const
{
return m_idByText.value(m_currentItems.at(index)->text());
}
bool BasicProposalItemListModel::supportsPrefixExpansion() const
{
return true;
}
QString BasicProposalItemListModel::proposalPrefix() const
{
if (m_currentItems.size() >= kMaxPrefixFilter)
return QString();
// Compute common prefix
QString firstKey = m_currentItems.first()->text();
QString lastKey = m_currentItems.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);
}
return firstKey;
}
IAssistProposalItem *BasicProposalItemListModel::proposalItem(int index) const
{
return m_currentItems.at(index);
}
QPair<QList<BasicProposalItem *>::iterator,
QList<BasicProposalItem *>::iterator>
BasicProposalItemListModel::currentItems()
{
return qMakePair(m_currentItems.begin(), m_currentItems.end());
}
@@ -0,0 +1,85 @@
/**************************************************************************
**
** 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 BASICPROPOSALITEMLISTMODEL_H
#define BASICPROPOSALITEMLISTMODEL_H
#include "igenericproposalmodel.h"
#include <texteditor/texteditor_global.h>
#include <QtCore/QList>
#include <QtCore/QHash>
#include <QtCore/QPair>
namespace TextEditor {
class BasicProposalItem;
class TEXTEDITOR_EXPORT BasicProposalItemListModel : public IGenericProposalModel
{
public:
BasicProposalItemListModel();
BasicProposalItemListModel(const QList<BasicProposalItem *> &items);
virtual ~BasicProposalItemListModel();
virtual void reset();
virtual int size() const;
virtual QString text(int index) const;
virtual QIcon icon(int index) const;
virtual QString detail(int index) const;
virtual int persistentId(int index) const;
virtual void removeDuplicates();
virtual void filter(const QString &prefix);
virtual bool isSortable() const;
virtual void sort();
virtual bool supportsPrefixExpansion() const;
virtual QString proposalPrefix() const;
virtual IAssistProposalItem *proposalItem(int index) const;
void loadContent(const QList<BasicProposalItem *> &items);
protected:
typedef QList<BasicProposalItem *>::iterator ItemIterator;
QPair<ItemIterator, ItemIterator> currentItems();
private:
void mapPersistentIds();
QHash<QString, int> m_idByText;
QList<BasicProposalItem *> m_originalItems;
QList<BasicProposalItem *> m_currentItems;
};
} // TextEditor
#endif // BASICPROPOSALITEMLISTMODEL_H
@@ -0,0 +1,506 @@
/**************************************************************************
**
** 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 "codeassistant.h"
#include "completionassistprovider.h"
#include "quickfixassistprovider.h"
#include "iassistprocessor.h"
#include "iassistproposal.h"
#include "iassistproposalwidget.h"
#include "iassistinterface.h"
#include "iassistproposalitem.h"
#include "runner.h"
#include <texteditor/basetexteditor.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/completionsettings.h>
#include <extensionsystem/pluginmanager.h>
#include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QTimer>
#include <QtCore/QDebug>
#include <QtGui/QKeyEvent>
using namespace TextEditor;
using namespace Internal;
namespace {
template <class T>
void filterEditorSpecificProviders(QList<T *> *providers, const QString &editorId)
{
typename QList<T *>::iterator it = providers->begin();
while (it != providers->end()) {
if ((*it)->supportsEditor(editorId))
++it;
else
it = providers->erase(it);
}
}
} // Anonymous
namespace TextEditor {
class CodeAssistantPrivate : public QObject
{
Q_OBJECT
public:
CodeAssistantPrivate(CodeAssistant *assistant);
virtual ~CodeAssistantPrivate();
void configure(BaseTextEditor *textEditor);
bool isConfigured() const;
void invoke(AssistKind kind, IAssistProvider *provider = 0);
void process();
void requestProposal(AssistReason reason, AssistKind kind, IAssistProvider *provider = 0);
void cancelCurrentRequest();
void invalidateCurrentRequestData();
void displayProposal(IAssistProposal *newProposal, AssistReason reason);
bool isDisplayingProposal() const;
bool isWaitingForProposal() const;
void notifyChange();
bool hasContext() const;
void destroyContext();
CompletionAssistProvider *identifyActivationSequence();
void stopAutomaticProposalTimer();
void startAutomaticProposalTimer();
virtual bool eventFilter(QObject *o, QEvent *e);
private slots:
void finalizeRequest();
void proposalComputed();
void processProposalItem(IAssistProposalItem *proposalItem);
void handlePrefixExpansion(const QString &newPrefix);
void finalizeProposal();
void automaticProposalTimeout();
void updateCompletionSettings(const TextEditor::CompletionSettings &settings);
private:
CodeAssistant *m_q;
BaseTextEditor *m_textEditor;
QList<CompletionAssistProvider *> m_completionProviders;
QList<QuickFixAssistProvider *> m_quickFixProviders;
Internal::ProcessorRunner *m_requestRunner;
CompletionAssistProvider *m_requestProvider;
AssistKind m_assistKind;
IAssistProposalWidget *m_proposalWidget;
QScopedPointer<IAssistProposal> m_proposal;
bool m_proposalApplied;
bool m_receivedContentWhileWaiting;
QTimer m_automaticProposalTimer;
CompletionSettings m_settings;
};
} // TextEditor
// --------------------
// CodeAssistantPrivate
// --------------------
CodeAssistantPrivate::CodeAssistantPrivate(CodeAssistant *assistant)
: m_q(assistant)
, m_textEditor(0)
, m_requestRunner(0)
, m_requestProvider(0)
, m_proposalWidget(0)
, m_proposalApplied(false)
, m_receivedContentWhileWaiting(false)
, m_settings(TextEditorSettings::instance()->completionSettings())
{
m_automaticProposalTimer.setSingleShot(true);
m_automaticProposalTimer.setInterval(250);
connect(&m_automaticProposalTimer, SIGNAL(timeout()), this, SLOT(automaticProposalTimeout()));
connect(TextEditorSettings::instance(),
SIGNAL(completionSettingsChanged(TextEditor::CompletionSettings)),
this,
SLOT(updateCompletionSettings(TextEditor::CompletionSettings)));
}
CodeAssistantPrivate::~CodeAssistantPrivate()
{}
void CodeAssistantPrivate::configure(BaseTextEditor *textEditor)
{
// @TODO: There's a list of providers but currently only the first one is used. Perhaps we
// should implement a truly mechanism to support multiple providers for an editor (either
// merging or not proposals) or just leave it as not extensible and store directly the one
// completion and quick-fix provider (getting rid of the list).
m_textEditor = textEditor;
m_completionProviders =
ExtensionSystem::PluginManager::instance()->getObjects<CompletionAssistProvider>();
filterEditorSpecificProviders(&m_completionProviders, m_textEditor->id());
m_quickFixProviders =
ExtensionSystem::PluginManager::instance()->getObjects<QuickFixAssistProvider>();
filterEditorSpecificProviders(&m_quickFixProviders, m_textEditor->id());
m_textEditor->editorWidget()->installEventFilter(this);
}
bool CodeAssistantPrivate::isConfigured() const
{
return m_textEditor != 0;
}
void CodeAssistantPrivate::invoke(AssistKind kind, IAssistProvider *provider)
{
if (!isConfigured())
return;
stopAutomaticProposalTimer();
if (isDisplayingProposal() && m_assistKind == kind && !m_proposal->isFragile()) {
m_proposalWidget->setReason(ExplicitlyInvoked);
} else {
destroyContext();
requestProposal(ExplicitlyInvoked, kind, provider);
}
}
void CodeAssistantPrivate::process()
{
if (!isConfigured())
return;
stopAutomaticProposalTimer();
if (m_settings.m_completionTrigger != ManualCompletion) {
if (CompletionAssistProvider *provider = identifyActivationSequence()) {
if (isWaitingForProposal())
cancelCurrentRequest();
requestProposal(ActivationCharacter, Completion, provider);
return;
}
}
startAutomaticProposalTimer();
}
void CodeAssistantPrivate::requestProposal(AssistReason reason,
AssistKind kind,
IAssistProvider *provider)
{
Q_ASSERT(!isWaitingForProposal());
if (!provider) {
if (kind == Completion) {
if (!m_completionProviders.isEmpty())
provider = m_completionProviders.at(0);
} else if (!m_quickFixProviders.isEmpty()) {
provider = m_quickFixProviders.at(0);
}
if (!provider)
return;
}
m_assistKind = kind;
IAssistProcessor *processor = provider->createProcessor();
IAssistInterface *assistInterface =
m_textEditor->editorWidget()->createAssistInterface(kind, reason);
if (!assistInterface)
return;
if (kind == Completion) {
CompletionAssistProvider *completionProvider =
static_cast<CompletionAssistProvider *>(provider);
if (completionProvider->isAsynchronous()) {
m_requestProvider = completionProvider;
m_requestRunner = new ProcessorRunner;
connect(m_requestRunner, SIGNAL(finished()), this, SLOT(proposalComputed()));
connect(m_requestRunner, SIGNAL(finished()), this, SLOT(finalizeRequest()));
assistInterface->detach(m_requestRunner);
m_requestRunner->setReason(reason);
m_requestRunner->setProcessor(processor);
m_requestRunner->setAssistInterface(assistInterface);
m_requestRunner->start();
return;
}
}
IAssistProposal *newProposal = processor->perform(assistInterface);
displayProposal(newProposal, reason);
delete processor;
}
void CodeAssistantPrivate::cancelCurrentRequest()
{
m_requestRunner->setDiscardProposal(true);
disconnect(m_requestRunner, SIGNAL(finished()), this, SLOT(proposalComputed()));
invalidateCurrentRequestData();
}
void CodeAssistantPrivate::proposalComputed()
{
// Since the request runner is a different thread, there's still a gap in which the queued
// signal could be processed after an invalidation of the current request.
if (!m_requestRunner)
return;
IAssistProposal *newProposal = m_requestRunner->proposal();
AssistReason reason = m_requestRunner->reason();
invalidateCurrentRequestData();
displayProposal(newProposal, reason);
}
void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistReason reason)
{
if (!newProposal)
return;
QScopedPointer<IAssistProposal> proposalCandidate(newProposal);
if (isDisplayingProposal()) {
if (!m_proposal->isFragile() || proposalCandidate->isFragile())
return;
destroyContext();
}
if (m_textEditor->position() < proposalCandidate->basePosition())
return;
m_proposal.reset(proposalCandidate.take());
if (m_proposal->isCorrective())
m_proposal->makeCorrection(m_textEditor);
m_proposalWidget = m_proposal->createWidget();
connect(m_proposalWidget, SIGNAL(destroyed()), this, SLOT(finalizeProposal()));
connect(m_proposalWidget, SIGNAL(prefixExpanded(QString)),
this, SLOT(handlePrefixExpansion(QString)));
connect(m_proposalWidget, SIGNAL(proposalItemActivated(IAssistProposalItem*)),
this, SLOT(processProposalItem(IAssistProposalItem*)));
m_proposalWidget->setAssistant(m_q);
m_proposalWidget->setReason(reason);
m_proposalWidget->setUnderlyingWidget(m_textEditor->widget());
m_proposalWidget->setModel(m_proposal->model());
m_proposalWidget->setDisplayRect(m_textEditor->cursorRect(m_proposal->basePosition()));
if (m_receivedContentWhileWaiting)
m_proposalWidget->setIsSynchronized(false);
else
m_proposalWidget->setIsSynchronized(true);
m_proposalWidget->showProposal(m_textEditor->textAt(
m_proposal->basePosition(),
m_textEditor->position() - m_proposal->basePosition()));
}
void CodeAssistantPrivate::processProposalItem(IAssistProposalItem *proposalItem)
{
proposalItem->apply(m_textEditor, m_proposal->basePosition());
destroyContext();
process();
}
void CodeAssistantPrivate::handlePrefixExpansion(const QString &newPrefix)
{
const int currentPosition = m_textEditor->position();
m_textEditor->setCursorPosition(m_proposal->basePosition());
m_textEditor->replace(currentPosition - m_proposal->basePosition(), newPrefix);
notifyChange();
}
void CodeAssistantPrivate::finalizeRequest()
{
if (ProcessorRunner *runner = qobject_cast<ProcessorRunner *>(sender()))
delete runner;
}
void CodeAssistantPrivate::finalizeProposal()
{
m_proposal.reset();
m_proposalWidget = 0;
if (m_receivedContentWhileWaiting)
m_receivedContentWhileWaiting = false;
}
bool CodeAssistantPrivate::isDisplayingProposal() const
{
return m_proposalWidget != 0;
}
bool CodeAssistantPrivate::isWaitingForProposal() const
{
return m_requestRunner != 0;
}
void CodeAssistantPrivate::invalidateCurrentRequestData()
{
m_requestRunner = 0;
m_requestProvider = 0;
}
CompletionAssistProvider *CodeAssistantPrivate::identifyActivationSequence()
{
for (int i = 0; i < m_completionProviders.size(); ++i) {
CompletionAssistProvider *provider = m_completionProviders.at(i);
const int length = provider->activationCharSequenceLength();
if (length == 0)
continue;
const QString &sequence = m_textEditor->textAt(m_textEditor->position() - length, length);
if (provider->isActivationCharSequence(sequence))
return provider;
}
return 0;
}
void CodeAssistantPrivate::notifyChange()
{
stopAutomaticProposalTimer();
if (isDisplayingProposal()) {
if (m_textEditor->position() < m_proposal->basePosition())
destroyContext();
else
m_proposalWidget->updateProposal(
m_textEditor->textAt(m_proposal->basePosition(),
m_textEditor->position() - m_proposal->basePosition()));
}
}
bool CodeAssistantPrivate::hasContext() const
{
return m_requestRunner || m_proposalWidget;
}
void CodeAssistantPrivate::destroyContext()
{
stopAutomaticProposalTimer();
if (isWaitingForProposal()) {
cancelCurrentRequest();
} else if (isDisplayingProposal()) {
m_proposalWidget->closeProposal();
disconnect(m_proposalWidget, SIGNAL(destroyed()), this, SLOT(finalizeProposal()));
finalizeProposal();
}
}
void CodeAssistantPrivate::startAutomaticProposalTimer()
{
if (m_settings.m_completionTrigger == AutomaticCompletion)
m_automaticProposalTimer.start();
}
void CodeAssistantPrivate::automaticProposalTimeout()
{
if (isWaitingForProposal() || (isDisplayingProposal() && !m_proposal->isFragile()))
return;
requestProposal(IdleEditor, Completion);
}
void CodeAssistantPrivate::stopAutomaticProposalTimer()
{
if (m_automaticProposalTimer.isActive())
m_automaticProposalTimer.stop();
}
void CodeAssistantPrivate::updateCompletionSettings(const TextEditor::CompletionSettings &settings)
{
m_settings = settings;
}
bool CodeAssistantPrivate::eventFilter(QObject *o, QEvent *e)
{
Q_UNUSED(o);
if (isWaitingForProposal()) {
QEvent::Type type = e->type();
if (type == QEvent::FocusOut) {
destroyContext();
} else if (type == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
const QString &keyText = keyEvent->text();
if ((keyText.isEmpty()
&& keyEvent->key() != Qt::LeftArrow
&& keyEvent->key() != Qt::RightArrow
&& keyEvent->key() != Qt::Key_Shift)
|| (!keyText.isEmpty() &&
!m_requestProvider->isContinuationChar(keyText.at(0)))) {
destroyContext();
} else if (!keyText.isEmpty() && !m_receivedContentWhileWaiting) {
m_receivedContentWhileWaiting = true;
}
}
}
return false;
}
// -------------
// CodeAssistant
// -------------
CodeAssistant::CodeAssistant() : m_d(new CodeAssistantPrivate(this))
{}
CodeAssistant::~CodeAssistant()
{}
void CodeAssistant::configure(BaseTextEditor *textEditor)
{
m_d->configure(textEditor);
}
void CodeAssistant::process()
{
m_d->process();
}
void CodeAssistant::notifyChange()
{
m_d->notifyChange();
}
bool CodeAssistant::hasContext() const
{
return m_d->hasContext();
}
void CodeAssistant::destroyContext()
{
m_d->destroyContext();
}
void CodeAssistant::invoke(AssistKind kind, IAssistProvider *provider)
{
m_d->invoke(kind, provider);
}
#include "codeassistant.moc"
@@ -30,39 +30,40 @@
**
**************************************************************************/
#ifndef QUICKFIXCOLLECTOR_H
#define QUICKFIXCOLLECTOR_H
#ifndef CODEASSISTANT_H
#define CODEASSISTANT_H
#include <texteditor/quickfix.h>
#include "assistenums.h"
namespace ExtensionSystem {
class IPlugin;
}
#include <texteditor/texteditor_global.h>
#include <QtCore/QScopedPointer>
namespace TextEditor {
class QuickFixState;
}
namespace CppEditor {
namespace Internal {
class CodeAssistantPrivate;
class IAssistProvider;
class BaseTextEditor;
class CppQuickFixCollector: public TextEditor::QuickFixCollector
class CodeAssistant
{
Q_OBJECT
public:
CppQuickFixCollector();
virtual ~CppQuickFixCollector();
CodeAssistant();
~CodeAssistant();
virtual bool supportsEditor(TextEditor::ITextEditor *editor) const;
virtual TextEditor::QuickFixState *initializeCompletion(TextEditor::BaseTextEditorWidget *editor);
void configure(BaseTextEditor *textEditor);
virtual QList<TextEditor::QuickFixFactory *> quickFixFactories() const;
void process();
void notifyChange();
bool hasContext() const;
void destroyContext();
/// Registers all quick-fixes in this plug-in as auto-released objects.
static void registerQuickFixes(ExtensionSystem::IPlugin *plugIn);
void invoke(AssistKind assistKind, IAssistProvider *provider = 0);
private:
QScopedPointer<CodeAssistantPrivate> m_d;
};
} // namespace Internal
} // namespace CppEditor
} //TextEditor
#endif // QUICKFIXCOLLECTOR_H
#endif // CODEASSISTANT_H
@@ -0,0 +1,64 @@
/**************************************************************************
**
** 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 "completionassistprovider.h"
#include <QtCore/QChar>
using namespace TextEditor;
CompletionAssistProvider::CompletionAssistProvider()
{}
CompletionAssistProvider::~CompletionAssistProvider()
{}
bool CompletionAssistProvider::isAsynchronous() const
{
return true;
}
int CompletionAssistProvider::activationCharSequenceLength() const
{
return 0;
}
bool CompletionAssistProvider::isActivationCharSequence(const QString &sequence) const
{
Q_UNUSED(sequence)
return false;
}
bool CompletionAssistProvider::isContinuationChar(const QChar &c) const
{
return c.isLetterOrNumber() || c == QLatin1Char('_');
}
@@ -0,0 +1,56 @@
/**************************************************************************
**
** 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 COMPLETIONASSISTPROVIDER_H
#define COMPLETIONASSISTPROVIDER_H
#include "iassistprovider.h"
namespace TextEditor {
class TEXTEDITOR_EXPORT CompletionAssistProvider : public IAssistProvider
{
Q_OBJECT
public:
CompletionAssistProvider();
virtual ~CompletionAssistProvider();
virtual bool isAsynchronous() const;
virtual int activationCharSequenceLength() const;
virtual bool isActivationCharSequence(const QString &sequence) const;
virtual bool isContinuationChar(const QChar &c) const;
};
} // TextEditor
#endif // COMPLETIONASSISTPROVIDER_H
@@ -0,0 +1,80 @@
/**************************************************************************
**
** 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 "defaultassistinterface.h"
#include <texteditor/convenience.h>
#include <QtCore/QThread>
#include <QtGui/QTextDocument>
#include <QtGui/QTextCursor>
using namespace TextEditor;
DefaultAssistInterface::DefaultAssistInterface(QTextDocument *document,
int position,
Core::IFile *file,
AssistReason reason)
: m_document(document)
, m_detached(false)
, m_position(position)
, m_file(file)
, m_reason(reason)
{}
DefaultAssistInterface::~DefaultAssistInterface()
{
if (m_detached)
delete m_document;
}
QChar DefaultAssistInterface::characterAt(int position) const
{
return m_document->characterAt(position);
}
QString DefaultAssistInterface::textAt(int pos, int length) const
{
return Convenience::textAt(QTextCursor(m_document), pos, length);
}
void DefaultAssistInterface::detach(QThread *destination)
{
m_document = new QTextDocument(m_document->toPlainText());
m_document->moveToThread(destination);
m_detached = true;
}
AssistReason DefaultAssistInterface::reason() const
{
return m_reason;
}
@@ -0,0 +1,67 @@
/**************************************************************************
**
** 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 DEFAULTASSISTINTERFACE_H
#define DEFAULTASSISTINTERFACE_H
#include "iassistinterface.h"
namespace TextEditor {
class TEXTEDITOR_EXPORT DefaultAssistInterface : public IAssistInterface
{
public:
DefaultAssistInterface(QTextDocument *document,
int position,
Core::IFile *file,
AssistReason reason);
virtual ~DefaultAssistInterface();
virtual int position() const { return m_position; }
virtual QChar characterAt(int position) const;
virtual QString textAt(int position, int length) const;
virtual const Core::IFile *file() const { return m_file; }
virtual QTextDocument *document() const { return m_document; }
virtual void detach(QThread *destination);
virtual AssistReason reason() const;
private:
QTextDocument *m_document;
bool m_detached;
int m_position;
Core::IFile *m_file;
AssistReason m_reason;
};
} // TextEditor
#endif // DEFAULTASSISTINTERFACE_H
@@ -0,0 +1,73 @@
/**************************************************************************
**
** 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 "functionhintproposal.h"
#include "ifunctionhintproposalmodel.h"
#include "functionhintproposalwidget.h"
using namespace TextEditor;
FunctionHintProposal::FunctionHintProposal(int cursorPos, IFunctionHintProposalModel *model)
: m_basePosition(cursorPos)
, m_model(model)
{}
FunctionHintProposal::~FunctionHintProposal()
{}
bool FunctionHintProposal::isFragile() const
{
return true;
}
int FunctionHintProposal::basePosition() const
{
return m_basePosition;
}
bool FunctionHintProposal::isCorrective() const
{
return false;
}
void FunctionHintProposal::makeCorrection(BaseTextEditor *)
{}
IAssistProposalModel *FunctionHintProposal::model() const
{
return m_model;
}
IAssistProposalWidget *FunctionHintProposal::createWidget() const
{
return new FunctionHintProposalWidget;
}
@@ -0,0 +1,62 @@
/**************************************************************************
**
** 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 FUNCTIONHINTPROPOSAL_H
#define FUNCTIONHINTPROPOSAL_H
#include "iassistproposal.h"
namespace TextEditor {
class IFunctionHintProposalModel;
class TEXTEDITOR_EXPORT FunctionHintProposal : public IAssistProposal
{
public:
FunctionHintProposal(int cursorPos, IFunctionHintProposalModel *model);
virtual ~FunctionHintProposal();
virtual bool isFragile() const;
virtual int basePosition() const;
virtual bool isCorrective() const;
virtual void makeCorrection(BaseTextEditor *editor);
virtual IAssistProposalModel *model() const;
virtual IAssistProposalWidget *createWidget() const;
private:
int m_basePosition;
IFunctionHintProposalModel *m_model;
};
} // TextEditor
#endif // FUNCTIONHINTPROPOSAL_H
@@ -0,0 +1,314 @@
/**************************************************************************
**
** 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 "functionhintproposalwidget.h"
#include "ifunctionhintproposalmodel.h"
#include "codeassistant.h"
#include <utils/faketooltip.h>
#include <QtCore/QDebug>
#include <QtGui/QApplication>
#include <QtGui/QLabel>
#include <QtGui/QToolButton>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QDesktopWidget>
#include <QtGui/QKeyEvent>
#include <QtGui/QShortcutEvent>
namespace TextEditor {
// -------------------------
// HintProposalWidgetPrivate
// -------------------------
struct FunctionHintProposalWidgetPrivate
{
FunctionHintProposalWidgetPrivate();
const QWidget *m_underlyingWidget;
CodeAssistant *m_assistant;
IFunctionHintProposalModel *m_model;
Utils::FakeToolTip *m_popupFrame;
QLabel *m_numberLabel;
QLabel *m_hintLabel;
QWidget *m_pager;
QRect m_displayRect;
int m_currentHint;
int m_totalHints;
int m_currentArgument;
bool m_escapePressed;
};
FunctionHintProposalWidgetPrivate::FunctionHintProposalWidgetPrivate()
: m_underlyingWidget(0)
, m_assistant(0)
, m_model(0)
, m_popupFrame(new Utils::FakeToolTip)
, m_numberLabel(new QLabel)
, m_hintLabel(new QLabel)
, m_pager(new QWidget)
, m_currentHint(-1)
, m_totalHints(0)
, m_currentArgument(-1)
, m_escapePressed(false)
{
m_hintLabel->setTextFormat(Qt::RichText);
}
// ------------------
// HintProposalWidget
// ------------------
FunctionHintProposalWidget::FunctionHintProposalWidget()
: m_d(new FunctionHintProposalWidgetPrivate)
{
QToolButton *downArrow = new QToolButton;
downArrow->setArrowType(Qt::DownArrow);
downArrow->setFixedSize(16, 16);
downArrow->setAutoRaise(true);
QToolButton *upArrow = new QToolButton;
upArrow->setArrowType(Qt::UpArrow);
upArrow->setFixedSize(16, 16);
upArrow->setAutoRaise(true);
QHBoxLayout *pagerLayout = new QHBoxLayout(m_d->m_pager);
pagerLayout->setMargin(0);
pagerLayout->setSpacing(0);
pagerLayout->addWidget(upArrow);
pagerLayout->addWidget(m_d->m_numberLabel);
pagerLayout->addWidget(downArrow);
QHBoxLayout *popupLayout = new QHBoxLayout(m_d->m_popupFrame);
popupLayout->setMargin(0);
popupLayout->setSpacing(0);
popupLayout->addWidget(m_d->m_pager);
popupLayout->addWidget(m_d->m_hintLabel);
connect(upArrow, SIGNAL(clicked()), SLOT(previousPage()));
connect(downArrow, SIGNAL(clicked()), SLOT(nextPage()));
qApp->installEventFilter(this);
setFocusPolicy(Qt::NoFocus);
}
FunctionHintProposalWidget::~FunctionHintProposalWidget()
{
delete m_d->m_model;
}
void FunctionHintProposalWidget::setAssistant(CodeAssistant *assistant)
{
m_d->m_assistant = assistant;
}
void FunctionHintProposalWidget::setReason(AssistReason reason)
{
Q_UNUSED(reason);
}
void FunctionHintProposalWidget::setUnderlyingWidget(const QWidget *underlyingWidget)
{
m_d->m_underlyingWidget = underlyingWidget;
}
void FunctionHintProposalWidget::setModel(IAssistProposalModel *model)
{
m_d->m_model = static_cast<IFunctionHintProposalModel *>(model);
}
void FunctionHintProposalWidget::setDisplayRect(const QRect &rect)
{
m_d->m_displayRect = rect;
}
void FunctionHintProposalWidget::setIsSynchronized(bool)
{}
void FunctionHintProposalWidget::showProposal(const QString &prefix)
{
m_d->m_totalHints = m_d->m_model->size();
if (m_d->m_totalHints == 0) {
abort();
return;
}
m_d->m_pager->setVisible(m_d->m_totalHints > 1);
m_d->m_currentHint = 0;
if (!updateAndCheck(prefix)) {
abort();
return;
}
m_d->m_popupFrame->show();
}
void FunctionHintProposalWidget::updateProposal(const QString &prefix)
{
updateAndCheck(prefix);
}
void FunctionHintProposalWidget::closeProposal()
{
abort();
}
void FunctionHintProposalWidget::abort()
{
if (m_d->m_popupFrame->isVisible())
m_d->m_popupFrame->close();
deleteLater();
}
bool FunctionHintProposalWidget::eventFilter(QObject *obj, QEvent *e)
{
switch (e->type()) {
case QEvent::ShortcutOverride:
if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
m_d->m_escapePressed = true;
}
break;
case QEvent::KeyPress:
if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
m_d->m_escapePressed = true;
}
if (m_d->m_model->size() > 1) {
QKeyEvent *ke = static_cast<QKeyEvent*>(e);
if (ke->key() == Qt::Key_Up) {
previousPage();
return true;
} else if (ke->key() == Qt::Key_Down) {
nextPage();
return true;
}
return false;
}
break;
case QEvent::KeyRelease:
if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && m_d->m_escapePressed) {
abort();
return false;
}
m_d->m_assistant->notifyChange();
break;
case QEvent::WindowDeactivate:
case QEvent::FocusOut:
if (obj != m_d->m_underlyingWidget) {
break;
}
abort();
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::Wheel: {
QWidget *widget = qobject_cast<QWidget *>(obj);
if (! (widget == this || isAncestorOf(widget))) {
abort();
}
}
break;
default:
break;
}
return false;
}
void FunctionHintProposalWidget::nextPage()
{
m_d->m_currentHint = (m_d->m_currentHint + 1) % m_d->m_totalHints;
updateContent();
}
void FunctionHintProposalWidget::previousPage()
{
if (m_d->m_currentHint == 0)
m_d->m_currentHint = m_d->m_totalHints - 1;
else
--m_d->m_currentHint;
updateContent();
}
bool FunctionHintProposalWidget::updateAndCheck(const QString &prefix)
{
const int activeArgument = m_d->m_model->activeArgument(prefix);
if (activeArgument == -1) {
abort();
return false;
} else if (activeArgument != m_d->m_currentArgument) {
m_d->m_currentArgument = activeArgument;
updateContent();
}
return true;
}
void FunctionHintProposalWidget::updateContent()
{
m_d->m_hintLabel->setText(m_d->m_model->text(m_d->m_currentHint));
m_d->m_numberLabel->setText(tr("%1 of %2").arg(m_d->m_currentHint + 1).arg(m_d->m_totalHints));
updatePosition();
}
void FunctionHintProposalWidget::updatePosition()
{
const QDesktopWidget *desktop = QApplication::desktop();
#ifdef Q_WS_MAC
const QRect &screen = desktop->availableGeometry(desktop->screenNumber(m_d->m_underlyingWidget));
#else
const QRect &screen = desktop->screenGeometry(desktop->screenNumber(m_d->m_underlyingWidget));
#endif
m_d->m_pager->setFixedWidth(m_d->m_pager->minimumSizeHint().width());
m_d->m_hintLabel->setWordWrap(false);
const int maxDesiredWidth = screen.width() - 10;
const QSize &minHint = m_d->m_popupFrame->minimumSizeHint();
if (minHint.width() > maxDesiredWidth) {
m_d->m_hintLabel->setWordWrap(true);
m_d->m_popupFrame->setFixedWidth(maxDesiredWidth);
const int extra = m_d->m_popupFrame->contentsMargins().bottom() +
m_d->m_popupFrame->contentsMargins().top();
m_d->m_popupFrame->setFixedHeight(
m_d->m_hintLabel->heightForWidth(maxDesiredWidth - m_d->m_pager->width()) + extra);
} else {
m_d->m_popupFrame->setFixedSize(minHint);
}
const QSize &sz = m_d->m_popupFrame->size();
QPoint pos = m_d->m_displayRect.topLeft();
pos.setY(pos.y() - sz.height() - 1);
if (pos.x() + sz.width() > screen.right())
pos.setX(screen.right() - sz.width());
m_d->m_popupFrame->move(pos);
}
} // TextEditor
@@ -0,0 +1,82 @@
/**************************************************************************
**
** 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 FUNCTIONHINTPROPOSALWIDGET_H
#define FUNCTIONHINTPROPOSALWIDGET_H
#include "iassistproposalwidget.h"
#include <QtCore/QScopedPointer>
namespace TextEditor {
struct FunctionHintProposalWidgetPrivate;
class TEXTEDITOR_EXPORT FunctionHintProposalWidget : public IAssistProposalWidget
{
Q_OBJECT
public:
FunctionHintProposalWidget();
virtual ~FunctionHintProposalWidget();
virtual void setAssistant(CodeAssistant *assistant);
virtual void setReason(AssistReason reason);
virtual void setUnderlyingWidget(const QWidget *underlyingWidget);
virtual void setModel(IAssistProposalModel *model);
virtual void setDisplayRect(const QRect &rect);
virtual void setIsSynchronized(bool isSync);
virtual void showProposal(const QString &prefix);
virtual void updateProposal(const QString &prefix);
virtual void closeProposal();
protected:
virtual bool eventFilter(QObject *o, QEvent *e);
private slots:
void nextPage();
void previousPage();
private:
bool updateAndCheck(const QString &prefix);
void updateContent();
void updatePosition();
void abort();
private:
QScopedPointer<FunctionHintProposalWidgetPrivate> m_d;
};
} // TextEditor
#endif // FUNCTIONHINTPROPOSALWIDGET_H
@@ -0,0 +1,78 @@
/**************************************************************************
**
** 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 "genericproposal.h"
#include "igenericproposalmodel.h"
#include "genericproposalwidget.h"
using namespace TextEditor;
GenericProposal::GenericProposal(int cursorPos, IGenericProposalModel *model)
: m_basePosition(cursorPos)
, m_model(model)
{}
GenericProposal::~GenericProposal()
{}
bool GenericProposal::isFragile() const
{
return false;
}
int GenericProposal::basePosition() const
{
return m_basePosition;
}
bool GenericProposal::isCorrective() const
{
return false;
}
void GenericProposal::makeCorrection(BaseTextEditor *)
{}
IAssistProposalModel *GenericProposal::model() const
{
return m_model;
}
IAssistProposalWidget *GenericProposal::createWidget() const
{
return new GenericProposalWidget;
}
void GenericProposal::moveBasePosition(int length)
{
m_basePosition += length;
}
@@ -0,0 +1,65 @@
/**************************************************************************
**
** 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 GENERICPROPOSAL_H
#define GENERICPROPOSAL_H
#include "iassistproposal.h"
namespace TextEditor {
class IGenericProposalModel;
class TEXTEDITOR_EXPORT GenericProposal : public IAssistProposal
{
public:
GenericProposal(int cursorPos, IGenericProposalModel *model);
~GenericProposal();
virtual bool isFragile() const;
virtual int basePosition() const;
virtual bool isCorrective() const;
virtual void makeCorrection(BaseTextEditor *editor);
virtual IAssistProposalModel *model() const;
virtual IAssistProposalWidget *createWidget() const;
protected:
void moveBasePosition(int length);
private:
int m_basePosition;
IGenericProposalModel *m_model;
};
} // TextEditor
#endif // GENERICPROPOSAL_H
@@ -0,0 +1,576 @@
/**************************************************************************
**
** 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 "genericproposalwidget.h"
#include "iassistprovider.h"
#include "igenericproposalmodel.h"
#include "iassistproposalitem.h"
#include "genericproposal.h"
#include "codeassistant.h"
#include <texteditor/texteditorsettings.h>
#include <texteditor/completionsettings.h>
#include <utils/faketooltip.h>
#include <QtCore/QRect>
#include <QtCore/QLatin1String>
#include <QtCore/QAbstractListModel>
#include <QtCore/QPointer>
#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtGui/QVBoxLayout>
#include <QtGui/QListView>
#include <QtGui/QAbstractItemView>
#include <QtGui/QScrollBar>
#include <QtGui/QKeyEvent>
#include <QtGui/QDesktopWidget>
#include <QtGui/QLabel>
namespace TextEditor {
// ------------
// ModelAdapter
// ------------
class ModelAdapter : public QAbstractListModel
{
Q_OBJECT
public:
ModelAdapter(IGenericProposalModel *completionModel, QWidget *parent);
virtual int rowCount(const QModelIndex &) const;
virtual QVariant data(const QModelIndex &index, int role) const;
private:
IGenericProposalModel *m_completionModel;
};
ModelAdapter::ModelAdapter(IGenericProposalModel *completionModel, QWidget *parent)
: QAbstractListModel(parent)
, m_completionModel(completionModel)
{}
int ModelAdapter::rowCount(const QModelIndex &) const
{
return m_completionModel->size();
}
QVariant ModelAdapter::data(const QModelIndex &index, int role) const
{
if (index.row() >= m_completionModel->size())
return QVariant();
if (role == Qt::DisplayRole) {
return m_completionModel->text(index.row());
} else if (role == Qt::DecorationRole) {
return m_completionModel->icon(index.row());
} else if (role == Qt::WhatsThisRole) {
return m_completionModel->detail(index.row());
}
return QVariant();
}
// ------------------------
// GenericProposalInfoFrame
// ------------------------
class GenericProposalInfoFrame : public Utils::FakeToolTip
{
public:
GenericProposalInfoFrame(QWidget *parent = 0)
: Utils::FakeToolTip(parent), m_label(new QLabel(this))
{
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(m_label);
m_label->setForegroundRole(QPalette::ToolTipText);
m_label->setBackgroundRole(QPalette::ToolTipBase);
}
void setText(const QString &text)
{
m_label->setText(text);
}
private:
QLabel *m_label;
};
// -----------------------
// GenericProposalListView
// -----------------------
class GenericProposalListView : public QListView
{
public:
GenericProposalListView(QWidget *parent) : QListView(parent) {}
QSize calculateSize() const;
QPoint infoFramePos() const;
int rowSelected() const { return currentIndex().row(); }
bool isFirstRowSelected() const { return rowSelected() == 0; }
bool isLastRowSelected() const { return rowSelected() == model()->rowCount() - 1; }
void selectRow(int row) { setCurrentIndex(model()->index(row, 0)); }
void selectFirstRow() { selectRow(0); }
void selectLastRow() { selectRow(model()->rowCount() - 1); }
};
QSize GenericProposalListView::calculateSize() const
{
static const int maxVisibleItems = 10;
// Determine size by calculating the space of the visible items
int visibleItems = model()->rowCount();
if (visibleItems > maxVisibleItems)
visibleItems = maxVisibleItems;
const QStyleOptionViewItem &option = viewOptions();
QSize shint;
for (int i = 0; i < visibleItems; ++i) {
QSize tmp = itemDelegate()->sizeHint(option, model()->index(i, 0));
if (shint.width() < tmp.width())
shint = tmp;
}
shint.rheight() *= visibleItems;
return shint;
}
QPoint GenericProposalListView::infoFramePos() const
{
const QRect &r = rectForIndex(currentIndex());
QPoint p((parentWidget()->mapToGlobal(
parentWidget()->rect().topRight())).x() + 3,
mapToGlobal(r.topRight()).y() - verticalOffset()
);
return p;
}
// ----------------------------
// GenericProposalWidgetPrivate
// ----------------------------
class GenericProposalWidgetPrivate : public QObject
{
Q_OBJECT
public:
GenericProposalWidgetPrivate(QWidget *completionWidget);
const QWidget *m_underlyingWidget;
GenericProposalListView *m_completionListView;
IGenericProposalModel *m_model;
QRect m_displayRect;
bool m_isSynchronized;
bool m_explicitlySelected;
AssistReason m_reason;
bool m_gotContent;
QPointer<GenericProposalInfoFrame> m_infoFrame;
QTimer m_infoTimer;
CodeAssistant *m_assistant;
public slots:
void handleActivation(const QModelIndex &modelIndex);
void maybeShowInfoTip();
};
GenericProposalWidgetPrivate::GenericProposalWidgetPrivate(QWidget *completionWidget)
: m_underlyingWidget(0)
, m_completionListView(new GenericProposalListView(completionWidget))
, m_model(0)
, m_isSynchronized(true)
, m_explicitlySelected(false)
, m_gotContent(false)
, m_assistant(0)
{
connect(m_completionListView, SIGNAL(activated(QModelIndex)),
this, SLOT(handleActivation(QModelIndex)));
m_infoTimer.setInterval(1000);
m_infoTimer.setSingleShot(true);
connect(&m_infoTimer, SIGNAL(timeout()), SLOT(maybeShowInfoTip()));
}
void GenericProposalWidgetPrivate::handleActivation(const QModelIndex &modelIndex)
{
static_cast<GenericProposalWidget *>
(m_completionListView->parent())->notifyActivation(modelIndex.row());
}
void GenericProposalWidgetPrivate::maybeShowInfoTip()
{
const QModelIndex &current = m_completionListView->currentIndex();
if (!current.isValid())
return;
const QString &infoTip = current.data(Qt::WhatsThisRole).toString();
if (infoTip.isEmpty()) {
delete m_infoFrame.data();
m_infoTimer.setInterval(200);
return;
}
if (m_infoFrame.isNull())
m_infoFrame = new GenericProposalInfoFrame(m_completionListView);
m_infoFrame->move(m_completionListView->infoFramePos());
m_infoFrame->setText(infoTip);
m_infoFrame->adjustSize();
m_infoFrame->show();
m_infoFrame->raise();
m_infoTimer.setInterval(0);
}
// ------------------------
// GenericProposalWidget
// ------------------------
GenericProposalWidget::GenericProposalWidget()
: m_d(new GenericProposalWidgetPrivate(this))
{
#ifdef Q_WS_MAC
if (m_d->m_completionListView->horizontalScrollBar())
m_d->m_completionListView->horizontalScrollBar()->setAttribute(Qt::WA_MacMiniSize);
if (m_d->m_completionListView->verticalScrollBar())
m_d->m_completionListView->verticalScrollBar()->setAttribute(Qt::WA_MacMiniSize);
#else
// This improves the look with QGTKStyle.
setFrameStyle(m_d->m_completionListView->frameStyle());
#endif
m_d->m_completionListView->setFrameStyle(QFrame::NoFrame);
m_d->m_completionListView->setAttribute(Qt::WA_MacShowFocusRect, false);
m_d->m_completionListView->setUniformItemSizes(true);
m_d->m_completionListView->setSelectionBehavior(QAbstractItemView::SelectItems);
m_d->m_completionListView->setSelectionMode(QAbstractItemView::SingleSelection);
m_d->m_completionListView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_d->m_completionListView->setMinimumSize(1, 1);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->addWidget(m_d->m_completionListView);
m_d->m_completionListView->installEventFilter(this);
setObjectName(QLatin1String("m_popupFrame"));
setMinimumSize(1, 1);
}
GenericProposalWidget::~GenericProposalWidget()
{
delete m_d->m_model;
}
void GenericProposalWidget::setAssistant(CodeAssistant *assistant)
{
m_d->m_assistant = assistant;
}
void GenericProposalWidget::setReason(AssistReason reason)
{
m_d->m_reason = reason;
}
void GenericProposalWidget::setUnderlyingWidget(const QWidget *underlyingWidget)
{
setFont(underlyingWidget->font());
m_d->m_underlyingWidget = underlyingWidget;
}
void GenericProposalWidget::setModel(IAssistProposalModel *model)
{
delete m_d->m_model;
m_d->m_model = static_cast<IGenericProposalModel *>(model);
m_d->m_completionListView->setModel(new ModelAdapter(m_d->m_model, m_d->m_completionListView));
connect(m_d->m_completionListView->selectionModel(),
SIGNAL(currentChanged(QModelIndex,QModelIndex)),
&m_d->m_infoTimer,
SLOT(start()));
}
void GenericProposalWidget::setDisplayRect(const QRect &rect)
{
m_d->m_displayRect = rect;
}
void GenericProposalWidget::setIsSynchronized(bool isSync)
{
m_d->m_isSynchronized = isSync;
}
void GenericProposalWidget::showProposal(const QString &prefix)
{
ensurePolished();
if (m_d->m_isSynchronized && !prefix.isEmpty())
m_d->m_gotContent = true;
m_d->m_model->removeDuplicates();
if (!updateAndCheck(prefix))
return;
show();
m_d->m_completionListView->setFocus();
}
void GenericProposalWidget::updateProposal(const QString &prefix)
{
if (!isVisible())
return;
updateAndCheck(prefix);
}
void GenericProposalWidget::closeProposal()
{
abort();
}
void GenericProposalWidget::notifyActivation(int index)
{
abort();
emit proposalItemActivated(m_d->m_model->proposalItem(index));
}
void GenericProposalWidget::abort()
{
if (isVisible())
close();
deleteLater();
}
bool GenericProposalWidget::updateAndCheck(const QString &prefix)
{
// Keep track in the case there has been an explicit selection.
int preferredItemId = -1;
if (m_d->m_explicitlySelected)
preferredItemId =
m_d->m_model->persistentId(m_d->m_completionListView->currentIndex().row());
// Filter, sort, etc.
m_d->m_model->reset();
if (!prefix.isEmpty())
m_d->m_model->filter(prefix);
if (m_d->m_model->size() == 0
|| (m_d->m_model->size() == 1 && prefix == m_d->m_model->proposalPrefix())) {
abort();
return false;
}
if (m_d->m_model->isSortable())
m_d->m_model->sort();
m_d->m_completionListView->reset();
// Try to find the previosly explicit selection (if any). If we can find the item set it
// as the current. Otherwise (it might have been filtered out) select the first row.
if (m_d->m_explicitlySelected) {
Q_ASSERT(preferredItemId != -1);
for (int i = 0; i < m_d->m_model->size(); ++i) {
if (m_d->m_model->persistentId(i) == preferredItemId) {
m_d->m_completionListView->selectRow(i);
break;
}
}
}
if (!m_d->m_completionListView->currentIndex().isValid()) {
m_d->m_completionListView->selectFirstRow();
if (m_d->m_explicitlySelected)
m_d->m_explicitlySelected = false;
}
if (TextEditorSettings::instance()->completionSettings().m_partiallyComplete
&& m_d->m_reason == ExplicitlyInvoked
&& m_d->m_gotContent) {
if (m_d->m_model->size() == 1) {
IAssistProposalItem *item = m_d->m_model->proposalItem(0);
if (item->implicitlyApplies()) {
abort();
emit proposalItemActivated(item);
return false;
}
}
if (m_d->m_model->supportsPrefixExpansion()) {
const QString &proposalPrefix = m_d->m_model->proposalPrefix();
if (proposalPrefix.length() > prefix.length())
emit prefixExpanded(proposalPrefix);
}
}
updatePositionAndSize();
return true;
}
void GenericProposalWidget::updatePositionAndSize()
{
const QSize &shint = m_d->m_completionListView->calculateSize();
const int fw = frameWidth();
const int width = shint.width() + fw * 2 + 30;
const int height = shint.height() + fw * 2;
// Determine the position, keeping the popup on the screen
const QDesktopWidget *desktop = QApplication::desktop();
#ifdef Q_WS_MAC
const QRect screen = desktop->availableGeometry(desktop->screenNumber(m_d->m_underlyingWidget));
#else
const QRect screen = desktop->screenGeometry(desktop->screenNumber(m_d->m_underlyingWidget));
#endif
QPoint pos = m_d->m_displayRect.bottomLeft();
pos.rx() -= 16 + fw; // Space for the icons
if (pos.y() + height > screen.bottom())
pos.setY(m_d->m_displayRect.top() - height);
if (pos.x() + width > screen.right())
pos.setX(screen.right() - width);
setGeometry(pos.x(), pos.y(), width, height);
}
bool GenericProposalWidget::eventFilter(QObject *o, QEvent *e)
{
if (e->type() == QEvent::FocusOut) {
abort();
#if defined(Q_OS_DARWIN) && ! defined(QT_MAC_USE_COCOA)
QFocusEvent *fe = static_cast<QFocusEvent *>(e);
if (fe->reason() == Qt::OtherFocusReason) {
// Qt/carbon workaround
// focus out is received before the key press event.
if (m_d->m_completionListView->currentIndex().isValid())
emit proposalItemActivated(m_d->m_model->proposalItem(
m_d->m_completionListView->currentIndex().row()));
}
#endif
if (m_d->m_infoFrame)
m_d->m_infoFrame->close();
return true;
} else if (e->type() == QEvent::ShortcutOverride) {
QKeyEvent *ke = static_cast<QKeyEvent *>(e);
switch (ke->key()) {
case Qt::Key_N:
case Qt::Key_P:
if (ke->modifiers() == Qt::ControlModifier) {
e->accept();
return true;
}
}
} else if (e->type() == QEvent::KeyPress) {
m_d->m_gotContent = false;
QKeyEvent *ke = static_cast<QKeyEvent *>(e);
switch (ke->key()) {
case Qt::Key_Escape:
abort();
return true;
case Qt::Key_N:
case Qt::Key_P:
// select next/previous completion
m_d->m_explicitlySelected = true;
if (ke->modifiers() == Qt::ControlModifier) {
int change = (ke->key() == Qt::Key_N) ? 1 : -1;
int nrows = m_d->m_model->size();
int row = m_d->m_completionListView->currentIndex().row();
int newRow = (row + change + nrows) % nrows;
if (newRow == row + change || !ke->isAutoRepeat())
m_d->m_completionListView->selectRow(newRow);
return true;
}
m_d->m_gotContent = true;
break;
case Qt::Key_Tab:
case Qt::Key_Return:
#if defined(QT_MAC_USE_COCOA) || !defined(Q_OS_DARWIN)
abort();
if (m_d->m_completionListView->currentIndex().isValid())
emit proposalItemActivated(m_d->m_model->proposalItem(
m_d->m_completionListView->currentIndex().row()));
#endif
return true;
case Qt::Key_Up:
m_d->m_explicitlySelected = true;
if (!ke->isAutoRepeat() && m_d->m_completionListView->isFirstRowSelected()) {
m_d->m_completionListView->selectLastRow();
return true;
}
return false;
case Qt::Key_Down:
m_d->m_explicitlySelected = true;
if (!ke->isAutoRepeat() && m_d->m_completionListView->isLastRowSelected()) {
m_d->m_completionListView->selectFirstRow();
return true;
}
return false;
case Qt::Key_Enter:
case Qt::Key_PageDown:
case Qt::Key_PageUp:
return false;
case Qt::Key_Right:
case Qt::Key_Left:
case Qt::Key_Home:
case Qt::Key_End:
case Qt::Key_Backspace:
// We want these navigation keys to work in the editor.
break;
default:
// Only forward keys that insert text and refine the completion.
if (ke->text().isEmpty())
return true;
m_d->m_gotContent = true;
break;
}
if (ke->text().length() == 1
&& m_d->m_completionListView->currentIndex().isValid()
&& qApp->focusWidget() == o) {
const QChar &typedChar = ke->text().at(0);
IAssistProposalItem *item =
m_d->m_model->proposalItem(m_d->m_completionListView->currentIndex().row());
if (item->prematurelyApplies(typedChar)) {
abort();
emit proposalItemActivated(item);
return true;
}
}
QApplication::sendEvent(const_cast<QWidget *>(m_d->m_underlyingWidget), e);
if (isVisible())
m_d->m_assistant->notifyChange();
return true;
}
return false;
}
#include "genericproposalwidget.moc"
} // TextEditor
@@ -0,0 +1,79 @@
/**************************************************************************
**
** 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 GENERICPROPOSALWIDGET_H
#define GENERICPROPOSALWIDGET_H
#include "iassistproposalwidget.h"
#include <QtCore/QScopedPointer>
namespace TextEditor {
class GenericProposalWidgetPrivate;
class GenericProposalWidget : public IAssistProposalWidget
{
friend class GenericProposalWidgetPrivate;
Q_OBJECT
public:
GenericProposalWidget();
virtual ~GenericProposalWidget();
virtual void setAssistant(CodeAssistant *assistant);
virtual void setReason(AssistReason reason);
virtual void setUnderlyingWidget(const QWidget *underlyingWidget);
virtual void setModel(IAssistProposalModel *model);
virtual void setDisplayRect(const QRect &rect);
virtual void setIsSynchronized(bool isSync);
virtual void showProposal(const QString &prefix);
virtual void updateProposal(const QString &prefix);
virtual void closeProposal();
private:
bool updateAndCheck(const QString &prefix);
void updatePositionAndSize();
void notifyActivation(int index);
void abort();
protected:
virtual bool eventFilter(QObject *o, QEvent *e);
private:
QScopedPointer<GenericProposalWidgetPrivate> m_d;
};
} // TextEditor
#endif // GENERICPROPOSALWIDGET_H
@@ -0,0 +1,100 @@
/**************************************************************************
**
** 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 "iassistinterface.h"
using namespace TextEditor;
/*!
\class IAssistInterface
\brief The IAssistInterface is an interface for providing access to the document from which
a proposal is computed.
This interface existis in order to avoid a direct dependency on the text editor. This is
particularly important and safer for asynchronous providers, since in such cases computation
of the proposal is not done in the GUI thread.
In general this API tries to be as decoupled as possible from the base text editor.
This is in order to make the design a bit more generic and allow code assist to be
pluggable into different types of documents (there are still issues to be treated).
\sa IAssistProposal, IAssistProvider, IAssistProcessor
*/
IAssistInterface::IAssistInterface()
{}
IAssistInterface::~IAssistInterface()
{}
/*!
\fn int position() const
Returns the cursor position.
*/
/*!
\fn QChar characterAt(int position) const
Returns the character at \a position.
*/
/*!
\fn QString textAt(int position, int length) const
Returns the text at \a position with the given \a length.
*/
/*!
\fn const Core::IFile *file() const
Returns the file associated.
*/
/*!
\fn QTextDocument *document() const
Returns the document.
*/
/*!
\fn void detach(QThread *destination)
Detaches the interface. If it is necessary to take any special care in order to allow
this interface to be run in a separate thread \a destination this needs to be done
in this method.
*/
/*!
\fn AssistReason reason() const
The reason which triggered the assist.
*/
@@ -0,0 +1,70 @@
/**************************************************************************
**
** 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 IASSISTINTERFACE_H
#define IASSISTINTERFACE_H
#include "assistenums.h"
#include <texteditor/texteditor_global.h>
#include <QtCore/QString>
QT_BEGIN_NAMESPACE
class QTextDocument;
class QThread;
QT_END_NAMESPACE
namespace Core {
class IFile;
}
namespace TextEditor {
class TEXTEDITOR_EXPORT IAssistInterface
{
public:
IAssistInterface();
virtual ~IAssistInterface();
virtual int position() const = 0;
virtual QChar characterAt(int position) const = 0;
virtual QString textAt(int position, int length) const = 0;
virtual const Core::IFile *file() const = 0;
virtual QTextDocument *document() const = 0;
virtual void detach(QThread *destination) = 0;
virtual AssistReason reason() const = 0;
};
} // TextEditor
#endif // IASSISTINTERFACE_H
@@ -0,0 +1,61 @@
/**************************************************************************
**
** 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 "iassistprocessor.h"
using namespace TextEditor;
/*!
\class IAssistProcessor
\brief The IAssistProcessor is an interface that actually computes an assist proposal.
\sa IAssistProposal, IAssistProvider
*/
IAssistProcessor::IAssistProcessor()
{}
IAssistProcessor::~IAssistProcessor()
{}
/*!
\fn IAssistProposal *perform(const IAssistInterface *interface)
Computes a proposal and returns it. Access to the document is made through the \a interface.
If this is an asynchronous processor the \a interface will be detached.
The processor takes ownership of the interface. Also, one should be careful in the case of
sharing data across asynchronous processors since there might be more than one instance of
them computing a proposal at a particular time.
\sa IAssistInterface::detach()
*/
@@ -0,0 +1,57 @@
/**************************************************************************
**
** 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 IASSISTPROCESSOR_H
#define IASSISTPROCESSOR_H
#include "iassistproposalwidget.h"
#include <texteditor/texteditor_global.h>
namespace TextEditor {
class IAssistProvider;
class IAssistInterface;
class IAssistProposal;
class TEXTEDITOR_EXPORT IAssistProcessor
{
public:
IAssistProcessor();
virtual ~IAssistProcessor();
virtual IAssistProposal *perform(const IAssistInterface *interface) = 0;
};
} // TextEditor
#endif // IASSISTPROCESSOR_H
@@ -0,0 +1,102 @@
/**************************************************************************
**
** 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 "iassistproposal.h"
using namespace TextEditor;
/*!
\class IAssistProposal
\brief The IAssistProposal is an interface for representing an assist proposal.
Known implenters of this interface are FunctionHintProposal and GenericProposal. The
former is recommended to be used when assisting function call constructs (overloads
and parameters) while the latter is quite generic so that it could be used to propose
snippets, refactoring operations (quickfixes), and contextual content (the member of
class or a string existent in the document, for example).
\sa IAssistProposalWidget, IAssistModel
*/
IAssistProposal::IAssistProposal()
{}
IAssistProposal::~IAssistProposal()
{}
/*!
\fn bool isFragile() const
Returns whether this is a fragile proposal. When a proposal is fragile it means that
it will be replaced by a new proposal in the case one is created, even if due to an
idle editor.
*/
/*!
\fn int basePosition() const
Returns the position from which this proposal starts.
*/
/*!
\fn bool isCorrective() const
Returns whether this proposal is also corrective. This could happen in C++, for example,
when a dot operator (.) needs to be replaced by an arrow operator (->) before the proposal
is displayed.
*/
/*!
\fn void makeCorrection(BaseTextEditor *editor)
This allows a correction to be made in the case this is a corrective proposal.
*/
/*!
\fn IAssistModel *model() const
Returns the model associated with this proposal.
Although the IAssistModel from this proposal may be used on its own, it needs to be
consistent with the widget returned by createWidget().
\sa createWidget()
*/
/*!
\fn IAssistProposalWidget *createWidget() const
Returns the widget associated with this proposal. The IAssistProposalWidget implementor
recommended for function hint proposals is FunctionHintProposalWidget. For snippets,
refactoring operations (quickfixes), and contextual content the recommeded implementor
is GenericProposalWidget.
*/
@@ -0,0 +1,60 @@
/**************************************************************************
**
** 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 IASSISTPROPOSAL_H
#define IASSISTPROPOSAL_H
#include <texteditor/texteditor_global.h>
namespace TextEditor {
class IAssistProposalModel;
class IAssistProposalWidget;
class BaseTextEditor;
class TEXTEDITOR_EXPORT IAssistProposal
{
public:
IAssistProposal();
virtual ~IAssistProposal();
virtual bool isFragile() const = 0;
virtual int basePosition() const = 0;
virtual bool isCorrective() const = 0;
virtual void makeCorrection(BaseTextEditor *editor) = 0;
virtual IAssistProposalModel *model() const = 0;
virtual IAssistProposalWidget *createWidget() const = 0;
};
} // TextEditor
#endif // IASSISTPROPOSAL_H
@@ -0,0 +1,65 @@
/**************************************************************************
**
** 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 "iassistproposalitem.h"
using namespace TextEditor;
/*!
\class IAssistProposalItem
\brief The IAssistProposalItem is an interface for representing an assist proposal item.
*/
IAssistProposalItem::IAssistProposalItem()
{}
IAssistProposalItem::~IAssistProposalItem()
{}
/*!
\fn bool implicitlyApplies() const
Returns whether this item should implicitly apply in the case it is the only proposal
item available.
*/
/*!
\fn bool prematurelyApplies(const QChar &c) const
Returns whether the character \a c causes this item to be applied.
*/
/*!
\fn void apply(BaseTextEditor *editor, int basePosition) const
This is the place to implement the actual application of the item.
*/
@@ -0,0 +1,59 @@
/**************************************************************************
**
** 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 IASSISTPROPOSALITEM_H
#define IASSISTPROPOSALITEM_H
#include <texteditor/texteditor_global.h>
QT_BEGIN_NAMESPACE
class QChar;
QT_END_NAMESPACE
namespace TextEditor {
class BaseTextEditor;
class TEXTEDITOR_EXPORT IAssistProposalItem
{
public:
IAssistProposalItem();
virtual ~IAssistProposalItem();
virtual bool implicitlyApplies() const = 0;
virtual bool prematurelyApplies(const QChar &c) const = 0;
virtual void apply(BaseTextEditor *editor, int basePosition) const = 0;
};
} // TextEditor
#endif // IASSISTPROPOSALITEM_H
@@ -0,0 +1,52 @@
/**************************************************************************
**
** 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 "iassistproposalmodel.h"
using namespace TextEditor;
/*!
\class IAssistProposalModel
\brief The IAssistProposalModel is an interface for representing proposals.
Known implenters of this interface are IFunctionHintProposalModel and IGenericProposalModel.
The former is recommeded to be used when assisting function calls constructs (overloads
and parameters) while the latter is quite generic so that it could be used to propose
snippets, refactoring operations (quickfixes), and contextual content (the member of class
or a string existent in the document, for example).
*/
IAssistProposalModel::IAssistProposalModel()
{}
IAssistProposalModel::~IAssistProposalModel()
{}
@@ -0,0 +1,57 @@
/**************************************************************************
**
** 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 IASSISTMODEL_H
#define IASSISTMODEL_H
#include <texteditor/texteditor_global.h>
#include <QtCore/QString>
namespace TextEditor {
class IAssistProposalItem;
class TEXTEDITOR_EXPORT IAssistProposalModel
{
public:
IAssistProposalModel();
virtual ~IAssistProposalModel();
virtual void reset() = 0;
virtual int size() const = 0;
virtual QString text(int index) const = 0;
};
} // TextEditor
#endif // IASSISTMODEL_H
@@ -0,0 +1,142 @@
/**************************************************************************
**
** 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 "iassistproposalwidget.h"
using namespace TextEditor;
/*!
\class IAssistProposalWidget
\brief The IAssistProposalWidget is an interface for widgets that display assist proposals.
Known implenters of this interface are FunctionHintProposalWidget and GenericProposalWidget.
The former is recommeded to be used when assisting function calls constructs (overloads
and parameters) while the latter is quite generic so that it could be used to propose
snippets, refactoring operations (quickfixes), and contextual content (the member of class
or a string existent in the document, for example).
In general this API tries to be as decoupled as possible from the base text editor.
This is in order to make the design a bit more generic and allow code assist to be
pluggable into different types of documents (there are still issues to be treated).
\sa IAssistProposal
*/
IAssistProposalWidget::IAssistProposalWidget()
: QFrame(0, Qt::Popup)
{}
IAssistProposalWidget::~IAssistProposalWidget()
{}
/*!
\fn void setAssistant(CodeAssistant *assistant)
Sets the code assistant which is the owner of this widget. This is used so that the code
assistant can be notified when changes on the underlying widget happen.
*/
/*!
\fn void setReason(AssistReason reason)
Sets the reason which triggered the assist.
*/
/*!
\fn void setUnderlyingWidget(const QWidget *underlyingWidget)
Sets the underlying widget upon which this proposal operates.
*/
/*!
\fn void setModel(IAssistModel *model)
Sets the model.
*/
/*!
\fn void setDisplayRect(const QRect &rect)
Sets the \a rect on which this widget should be displayed.
*/
/*!
\fn void showProposal(const QString &prefix)
Shows the proposal. The \a prefix is the string comprised from the character at the base
position of the proposal until the character immediately after the cursor at the moment
the proposal is displayed.
\sa IAssistProposal::basePosition()
*/
/*!
\fn virtual void updateProposal(const QString &prefix)
Updates the proposal base on the give \a prefix.
\sa showProposal()
*/
/*!
\fn void closeProposal()
Closes the proposal.
*/
/*!
\fn void setIsSynchronized(bool isSync)
Sets whether this widget is synchronized. If a widget is synchronized it means that from
the moment a proposal started being computed until the moment it is actually displayed,
there was no content input into the underlying widget.
A widget is not synchronized in the case a proposal is computed in a separate thread and
in the meanwhile (while it is still being processed) content is input into the underlying
widget.
*/
/*!
\fn void prefixExpanded(const QString &newPrefix)
The signal is emitted whenever this widget automatically expands the prefix of the proposal.
This can happen if all available proposal items share the same prefix and if the proposal's
model supports prefix expansion.
\sa IGenericProposalModel::supportsPrefixExpansion()
*/
/*!
void proposalItemActivated(IAssistProposalItem *proposalItem)
This signal is emitted whenever \a proposalItem is chosen to be applied.
*/
@@ -0,0 +1,74 @@
/**************************************************************************
**
** 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 IASSISTPROPOSALWIDGET_H
#define IASSISTPROPOSALWIDGET_H
#include "assistenums.h"
#include <texteditor/texteditor_global.h>
#include <QtGui/QFrame>
namespace TextEditor {
class CodeAssistant;
class IAssistProposalModel;
class IAssistProposalItem;
class TEXTEDITOR_EXPORT IAssistProposalWidget : public QFrame
{
Q_OBJECT
public:
IAssistProposalWidget();
virtual ~IAssistProposalWidget();
virtual void setAssistant(CodeAssistant *assistant) = 0;
virtual void setReason(AssistReason reason) = 0;
virtual void setUnderlyingWidget(const QWidget *underlyingWidget) = 0;
virtual void setModel(IAssistProposalModel *model) = 0;
virtual void setDisplayRect(const QRect &rect) = 0;
virtual void setIsSynchronized(bool isSync) = 0;
virtual void showProposal(const QString &prefix) = 0;
virtual void updateProposal(const QString &prefix) = 0;
virtual void closeProposal() = 0;
signals:
void prefixExpanded(const QString &newPrefix);
void proposalItemActivated(IAssistProposalItem *proposalItem);
};
} // TextEditor
#endif // IASSISTPROPOSALWIDGET_H
@@ -0,0 +1,68 @@
/**************************************************************************
**
** 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 "iassistprovider.h"
using namespace TextEditor;
/*!
\class IAssistProvider
\brief The IAssistProvider is an interface for providing code assist.
There might be different kinds of assist such as completions or refactoring
actions (quickfixes).
Within this API the term completion denotes any kind of information prompted
to the user in order to auxiliate her to "complete" a particular code construction.
Examples of completions currently supported are snippets, function hints, and
contextual contents.
\sa IAssistProposal, IAssistProcessor
*/
IAssistProvider::IAssistProvider()
{}
IAssistProvider::~IAssistProvider()
{}
/*!
\fn bool supportsEditor(const QString &editorId) const
Returns whether this provider supports the editor which has the give \a editorId.
*/
/*!
\fn IAssistProcessor *createProcessor() const
Creates and returns the IAssistProcessor responsible for computing an IAssistProposal.
*/
@@ -30,44 +30,29 @@
**
**************************************************************************/
#ifndef COMPLETIONSUPPORT_H
#define COMPLETIONSUPPORT_H
#ifndef IASSISTPROVIDER_H
#define IASSISTPROVIDER_H
#include <texteditor/texteditor_global.h>
#include <texteditor/icompletioncollector.h>
#include <QtCore/QObject>
namespace TextEditor {
class ITextEditor;
class CompletionSupportPrivate;
class IAssistProcessor;
/* Completion support is responsible for querying the list of completion collectors
and popping up the CompletionWidget with the available completions.
*/
class TEXTEDITOR_EXPORT CompletionSupport : public QObject
class TEXTEDITOR_EXPORT IAssistProvider : public QObject
{
Q_OBJECT
public:
virtual ~CompletionSupport();
IAssistProvider();
virtual ~IAssistProvider();
static CompletionSupport *instance();
bool isActive() const;
CompletionPolicy policy() const;
public slots:
void complete(TextEditor::ITextEditor *editor,
TextEditor::CompletionPolicy policy, bool forced);
private:
CompletionSupport();
QScopedPointer<CompletionSupportPrivate> d;
virtual bool supportsEditor(const QString &editorId) const = 0;
virtual IAssistProcessor *createProcessor() const = 0;
};
} // namespace TextEditor
#endif // COMPLETIONSUPPORT_H
} // TextEditor
#endif // IASSISTPROVIDER_H
@@ -0,0 +1,41 @@
/**************************************************************************
**
** 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 "ifunctionhintproposalmodel.h"
using namespace TextEditor;
IFunctionHintProposalModel::IFunctionHintProposalModel()
{}
IFunctionHintProposalModel::~IFunctionHintProposalModel()
{}
@@ -0,0 +1,53 @@
/**************************************************************************
**
** 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 IFUNCTIONHINTPROPOSALMODEL_H
#define IFUNCTIONHINTPROPOSALMODEL_H
#include "iassistproposalmodel.h"
#include <texteditor/texteditor_global.h>
namespace TextEditor {
class TEXTEDITOR_EXPORT IFunctionHintProposalModel : public IAssistProposalModel
{
public:
IFunctionHintProposalModel();
virtual ~IFunctionHintProposalModel();
virtual int activeArgument(const QString &prefix) const = 0;
};
} // TextEditor
#endif // IFUNCTIONHINTPROPOSALMODEL_H
@@ -0,0 +1,41 @@
/**************************************************************************
**
** 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 "igenericproposalmodel.h"
using namespace TextEditor;
IGenericProposalModel::IGenericProposalModel()
{}
IGenericProposalModel::~IGenericProposalModel()
{}
@@ -0,0 +1,66 @@
/**************************************************************************
**
** 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 IGENERICPROPOSALMODEL_H
#define IGENERICPROPOSALMODEL_H
#include "iassistproposalmodel.h"
#include <texteditor/texteditor_global.h>
#include <QtGui/QIcon>
namespace TextEditor {
class IAssistProposalItem;
class TEXTEDITOR_EXPORT IGenericProposalModel : public IAssistProposalModel
{
public:
IGenericProposalModel();
virtual ~IGenericProposalModel();
virtual QIcon icon(int index) const = 0;
virtual QString detail(int index) const = 0;
virtual int persistentId(int index) const = 0;
virtual void removeDuplicates() = 0;
virtual void filter(const QString &prefix) = 0;
virtual bool isSortable() const = 0;
virtual void sort() = 0;
virtual bool supportsPrefixExpansion() const = 0;
virtual QString proposalPrefix() const = 0;
virtual IAssistProposalItem *proposalItem(int index) const = 0;
};
} // TextEditor
#endif // IGENERICPROPOSALMODEL_H
@@ -0,0 +1,96 @@
/**************************************************************************
**
** 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 "quickfixassistprocessor.h"
#include "quickfixassistprovider.h"
#include "iassistinterface.h"
#include "basicproposalitemlistmodel.h"
#include "basicproposalitem.h"
#include "genericproposal.h"
// @TODO: Move...
#include <texteditor/quickfix.h>
#include <QtCore/QMap>
#include <QtCore/QDebug>
using namespace TextEditor;
QuickFixAssistProcessor::QuickFixAssistProcessor()
{}
QuickFixAssistProcessor::~QuickFixAssistProcessor()
{}
IAssistProposal *QuickFixAssistProcessor::perform(const IAssistInterface *interface)
{
if (!interface)
return 0;
QSharedPointer<const IAssistInterface> assistInterface(interface);
const QuickFixAssistProvider *quickFixProvider =
static_cast<const QuickFixAssistProvider *>(provider());
QMap<int, QList<QuickFixOperation::Ptr> > matchedOps;
foreach (QuickFixFactory *factory, quickFixProvider->quickFixFactories()) {
QList<QuickFixOperation::Ptr> ops = factory->matchingOperations(assistInterface);
foreach (QuickFixOperation::Ptr op, ops) {
const int priority = op->priority();
if (priority != -1)
matchedOps[priority].append(op);
}
}
QList<QuickFixOperation::Ptr> quickFixes;
QMapIterator<int, QList<QuickFixOperation::Ptr> > it(matchedOps);
it.toBack();
if (it.hasPrevious()) {
it.previous();
quickFixes = it.value();
}
if (!quickFixes.isEmpty()) {
QList<BasicProposalItem *> items;
foreach (const QuickFixOperation::Ptr &op, quickFixes) {
QVariant v;
v.setValue(op);
BasicProposalItem *item = new BasicProposalItem;
item->setText(op->description());
item->setData(v);
items.append(item);
}
return new GenericProposal(interface->position(), new BasicProposalItemListModel(items));
}
return 0;
}

Some files were not shown because too many files have changed in this diff Show More