summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLeandro Melo <leandro.melo@nokia.com>2011-04-15 16:19:23 +0200
committerLeandro Melo <leandro.melo@nokia.com>2011-05-18 10:46:20 +0200
commitbec4f02495b97b17e0b0f8cb67d0909634c16228 (patch)
tree21759e0b9ebc6b0dca84f01875223020665d7843 /src
parentd835b769c7d6b37e59a8a74a0d68260d34e7a7f9 (diff)
downloadqt-creator-bec4f02495b97b17e0b0f8cb67d0909634c16228.tar.gz
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).
Diffstat (limited to 'src')
-rw-r--r--src/plugins/cppeditor/cppcompleteswitch.cpp31
-rw-r--r--src/plugins/cppeditor/cppcompleteswitch.h3
-rw-r--r--src/plugins/cppeditor/cppeditor.cpp70
-rw-r--r--src/plugins/cppeditor/cppeditor.h5
-rw-r--r--src/plugins/cppeditor/cppeditor.pro12
-rw-r--r--src/plugins/cppeditor/cppinsertdecldef.cpp40
-rw-r--r--src/plugins/cppeditor/cppinsertdecldef.h8
-rw-r--r--src/plugins/cppeditor/cppinsertqtpropertymembers.cpp18
-rw-r--r--src/plugins/cppeditor/cppinsertqtpropertymembers.h6
-rw-r--r--src/plugins/cppeditor/cppplugin.cpp52
-rw-r--r--src/plugins/cppeditor/cppplugin.h8
-rw-r--r--src/plugins/cppeditor/cppquickfix.cpp73
-rw-r--r--src/plugins/cppeditor/cppquickfix.h44
-rw-r--r--src/plugins/cppeditor/cppquickfixassistant.cpp152
-rw-r--r--src/plugins/cppeditor/cppquickfixassistant.h101
-rw-r--r--src/plugins/cppeditor/cppquickfixcollector.cpp100
-rw-r--r--src/plugins/cppeditor/cppquickfixes.cpp267
-rw-r--r--src/plugins/cpptools/cppcodecompletion.h175
-rw-r--r--src/plugins/cpptools/cppcompletionassist.cpp (renamed from src/plugins/cpptools/cppcodecompletion.cpp)2471
-rw-r--r--src/plugins/cpptools/cppcompletionassist.h172
-rw-r--r--src/plugins/cpptools/cpptools.pro8
-rw-r--r--src/plugins/cpptools/cpptoolsplugin.cpp12
-rw-r--r--src/plugins/fakevim/fakevimplugin.cpp212
-rw-r--r--src/plugins/glsleditor/glslcodecompletion.cpp731
-rw-r--r--src/plugins/glsleditor/glslcodecompletion.h134
-rw-r--r--src/plugins/glsleditor/glslcompletionassist.cpp478
-rw-r--r--src/plugins/glsleditor/glslcompletionassist.h115
-rw-r--r--src/plugins/glsleditor/glsleditor.cpp15
-rw-r--r--src/plugins/glsleditor/glsleditor.h3
-rw-r--r--src/plugins/glsleditor/glsleditor.pro10
-rw-r--r--src/plugins/glsleditor/glsleditorplugin.cpp12
-rw-r--r--src/plugins/glsleditor/reuse.cpp83
-rw-r--r--src/plugins/glsleditor/reuse.h46
-rw-r--r--src/plugins/qmljseditor/qmljscodecompletion.cpp1146
-rw-r--r--src/plugins/qmljseditor/qmljscodecompletion.h114
-rw-r--r--src/plugins/qmljseditor/qmljscompletionassist.cpp854
-rw-r--r--src/plugins/qmljseditor/qmljscompletionassist.h158
-rw-r--r--src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp20
-rw-r--r--src/plugins/qmljseditor/qmljscomponentfromobjectdef.h3
-rw-r--r--src/plugins/qmljseditor/qmljseditor.cpp54
-rw-r--r--src/plugins/qmljseditor/qmljseditor.h3
-rw-r--r--src/plugins/qmljseditor/qmljseditor.pro16
-rw-r--r--src/plugins/qmljseditor/qmljseditorplugin.cpp61
-rw-r--r--src/plugins/qmljseditor/qmljseditorplugin.h9
-rw-r--r--src/plugins/qmljseditor/qmljshoverhandler.h2
-rw-r--r--src/plugins/qmljseditor/qmljsquickfix.cpp95
-rw-r--r--src/plugins/qmljseditor/qmljsquickfix.h75
-rw-r--r--src/plugins/qmljseditor/qmljsquickfixassist.cpp115
-rw-r--r--src/plugins/qmljseditor/qmljsquickfixassist.h91
-rw-r--r--src/plugins/qmljseditor/qmljsquickfixes.cpp17
-rw-r--r--src/plugins/qmljseditor/qmljsreuse.cpp122
-rw-r--r--src/plugins/qmljseditor/qmljsreuse.h55
-rw-r--r--src/plugins/qt4projectmanager/profilecompletion.cpp224
-rw-r--r--src/plugins/qt4projectmanager/profilecompletion.h78
-rw-r--r--src/plugins/qt4projectmanager/profilecompletionassist.cpp231
-rw-r--r--src/plugins/qt4projectmanager/profilecompletionassist.h106
-rw-r--r--src/plugins/qt4projectmanager/profileeditorfactory.cpp1
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanager.pro9
-rw-r--r--src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp10
-rw-r--r--src/plugins/texteditor/basetexteditor.cpp108
-rw-r--r--src/plugins/texteditor/basetexteditor.h14
-rw-r--r--src/plugins/texteditor/basetexteditor_p.h6
-rw-r--r--src/plugins/texteditor/codeassist/assistenums.h53
-rw-r--r--src/plugins/texteditor/codeassist/basicproposalitem.cpp142
-rw-r--r--src/plugins/texteditor/codeassist/basicproposalitem.h83
-rw-r--r--src/plugins/texteditor/codeassist/basicproposalitemlistmodel.cpp267
-rw-r--r--src/plugins/texteditor/codeassist/basicproposalitemlistmodel.h85
-rw-r--r--src/plugins/texteditor/codeassist/codeassistant.cpp506
-rw-r--r--src/plugins/texteditor/codeassist/codeassistant.h (renamed from src/plugins/cppeditor/cppquickfixcollector.h)45
-rw-r--r--src/plugins/texteditor/codeassist/completionassistprovider.cpp64
-rw-r--r--src/plugins/texteditor/codeassist/completionassistprovider.h56
-rw-r--r--src/plugins/texteditor/codeassist/defaultassistinterface.cpp80
-rw-r--r--src/plugins/texteditor/codeassist/defaultassistinterface.h67
-rw-r--r--src/plugins/texteditor/codeassist/functionhintproposal.cpp73
-rw-r--r--src/plugins/texteditor/codeassist/functionhintproposal.h62
-rw-r--r--src/plugins/texteditor/codeassist/functionhintproposalwidget.cpp314
-rw-r--r--src/plugins/texteditor/codeassist/functionhintproposalwidget.h82
-rw-r--r--src/plugins/texteditor/codeassist/genericproposal.cpp78
-rw-r--r--src/plugins/texteditor/codeassist/genericproposal.h65
-rw-r--r--src/plugins/texteditor/codeassist/genericproposalwidget.cpp576
-rw-r--r--src/plugins/texteditor/codeassist/genericproposalwidget.h79
-rw-r--r--src/plugins/texteditor/codeassist/iassistinterface.cpp100
-rw-r--r--src/plugins/texteditor/codeassist/iassistinterface.h70
-rw-r--r--src/plugins/texteditor/codeassist/iassistprocessor.cpp61
-rw-r--r--src/plugins/texteditor/codeassist/iassistprocessor.h57
-rw-r--r--src/plugins/texteditor/codeassist/iassistproposal.cpp102
-rw-r--r--src/plugins/texteditor/codeassist/iassistproposal.h60
-rw-r--r--src/plugins/texteditor/codeassist/iassistproposalitem.cpp65
-rw-r--r--src/plugins/texteditor/codeassist/iassistproposalitem.h59
-rw-r--r--src/plugins/texteditor/codeassist/iassistproposalmodel.cpp52
-rw-r--r--src/plugins/texteditor/codeassist/iassistproposalmodel.h57
-rw-r--r--src/plugins/texteditor/codeassist/iassistproposalwidget.cpp142
-rw-r--r--src/plugins/texteditor/codeassist/iassistproposalwidget.h74
-rw-r--r--src/plugins/texteditor/codeassist/iassistprovider.cpp68
-rw-r--r--src/plugins/texteditor/codeassist/iassistprovider.h (renamed from src/plugins/texteditor/completionsupport.h)35
-rw-r--r--src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.cpp41
-rw-r--r--src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.h53
-rw-r--r--src/plugins/texteditor/codeassist/igenericproposalmodel.cpp41
-rw-r--r--src/plugins/texteditor/codeassist/igenericproposalmodel.h66
-rw-r--r--src/plugins/texteditor/codeassist/quickfixassistprocessor.cpp96
-rw-r--r--src/plugins/texteditor/codeassist/quickfixassistprocessor.h52
-rw-r--r--src/plugins/texteditor/codeassist/quickfixassistprovider.cpp46
-rw-r--r--src/plugins/texteditor/codeassist/quickfixassistprovider.h57
-rw-r--r--src/plugins/texteditor/codeassist/runner.cpp88
-rw-r--r--src/plugins/texteditor/codeassist/runner.h79
-rw-r--r--src/plugins/texteditor/completionsettings.h6
-rw-r--r--src/plugins/texteditor/completionsupport.cpp243
-rw-r--r--src/plugins/texteditor/completionwidget.cpp499
-rw-r--r--src/plugins/texteditor/completionwidget.h136
-rw-r--r--src/plugins/texteditor/convenience.cpp70
-rw-r--r--src/plugins/texteditor/convenience.h57
-rw-r--r--src/plugins/texteditor/icompletioncollector.cpp218
-rw-r--r--src/plugins/texteditor/icompletioncollector.h204
-rw-r--r--src/plugins/texteditor/quickfix.cpp113
-rw-r--r--src/plugins/texteditor/quickfix.h77
-rw-r--r--src/plugins/texteditor/snippets/snippetassistcollector.cpp (renamed from src/plugins/texteditor/snippets/snippetcollector.cpp)40
-rw-r--r--src/plugins/texteditor/snippets/snippetassistcollector.h (renamed from src/plugins/texteditor/snippets/snippetcollector.h)17
-rw-r--r--src/plugins/texteditor/texteditor.pro62
-rw-r--r--src/plugins/texteditor/texteditorplugin.cpp12
119 files changed, 9184 insertions, 6432 deletions
diff --git a/src/plugins/cppeditor/cppcompleteswitch.cpp b/src/plugins/cppeditor/cppcompleteswitch.cpp
index 62222ac7bf..05ec2c440e 100644
--- a/src/plugins/cppeditor/cppcompleteswitch.cpp
+++ b/src/plugins/cppeditor/cppcompleteswitch.cpp
@@ -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();
diff --git a/src/plugins/cppeditor/cppcompleteswitch.h b/src/plugins/cppeditor/cppcompleteswitch.h
index f1d9c9b361..b0cd42cdde 100644
--- a/src/plugins/cppeditor/cppcompleteswitch.h
+++ b/src/plugins/cppeditor/cppcompleteswitch.h
@@ -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
diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
index 354d4cea7d..0e63fffcd4 100644
--- a/src/plugins/cppeditor/cppeditor.cpp
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -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,22 +1620,29 @@ 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);
- QAction *action = quickFixMenu->addAction(op->description());
- mapper.setMapping(action, index);
- connect(action, SIGNAL(triggered()), &mapper, SLOT(map()));
+ TextEditor::IAssistInterface *interface =
+ createAssistInterface(TextEditor::QuickFix, TextEditor::ExplicitlyInvoked);
+ if (interface) {
+ QScopedPointer<TextEditor::IAssistProcessor> processor(
+ 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"
diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h
index 9250ba15bb..7ac1eee8e6 100644
--- a/src/plugins/cppeditor/cppeditor.h
+++ b/src/plugins/cppeditor/cppeditor.h
@@ -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);
diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro
index 95abbbde12..0431b33ee5 100644
--- a/src/plugins/cppeditor/cppeditor.pro
+++ b/src/plugins/cppeditor/cppeditor.pro
@@ -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
diff --git a/src/plugins/cppeditor/cppinsertdecldef.cpp b/src/plugins/cppeditor/cppinsertdecldef.cpp
index 10032a9862..019af89a13 100644
--- a/src/plugins/cppeditor/cppinsertdecldef.cpp
+++ b/src/plugins/cppeditor/cppinsertdecldef.cpp
@@ -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;
}
diff --git a/src/plugins/cppeditor/cppinsertdecldef.h b/src/plugins/cppeditor/cppinsertdecldef.h
index 61273cb33d..793640bcb8 100644
--- a/src/plugins/cppeditor/cppinsertdecldef.h
+++ b/src/plugins/cppeditor/cppinsertdecldef.h
@@ -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
diff --git a/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp b/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp
index 485acecf4e..9945746f06 100644
--- a/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp
+++ b/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp
@@ -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)
diff --git a/src/plugins/cppeditor/cppinsertqtpropertymembers.h b/src/plugins/cppeditor/cppinsertqtpropertymembers.h
index 4a36a0a6e6..785ac87ba1 100644
--- a/src/plugins/cppeditor/cppinsertqtpropertymembers.h
+++ b/src/plugins/cppeditor/cppinsertqtpropertymembers.h
@@ -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,
diff --git a/src/plugins/cppeditor/cppplugin.cpp b/src/plugins/cppeditor/cppplugin.cpp
index 22b60e21d9..2612fd01e6 100644
--- a/src/plugins/cppeditor/cppplugin.cpp
+++ b/src/plugins/cppeditor/cppplugin.cpp
@@ -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) {
diff --git a/src/plugins/cppeditor/cppplugin.h b/src/plugins/cppeditor/cppplugin.h
index 5529de18d6..9a0946d2e4 100644
--- a/src/plugins/cppeditor/cppplugin.h
+++ b/src/plugins/cppeditor/cppplugin.h
@@ -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;
};
diff --git a/src/plugins/cppeditor/cppquickfix.cpp b/src/plugins/cppeditor/cppquickfix.cpp
index cec45fd890..ae63fb43ed 100644
--- a/src/plugins/cppeditor/cppquickfix.cpp
+++ b/src/plugins/cppeditor/cppquickfix.cpp
@@ -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)
diff --git a/src/plugins/cppeditor/cppquickfix.h b/src/plugins/cppeditor/cppquickfix.h
index 034ab9e2f5..71da104263 100644
--- a/src/plugins/cppeditor/cppquickfix.h
+++ b/src/plugins/cppeditor/cppquickfix.h
@@ -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:
/*!
diff --git a/src/plugins/cppeditor/cppquickfixassistant.cpp b/src/plugins/cppeditor/cppquickfixassistant.cpp
new file mode 100644
index 0000000000..9b998c2db3
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixassistant.cpp
@@ -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);
+}
diff --git a/src/plugins/cppeditor/cppquickfixassistant.h b/src/plugins/cppeditor/cppquickfixassistant.h
new file mode 100644
index 0000000000..f08a9ea610
--- /dev/null
+++ b/src/plugins/cppeditor/cppquickfixassistant.h
@@ -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
diff --git a/src/plugins/cppeditor/cppquickfixcollector.cpp b/src/plugins/cppeditor/cppquickfixcollector.cpp
deleted file mode 100644
index a48f832d85..0000000000
--- a/src/plugins/cppeditor/cppquickfixcollector.cpp
+++ /dev/null
@@ -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
diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp
index fa7da44fff..1f76416755 100644
--- a/src/plugins/cppeditor/cppquickfixes.cpp
+++ b/src/plugins/cppeditor/cppquickfixes.cpp
@@ -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);
}
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
deleted file mode 100644
index 8d14095f83..0000000000
--- a/src/plugins/cpptools/cppcodecompletion.h
+++ /dev/null
@@ -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
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcompletionassist.cpp
index 5b2c309277..d6e89dc3dc 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcompletionassist.cpp
@@ -30,11 +30,11 @@
**
**************************************************************************/
-#include "cppcodecompletion.h"
#include "cppmodelmanager.h"
+#include "cppcompletionassist.h"
#include "cppdoxygen.h"
+#include "cppmodelmanager.h"
#include "cpptoolsconstants.h"
-#include "cpptoolseditorsupport.h"
#include <Control.h>
#include <AST.h>
@@ -55,277 +55,406 @@
#include <cplusplus/BackwardsScanner.h>
#include <cplusplus/LookupContext.h>
-#include <cppeditor/cppeditorconstants.h>
-
+#include <coreplugin/ifile.h>
#include <coreplugin/icore.h>
#include <coreplugin/mimedatabase.h>
-#include <coreplugin/editormanager/editormanager.h>
-#include <texteditor/completionsettings.h>
-#include <texteditor/basetexteditor.h>
+#include <cppeditor/cppeditorconstants.h>
+#include <texteditor/codeassist/basicproposalitem.h>
+#include <texteditor/codeassist/basicproposalitemlistmodel.h>
+#include <texteditor/codeassist/genericproposal.h>
+#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
+#include <texteditor/codeassist/functionhintproposal.h>
+#include <texteditor/convenience.h>
#include <texteditor/snippets/snippet.h>
-#include <projectexplorer/projectexplorer.h>
-
-#include <utils/faketooltip.h>
-#include <utils/qtcassert.h>
-
-#include <QtCore/QMap>
-#include <QtCore/QFile>
-#include <QtGui/QAction>
-#include <QtGui/QApplication>
-#include <QtGui/QDesktopWidget>
-#include <QtGui/QKeyEvent>
-#include <QtGui/QLabel>
-#include <QtGui/QStyle>
-#include <QtGui/QTextDocument> // Qt::escape()
-#include <QtGui/QToolButton>
-#include <QtGui/QVBoxLayout>
-#include <QtAlgorithms>
+#include <texteditor/texteditorsettings.h>
+#include <texteditor/completionsettings.h>
-namespace {
- const bool debug = ! qgetenv("CPLUSPLUS_DEBUG").isEmpty();
-}
+#include <QtCore/QLatin1String>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextDocument>
+#include <QtGui/QIcon>
using namespace CPlusPlus;
+using namespace CppEditor;
+using namespace CppTools;
+using namespace Internal;
+using namespace TextEditor;
-namespace CppTools {
-namespace Internal {
+namespace {
-class FunctionArgumentWidget : public QLabel
+int activationSequenceChar(const QChar &ch,
+ const QChar &ch2,
+ const QChar &ch3,
+ unsigned *kind,
+ bool wantFunctionCall)
{
- Q_OBJECT
+ int referencePosition = 0;
+ int completionKind = T_EOF_SYMBOL;
+ switch (ch.toLatin1()) {
+ case '.':
+ if (ch2 != QLatin1Char('.')) {
+ completionKind = T_DOT;
+ referencePosition = 1;
+ }
+ break;
+ case ',':
+ completionKind = T_COMMA;
+ referencePosition = 1;
+ break;
+ case '(':
+ if (wantFunctionCall) {
+ completionKind = T_LPAREN;
+ referencePosition = 1;
+ }
+ break;
+ case ':':
+ if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':')) {
+ completionKind = T_COLON_COLON;
+ referencePosition = 2;
+ }
+ break;
+ case '>':
+ if (ch2 == QLatin1Char('-')) {
+ completionKind = T_ARROW;
+ referencePosition = 2;
+ }
+ break;
+ case '*':
+ if (ch2 == QLatin1Char('.')) {
+ completionKind = T_DOT_STAR;
+ referencePosition = 2;
+ } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>')) {
+ completionKind = T_ARROW_STAR;
+ referencePosition = 3;
+ }
+ break;
+ case '\\':
+ case '@':
+ if (ch2.isNull() || ch2.isSpace()) {
+ completionKind = T_DOXY_COMMENT;
+ referencePosition = 1;
+ }
+ break;
+ case '<':
+ completionKind = T_ANGLE_STRING_LITERAL;
+ referencePosition = 1;
+ break;
+ case '"':
+ completionKind = T_STRING_LITERAL;
+ referencePosition = 1;
+ break;
+ case '/':
+ completionKind = T_SLASH;
+ referencePosition = 1;
+ break;
+ case '#':
+ completionKind = T_POUND;
+ referencePosition = 1;
+ break;
+ }
-public:
- FunctionArgumentWidget();
- void showFunctionHint(QList<Function *> functionSymbols,
- const LookupContext &context,
- int startPosition);
+ if (kind)
+ *kind = completionKind;
-protected:
- bool eventFilter(QObject *obj, QEvent *e);
+ return referencePosition;
+}
-private slots:
- void nextPage();
- void previousPage();
+} // Anonymous
-private:
- void updateArgumentHighlight();
- void updateHintText();
- void placeInsideScreen();
+namespace CppTools {
+namespace Internal {
- Function *currentFunction() const
- { return m_items.at(m_current); }
+struct CompleteFunctionDeclaration
+{
+ explicit CompleteFunctionDeclaration(Function *f = 0)
+ : function(f)
+ {}
+
+ Function *function;
+};
- int m_startpos;
- int m_currentarg;
- int m_current;
- bool m_escapePressed;
+// ----------------------
+// CppAssistProposalModel
+// ----------------------
+class CppAssistProposalModel : public TextEditor::BasicProposalItemListModel
+{
+public:
+ CppAssistProposalModel()
+ : TextEditor::BasicProposalItemListModel()
+ , m_sortable(false)
+ , m_completionOperator(T_EOF_SYMBOL)
+ , m_replaceDotForArrow(false)
+ {}
- TextEditor::ITextEditor *m_editor;
+ virtual bool isSortable() const { return m_sortable; }
+ virtual IAssistProposalItem *proposalItem(int index) const;
- QWidget *m_pager;
- QLabel *m_numberLabel;
- Utils::FakeToolTip *m_popupFrame;
- QList<Function *> m_items;
- LookupContext m_context;
+ bool m_sortable;
+ unsigned m_completionOperator;
+ bool m_replaceDotForArrow;
+ Snapshot m_snapshot;
};
-class ConvertToCompletionItem: protected NameVisitor
+// ---------------------
+// CppAssistProposalItem
+// ---------------------
+class CppAssistProposalItem : public TextEditor::BasicProposalItem
{
- // The completion collector.
- CppCodeCompletion *_collector;
-
- // The completion item.
- TextEditor::CompletionItem _item;
+public:
+ CppAssistProposalItem() : m_isOverloaded(false) {}
- // The current symbol.
- Symbol *_symbol;
+ virtual bool prematurelyApplies(const QChar &c) const;
+ virtual void applyContextualContent(TextEditor::BaseTextEditor *editor,
+ int basePosition) const;
- // The pretty printer.
- Overview overview;
+ bool isOverloaded() const { return m_isOverloaded; }
+ void markAsOverloaded() { m_isOverloaded = true; }
+ void keepCompletionOperator(unsigned compOp) { m_completionOperator = compOp; }
+ void keepSnapshot(const Snapshot &snapshot) { m_snapshot = snapshot; }
-public:
- ConvertToCompletionItem(CppCodeCompletion *collector)
- : _collector(collector),
- _item(0),
- _symbol(0)
- { }
+private:
+ bool m_isOverloaded;
+ unsigned m_completionOperator;
+ mutable QChar m_typedChar;
+ Snapshot m_snapshot;
+};
- TextEditor::CompletionItem operator()(Symbol *symbol)
- {
- if (! symbol || ! symbol->name() || symbol->name()->isQualifiedNameId())
- return 0;
+} // Internal
+} // CppTools
- TextEditor::CompletionItem previousItem = switchCompletionItem(0);
- Symbol *previousSymbol = switchSymbol(symbol);
- accept(symbol->unqualifiedName());
- if (_item.isValid())
- _item.data = QVariant::fromValue(symbol);
- (void) switchSymbol(previousSymbol);
- return switchCompletionItem(previousItem);
- }
+Q_DECLARE_METATYPE(CppTools::Internal::CompleteFunctionDeclaration)
-protected:
- Symbol *switchSymbol(Symbol *symbol)
- {
- Symbol *previousSymbol = _symbol;
- _symbol = symbol;
- return previousSymbol;
- }
+IAssistProposalItem *CppAssistProposalModel::proposalItem(int index) const
+{
+ BasicProposalItem *item =
+ static_cast<BasicProposalItem *>(BasicProposalItemListModel::proposalItem(index));
+ if (!item->data().canConvert<QString>()) {
+ CppAssistProposalItem *cppItem = static_cast<CppAssistProposalItem *>(item);
+ cppItem->keepCompletionOperator(m_completionOperator);
+ cppItem->keepSnapshot(m_snapshot);
+ }
+ return item;
+}
- TextEditor::CompletionItem switchCompletionItem(TextEditor::CompletionItem item)
- {
- TextEditor::CompletionItem previousItem = _item;
- _item = item;
- return previousItem;
+bool CppAssistProposalItem::prematurelyApplies(const QChar &typedChar) const
+{
+ if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
+ if (typedChar == QLatin1Char('(') || typedChar == QLatin1Char(',')) {
+ m_typedChar = typedChar;
+ return true;
+ }
+ } else if (m_completionOperator == T_STRING_LITERAL
+ || m_completionOperator == T_ANGLE_STRING_LITERAL) {
+ if (typedChar == QLatin1Char('/') && text().endsWith(QLatin1Char('/'))) {
+ m_typedChar = typedChar;
+ return true;
+ }
+ } else if (data().value<Symbol *>()) {
+ if (typedChar == QLatin1Char(':')
+ || typedChar == QLatin1Char(';')
+ || typedChar == QLatin1Char('.')
+ || typedChar == QLatin1Char(',')
+ || typedChar == QLatin1Char('(')) {
+ m_typedChar = typedChar;
+ return true;
+ }
+ } else if (data().canConvert<CompleteFunctionDeclaration>()) {
+ if (typedChar == QLatin1Char('(')) {
+ m_typedChar = typedChar;
+ return true;
+ }
}
- TextEditor::CompletionItem newCompletionItem(const Name *name)
- {
- TextEditor::CompletionItem item(_collector);
- item.text = overview.prettyName(name);
- item.icon = _collector->iconForSymbol(_symbol);
- return item;
- }
+ return false;
+}
- virtual void visit(const Identifier *name)
- { _item = newCompletionItem(name); }
+void CppAssistProposalItem::applyContextualContent(TextEditor::BaseTextEditor *editor,
+ int basePosition) const
+{
+ Symbol *symbol = 0;
- virtual void visit(const TemplateNameId *name)
- {
- _item = newCompletionItem(name);
- _item.text = QLatin1String(name->identifier()->chars());
- }
+ if (data().isValid())
+ symbol = data().value<Symbol *>();
- virtual void visit(const DestructorNameId *name)
- { _item = newCompletionItem(name); }
+ QString toInsert;
+ QString extraChars;
+ int extraLength = 0;
+ int cursorOffset = 0;
- virtual void visit(const OperatorNameId *name)
- { _item = newCompletionItem(name); }
+ bool autoParenthesesEnabled = true;
- virtual void visit(const ConversionNameId *name)
- { _item = newCompletionItem(name); }
+ if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
+ toInsert = text();
+ extraChars += QLatin1Char(')');
- virtual void visit(const QualifiedNameId *name)
- { _item = newCompletionItem(name->name()); }
-};
+ if (m_typedChar == QLatin1Char('(')) // Eat the opening parenthesis
+ m_typedChar = QChar();
+ } else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) {
+ toInsert = text();
+ if (!toInsert.endsWith(QLatin1Char('/'))) {
+ extraChars += QLatin1Char((m_completionOperator == T_ANGLE_STRING_LITERAL) ? '>' : '"');
+ } else {
+ if (m_typedChar == QLatin1Char('/')) // Eat the slash
+ m_typedChar = QChar();
+ }
+ } else {
+ toInsert = text();
-struct CompleteFunctionDeclaration
-{
- explicit CompleteFunctionDeclaration(Function *f = 0)
- : function(f)
- {}
+ const CompletionSettings &completionSettings =
+ TextEditorSettings::instance()->completionSettings();
+ const bool autoInsertBrackets = completionSettings.m_autoInsertBrackets;
- Function *function;
-};
+ if (autoInsertBrackets && symbol && symbol->type()) {
+ if (Function *function = symbol->type()->asFunctionType()) {
+ // If the member is a function, automatically place the opening parenthesis,
+ // except when it might take template parameters.
+ if (! function->hasReturnType() && (function->unqualifiedName() && !function->unqualifiedName()->isDestructorNameId())) {
+ // Don't insert any magic, since the user might have just wanted to select the class
-} // namespace Internal
-} // namespace CppTools
+ /// ### port me
+#if 0
+ } else if (function->templateParameterCount() != 0 && typedChar != QLatin1Char('(')) {
+ // If there are no arguments, then we need the template specification
+ if (function->argumentCount() == 0) {
+ extraChars += QLatin1Char('<');
+ }
+#endif
+ } else if (! function->isAmbiguous()) {
+ // When the user typed the opening parenthesis, he'll likely also type the closing one,
+ // in which case it would be annoying if we put the cursor after the already automatically
+ // inserted closing parenthesis.
+ const bool skipClosingParenthesis = m_typedChar != QLatin1Char('(');
-using namespace CppTools::Internal;
+ if (completionSettings.m_spaceAfterFunctionName)
+ extraChars += QLatin1Char(' ');
+ extraChars += QLatin1Char('(');
+ if (m_typedChar == QLatin1Char('('))
+ m_typedChar = QChar();
-Q_DECLARE_METATYPE(CompleteFunctionDeclaration)
+ // If the function doesn't return anything, automatically place the semicolon,
+ // unless we're doing a scope completion (then it might be function definition).
+ const QChar characterAtCursor = editor->characterAt(editor->position());
+ bool endWithSemicolon = m_typedChar == QLatin1Char(';')
+ || (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON);
+ const QChar semicolon = m_typedChar.isNull() ? QLatin1Char(';') : m_typedChar;
+ if (endWithSemicolon && characterAtCursor == semicolon) {
+ endWithSemicolon = false;
+ m_typedChar = QChar();
+ }
-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);
-}
+ // If the function takes no arguments, automatically place the closing parenthesis
+ if (!isOverloaded() && ! function->hasArguments() && skipClosingParenthesis) {
+ extraChars += QLatin1Char(')');
+ if (endWithSemicolon) {
+ extraChars += semicolon;
+ m_typedChar = QChar();
+ }
+ } else if (autoParenthesesEnabled) {
+ const QChar lookAhead = editor->characterAt(editor->position() + 1);
+ if (MatchingText::shouldInsertMatchingText(lookAhead)) {
+ extraChars += QLatin1Char(')');
+ --cursorOffset;
+ if (endWithSemicolon) {
+ extraChars += semicolon;
+ --cursorOffset;
+ m_typedChar = QChar();
+ }
+ }
+ // TODO: When an opening parenthesis exists, the "semicolon" should really be
+ // inserted after the matching closing parenthesis.
+ }
+ }
+ }
+ }
-void FunctionArgumentWidget::showFunctionHint(QList<Function *> functionSymbols,
- const LookupContext &context,
- int startPosition)
-{
- Q_ASSERT(!functionSymbols.isEmpty());
+ if (autoInsertBrackets && data().canConvert<CompleteFunctionDeclaration>()) {
+ if (m_typedChar == QLatin1Char('('))
+ m_typedChar = QChar();
- if (m_startpos == startPosition)
- return;
+ // everything from the closing parenthesis on are extra chars, to
+ // make sure an auto-inserted ")" gets replaced by ") const" if necessary
+ int closingParen = toInsert.lastIndexOf(QLatin1Char(')'));
+ extraChars = toInsert.mid(closingParen);
+ toInsert.truncate(closingParen);
+ }
+ }
- m_pager->setVisible(functionSymbols.size() > 1);
+ // Append an unhandled typed character, adjusting cursor offset when it had been adjusted before
+ if (!m_typedChar.isNull()) {
+ extraChars += m_typedChar;
+ if (cursorOffset != 0)
+ --cursorOffset;
+ }
- m_items = functionSymbols;
- m_context = context;
- m_startpos = startPosition;
- m_current = 0;
- m_escapePressed = false;
+ // Avoid inserting characters that are already there
+ for (int i = 0; i < extraChars.length(); ++i) {
+ const QChar a = extraChars.at(i);
+ const QChar b = editor->characterAt(editor->position() + i);
+ if (a == b)
+ ++extraLength;
+ else
+ break;
+ }
- // update the text
- m_currentarg = -1;
- updateArgumentHighlight();
+ toInsert += extraChars;
- m_popupFrame->show();
+ // Insert the remainder of the name
+ int length = editor->position() - basePosition + extraLength;
+ editor->setCursorPosition(basePosition);
+ editor->replace(length, toInsert);
+ if (cursorOffset)
+ editor->setCursorPosition(editor->position() + cursorOffset);
}
-void FunctionArgumentWidget::nextPage()
+// --------------------
+// CppFunctionHintModel
+// --------------------
+class CppFunctionHintModel : public TextEditor::IFunctionHintProposalModel
{
- m_current = (m_current + 1) % m_items.size();
- updateHintText();
-}
+public:
+ CppFunctionHintModel(QList<Function *> functionSymbols)
+ : m_functionSymbols(functionSymbols)
+ , m_currentArg(-1)
+ {}
-void FunctionArgumentWidget::previousPage()
+ virtual void reset() {}
+ virtual int size() const { return m_functionSymbols.size(); }
+ virtual QString text(int index) const;
+ virtual int activeArgument(const QString &prefix) const;
+
+private:
+ QList<Function *> m_functionSymbols;
+ mutable int m_currentArg;
+};
+
+QString CppFunctionHintModel::text(int index) const
{
- if (m_current == 0)
- m_current = m_items.size() - 1;
- else
- --m_current;
+ Overview overview;
+ overview.setShowReturnTypes(true);
+ overview.setShowArgumentNames(true);
+ overview.setMarkedArgument(m_currentArg + 1);
+ Function *f = m_functionSymbols.at(index);
+
+ const QString prettyMethod = overview(f->type(), f->name());
+ const int begin = overview.markedArgumentBegin();
+ const int end = overview.markedArgumentEnd();
- updateHintText();
+ QString hintText;
+ hintText += Qt::escape(prettyMethod.left(begin));
+ hintText += "<b>";
+ hintText += Qt::escape(prettyMethod.mid(begin, end - begin));
+ hintText += "</b>";
+ hintText += Qt::escape(prettyMethod.mid(end));
+ return hintText;
}
-void FunctionArgumentWidget::updateArgumentHighlight()
+int CppFunctionHintModel::activeArgument(const QString &prefix) const
{
- int curpos = m_editor->position();
- if (curpos < m_startpos) {
- m_popupFrame->close();
- return;
- }
-
- QString str = m_editor->textAt(m_startpos, curpos - m_startpos);
int argnr = 0;
int parcount = 0;
SimpleLexer tokenize;
- QList<Token> tokens = tokenize(str);
+ QList<Token> tokens = tokenize(prefix);
for (int i = 0; i < tokens.count(); ++i) {
const Token &tk = tokens.at(i);
if (tk.is(T_LPAREN))
@@ -336,367 +465,279 @@ void FunctionArgumentWidget::updateArgumentHighlight()
++argnr;
}
- if (m_currentarg != argnr) {
- m_currentarg = argnr;
- updateHintText();
- }
-
if (parcount < 0)
- m_popupFrame->close();
+ return -1;
+
+ if (argnr != m_currentArg)
+ m_currentArg = argnr;
+
+ return argnr;
}
-bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e)
+// ---------------------------
+// CppCompletionAssistProvider
+// ---------------------------
+bool CppCompletionAssistProvider::supportsEditor(const QString &editorId) const
{
- 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;
+ return editorId == QLatin1String(CppEditor::Constants::CPPEDITOR_ID);
}
-void FunctionArgumentWidget::updateHintText()
+int CppCompletionAssistProvider::activationCharSequenceLength() const
{
- Overview overview;
- overview.setShowReturnTypes(true);
- overview.setShowArgumentNames(true);
- overview.setMarkedArgument(m_currentarg + 1);
- Function *f = currentFunction();
-
- const QString prettyMethod = overview(f->type(), f->name());
- const int begin = overview.markedArgumentBegin();
- const int end = overview.markedArgumentEnd();
-
- QString hintText;
- hintText += Qt::escape(prettyMethod.left(begin));
- hintText += "<b>";
- hintText += Qt::escape(prettyMethod.mid(begin, end - begin));
- hintText += "</b>";
- hintText += Qt::escape(prettyMethod.mid(end));
- setText(hintText);
-
- m_numberLabel->setText(tr("%1 of %2").arg(m_current + 1).arg(m_items.size()));
-
- placeInsideScreen();
+ return 3;
}
-void FunctionArgumentWidget::placeInsideScreen()
+bool CppCompletionAssistProvider::isActivationCharSequence(const QString &sequence) const
{
- 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
+ const QChar &ch = sequence.at(2);
+ const QChar &ch2 = sequence.at(1);
+ const QChar &ch3 = sequence.at(0);
+ if (activationSequenceChar(ch, ch2, ch3, 0, true) != 0)
+ return true;
+ return false;
+}
- 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);
- }
+IAssistProcessor *CppCompletionAssistProvider::createProcessor() const
+{
+ return new CppCompletionAssistProcessor;
+}
- const QSize sz = m_popupFrame->size();
- QPoint pos = m_editor->cursorRect(m_startpos).topLeft();
- pos.setY(pos.y() - sz.height() - 1);
+// -----------------
+// CppAssistProposal
+// -----------------
+class CppAssistProposal : public TextEditor::GenericProposal
+{
+public:
+ CppAssistProposal(int cursorPos, TextEditor::IGenericProposalModel *model)
+ : TextEditor::GenericProposal(cursorPos, model)
+ , m_replaceDotForArrow(static_cast<CppAssistProposalModel *>(model)->m_replaceDotForArrow)
+ {}
- if (pos.x() + sz.width() > screen.right())
- pos.setX(screen.right() - sz.width());
+ virtual bool isCorrective() const { return m_replaceDotForArrow; }
+ virtual void makeCorrection(BaseTextEditor *editor);
- m_popupFrame->move(pos);
-}
+private:
+ bool m_replaceDotForArrow;
+};
-CppCodeCompletion::CppCodeCompletion(CppModelManager *manager)
- : ICompletionCollector(manager),
- m_manager(manager),
- m_editor(0),
- m_startPosition(-1),
- m_shouldRestartCompletion(false),
- m_automaticCompletion(false),
- m_completionOperator(T_EOF_SYMBOL),
- m_objcEnabled(true),
- m_snippetProvider(CppEditor::Constants::CPP_SNIPPETS_GROUP_ID,
- QIcon(QLatin1String(":/texteditor/images/snippet.png")))
+void CppAssistProposal::makeCorrection(BaseTextEditor *editor)
{
+ editor->setCursorPosition(basePosition() - 1);
+ editor->replace(1, QLatin1String("->"));
+ moveBasePosition(1);
}
-QIcon CppCodeCompletion::iconForSymbol(Symbol *symbol) const
-{
- return m_icons.iconForSymbol(symbol);
-}
+namespace {
-/*
- Searches backwards for an access operator.
-*/
-static int startOfOperator(TextEditor::ITextEditor *editor,
- int pos, unsigned *kind,
- bool wantFunctionCall)
+class ConvertToCompletionItem: protected NameVisitor
{
- const QChar ch = pos > -1 ? editor->characterAt(pos - 1) : QChar();
- const QChar ch2 = pos > 0 ? editor->characterAt(pos - 2) : QChar();
- const QChar ch3 = pos > 1 ? editor->characterAt(pos - 3) : QChar();
+ // The completion item.
+ BasicProposalItem *_item;
- int start = pos;
- int completionKind = T_EOF_SYMBOL;
+ // The current symbol.
+ Symbol *_symbol;
- switch (ch.toLatin1()) {
- case '.':
- if (ch2 != QLatin1Char('.')) {
- completionKind = T_DOT;
- --start;
- }
- break;
- case ',':
- completionKind = T_COMMA;
- --start;
- break;
- case '(':
- if (wantFunctionCall) {
- completionKind = T_LPAREN;
- --start;
- }
- break;
- case ':':
- if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':')) {
- completionKind = T_COLON_COLON;
- start -= 2;
- }
- break;
- case '>':
- if (ch2 == QLatin1Char('-')) {
- completionKind = T_ARROW;
- start -= 2;
- }
- break;
- case '*':
- if (ch2 == QLatin1Char('.')) {
- completionKind = T_DOT_STAR;
- start -= 2;
- } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>')) {
- completionKind = T_ARROW_STAR;
- start -= 3;
- }
- break;
- case '\\':
- case '@':
- if (ch2.isNull() || ch2.isSpace()) {
- completionKind = T_DOXY_COMMENT;
- --start;
- }
- break;
- case '<':
- completionKind = T_ANGLE_STRING_LITERAL;
- --start;
- break;
- case '"':
- completionKind = T_STRING_LITERAL;
- --start;
- break;
- case '/':
- completionKind = T_SLASH;
- --start;
- break;
- case '#':
- completionKind = T_POUND;
- --start;
- break;
- }
+ // The pretty printer.
+ Overview overview;
- if (start == pos)
- return start;
+public:
+ ConvertToCompletionItem()
+ : _item(0)
+ , _symbol(0)
+ { }
- TextEditor::BaseTextEditorWidget *edit = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget());
- QTextCursor tc(edit->textCursor());
- tc.setPosition(pos);
+ BasicProposalItem *operator()(Symbol *symbol)
+ {
+ if (! symbol || ! symbol->name() || symbol->name()->isQualifiedNameId())
+ return 0;
- // Include completion: make sure the quote character is the first one on the line
- if (completionKind == T_STRING_LITERAL) {
- QTextCursor s = tc;
- s.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
- QString sel = s.selectedText();
- if (sel.indexOf(QLatin1Char('"')) < sel.length() - 1) {
- completionKind = T_EOF_SYMBOL;
- start = pos;
- }
+ BasicProposalItem *previousItem = switchCompletionItem(0);
+ Symbol *previousSymbol = switchSymbol(symbol);
+ accept(symbol->unqualifiedName());
+ if (_item)
+ _item->setData(QVariant::fromValue(symbol));
+ (void) switchSymbol(previousSymbol);
+ return switchCompletionItem(previousItem);
}
- if (completionKind == T_COMMA) {
- ExpressionUnderCursor expressionUnderCursor;
- if (expressionUnderCursor.startOfFunctionCall(tc) == -1) {
- completionKind = T_EOF_SYMBOL;
- start = pos;
- }
+protected:
+ Symbol *switchSymbol(Symbol *symbol)
+ {
+ Symbol *previousSymbol = _symbol;
+ _symbol = symbol;
+ return previousSymbol;
}
- SimpleLexer tokenize;
- tokenize.setQtMocRunEnabled(true);
- tokenize.setObjCEnabled(true);
- tokenize.setSkipComments(false);
- const QList<Token> &tokens = tokenize(tc.block().text(), BackwardsScanner::previousBlockState(tc.block()));
- const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); // get the token at the left of the cursor
- const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx);
-
- if (completionKind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) {
- completionKind = T_EOF_SYMBOL;
- start = pos;
- }
- // Don't complete in comments or strings, but still check for include completion
- else if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT) ||
- (tk.isLiteral() && (completionKind != T_STRING_LITERAL
- && completionKind != T_ANGLE_STRING_LITERAL
- && completionKind != T_SLASH))) {
- completionKind = T_EOF_SYMBOL;
- start = pos;
- }
- // Include completion: can be triggered by slash, but only in a string
- else if (completionKind == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) {
- completionKind = T_EOF_SYMBOL;
- start = pos;
+ BasicProposalItem *switchCompletionItem(BasicProposalItem *item)
+ {
+ BasicProposalItem *previousItem = _item;
+ _item = item;
+ return previousItem;
}
- else if (completionKind == T_LPAREN) {
- if (tokenIdx > 0) {
- const Token &previousToken = tokens.at(tokenIdx - 1); // look at the token at the left of T_LPAREN
- switch (previousToken.kind()) {
- case T_IDENTIFIER:
- case T_GREATER:
- case T_SIGNAL:
- case T_SLOT:
- break; // good
-
- default:
- // that's a bad token :)
- completionKind = T_EOF_SYMBOL;
- start = pos;
- }
- }
+
+ BasicProposalItem *newCompletionItem(const Name *name)
+ {
+ BasicProposalItem *item = new CppAssistProposalItem;
+ item->setText(overview.prettyName(name));
+ return item;
}
- // Check for include preprocessor directive
- else if (completionKind == T_STRING_LITERAL || completionKind == T_ANGLE_STRING_LITERAL || completionKind == T_SLASH) {
- bool include = false;
- if (tokens.size() >= 3) {
- if (tokens.at(0).is(T_POUND) && tokens.at(1).is(T_IDENTIFIER) && (tokens.at(2).is(T_STRING_LITERAL) ||
- tokens.at(2).is(T_ANGLE_STRING_LITERAL))) {
- const Token &directiveToken = tokens.at(1);
- QString directive = tc.block().text().mid(directiveToken.begin(),
- directiveToken.length());
- if (directive == QLatin1String("include") ||
- directive == QLatin1String("include_next") ||
- directive == QLatin1String("import")) {
- include = true;
- }
- }
- }
- if (!include) {
- completionKind = T_EOF_SYMBOL;
- start = pos;
- }
+ virtual void visit(const Identifier *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(const TemplateNameId *name)
+ {
+ _item = newCompletionItem(name);
+ _item->setText(QLatin1String(name->identifier()->chars()));
}
- if (kind)
- *kind = completionKind;
+ virtual void visit(const DestructorNameId *name)
+ { _item = newCompletionItem(name); }
- return start;
-}
+ virtual void visit(const OperatorNameId *name)
+ { _item = newCompletionItem(name); }
+
+ virtual void visit(const ConversionNameId *name)
+ { _item = newCompletionItem(name); }
-bool CppCodeCompletion::supportsPolicy(TextEditor::CompletionPolicy policy) const
+ virtual void visit(const QualifiedNameId *name)
+ { _item = newCompletionItem(name->name()); }
+};
+
+Class *asClassOrTemplateClassType(FullySpecifiedType ty)
{
- return policy == TextEditor::SemanticCompletion;
+ if (Class *classTy = ty->asClassType())
+ return classTy;
+ else if (Template *templ = ty->asTemplateType()) {
+ if (Symbol *decl = templ->declaration())
+ return decl->asClass();
+ }
+ return 0;
}
-bool CppCodeCompletion::supportsEditor(TextEditor::ITextEditor *editor) const
+Scope *enclosingNonTemplateScope(Symbol *symbol)
{
- return m_manager->isCppEditor(editor);
+ if (symbol) {
+ if (Scope *scope = symbol->enclosingScope()) {
+ if (Template *templ = scope->asTemplate())
+ return templ->enclosingScope();
+ return scope;
+ }
+ }
+ return 0;
}
-TextEditor::ITextEditor *CppCodeCompletion::editor() const
-{ return m_editor; }
+Function *asFunctionOrTemplateFunctionType(FullySpecifiedType ty)
+{
+ if (Function *funTy = ty->asFunctionType())
+ return funTy;
+ else if (Template *templ = ty->asTemplateType()) {
+ if (Symbol *decl = templ->declaration())
+ return decl->asFunction();
+ }
+ return 0;
+}
-int CppCodeCompletion::startPosition() const
-{ return m_startPosition; }
+} // Anonymous
+
+// ----------------------------
+// CppCompletionAssistProcessor
+// ----------------------------
+CppCompletionAssistProcessor::CppCompletionAssistProcessor()
+ : m_startPosition(-1)
+ , m_objcEnabled(true)
+ , m_snippetCollector(CppEditor::Constants::CPP_SNIPPETS_GROUP_ID,
+ QIcon(QLatin1String(":/texteditor/images/snippet.png")))
+ , preprocessorCompletions(QStringList()
+ << QLatin1String("define")
+ << QLatin1String("error")
+ << QLatin1String("include")
+ << QLatin1String("line")
+ << QLatin1String("pragma")
+ << QLatin1String("undef")
+ << QLatin1String("if")
+ << QLatin1String("ifdef")
+ << QLatin1String("ifndef")
+ << QLatin1String("elif")
+ << QLatin1String("else")
+ << QLatin1String("endif"))
+ , m_model(new CppAssistProposalModel)
+ , m_hintProposal(0)
+{}
-bool CppCodeCompletion::shouldRestartCompletion()
-{ return m_shouldRestartCompletion; }
+CppCompletionAssistProcessor::~CppCompletionAssistProcessor()
+{}
-bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditor *editor)
+IAssistProposal * CppCompletionAssistProcessor::perform(const IAssistInterface *interface)
{
- m_editor = editor;
- m_automaticCompletion = false;
+ m_interface.reset(static_cast<const CppCompletionAssistInterface *>(interface));
+
+ if (interface->reason() != ExplicitlyInvoked && !accepts())
+ return 0;
- const int pos = editor->position();
+ m_model->m_snapshot = m_interface->snapshot();
+
+ int index = startCompletionHelper();
+ if (index != -1) {
+ if (m_hintProposal)
+ return m_hintProposal;
+
+ if (interface->reason() == IdleEditor) {
+ const int pos = m_interface->position();
+ const QChar ch = m_interface->characterAt(pos);
+ if (! (ch.isLetterOrNumber() || ch == QLatin1Char('_'))) {
+ for (int i = pos - 1;; --i) {
+ const QChar ch = m_interface->characterAt(i);
+ if (ch.isLetterOrNumber() || ch == QLatin1Char('_')) {
+ const QString wordUnderCursor = m_interface->textAt(i, pos - i);
+ if (wordUnderCursor.at(0).isLetter() || wordUnderCursor.at(0) == QLatin1Char('_')) {
+ foreach (const BasicProposalItem *item, m_completions) {
+ if (item->text() == wordUnderCursor)
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else
+ break;
+ }
+ }
+ }
+
+ if (m_model->m_completionOperator != T_EOF_SYMBOL)
+ m_model->m_sortable = true;
+ else
+ m_model->m_sortable = false;
+ return createContentProposal();
+ }
+
+ return 0;
+}
+
+bool CppCompletionAssistProcessor::accepts() const
+{
+ const int pos = m_interface->position();
unsigned token = T_EOF_SYMBOL;
- if (startOfOperator(editor, pos, &token, /*want function call=*/ true) != pos) {
+ const int start = startOfOperator(pos, &token, /*want function call=*/ true);
+ if (start != pos) {
if (token == T_POUND) {
- int line, column;
- editor->convertPosition(pos, &line, &column);
+ const int column = pos - m_interface->document()->findBlock(start).position();
if (column != 1)
return false;
}
return true;
- } else if (completionSettings().m_completionTrigger == TextEditor::AutomaticCompletion) {
+ } else {
// Trigger completion after three characters of a name have been typed, when not editing an existing name
- QChar characterUnderCursor = editor->characterAt(pos);
+ QChar characterUnderCursor = m_interface->characterAt(pos);
if (!characterUnderCursor.isLetterOrNumber()) {
const int startOfName = findStartOfName(pos);
if (pos - startOfName >= 3) {
- const QChar firstCharacter = editor->characterAt(startOfName);
+ const QChar firstCharacter = m_interface->characterAt(startOfName);
if (firstCharacter.isLetter() || firstCharacter == QLatin1Char('_')) {
// Finally check that we're not inside a comment or string (code copied from startOfOperator)
- TextEditor::BaseTextEditorWidget *edit = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget());
- QTextCursor tc(edit->textCursor());
+ QTextCursor tc(m_interface->document());
tc.setPosition(pos);
SimpleLexer tokenize;
@@ -707,10 +748,8 @@ bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditor *editor)
const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1));
const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx);
- if (!tk.isComment() && !tk.isLiteral()) {
- m_automaticCompletion = true;
+ if (!tk.isComment() && !tk.isLiteral())
return true;
- }
}
}
}
@@ -719,215 +758,201 @@ bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditor *editor)
return false;
}
-int CppCodeCompletion::startCompletion(TextEditor::ITextEditor *editor)
+IAssistProposal *CppCompletionAssistProcessor::createContentProposal()
{
- int index = startCompletionHelper(editor);
- if (index != -1) {
- if (m_automaticCompletion) {
- const int pos = editor->position();
- const QChar ch = editor->characterAt(pos);
- if (! (ch.isLetterOrNumber() || ch == QLatin1Char('_'))) {
- for (int i = pos - 1;; --i) {
- const QChar ch = editor->characterAt(i);
- if (ch.isLetterOrNumber() || ch == QLatin1Char('_')) {
- const QString wordUnderCursor = editor->textAt(i, pos - i);
- if (wordUnderCursor.at(0).isLetter() || wordUnderCursor.at(0) == QLatin1Char('_')) {
- foreach (const TextEditor::CompletionItem &i, m_completions) {
- if (i.text == wordUnderCursor) {
- cleanup();
- return -1;
- }
- }
- } else {
- cleanup();
- return -1;
+ // Duplicates are kept only if they are snippets.
+ QSet<QString> processed;
+ QList<BasicProposalItem *>::iterator it = m_completions.begin();
+ while (it != m_completions.end()) {
+ CppAssistProposalItem *item = static_cast<CppAssistProposalItem *>(*it);
+ if (!processed.contains(item->text()) || item->data().canConvert<QString>()) {
+ ++it;
+ if (!item->data().canConvert<QString>()) {
+ processed.insert(item->text());
+ if (!item->isOverloaded()) {
+ if (Symbol *symbol = qvariant_cast<Symbol *>(item->data())) {
+ if (Function *funTy = symbol->type()->asFunctionType()) {
+ if (funTy->hasArguments())
+ item->markAsOverloaded();
}
- } else
- break;
+ }
}
}
+ } else {
+ it = m_completions.erase(it);
}
-
- if (m_completionOperator != T_EOF_SYMBOL)
- sortCompletion(m_completions);
-
- // always remove duplicates
- m_completions = removeDuplicates(m_completions);
}
- for (int i = 0; i < m_completions.size(); ++i)
- m_completions[i].originalIndex = i;
+ m_model->loadContent(m_completions);
+ return new CppAssistProposal(m_startPosition, m_model.take());
+}
- return index;
+IAssistProposal *CppCompletionAssistProcessor::createHintProposal(
+ QList<CPlusPlus::Function *> functionSymbols) const
+{
+ IFunctionHintProposalModel *model = new CppFunctionHintModel(functionSymbols);
+ IAssistProposal *proposal = new FunctionHintProposal(m_startPosition, model);
+ return proposal;
}
-void CppCodeCompletion::completeObjCMsgSend(ClassOrNamespace *binding,
- bool staticClassAccess)
+int CppCompletionAssistProcessor::startOfOperator(int pos,
+ unsigned *kind,
+ bool wantFunctionCall) const
{
- QList<Scope*> memberScopes;
- foreach (Symbol *s, binding->symbols()) {
- if (ObjCClass *c = s->asObjCClass())
- memberScopes.append(c);
- }
+ const QChar ch = pos > -1 ? m_interface->characterAt(pos - 1) : QChar();
+ const QChar ch2 = pos > 0 ? m_interface->characterAt(pos - 2) : QChar();
+ const QChar ch3 = pos > 1 ? m_interface->characterAt(pos - 3) : QChar();
+
+ int start = pos - activationSequenceChar(ch, ch2, ch3, kind, wantFunctionCall);
+ if (start != pos) {
+ QTextCursor tc(m_interface->document());
+ tc.setPosition(pos);
+
+ // Include completion: make sure the quote character is the first one on the line
+ if (*kind == T_STRING_LITERAL) {
+ QTextCursor s = tc;
+ s.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
+ QString sel = s.selectedText();
+ if (sel.indexOf(QLatin1Char('"')) < sel.length() - 1) {
+ *kind = T_EOF_SYMBOL;
+ start = pos;
+ }
+ }
- foreach (Scope *scope, memberScopes) {
- for (unsigned i = 0; i < scope->memberCount(); ++i) {
- Symbol *symbol = scope->memberAt(i);
+ if (*kind == T_COMMA) {
+ ExpressionUnderCursor expressionUnderCursor;
+ if (expressionUnderCursor.startOfFunctionCall(tc) == -1) {
+ *kind = T_EOF_SYMBOL;
+ start = pos;
+ }
+ }
- if (ObjCMethod *method = symbol->type()->asObjCMethodType()) {
- if (method->isStatic() == staticClassAccess) {
- Overview oo;
- const SelectorNameId *selectorName =
- method->name()->asSelectorNameId();
- QString text;
- QString data;
- if (selectorName->hasArguments()) {
- for (unsigned i = 0; i < selectorName->nameCount(); ++i) {
- if (i > 0)
- text += QLatin1Char(' ');
- Symbol *arg = method->argumentAt(i);
- text += selectorName->nameAt(i)->identifier()->chars();
- text += QLatin1Char(':');
- text += TextEditor::Snippet::kVariableDelimiter;
- text += QLatin1Char('(');
- text += oo(arg->type());
- text += QLatin1Char(')');
- text += oo(arg->name());
- text += TextEditor::Snippet::kVariableDelimiter;
- }
- } else {
- text = selectorName->identifier()->chars();
- }
- data = text;
+ SimpleLexer tokenize;
+ tokenize.setQtMocRunEnabled(true);
+ tokenize.setObjCEnabled(true);
+ tokenize.setSkipComments(false);
+ const QList<Token> &tokens = tokenize(tc.block().text(), BackwardsScanner::previousBlockState(tc.block()));
+ const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); // get the token at the left of the cursor
+ const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx);
- if (!text.isEmpty()) {
- TextEditor::CompletionItem item(this);
- item.text = text;
- item.data = QVariant::fromValue(data);
- m_completions.append(item);
- }
+ if (*kind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) {
+ *kind = T_EOF_SYMBOL;
+ start = pos;
+ }
+ // Don't complete in comments or strings, but still check for include completion
+ else if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT) ||
+ (tk.isLiteral() && (*kind != T_STRING_LITERAL
+ && *kind != T_ANGLE_STRING_LITERAL
+ && *kind != T_SLASH))) {
+ *kind = T_EOF_SYMBOL;
+ start = pos;
+ }
+ // Include completion: can be triggered by slash, but only in a string
+ else if (*kind == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) {
+ *kind = T_EOF_SYMBOL;
+ start = pos;
+ }
+ else if (*kind == T_LPAREN) {
+ if (tokenIdx > 0) {
+ const Token &previousToken = tokens.at(tokenIdx - 1); // look at the token at the left of T_LPAREN
+ switch (previousToken.kind()) {
+ case T_IDENTIFIER:
+ case T_GREATER:
+ case T_SIGNAL:
+ case T_SLOT:
+ break; // good
+
+ default:
+ // that's a bad token :)
+ *kind = T_EOF_SYMBOL;
+ start = pos;
}
}
}
- }
-}
-
-bool CppCodeCompletion::tryObjCCompletion(TextEditor::BaseTextEditorWidget *edit)
-{
- Q_ASSERT(edit);
-
- int end = m_editor->position();
- while (m_editor->characterAt(end).isSpace())
- ++end;
- if (m_editor->characterAt(end) != QLatin1Char(']'))
- return false;
-
- QTextCursor tc(edit->document());
- tc.setPosition(end);
- BackwardsScanner tokens(tc);
- if (tokens[tokens.startToken() - 1].isNot(T_RBRACKET))
- return false;
-
- const int start = tokens.startOfMatchingBrace(tokens.startToken());
- if (start == tokens.startToken())
- return false;
-
- const int startPos = tokens[start].begin() + tokens.startPosition();
- const QString expr = m_editor->textAt(startPos, m_editor->position() - startPos);
-
- const Snapshot snapshot = m_manager->snapshot();
- Document::Ptr thisDocument = snapshot.document(m_editor->file()->fileName());
- if (! thisDocument)
- return false;
-
- typeOfExpression.init(thisDocument, snapshot);
- int line = 0, column = 0;
- edit->convertPosition(m_editor->position(), &line, &column);
- Scope *scope = thisDocument->scopeAt(line, column);
- if (!scope)
- return false;
-
- const QList<LookupItem> items = typeOfExpression(expr, scope);
- LookupContext lookupContext(thisDocument, snapshot);
-
- foreach (const LookupItem &item, items) {
- FullySpecifiedType ty = item.type().simplified();
- if (ty->isPointerType()) {
- ty = ty->asPointerType()->elementType().simplified();
-
- if (NamedType *namedTy = ty->asNamedType()) {
- ClassOrNamespace *binding = lookupContext.lookupType(namedTy->name(), item.scope());
- completeObjCMsgSend(binding, false);
+ // Check for include preprocessor directive
+ else if (*kind == T_STRING_LITERAL || *kind == T_ANGLE_STRING_LITERAL || *kind == T_SLASH) {
+ bool include = false;
+ if (tokens.size() >= 3) {
+ if (tokens.at(0).is(T_POUND) && tokens.at(1).is(T_IDENTIFIER) && (tokens.at(2).is(T_STRING_LITERAL) ||
+ tokens.at(2).is(T_ANGLE_STRING_LITERAL))) {
+ const Token &directiveToken = tokens.at(1);
+ QString directive = tc.block().text().mid(directiveToken.begin(),
+ directiveToken.length());
+ if (directive == QLatin1String("include") ||
+ directive == QLatin1String("include_next") ||
+ directive == QLatin1String("import")) {
+ include = true;
+ }
+ }
}
- } else {
- if (ObjCClass *clazz = ty->asObjCClassType()) {
- ClassOrNamespace *binding = lookupContext.lookupType(clazz->name(), item.scope());
- completeObjCMsgSend(binding, true);
+
+ if (!include) {
+ *kind = T_EOF_SYMBOL;
+ start = pos;
}
}
}
- if (m_completions.isEmpty())
- return false;
-
- m_startPosition = m_editor->position();
- return true;
+ return start;
}
-int CppCodeCompletion::startCompletionHelper(TextEditor::ITextEditor *editor)
+int CppCompletionAssistProcessor::findStartOfName(int pos) const
{
- TextEditor::BaseTextEditorWidget *edit = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget());
- if (! edit)
- return -1;
+ if (pos == -1)
+ pos = m_interface->position();
+ QChar chr;
- m_editor = editor;
+ // Skip to the start of a name
+ do {
+ chr = m_interface->characterAt(--pos);
+ } while (chr.isLetterOrNumber() || chr == QLatin1Char('_'));
+ return pos + 1;
+}
+
+int CppCompletionAssistProcessor::startCompletionHelper()
+{
if (m_objcEnabled) {
- if (tryObjCCompletion(edit))
+ if (tryObjCCompletion())
return m_startPosition;
}
const int startOfName = findStartOfName();
m_startPosition = startOfName;
- m_completionOperator = T_EOF_SYMBOL;
+ m_model->m_completionOperator = T_EOF_SYMBOL;
int endOfOperator = m_startPosition;
// Skip whitespace preceding this position
- while (editor->characterAt(endOfOperator - 1).isSpace())
+ while (m_interface->characterAt(endOfOperator - 1).isSpace())
--endOfOperator;
- int endOfExpression = startOfOperator(editor, endOfOperator,
- &m_completionOperator,
+ int endOfExpression = startOfOperator(endOfOperator,
+ &m_model->m_completionOperator,
/*want function call =*/ true);
- Core::IFile *file = editor->file();
+ const Core::IFile *file = m_interface->file();
QString fileName = file->fileName();
- if (m_completionOperator == T_DOXY_COMMENT) {
- for (int i = 1; i < T_DOXY_LAST_TAG; ++i) {
- TextEditor::CompletionItem item(this);
- item.text.append(QString::fromLatin1(doxygenTagSpell(i)));
- item.icon = m_icons.keywordIcon();
- m_completions.append(item);
- }
-
+ if (m_model->m_completionOperator == T_DOXY_COMMENT) {
+ for (int i = 1; i < T_DOXY_LAST_TAG; ++i)
+ addCompletionItem(QString::fromLatin1(doxygenTagSpell(i)), m_icons.keywordIcon());
return m_startPosition;
}
// Pre-processor completion
- if (m_completionOperator == T_POUND) {
+ if (m_model->m_completionOperator == T_POUND) {
completePreprocessor();
m_startPosition = startOfName;
return m_startPosition;
}
// Include completion
- if (m_completionOperator == T_STRING_LITERAL
- || m_completionOperator == T_ANGLE_STRING_LITERAL
- || m_completionOperator == T_SLASH) {
+ if (m_model->m_completionOperator == T_STRING_LITERAL
+ || m_model->m_completionOperator == T_ANGLE_STRING_LITERAL
+ || m_model->m_completionOperator == T_SLASH) {
- QTextCursor c = edit->textCursor();
+ QTextCursor c(m_interface->document());
c.setPosition(endOfExpression);
if (completeInclude(c))
m_startPosition = startOfName;
@@ -935,76 +960,271 @@ int CppCodeCompletion::startCompletionHelper(TextEditor::ITextEditor *editor)
}
ExpressionUnderCursor expressionUnderCursor;
- QTextCursor tc(edit->document());
+ QTextCursor tc(m_interface->document());
- if (m_completionOperator == T_COMMA) {
+ if (m_model->m_completionOperator == T_COMMA) {
tc.setPosition(endOfExpression);
const int start = expressionUnderCursor.startOfFunctionCall(tc);
if (start == -1) {
- m_completionOperator = T_EOF_SYMBOL;
+ m_model->m_completionOperator = T_EOF_SYMBOL;
return -1;
}
endOfExpression = start;
m_startPosition = start + 1;
- m_completionOperator = T_LPAREN;
+ m_model->m_completionOperator = T_LPAREN;
}
QString expression;
- int startOfExpression = editor->position();
+ int startOfExpression = m_interface->position();
tc.setPosition(endOfExpression);
- if (m_completionOperator) {
+ if (m_model->m_completionOperator) {
expression = expressionUnderCursor(tc);
startOfExpression = endOfExpression - expression.length();
- if (m_completionOperator == T_LPAREN) {
+ if (m_model->m_completionOperator == T_LPAREN) {
if (expression.endsWith(QLatin1String("SIGNAL")))
- m_completionOperator = T_SIGNAL;
+ m_model->m_completionOperator = T_SIGNAL;
else if (expression.endsWith(QLatin1String("SLOT")))
- m_completionOperator = T_SLOT;
+ m_model->m_completionOperator = T_SLOT;
- else if (editor->position() != endOfOperator) {
+ else if (m_interface->position() != endOfOperator) {
// We don't want a function completion when the cursor isn't at the opening brace
expression.clear();
- m_completionOperator = T_EOF_SYMBOL;
+ m_model->m_completionOperator = T_EOF_SYMBOL;
m_startPosition = startOfName;
- startOfExpression = editor->position();
+ startOfExpression = m_interface->position();
}
}
} else if (expression.isEmpty()) {
- while (startOfExpression > 0 && editor->characterAt(startOfExpression).isSpace())
+ while (startOfExpression > 0 && m_interface->characterAt(startOfExpression).isSpace())
--startOfExpression;
}
int line = 0, column = 0;
- edit->convertPosition(startOfExpression, &line, &column);
-// qDebug() << "***** line:" << line << "column:" << column;
-// qDebug() << "***** expression:" << expression;
- return startCompletionInternal(edit, fileName, line, column, expression, endOfExpression);
+ Convenience::convertPosition(m_interface->document(), startOfExpression, &line, &column);
+ return startCompletionInternal(fileName, line, column, expression, endOfExpression);
}
-int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditorWidget *edit,
- const QString fileName,
- unsigned line, unsigned column,
- const QString &expr,
- int endOfExpression)
+bool CppCompletionAssistProcessor::tryObjCCompletion()
+{
+ int end = m_interface->position();
+ while (m_interface->characterAt(end).isSpace())
+ ++end;
+ if (m_interface->characterAt(end) != QLatin1Char(']'))
+ return false;
+
+ QTextCursor tc(m_interface->document());
+ tc.setPosition(end);
+ BackwardsScanner tokens(tc);
+ if (tokens[tokens.startToken() - 1].isNot(T_RBRACKET))
+ return false;
+
+ const int start = tokens.startOfMatchingBrace(tokens.startToken());
+ if (start == tokens.startToken())
+ return false;
+
+ const int startPos = tokens[start].begin() + tokens.startPosition();
+ const QString expr = m_interface->textAt(startPos, m_interface->position() - startPos);
+
+ Document::Ptr thisDocument = m_model->m_snapshot.document(m_interface->file()->fileName());
+ if (! thisDocument)
+ return false;
+
+ typeOfExpression.init(thisDocument, m_model->m_snapshot);
+ int line = 0, column = 0;
+ Convenience::convertPosition(m_interface->document(), m_interface->position(), &line, &column);
+ Scope *scope = thisDocument->scopeAt(line, column);
+ if (!scope)
+ return false;
+
+ const QList<LookupItem> items = typeOfExpression(expr, scope);
+ LookupContext lookupContext(thisDocument, m_model->m_snapshot);
+
+ foreach (const LookupItem &item, items) {
+ FullySpecifiedType ty = item.type().simplified();
+ if (ty->isPointerType()) {
+ ty = ty->asPointerType()->elementType().simplified();
+
+ if (NamedType *namedTy = ty->asNamedType()) {
+ ClassOrNamespace *binding = lookupContext.lookupType(namedTy->name(), item.scope());
+ completeObjCMsgSend(binding, false);
+ }
+ } else {
+ if (ObjCClass *clazz = ty->asObjCClassType()) {
+ ClassOrNamespace *binding = lookupContext.lookupType(clazz->name(), item.scope());
+ completeObjCMsgSend(binding, true);
+ }
+ }
+ }
+
+ if (m_completions.isEmpty())
+ return false;
+
+ m_startPosition = m_interface->position();
+ return true;
+}
+
+void CppCompletionAssistProcessor::addCompletionItem(const QString &text,
+ const QIcon &icon,
+ int order,
+ const QVariant &data)
+{
+ BasicProposalItem *item = new CppAssistProposalItem;
+ item->setText(text);
+ item->setIcon(icon);
+ item->setOrder(order);
+ item->setData(data);
+ m_completions.append(item);
+}
+
+void CppCompletionAssistProcessor::addCompletionItem(CPlusPlus::Symbol *symbol)
+{
+ ConvertToCompletionItem toCompletionItem;
+ BasicProposalItem *item = toCompletionItem(symbol);
+ if (item) {
+ item->setIcon(m_icons.iconForSymbol(symbol));
+ m_completions.append(item);
+ }
+}
+
+void CppCompletionAssistProcessor::completeObjCMsgSend(CPlusPlus::ClassOrNamespace *binding,
+ bool staticClassAccess)
+{
+ QList<Scope*> memberScopes;
+ foreach (Symbol *s, binding->symbols()) {
+ if (ObjCClass *c = s->asObjCClass())
+ memberScopes.append(c);
+ }
+
+ foreach (Scope *scope, memberScopes) {
+ for (unsigned i = 0; i < scope->memberCount(); ++i) {
+ Symbol *symbol = scope->memberAt(i);
+
+ if (ObjCMethod *method = symbol->type()->asObjCMethodType()) {
+ if (method->isStatic() == staticClassAccess) {
+ Overview oo;
+ const SelectorNameId *selectorName =
+ method->name()->asSelectorNameId();
+ QString text;
+ QString data;
+ if (selectorName->hasArguments()) {
+ for (unsigned i = 0; i < selectorName->nameCount(); ++i) {
+ if (i > 0)
+ text += QLatin1Char(' ');
+ Symbol *arg = method->argumentAt(i);
+ text += selectorName->nameAt(i)->identifier()->chars();
+ text += QLatin1Char(':');
+ text += TextEditor::Snippet::kVariableDelimiter;
+ text += QLatin1Char('(');
+ text += oo(arg->type());
+ text += QLatin1Char(')');
+ text += oo(arg->name());
+ text += TextEditor::Snippet::kVariableDelimiter;
+ }
+ } else {
+ text = selectorName->identifier()->chars();
+ }
+ data = text;
+
+ if (!text.isEmpty())
+ addCompletionItem(text, QIcon(), 0, QVariant::fromValue(data));
+ }
+ }
+ }
+ }
+}
+
+bool CppCompletionAssistProcessor::completeInclude(const QTextCursor &cursor)
+{
+ QString directoryPrefix;
+ if (m_model->m_completionOperator == T_SLASH) {
+ QTextCursor c = cursor;
+ c.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
+ QString sel = c.selectedText();
+ int startCharPos = sel.indexOf(QLatin1Char('"'));
+ if (startCharPos == -1) {
+ startCharPos = sel.indexOf(QLatin1Char('<'));
+ m_model->m_completionOperator = T_ANGLE_STRING_LITERAL;
+ } else {
+ m_model->m_completionOperator = T_STRING_LITERAL;
+ }
+ if (startCharPos != -1)
+ directoryPrefix = sel.mid(startCharPos + 1, sel.length() - 1);
+ }
+
+ // Make completion for all relevant includes
+ CppModelManagerInterface *manager = CppModelManagerInterface::instance();
+ QStringList includePaths = m_interface->includePaths();
+ const QString &currentFilePath = QFileInfo(m_interface->file()->fileName()).path();
+ if (!includePaths.contains(currentFilePath))
+ includePaths.append(currentFilePath);
+
+ foreach (const QString &includePath, includePaths) {
+ QString realPath = includePath;
+ if (!directoryPrefix.isEmpty()) {
+ realPath += QLatin1Char('/');
+ realPath += directoryPrefix;
+ }
+ foreach (const QString &itemText, manager->includesInPath(realPath))
+ addCompletionItem(itemText, m_icons.keywordIcon());
+ }
+
+ foreach (const QString &frameworkPath, m_interface->frameworkPaths()) {
+ QString realPath = frameworkPath;
+ if (!directoryPrefix.isEmpty()) {
+ realPath += QLatin1Char('/');
+ realPath += directoryPrefix;
+ realPath += QLatin1String(".framework/Headers");
+ }
+ foreach (const QString &itemText, manager->includesInPath(realPath))
+ addCompletionItem(itemText, m_icons.keywordIcon());
+ }
+
+ return !m_completions.isEmpty();
+}
+
+void CppCompletionAssistProcessor::completePreprocessor()
+{
+ foreach (const QString &preprocessorCompletion, preprocessorCompletions)
+ addCompletionItem(preprocessorCompletion);
+
+ if (objcKeywordsWanted())
+ addCompletionItem(QLatin1String("import"));
+}
+
+bool CppCompletionAssistProcessor::objcKeywordsWanted() const
+{
+ if (!m_objcEnabled)
+ return false;
+
+ const Core::IFile *file = m_interface->file();
+ QString fileName = file->fileName();
+
+ const Core::MimeDatabase *mdb = Core::ICore::instance()->mimeDatabase();
+ return mdb->findByFile(fileName).type() == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE;
+}
+
+int CppCompletionAssistProcessor::startCompletionInternal(const QString fileName,
+ unsigned line, unsigned column,
+ const QString &expr,
+ int endOfExpression)
{
QString expression = expr.trimmed();
- const Snapshot snapshot = m_manager->snapshot();
- Document::Ptr thisDocument = snapshot.document(fileName);
+ Document::Ptr thisDocument = m_model->m_snapshot.document(fileName);
if (! thisDocument)
return -1;
- typeOfExpression.init(thisDocument, snapshot);
+ typeOfExpression.init(thisDocument, m_model->m_snapshot);
Scope *scope = thisDocument->scopeAt(line, column);
Q_ASSERT(scope != 0);
if (expression.isEmpty()) {
- if (m_completionOperator == T_EOF_SYMBOL || m_completionOperator == T_COLON_COLON) {
+ if (m_model->m_completionOperator == T_EOF_SYMBOL || m_model->m_completionOperator == T_COLON_COLON) {
(void) typeOfExpression(expression, scope);
globalCompletion(scope);
if (m_completions.isEmpty())
@@ -1012,7 +1232,7 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditorWidget
return m_startPosition;
}
- else if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
+ else if (m_model->m_completionOperator == T_SIGNAL || m_model->m_completionOperator == T_SLOT) {
// Apply signal/slot completion on 'this'
expression = QLatin1String("this");
}
@@ -1021,7 +1241,7 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditorWidget
QList<LookupItem> results = typeOfExpression(expression, scope, TypeOfExpression::Preprocess);
if (results.isEmpty()) {
- if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
+ if (m_model->m_completionOperator == T_SIGNAL || m_model->m_completionOperator == T_SLOT) {
if (! (expression.isEmpty() || expression == QLatin1String("this"))) {
expression = QLatin1String("this");
results = typeOfExpression(expression, scope);
@@ -1030,14 +1250,14 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditorWidget
if (results.isEmpty())
return -1;
- } else if (m_completionOperator == T_LPAREN) {
+ } else if (m_model->m_completionOperator == T_LPAREN) {
// Find the expression that precedes the current name
int index = endOfExpression;
- while (m_editor->characterAt(index - 1).isSpace())
+ while (m_interface->characterAt(index - 1).isSpace())
--index;
index = findStartOfName(index);
- QTextCursor tc(edit->document());
+ QTextCursor tc(m_interface->document());
tc.setPosition(index);
ExpressionUnderCursor expressionUnderCursor;
@@ -1066,7 +1286,7 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditorWidget
}
}
- switch (m_completionOperator) {
+ switch (m_model->m_completionOperator) {
case T_LPAREN:
if (completeConstructorOrFunction(results, endOfExpression, false))
return m_startPosition;
@@ -1101,11 +1321,11 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditorWidget
return -1;
}
-void CppCodeCompletion::globalCompletion(Scope *currentScope)
+void CppCompletionAssistProcessor::globalCompletion(CPlusPlus::Scope *currentScope)
{
const LookupContext &context = typeOfExpression.context();
- if (m_completionOperator == T_COLON_COLON) {
+ if (m_model->m_completionOperator == T_COLON_COLON) {
completeNamespace(context.globalNamespace());
return;
}
@@ -1168,266 +1388,29 @@ void CppCodeCompletion::globalCompletion(Scope *currentScope)
addSnippets();
}
-static Scope *enclosingNonTemplateScope(Symbol *symbol)
-{
- if (symbol) {
- if (Scope *scope = symbol->enclosingScope()) {
- if (Template *templ = scope->asTemplate())
- return templ->enclosingScope();
- return scope;
- }
- }
- return 0;
-}
-
-static Function *asFunctionOrTemplateFunctionType(FullySpecifiedType ty)
-{
- if (Function *funTy = ty->asFunctionType())
- return funTy;
- else if (Template *templ = ty->asTemplateType()) {
- if (Symbol *decl = templ->declaration())
- return decl->asFunction();
- }
- return 0;
-}
-
-static Class *asClassOrTemplateClassType(FullySpecifiedType ty)
-{
- if (Class *classTy = ty->asClassType())
- return classTy;
- else if (Template *templ = ty->asTemplateType()) {
- if (Symbol *decl = templ->declaration())
- return decl->asClass();
- }
- return 0;
-}
-
-bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &results,
- int endOfExpression, bool toolTipOnly)
+bool CppCompletionAssistProcessor::completeMember(const QList<CPlusPlus::LookupItem> &baseResults)
{
const LookupContext &context = typeOfExpression.context();
- QList<Function *> functions;
-
- foreach (const LookupItem &result, results) {
- FullySpecifiedType exprTy = result.type().simplified();
-
- if (Class *klass = asClassOrTemplateClassType(exprTy)) {
- const Name *className = klass->name();
- if (! className)
- continue; // nothing to do for anonymous classes.
-
- for (unsigned i = 0; i < klass->memberCount(); ++i) {
- Symbol *member = klass->memberAt(i);
- const Name *memberName = member->name();
-
- if (! memberName)
- continue; // skip anonymous member.
-
- else if (memberName->isQualifiedNameId())
- continue; // skip
-
- if (Function *funTy = member->type()->asFunctionType()) {
- if (memberName->isEqualTo(className)) {
- // it's a ctor.
- functions.append(funTy);
- }
- }
- }
-
- break;
- }
- }
-
- if (functions.isEmpty()) {
- foreach (const LookupItem &result, results) {
- FullySpecifiedType ty = result.type().simplified();
-
- if (Function *fun = asFunctionOrTemplateFunctionType(ty)) {
-
- if (! fun->name())
- continue;
- else if (! functions.isEmpty() && enclosingNonTemplateScope(functions.first()) != enclosingNonTemplateScope(fun))
- continue; // skip fun, it's an hidden declaration.
-
- bool newOverload = true;
-
- foreach (Function *f, functions) {
- if (fun->isEqualTo(f)) {
- newOverload = false;
- break;
- }
- }
-
- if (newOverload)
- functions.append(fun);
- }
- }
- }
-
- if (functions.isEmpty()) {
- const Name *functionCallOp = context.control()->operatorNameId(OperatorNameId::FunctionCallOp);
-
- foreach (const LookupItem &result, results) {
- FullySpecifiedType ty = result.type().simplified();
- Scope *scope = result.scope();
-
- if (NamedType *namedTy = ty->asNamedType()) {
- if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) {
- foreach (const LookupItem &r, b->lookup(functionCallOp)) {
- Symbol *overload = r.declaration();
- FullySpecifiedType overloadTy = overload->type().simplified();
-
- if (Function *funTy = overloadTy->asFunctionType()) {
- functions.append(funTy);
- }
- }
- }
- }
- }
- }
-
- // There are two different kinds of completion we want to provide:
- // 1. If this is a function call, we want to pop up a tooltip that shows the user
- // the possible overloads with their argument types and names.
- // 2. If this is a function definition, we want to offer autocompletion of
- // the function signature.
-
- // check if function signature autocompletion is appropriate
- // Also check if the function name is a destructor name.
- bool isDestructor = false;
- if (! functions.isEmpty() && ! toolTipOnly) {
-
- // function definitions will only happen in class or namespace scope,
- // so get the current location's enclosing scope.
-
- // get current line and column
- TextEditor::BaseTextEditorWidget *edit = qobject_cast<TextEditor::BaseTextEditorWidget *>(m_editor->widget());
- int lineSigned = 0, columnSigned = 0;
- edit->convertPosition(m_editor->position(), &lineSigned, &columnSigned);
- unsigned line = lineSigned, column = columnSigned;
-
- // find a scope that encloses the current location, starting from the lastVisibileSymbol
- // and moving outwards
-
- Scope *sc = context.thisDocument()->scopeAt(line, column);
-
- if (sc && (sc->isClass() || sc->isNamespace())) {
- // It may still be a function call. If the whole line parses as a function
- // declaration, we should be certain that it isn't.
- bool autocompleteSignature = false;
-
- QTextCursor tc(edit->document());
- tc.setPosition(endOfExpression);
- BackwardsScanner bs(tc);
- const int startToken = bs.startToken();
- int lineStartToken = bs.startOfLine(startToken);
- // make sure the required tokens are actually available
- bs.LA(startToken - lineStartToken);
- QString possibleDecl = bs.mid(lineStartToken).trimmed().append("();");
-
- Document::Ptr doc = Document::create(QLatin1String("<completion>"));
- doc->setSource(possibleDecl.toLatin1());
- if (doc->parse(Document::ParseDeclaration)) {
- doc->check();
- if (SimpleDeclarationAST *sd = doc->translationUnit()->ast()->asSimpleDeclaration()) {
- if (sd->declarator_list &&
- sd->declarator_list && sd->declarator_list->value->postfix_declarator_list
- && sd->declarator_list->value->postfix_declarator_list->value->asFunctionDeclarator()) {
-
- autocompleteSignature = true;
-
- CoreDeclaratorAST *coreDecl = sd->declarator_list->value->core_declarator;
- if (coreDecl && coreDecl->asDeclaratorId() && coreDecl->asDeclaratorId()->name) {
- NameAST *declName = coreDecl->asDeclaratorId()->name;
- if (declName->asDestructorName()) {
- isDestructor = true;
- } else if (QualifiedNameAST *qName = declName->asQualifiedName()) {
- if (qName->unqualified_name && qName->unqualified_name->asDestructorName())
- isDestructor = true;
- }
- }
- }
- }
- }
-
- if (autocompleteSignature && !isDestructor) {
- // set up signature autocompletion
- foreach (Function *f, functions) {
- Overview overview;
- overview.setShowArgumentNames(true);
- overview.setShowDefaultArguments(false);
-
- // gets: "parameter list) cv-spec",
- QString completion = overview(f->type()).mid(1);
-
- TextEditor::CompletionItem item(this);
- item.text = completion;
- item.data = QVariant::fromValue(CompleteFunctionDeclaration(f));
- m_completions.append(item);
- }
- return true;
- }
- }
- }
-
- if (! functions.empty() && !isDestructor) {
- // set up function call tooltip
-
- // Recreate if necessary
- if (!m_functionArgumentWidget)
- m_functionArgumentWidget = new FunctionArgumentWidget;
-
- m_functionArgumentWidget->showFunctionHint(functions,
- typeOfExpression.context(),
- m_startPosition);
- }
-
- return false;
-}
-
-bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults)
-{
- const LookupContext &context = typeOfExpression.context();
-
-// if (debug)
-// qDebug() << Q_FUNC_INFO << __LINE__;
if (baseResults.isEmpty())
return false;
ResolveExpression resolveExpression(context);
- bool replacedDotOperator = false;
-
- if (ClassOrNamespace *binding = resolveExpression.baseExpression(baseResults,
- m_completionOperator,
- &replacedDotOperator)) {
-// if (debug)
-// qDebug() << "cool we got a binding for the base expression";
-
- if (replacedDotOperator && binding) {
- // Replace . with ->
- int length = m_editor->position() - m_startPosition + 1;
- m_editor->setCursorPosition(m_startPosition - 1);
- m_editor->replace(length, QLatin1String("->"));
- ++m_startPosition;
- }
-
+ if (ClassOrNamespace *binding =
+ resolveExpression.baseExpression(baseResults,
+ m_model->m_completionOperator,
+ &m_model->m_replaceDotForArrow)) {
if (binding)
completeClass(binding, /*static lookup = */ false);
return ! m_completions.isEmpty();
}
-// if (debug) {
-// Overview oo;
-// qDebug() << "hmm, got:" << oo(baseResults.first().type());
-// }
-
return false;
}
-bool CppCodeCompletion::completeScope(const QList<LookupItem> &results)
+bool CppCompletionAssistProcessor::completeScope(const QList<CPlusPlus::LookupItem> &results)
{
const LookupContext &context = typeOfExpression.context();
if (results.isEmpty())
@@ -1461,162 +1444,7 @@ bool CppCodeCompletion::completeScope(const QList<LookupItem> &results)
return ! m_completions.isEmpty();
}
-void CppCodeCompletion::addKeywords()
-{
- int keywordLimit = T_FIRST_OBJC_AT_KEYWORD;
- if (objcKeywordsWanted())
- keywordLimit = T_LAST_OBJC_AT_KEYWORD + 1;
-
- // keyword completion items.
- for (int i = T_FIRST_KEYWORD; i < keywordLimit; ++i) {
- TextEditor::CompletionItem item(this);
- item.text = QLatin1String(Token::name(i));
- item.icon = m_icons.keywordIcon();
- m_completions.append(item);
- }
-}
-
-void CppCodeCompletion::addMacros(const QString &fileName, const Snapshot &snapshot)
-{
- QSet<QString> processed;
- QSet<QString> definedMacros;
-
- addMacros_helper(snapshot, fileName, &processed, &definedMacros);
-
- foreach (const QString &macroName, definedMacros) {
- TextEditor::CompletionItem item(this);
- item.text = macroName;
- item.icon = m_icons.macroIcon();
- m_completions.append(item);
- }
-}
-
-void CppCodeCompletion::addMacros_helper(const Snapshot &snapshot,
- const QString &fileName,
- QSet<QString> *processed,
- QSet<QString> *definedMacros)
-{
- Document::Ptr doc = snapshot.document(fileName);
-
- if (! doc || processed->contains(doc->fileName()))
- return;
-
- processed->insert(doc->fileName());
-
- foreach (const Document::Include &i, doc->includes()) {
- addMacros_helper(snapshot, i.fileName(), processed, definedMacros);
- }
-
- foreach (const Macro &macro, doc->definedMacros()) {
- const QString macroName = QString::fromUtf8(macro.name().constData(), macro.name().length());
- if (! macro.isHidden())
- definedMacros->insert(macroName);
- else
- definedMacros->remove(macroName);
- }
-}
-
-void CppCodeCompletion::addCompletionItem(Symbol *symbol)
-{
- ConvertToCompletionItem toCompletionItem(this);
- TextEditor::CompletionItem item = toCompletionItem(symbol);
- if (item.isValid())
- m_completions.append(item);
-}
-
-bool CppCodeCompletion::completeInclude(const QTextCursor &cursor)
-{
- QString directoryPrefix;
- if (m_completionOperator == T_SLASH) {
- QTextCursor c = cursor;
- c.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
- QString sel = c.selectedText();
- int startCharPos = sel.indexOf(QLatin1Char('"'));
- if (startCharPos == -1) {
- startCharPos = sel.indexOf(QLatin1Char('<'));
- m_completionOperator = T_ANGLE_STRING_LITERAL;
- } else {
- m_completionOperator = T_STRING_LITERAL;
- }
- if (startCharPos != -1)
- directoryPrefix = sel.mid(startCharPos + 1, sel.length() - 1);
- }
-
- // Make completion for all relevant includes
- if (ProjectExplorer::Project *project = ProjectExplorer::ProjectExplorerPlugin::instance()->currentProject()) {
- QStringList includePaths = m_manager->projectInfo(project).includePaths;
- const QString currentFilePath = QFileInfo(m_editor->file()->fileName()).path();
- if (!includePaths.contains(currentFilePath))
- includePaths.append(currentFilePath);
-
- foreach (const QString &includePath, includePaths) {
- QString realPath = includePath;
- if (!directoryPrefix.isEmpty()) {
- realPath += QLatin1Char('/');
- realPath += directoryPrefix;
- }
- foreach (const QString &itemText, m_manager->includesInPath(realPath)) {
- TextEditor::CompletionItem item(this);
- item.text += itemText;
- // TODO: Icon for include files
- item.icon = m_icons.keywordIcon();
- m_completions.append(item);
- }
- }
-
- QStringList frameworkPaths = m_manager->projectInfo(project).frameworkPaths;
- foreach (const QString &frameworkPath, frameworkPaths) {
- QString realPath = frameworkPath;
- if (!directoryPrefix.isEmpty()) {
- realPath += QLatin1Char('/');
- realPath += directoryPrefix;
- realPath += QLatin1String(".framework/Headers");
- }
- foreach (const QString &itemText, m_manager->includesInPath(realPath)) {
- TextEditor::CompletionItem item(this);
- item.text += itemText;
- // TODO: Icon for include files
- item.icon = m_icons.keywordIcon();
- m_completions.append(item);
- }
- }
- }
-
- return !m_completions.isEmpty();
-}
-
-QStringList CppCodeCompletion::preprocessorCompletions
- = QStringList()
- << QLatin1String("define")
- << QLatin1String("error")
- << QLatin1String("include")
- << QLatin1String("line")
- << QLatin1String("pragma")
- << QLatin1String("undef")
- << QLatin1String("if")
- << QLatin1String("ifdef")
- << QLatin1String("ifndef")
- << QLatin1String("elif")
- << QLatin1String("else")
- << QLatin1String("endif")
- ;
-
-void CppCodeCompletion::completePreprocessor()
-{
- TextEditor::CompletionItem item(this);
-
- foreach (const QString &preprocessorCompletion, preprocessorCompletions) {
- item.text = preprocessorCompletion;
- m_completions.append(item);
- }
-
- if (objcKeywordsWanted()) {
- item.text = QLatin1String("import");
- m_completions.append(item);
- }
-}
-
-void CppCodeCompletion::completeNamespace(ClassOrNamespace *b)
+void CppCompletionAssistProcessor::completeNamespace(CPlusPlus::ClassOrNamespace *b)
{
QSet<ClassOrNamespace *> bindingsVisited;
QList<ClassOrNamespace *> bindingsToVisit;
@@ -1657,7 +1485,7 @@ void CppCodeCompletion::completeNamespace(ClassOrNamespace *b)
}
}
-void CppCodeCompletion::completeClass(ClassOrNamespace *b, bool staticLookup)
+void CppCompletionAssistProcessor::completeClass(CPlusPlus::ClassOrNamespace *b, bool staticLookup)
{
QSet<ClassOrNamespace *> bindingsVisited;
QList<ClassOrNamespace *> bindingsToVisit;
@@ -1709,15 +1537,14 @@ void CppCodeCompletion::completeClass(ClassOrNamespace *b, bool staticLookup)
}
}
-bool CppCodeCompletion::completeQtMethod(const QList<LookupItem> &results,
- bool wantSignals)
+bool CppCompletionAssistProcessor::completeQtMethod(const QList<CPlusPlus::LookupItem> &results, bool wantSignals)
{
if (results.isEmpty())
return false;
const LookupContext &context = typeOfExpression.context();
- ConvertToCompletionItem toCompletionItem(this);
+ ConvertToCompletionItem toCompletionItem;
Overview o;
o.setShowReturnTypes(false);
o.setShowArgumentNames(false);
@@ -1770,14 +1597,14 @@ bool CppCodeCompletion::completeQtMethod(const QList<LookupItem> &results,
continue;
else if (! wantSignals && ! fun->isSlot())
continue;
- TextEditor::CompletionItem item = toCompletionItem(fun);
- if (item.isValid()) {
+ BasicProposalItem *item = toCompletionItem(fun);
+ if (item) {
unsigned count = fun->argumentCount();
while (true) {
- TextEditor::CompletionItem ci = item;
+ BasicProposalItem *ci = item;
QString signature;
- signature += overview.prettyName(fun->name());
+ signature += Overview().prettyName(fun->name());
signature += QLatin1Char('(');
for (unsigned i = 0; i < count; ++i) {
Symbol *arg = fun->argumentAt(i);
@@ -1795,7 +1622,7 @@ bool CppCodeCompletion::completeQtMethod(const QList<LookupItem> &results,
if (! signatures.contains(signature)) {
signatures.insert(signature);
- ci.text = signature; // fix the completion item.
+ ci->setText(signature); // fix the completion item.
m_completions.append(ci);
}
@@ -1812,312 +1639,228 @@ bool CppCodeCompletion::completeQtMethod(const QList<LookupItem> &results,
return ! m_completions.isEmpty();
}
-void CppCodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)
+void CppCompletionAssistProcessor::addSnippets()
{
- const int length = m_editor->position() - m_startPosition;
- if (length < 0)
- return;
-
- const QString key = m_editor->textAt(m_startPosition, length);
-
- if (length == 0)
- *completions = m_completions;
- else if (length > 0) {
- /* Close on the trailing slash for include completion, to enable the slash to
- * trigger a new completion list. */
- if ((m_completionOperator == T_STRING_LITERAL ||
- m_completionOperator == T_ANGLE_STRING_LITERAL) && key.endsWith(QLatin1Char('/')))
- return;
-
- if (m_completionOperator != T_LPAREN) {
- filter(m_completions, completions, key);
-
- } else if (m_completionOperator == T_LPAREN ||
- m_completionOperator == T_SIGNAL ||
- m_completionOperator == T_SLOT) {
- foreach (const TextEditor::CompletionItem &item, m_completions) {
- if (item.text.startsWith(key, Qt::CaseInsensitive)) {
- completions->append(item);
- }
- }
- }
- }
-
- if (m_automaticCompletion && completions->size() == 1 && key == completions->first().text) {
- completions->clear();
- }
+ m_completions.append(m_snippetCollector.collect());
}
-QList<TextEditor::CompletionItem> CppCodeCompletion::removeDuplicates(const QList<TextEditor::CompletionItem> &items)
+void CppCompletionAssistProcessor::addKeywords()
{
- // Duplicates are kept only if they are snippets.
- QList<TextEditor::CompletionItem> uniquelist;
- QSet<QString> processed;
- foreach (const TextEditor::CompletionItem &item, items) {
- if (!processed.contains(item.text) || item.isSnippet) {
- uniquelist.append(item);
- if (!item.isSnippet) {
- processed.insert(item.text);
- if (Symbol *symbol = qvariant_cast<Symbol *>(item.data)) {
- if (Function *funTy = symbol->type()->asFunctionType()) {
- if (funTy->hasArguments())
- ++uniquelist.back().duplicateCount;
- }
- }
- }
- }
- }
+ int keywordLimit = T_FIRST_OBJC_AT_KEYWORD;
+ if (objcKeywordsWanted())
+ keywordLimit = T_LAST_OBJC_AT_KEYWORD + 1;
- return uniquelist;
+ // keyword completion items.
+ for (int i = T_FIRST_KEYWORD; i < keywordLimit; ++i)
+ addCompletionItem(QLatin1String(Token::name(i)), m_icons.keywordIcon());
}
-QList<TextEditor::CompletionItem> CppCodeCompletion::getCompletions()
+void CppCompletionAssistProcessor::addMacros(const QString &fileName, const CPlusPlus::Snapshot &snapshot)
{
- QList<TextEditor::CompletionItem> completionItems;
- completions(&completionItems);
+ QSet<QString> processed;
+ QSet<QString> definedMacros;
+
+ addMacros_helper(snapshot, fileName, &processed, &definedMacros);
- return completionItems;
+ foreach (const QString &macroName, definedMacros)
+ addCompletionItem(macroName, m_icons.macroIcon());
}
-bool CppCodeCompletion::typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar)
+void CppCompletionAssistProcessor::addMacros_helper(const CPlusPlus::Snapshot &snapshot,
+ const QString &fileName,
+ QSet<QString> *processed,
+ QSet<QString> *definedMacros)
{
- if (m_automaticCompletion)
- return false;
-
- if (item.data.canConvert<QString>()) // snippet
- return false;
-
- if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT)
- return typedChar == QLatin1Char('(')
- || typedChar == QLatin1Char(',');
+ Document::Ptr doc = snapshot.document(fileName);
- if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL)
- return typedChar == QLatin1Char('/')
- && item.text.endsWith(QLatin1Char('/'));
+ if (! doc || processed->contains(doc->fileName()))
+ return;
- if (item.data.value<Symbol *>())
- return typedChar == QLatin1Char(':')
- || typedChar == QLatin1Char(';')
- || typedChar == QLatin1Char('.')
- || typedChar == QLatin1Char(',')
- || typedChar == QLatin1Char('(');
+ processed->insert(doc->fileName());
- if (item.data.canConvert<CompleteFunctionDeclaration>())
- return typedChar == QLatin1Char('(');
+ foreach (const Document::Include &i, doc->includes()) {
+ addMacros_helper(snapshot, i.fileName(), processed, definedMacros);
+ }
- return false;
+ foreach (const Macro &macro, doc->definedMacros()) {
+ const QString macroName = QString::fromUtf8(macro.name().constData(), macro.name().length());
+ if (! macro.isHidden())
+ definedMacros->insert(macroName);
+ else
+ definedMacros->remove(macroName);
+ }
}
-void CppCodeCompletion::complete(const TextEditor::CompletionItem &item, QChar typedChar)
+bool CppCompletionAssistProcessor::completeConstructorOrFunction(const QList<CPlusPlus::LookupItem> &results,
+ int endOfExpression,
+ bool toolTipOnly)
{
- m_shouldRestartCompletion = false; // Enabled for specific cases
+ const LookupContext &context = typeOfExpression.context();
+ QList<Function *> functions;
- Symbol *symbol = 0;
+ foreach (const LookupItem &result, results) {
+ FullySpecifiedType exprTy = result.type().simplified();
- if (item.data.isValid()) {
- if (item.data.canConvert<QString>()) {
- TextEditor::BaseTextEditorWidget *edit = qobject_cast<TextEditor::BaseTextEditorWidget *>(m_editor->widget());
- QTextCursor tc = edit->textCursor();
- tc.setPosition(m_startPosition, QTextCursor::KeepAnchor);
- edit->insertCodeSnippet(tc, item.data.toString());
- return;
- } else {
- symbol = item.data.value<Symbol *>();
- }
- }
+ if (Class *klass = asClassOrTemplateClassType(exprTy)) {
+ const Name *className = klass->name();
+ if (! className)
+ continue; // nothing to do for anonymous classes.
- QString toInsert;
- QString extraChars;
- int extraLength = 0;
- int cursorOffset = 0;
+ for (unsigned i = 0; i < klass->memberCount(); ++i) {
+ Symbol *member = klass->memberAt(i);
+ const Name *memberName = member->name();
- bool autoParenthesesEnabled = true;
+ if (! memberName)
+ continue; // skip anonymous member.
- if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
- toInsert = item.text;
- extraChars += QLatin1Char(')');
+ else if (memberName->isQualifiedNameId())
+ continue; // skip
- if (typedChar == QLatin1Char('(')) // Eat the opening parenthesis
- typedChar = QChar();
- } else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) {
- toInsert = item.text;
- if (!toInsert.endsWith(QLatin1Char('/'))) {
- extraChars += QLatin1Char((m_completionOperator == T_ANGLE_STRING_LITERAL) ? '>' : '"');
- } else {
- m_shouldRestartCompletion = true; // Re-trigger for subdirectory
- if (typedChar == QLatin1Char('/')) // Eat the slash
- typedChar = QChar();
+ if (Function *funTy = member->type()->asFunctionType()) {
+ if (memberName->isEqualTo(className)) {
+ // it's a ctor.
+ functions.append(funTy);
+ }
+ }
+ }
+
+ break;
}
- } else {
- toInsert = item.text;
+ }
- //qDebug() << "current symbol:" << overview.prettyName(symbol->name())
- //<< overview.prettyType(symbol->type());
+ if (functions.isEmpty()) {
+ foreach (const LookupItem &result, results) {
+ FullySpecifiedType ty = result.type().simplified();
- const bool autoInsertBrackets = completionSettings().m_autoInsertBrackets;
+ if (Function *fun = asFunctionOrTemplateFunctionType(ty)) {
- if (autoInsertBrackets && symbol && symbol->type()) {
- if (Function *function = symbol->type()->asFunctionType()) {
- // If the member is a function, automatically place the opening parenthesis,
- // except when it might take template parameters.
- if (! function->hasReturnType() && (function->unqualifiedName() && !function->unqualifiedName()->isDestructorNameId())) {
- // Don't insert any magic, since the user might have just wanted to select the class
+ if (! fun->name())
+ continue;
+ else if (! functions.isEmpty() && enclosingNonTemplateScope(functions.first()) != enclosingNonTemplateScope(fun))
+ continue; // skip fun, it's an hidden declaration.
- /// ### port me
-#if 0
- } else if (function->templateParameterCount() != 0 && typedChar != QLatin1Char('(')) {
- // If there are no arguments, then we need the template specification
- if (function->argumentCount() == 0) {
- extraChars += QLatin1Char('<');
+ bool newOverload = true;
+
+ foreach (Function *f, functions) {
+ if (fun->isEqualTo(f)) {
+ newOverload = false;
+ break;
}
-#endif
- } else if (! function->isAmbiguous()) {
- // When the user typed the opening parenthesis, he'll likely also type the closing one,
- // in which case it would be annoying if we put the cursor after the already automatically
- // inserted closing parenthesis.
- const bool skipClosingParenthesis = typedChar != QLatin1Char('(');
+ }
- if (completionSettings().m_spaceAfterFunctionName)
- extraChars += QLatin1Char(' ');
- extraChars += QLatin1Char('(');
- if (typedChar == QLatin1Char('('))
- typedChar = QChar();
+ if (newOverload)
+ functions.append(fun);
+ }
+ }
+ }
- // If the function doesn't return anything, automatically place the semicolon,
- // unless we're doing a scope completion (then it might be function definition).
- const QChar characterAtCursor = m_editor->characterAt(m_editor->position());
- bool endWithSemicolon = typedChar == QLatin1Char(';')
- || (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON);
- const QChar semicolon = typedChar.isNull() ? QLatin1Char(';') : typedChar;
+ if (functions.isEmpty()) {
+ const Name *functionCallOp = context.control()->operatorNameId(OperatorNameId::FunctionCallOp);
- if (endWithSemicolon && characterAtCursor == semicolon) {
- endWithSemicolon = false;
- typedChar = QChar();
- }
+ foreach (const LookupItem &result, results) {
+ FullySpecifiedType ty = result.type().simplified();
+ Scope *scope = result.scope();
- // If the function takes no arguments, automatically place the closing parenthesis
- if (item.duplicateCount == 0 && ! function->hasArguments() && skipClosingParenthesis) {
- extraChars += QLatin1Char(')');
- if (endWithSemicolon) {
- extraChars += semicolon;
- typedChar = QChar();
- }
- } else if (autoParenthesesEnabled) {
- const QChar lookAhead = m_editor->characterAt(m_editor->position() + 1);
- if (MatchingText::shouldInsertMatchingText(lookAhead)) {
- extraChars += QLatin1Char(')');
- --cursorOffset;
- if (endWithSemicolon) {
- extraChars += semicolon;
- --cursorOffset;
- typedChar = QChar();
- }
+ if (NamedType *namedTy = ty->asNamedType()) {
+ if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) {
+ foreach (const LookupItem &r, b->lookup(functionCallOp)) {
+ Symbol *overload = r.declaration();
+ FullySpecifiedType overloadTy = overload->type().simplified();
+
+ if (Function *funTy = overloadTy->asFunctionType()) {
+ functions.append(funTy);
}
- // TODO: When an opening parenthesis exists, the "semicolon" should really be
- // inserted after the matching closing parenthesis.
}
}
}
}
-
- if (autoInsertBrackets && item.data.canConvert<CompleteFunctionDeclaration>()) {
- if (typedChar == QLatin1Char('('))
- typedChar = QChar();
-
- // everything from the closing parenthesis on are extra chars, to
- // make sure an auto-inserted ")" gets replaced by ") const" if necessary
- int closingParen = toInsert.lastIndexOf(QLatin1Char(')'));
- extraChars = toInsert.mid(closingParen);
- toInsert.truncate(closingParen);
- }
}
- // Append an unhandled typed character, adjusting cursor offset when it had been adjusted before
- if (!typedChar.isNull()) {
- extraChars += typedChar;
- if (cursorOffset != 0)
- --cursorOffset;
- }
+ // There are two different kinds of completion we want to provide:
+ // 1. If this is a function call, we want to pop up a tooltip that shows the user
+ // the possible overloads with their argument types and names.
+ // 2. If this is a function definition, we want to offer autocompletion of
+ // the function signature.
- if (!extraChars.isEmpty() && extraChars.length() + cursorOffset > 0) {
- const QChar c = extraChars.at(extraChars.length() - 1 + cursorOffset);
- if (c == QLatin1Char('.') || c == QLatin1Char('('))
- m_shouldRestartCompletion = true;
- }
+ // check if function signature autocompletion is appropriate
+ // Also check if the function name is a destructor name.
+ bool isDestructor = false;
+ if (! functions.isEmpty() && ! toolTipOnly) {
- // Avoid inserting characters that are already there
- for (int i = 0; i < extraChars.length(); ++i) {
- const QChar a = extraChars.at(i);
- const QChar b = m_editor->characterAt(m_editor->position() + i);
- if (a == b)
- ++extraLength;
- else
- break;
- }
+ // function definitions will only happen in class or namespace scope,
+ // so get the current location's enclosing scope.
- toInsert += extraChars;
+ // get current line and column
+ int lineSigned = 0, columnSigned = 0;
+ Convenience::convertPosition(m_interface->document(), m_interface->position(), &lineSigned, &columnSigned);
+ unsigned line = lineSigned, column = columnSigned;
- // Insert the remainder of the name
- int length = m_editor->position() - m_startPosition + extraLength;
- m_editor->setCursorPosition(m_startPosition);
- m_editor->replace(length, toInsert);
- if (cursorOffset)
- m_editor->setCursorPosition(m_editor->position() + cursorOffset);
-}
+ // find a scope that encloses the current location, starting from the lastVisibileSymbol
+ // and moving outwards
-bool CppCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)
-{
- if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
- return false;
- } else if (completionItems.count() == 1) {
- complete(completionItems.first(), QChar());
- return true;
- } else if (m_completionOperator != T_LPAREN) {
- return TextEditor::ICompletionCollector::partiallyComplete(completionItems);
- }
+ Scope *sc = context.thisDocument()->scopeAt(line, column);
- return false;
-}
+ if (sc && (sc->isClass() || sc->isNamespace())) {
+ // It may still be a function call. If the whole line parses as a function
+ // declaration, we should be certain that it isn't.
+ bool autocompleteSignature = false;
-void CppCodeCompletion::cleanup()
-{
- m_automaticCompletion = false;
- m_completions.clear();
+ QTextCursor tc(m_interface->document());
+ tc.setPosition(endOfExpression);
+ BackwardsScanner bs(tc);
+ const int startToken = bs.startToken();
+ int lineStartToken = bs.startOfLine(startToken);
+ // make sure the required tokens are actually available
+ bs.LA(startToken - lineStartToken);
+ QString possibleDecl = bs.mid(lineStartToken).trimmed().append("();");
- // Set empty map in order to avoid referencing old versions of the documents
- // until the next completion
- typeOfExpression.reset();
-}
+ Document::Ptr doc = Document::create(QLatin1String("<completion>"));
+ doc->setSource(possibleDecl.toLatin1());
+ if (doc->parse(Document::ParseDeclaration)) {
+ doc->check();
+ if (SimpleDeclarationAST *sd = doc->translationUnit()->ast()->asSimpleDeclaration()) {
+ if (sd->declarator_list &&
+ sd->declarator_list && sd->declarator_list->value->postfix_declarator_list
+ && sd->declarator_list->value->postfix_declarator_list->value->asFunctionDeclarator()) {
-int CppCodeCompletion::findStartOfName(int pos) const
-{
- if (pos == -1)
- pos = m_editor->position();
- QChar chr;
+ autocompleteSignature = true;
- // Skip to the start of a name
- do {
- chr = m_editor->characterAt(--pos);
- } while (chr.isLetterOrNumber() || chr == QLatin1Char('_'));
+ CoreDeclaratorAST *coreDecl = sd->declarator_list->value->core_declarator;
+ if (coreDecl && coreDecl->asDeclaratorId() && coreDecl->asDeclaratorId()->name) {
+ NameAST *declName = coreDecl->asDeclaratorId()->name;
+ if (declName->asDestructorName()) {
+ isDestructor = true;
+ } else if (QualifiedNameAST *qName = declName->asQualifiedName()) {
+ if (qName->unqualified_name && qName->unqualified_name->asDestructorName())
+ isDestructor = true;
+ }
+ }
+ }
+ }
+ }
- return pos + 1;
-}
+ if (autocompleteSignature && !isDestructor) {
+ // set up signature autocompletion
+ foreach (Function *f, functions) {
+ Overview overview;
+ overview.setShowArgumentNames(true);
+ overview.setShowDefaultArguments(false);
-bool CppCodeCompletion::objcKeywordsWanted() const
-{
- if (!m_objcEnabled)
- return false;
+ // gets: "parameter list) cv-spec",
+ QString completion = overview(f->type()).mid(1);
- Core::IFile *file = m_editor->file();
- QString fileName = file->fileName();
+ addCompletionItem(completion, QIcon(), 0,
+ QVariant::fromValue(CompleteFunctionDeclaration(f)));
+ }
+ return true;
+ }
+ }
+ }
- const Core::MimeDatabase *mdb = Core::ICore::instance()->mimeDatabase();
- return mdb->findByFile(fileName).type() == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE;
-}
+ if (! functions.empty() && !isDestructor) {
+ m_hintProposal = createHintProposal(functions);
+ return true;
+ }
-void CppCodeCompletion::addSnippets()
-{
- m_completions.append(m_snippetProvider.getSnippets(this));
+ return false;
}
-
-#include "cppcodecompletion.moc"
diff --git a/src/plugins/cpptools/cppcompletionassist.h b/src/plugins/cpptools/cppcompletionassist.h
new file mode 100644
index 0000000000..8ed0282736
--- /dev/null
+++ b/src/plugins/cpptools/cppcompletionassist.h
@@ -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
diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro
index f970e74860..ca8d89ce8a 100644
--- a/src/plugins/cpptools/cpptools.pro
+++ b/src/plugins/cpptools/cpptools.pro
@@ -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
diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp
index 44f2da4639..8bff1f858f 100644
--- a/src/plugins/cpptools/cpptoolsplugin.cpp
+++ b/src/plugins/cpptools/cpptoolsplugin.cpp
@@ -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;
}
diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp
index b34d673a4b..d65121f184 100644
--- a/src/plugins/fakevim/fakevimplugin.cpp
+++ b/src/plugins/fakevim/fakevimplugin.cpp
@@ -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,155 +585,154 @@ 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;
+ return false;
}
- virtual bool shouldRestartCompletion()
+ virtual TextEditor::IAssistProcessor *createProcessor() const;
+
+ void setActive(const QString &needle, bool forward, FakeVimHandler *handler)
{
- //qDebug() << "SHOULD RESTART COMPLETION?";
- return false;
+ Q_UNUSED(forward);
+ m_handler = handler;
+ if (!m_handler)
+ return;
+
+ BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(handler->widget());
+ if (!editor)
+ return;
+
+ //qDebug() << "ACTIVATE: " << needle << forward;
+ m_needle = needle;
+ editor->invokeAssist(Completion, this);
}
- virtual ITextEditor *editor() const
+ void setInactive()
{
- //qDebug() << "NO EDITOR?";
- return m_editable;
+ m_needle.clear();
+ m_handler = 0;
}
- virtual int startPosition() const
+ const QString &needle() const
{
- return m_startPosition;
+ return m_needle;
}
- virtual bool supportsEditor(ITextEditor *) const
+ void appendNeedle(const QChar &c)
{
- return true;
+ m_needle.append(c);
}
- virtual bool supportsPolicy(CompletionPolicy policy) const
+ FakeVimHandler *handler() const
{
- return policy == TextCompletion;
+ return m_handler;
}
- virtual bool triggersCompletion(ITextEditor *editable)
+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
{
- //qDebug() << "TRIGGERS?";
- QTC_ASSERT(m_editable == editable, /**/);
- return true;
+ return false;
}
- virtual int startCompletion(ITextEditor *editable)
+ virtual bool prematurelyApplies(const QChar &c) const
{
- //qDebug() << "START COMPLETION";
- QTC_ASSERT(m_editor, return -1);
- QTC_ASSERT(m_editable == editable, return -1);
- return m_editor->textCursor().position();
+ m_provider->appendNeedle(c);
+ return text() == m_provider->needle();
}
- void setActive(const QString &needle, bool forward, FakeVimHandler *handler)
+ virtual void applyContextualContent(BaseTextEditor *, int) const
{
- Q_UNUSED(forward);
- m_handler = handler;
- if (!m_handler)
- return;
- m_editor = qobject_cast<BaseTextEditorWidget *>(handler->widget());
- if (!m_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);
+ QTC_ASSERT(m_provider->handler(), return);
+ m_provider->handler()->handleReplay(text().mid(m_provider->needle().size()));
+ const_cast<FakeVimCompletionAssistProvider *>(m_provider)->setInactive();
}
- void setInactive()
+private:
+ FakeVimCompletionAssistProvider *m_provider;
+};
+
+
+class FakeVimAssistProposalModel : public BasicProposalItemListModel
+{
+public:
+ FakeVimAssistProposalModel(const QList<BasicProposalItem *> &items)
+ : BasicProposalItemListModel(items)
+ {}
+
+ virtual bool supportsPrefixExpansion() const
{
- m_needle.clear();
- m_editable = 0;
- m_editor = 0;
- m_handler = 0;
- m_startPosition = -1;
+ return false;
}
+};
- virtual void completions(QList<CompletionItem> *completions)
+class FakeVimCompletionAssistProcessor : public IAssistProcessor
+{
+public:
+ FakeVimCompletionAssistProcessor(const TextEditor::IAssistProvider *provider)
+ : m_provider(static_cast<const FakeVimCompletionAssistProvider *>(provider))
+ {}
+
+ virtual TextEditor::IAssistProposal *perform(const IAssistInterface *interface)
{
- QTC_ASSERT(m_editor, return);
- QTC_ASSERT(completions, return);
- QTextCursor tc = m_editor->textCursor();
+ 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;
- }
- 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;
+ delete interface;
+ return new GenericProposal(basePosition, new FakeVimAssistProposalModel(items));
}
- 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)
diff --git a/src/plugins/glsleditor/glslcodecompletion.cpp b/src/plugins/glsleditor/glslcodecompletion.cpp
deleted file mode 100644
index 5493ad7e84..0000000000
--- a/src/plugins/glsleditor/glslcodecompletion.cpp
+++ /dev/null
@@ -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"
diff --git a/src/plugins/glsleditor/glslcodecompletion.h b/src/plugins/glsleditor/glslcodecompletion.h
deleted file mode 100644
index bb3d10a52e..0000000000
--- a/src/plugins/glsleditor/glslcodecompletion.h
+++ /dev/null
@@ -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
diff --git a/src/plugins/glsleditor/glslcompletionassist.cpp b/src/plugins/glsleditor/glslcompletionassist.cpp
new file mode 100644
index 0000000000..125dbad66f
--- /dev/null
+++ b/src/plugins/glsleditor/glslcompletionassist.cpp
@@ -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)
+{
+}
diff --git a/src/plugins/glsleditor/glslcompletionassist.h b/src/plugins/glsleditor/glslcompletionassist.h
new file mode 100644
index 0000000000..78daea8818
--- /dev/null
+++ b/src/plugins/glsleditor/glslcompletionassist.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.
+**
+**************************************************************************/
+
+#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
diff --git a/src/plugins/glsleditor/glsleditor.cpp b/src/plugins/glsleditor/glsleditor.cpp
index 83c84d13e9..18fa55228f 100644
--- a/src/plugins/glsleditor/glsleditor.cpp
+++ b/src/plugins/glsleditor/glsleditor.cpp
@@ -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);
+}
diff --git a/src/plugins/glsleditor/glsleditor.h b/src/plugins/glsleditor/glsleditor.h
index 8c5712d9be..ba228f4c22 100644
--- a/src/plugins/glsleditor/glsleditor.h
+++ b/src/plugins/glsleditor/glsleditor.h
@@ -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 &);
diff --git a/src/plugins/glsleditor/glsleditor.pro b/src/plugins/glsleditor/glsleditor.pro
index be0cdf3b43..7a5385842a 100644
--- a/src/plugins/glsleditor/glsleditor.pro
+++ b/src/plugins/glsleditor/glsleditor.pro
@@ -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
diff --git a/src/plugins/glsleditor/glsleditorplugin.cpp b/src/plugins/glsleditor/glsleditorplugin.cpp
index 7e372bfea1..319982888a 100644
--- a/src/plugins/glsleditor/glsleditorplugin.cpp
+++ b/src/plugins/glsleditor/glsleditorplugin.cpp
@@ -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();
diff --git a/src/plugins/glsleditor/reuse.cpp b/src/plugins/glsleditor/reuse.cpp
new file mode 100644
index 0000000000..aeb8932513
--- /dev/null
+++ b/src/plugins/glsleditor/reuse.cpp
@@ -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
+
diff --git a/src/plugins/glsleditor/reuse.h b/src/plugins/glsleditor/reuse.h
new file mode 100644
index 0000000000..5fb12112e6
--- /dev/null
+++ b/src/plugins/glsleditor/reuse.h
@@ -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
diff --git a/src/plugins/qmljseditor/qmljscodecompletion.cpp b/src/plugins/qmljseditor/qmljscodecompletion.cpp
deleted file mode 100644
index 9ad60f4f51..0000000000
--- a/src/plugins/qmljseditor/qmljscodecompletion.cpp
+++ /dev/null
@@ -1,1146 +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 "qmljscodecompletion.h"
-#include "qmlexpressionundercursor.h"
-#include "qmljseditor.h"
-#include "qmljseditorconstants.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 <texteditor/basetexteditor.h>
-#include <texteditor/completionsettings.h>
-
-#include <coreplugin/icore.h>
-#include <coreplugin/editormanager/editormanager.h>
-
-#include <utils/faketooltip.h>
-#include <utils/qtcassert.h>
-
-#include <QtCore/QFile>
-#include <QtCore/QFileInfo>
-#include <QtCore/QDir>
-#include <QtCore/QDebug>
-#include <QtCore/QDirIterator>
-
-#include <QtGui/QApplication>
-#include <QtGui/QDesktopWidget>
-#include <QtGui/QHBoxLayout>
-#include <QtGui/QLabel>
-#include <QtGui/QPainter>
-#include <QtGui/QStyle>
-#include <QtGui/QTextBlock>
-#include <QtGui/QToolButton>
-
-using namespace QmlJSEditor;
-using namespace QmlJSEditor::Internal;
-using namespace QmlJS;
-
-namespace {
-
-enum CompletionOrder {
- EnumValueOrder = -5,
- SnippetOrder = -15,
- PropertyOrder = -10,
- SymbolOrder = -20,
- KeywordOrder = -25,
- TypeOrder = -30
-};
-
-// Temporary workaround until we have proper icons for QML completion items
-static 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;
-}
-
-static bool checkStartOfIdentifier(const QString &word)
-{
- if (word.isEmpty())
- return false;
-
- const QChar ch = word.at(0);
-
- switch (ch.unicode()) {
- case '_': case '$':
- return true;
-
- default:
- return ch.isLetter();
- }
-}
-
-static bool isIdentifierChar(QChar ch)
-{
- switch (ch.unicode()) {
- case '_': case '$':
- return true;
-
- default:
- return ch.isLetterOrNumber();
- }
-}
-
-class SearchPropertyDefinitions: protected AST::Visitor
-{
- QList<AST::UiPublicMember *> _properties;
-
-public:
- QList<AST::UiPublicMember *> operator()(Document::Ptr doc)
- {
- _properties.clear();
- if (doc && doc->qmlProgram())
- doc->qmlProgram()->accept(this);
- return _properties;
- }
-
-
-protected:
- using AST::Visitor::visit;
-
- virtual bool visit(AST::UiPublicMember *member)
- {
- if (member->propertyToken.isValid()) {
- _properties.append(member);
- }
-
- return true;
- }
-};
-
-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);
- }
-};
-
-} // end of anonymous namespace
-
-namespace QmlJSEditor {
-namespace Internal {
-
-class FunctionArgumentWidget : public QLabel
-{
-public:
- FunctionArgumentWidget();
- void showFunctionHint(const QString &functionName,
- const QStringList &signature,
- int startPosition);
-
-protected:
- bool eventFilter(QObject *obj, QEvent *e);
-
-private:
- void updateArgumentHighlight();
- void updateHintText();
-
- QString m_functionName;
- QStringList m_signature;
- int m_minimumArgumentCount;
- 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;
-};
-
-
-FunctionArgumentWidget::FunctionArgumentWidget():
- m_minimumArgumentCount(0),
- 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());
-
- setParent(m_popupFrame);
- setFocusPolicy(Qt::NoFocus);
-
- m_pager = new QWidget;
- QHBoxLayout *hbox = new QHBoxLayout(m_pager);
- hbox->setMargin(0);
- hbox->setSpacing(0);
- m_numberLabel = new QLabel;
- hbox->addWidget(m_numberLabel);
-
- QHBoxLayout *layout = new QHBoxLayout;
- layout->setMargin(0);
- layout->setSpacing(0);
- layout->addWidget(m_pager);
- layout->addWidget(this);
- m_popupFrame->setLayout(layout);
-
- setTextFormat(Qt::RichText);
-
- qApp->installEventFilter(this);
-}
-
-void FunctionArgumentWidget::showFunctionHint(const QString &functionName, const QStringList &signature, int startPosition)
-{
- if (m_startpos == startPosition)
- return;
-
- m_functionName = functionName;
- m_signature = signature;
- m_minimumArgumentCount = signature.size();
- m_startpos = startPosition;
- m_current = 0;
- m_escapePressed = false;
-
- // update the text
- m_currentarg = -1;
- updateArgumentHighlight();
-
- m_popupFrame->show();
-}
-
-void FunctionArgumentWidget::updateArgumentHighlight()
-{
- int curpos = m_editor->position();
- if (curpos < m_startpos) {
- m_popupFrame->close();
- return;
- }
-
- updateHintText();
-
- QString str = m_editor->textAt(m_startpos, curpos - m_startpos);
- int argnr = 0;
- int parcount = 0;
- Scanner tokenize;
- const QList<Token> tokens = tokenize(str);
- 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 (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;
- }
- 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()
-{
- 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(')');
-
- m_numberLabel->setText(prettyMethod);
-
- m_popupFrame->setFixedWidth(m_popupFrame->minimumSizeHint().width());
-
- 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
-
- const QSize sz = m_popupFrame->sizeHint();
- 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);
-}
-
-} } // namespace QmlJSEditor::Internal
-
-CodeCompletion::CodeCompletion(ModelManagerInterface *modelManager, QObject *parent)
- : TextEditor::ICompletionCollector(parent),
- m_modelManager(modelManager),
- m_editor(0),
- m_startPosition(0),
- m_restartCompletion(false),
- m_snippetProvider(Constants::QML_SNIPPETS_GROUP_ID, iconForColor(Qt::red), SnippetOrder)
-{
- Q_ASSERT(modelManager);
-}
-
-CodeCompletion::~CodeCompletion()
-{ }
-
-TextEditor::ITextEditor *CodeCompletion::editor() const
-{ return m_editor; }
-
-int CodeCompletion::startPosition() const
-{ return m_startPosition; }
-
-bool CodeCompletion::shouldRestartCompletion()
-{ return m_restartCompletion; }
-
-bool CodeCompletion::supportsEditor(TextEditor::ITextEditor *editor) const
-{
- if (qobject_cast<QmlJSTextEditorWidget *>(editor->widget()))
- return true;
-
- return false;
-}
-
-bool CodeCompletion::supportsPolicy(TextEditor::CompletionPolicy policy) const
-{
- return policy == TextEditor::SemanticCompletion;
-}
-
-bool CodeCompletion::triggersCompletion(TextEditor::ITextEditor *editor)
-{
- if (maybeTriggersCompletion(editor)) {
- // check the token under cursor
-
- if (QmlJSTextEditorWidget *ed = qobject_cast<QmlJSTextEditorWidget *>(editor->widget())) {
-
- QTextCursor tc = ed->textCursor();
- QTextBlock block = tc.block();
- const int column = tc.positionInBlock();
- const QChar ch = block.text().at(column - 1);
- const int blockState = qMax(0, block.previous().userState()) & 0xff;
- const QString blockText = block.text();
-
- Scanner scanner;
- const QList<Token> tokens = scanner(blockText, blockState);
- foreach (const Token &tk, tokens) {
- if (column >= tk.begin() && column <= tk.end()) {
- if (ch == 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 (ch == QLatin1Char('/'))
- return false;
- }
- return true;
- }
-
- return false;
-}
-
-bool CodeCompletion::maybeTriggersCompletion(TextEditor::ITextEditor *editor)
-{
- const int cursorPosition = editor->position();
- const QChar ch = editor->characterAt(cursorPosition - 1);
-
- if (ch == QLatin1Char('(') || ch == QLatin1Char('.') || ch == QLatin1Char('/'))
- return true;
- if (completionSettings().m_completionTrigger != TextEditor::AutomaticCompletion)
- return false;
-
- 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;
- }
- }
-
- return false;
-}
-
-bool CodeCompletion::isDelimiter(QChar ch) const
-{
- switch (ch.unicode()) {
- case '{':
- case '}':
- case '[':
- case ']':
- case ')':
- case '?':
- case '!':
- case ':':
- case ';':
- case ',':
- case '+':
- case '-':
- case '*':
- case '/':
- return true;
-
- default:
- return false;
- }
-}
-
-static 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;
-}
-
-bool CodeCompletion::completeUrl(const QString &relativeBasePath, const QString &urlString)
-{
- const QUrl url(urlString);
- QString fileName = url.toLocalFile();
- if (fileName.isEmpty())
- return false;
-
- return completeFileName(relativeBasePath, fileName);
-}
-
-class FileNameCompletion
-{
-public:
- bool isDirectory;
-};
-Q_DECLARE_METATYPE(FileNameCompletion)
-
-bool CodeCompletion::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();
-
- TextEditor::CompletionItem item(this);
- item.text += fileName;
- FileNameCompletion extraData;
- extraData.isDirectory = dirIterator.fileInfo().isDir();
- if (extraData.isDirectory)
- item.text += QLatin1Char('/');
- item.data = QVariant::fromValue(extraData);
- // ### Icon for file completions
- item.icon = iconForColor(Qt::darkBlue);
- m_completions.append(item);
- }
-
- return !m_completions.isEmpty();
-}
-
-void CodeCompletion::addCompletions(const QHash<QString, const Interpreter::Value *> &newCompletions,
- const QIcon &icon, int order)
-{
- QHashIterator<QString, const Interpreter::Value *> it(newCompletions);
- while (it.hasNext()) {
- it.next();
-
- TextEditor::CompletionItem item(this);
- item.text = it.key();
- item.icon = icon;
- item.order = order;
- m_completions.append(item);
- }
-}
-
-void CodeCompletion::addCompletions(const QStringList &newCompletions,
- const QIcon &icon, int order)
-{
- foreach (const QString &text, newCompletions) {
- TextEditor::CompletionItem item(this);
- item.text = text;
- item.icon = icon;
- item.order = order;
- m_completions.append(item);
- }
-}
-
-void CodeCompletion::addCompletionsPropertyLhs(
- const QHash<QString, const Interpreter::Value *> &newCompletions,
- const QIcon &icon, int order, bool afterOn)
-{
- QHashIterator<QString, const Interpreter::Value *> it(newCompletions);
- while (it.hasNext()) {
- it.next();
-
- TextEditor::CompletionItem item(this);
- item.text = 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())
- item.text.append(postfix);
- else
- item.text.append(QLatin1Char('.'));
- } else {
- item.text.append(postfix);
- }
- item.icon = icon;
- item.order = order;
- m_completions.append(item);
- }
-}
-
-static 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;
-}
-
-int CodeCompletion::startCompletion(TextEditor::ITextEditor *editor)
-{
- m_restartCompletion = false;
-
- m_editor = editor;
-
- QmlJSTextEditorWidget *edit = qobject_cast<QmlJSTextEditorWidget *>(m_editor->widget());
- if (! edit)
- return -1;
-
- m_startPosition = editor->position();
- const QString fileName = editor->file()->fileName();
-
- while (editor->characterAt(m_startPosition - 1).isLetterOrNumber() ||
- editor->characterAt(m_startPosition - 1) == QLatin1Char('_'))
- --m_startPosition;
-
- m_completions.clear();
-
- const SemanticInfo semanticInfo = edit->semanticInfo();
-
- if (! semanticInfo.isValid())
- return -1;
-
- const Document::Ptr document = semanticInfo.document;
- const QFileInfo currentFileInfo(fileName);
-
- bool isQmlFile = false;
- if (currentFileInfo.suffix() == QLatin1String("qml"))
- isQmlFile = true;
-
- const QIcon symbolIcon = iconForColor(Qt::darkCyan);
- const QIcon keywordIcon = iconForColor(Qt::darkYellow);
-
- const QList<AST::Node *> path = semanticInfo.astPath(editor->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 = editor->characterAt(m_startPosition - 1);
-
- QTextCursor startPositionCursor(edit->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 = edit->textCursor();
- QmlExpressionUnderCursor expressionUnderCursor;
- expressionUnderCursor(tc);
- QString literalText = expressionUnderCursor.text();
- QTC_ASSERT(!literalText.isEmpty() && (
- literalText.at(0) == QLatin1Char('"')
- || literalText.at(0) == QLatin1Char('\'')), return -1);
- literalText = literalText.mid(1);
-
- if (contextFinder.isInImport()) {
- QStringList patterns;
- patterns << QLatin1String("*.qml") << QLatin1String("*.js");
- if (completeFileName(document->path(), literalText, patterns))
- return m_startPosition;
- return -1;
- }
-
- const Interpreter::Value *value = getPropertyValue(qmlScopeType, contextFinder.bindingPropertyName(), context);
- if (!value) {
- // do nothing
- } else if (value->asUrlValue()) {
- if (completeUrl(document->path(), literalText))
- return m_startPosition;
- }
-
- // ### 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 -1;
- } else if (completionOperator.isSpace() || completionOperator.isNull() || isDelimiter(completionOperator) ||
- (completionOperator == QLatin1Char('(') && m_startPosition != editor->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
- TextEditor::CompletionItem idPropertyCompletion(this);
- idPropertyCompletion.text = QLatin1String("id: ");
- idPropertyCompletion.icon = symbolIcon;
- idPropertyCompletion.order = PropertyOrder;
- m_completions.append(idPropertyCompletion);
-
- addCompletionsPropertyLhs(enumerateProperties(qmlScopeType), symbolIcon, PropertyOrder, contextFinder.isAfterOnInLhsOfBinding());
-
- if (ScopeBuilder::isPropertyChangesObject(context, qmlScopeType)
- && context->scopeChain().qmlScopeObjects.size() == 2) {
- addCompletions(enumerateProperties(context->scopeChain().qmlScopeObjects.first()), 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()) {
- TextEditor::CompletionItem item(this);
- item.text = key;
- item.data = QString("\"%1\"").arg(key);
- item.icon = symbolIcon;
- item.order = EnumValueOrder;
- m_completions.append(item);
- }
- }
- }
-
- if (!contextFinder.isInImport() && !contextFinder.isInQmlContext())
- doQmlTypeCompletion = true;
-
- if (doQmlTypeCompletion) {
- if (const Interpreter::ObjectValue *qmlTypes = context->scopeChain().qmlTypes) {
- EnumerateProperties enumerateProperties(context);
- addCompletions(enumerateProperties(qmlTypes), symbolIcon, TypeOrder);
- }
- }
-
- if (doGlobalCompletion) {
- // It's a global completion.
- EnumerateProperties enumerateProperties(context);
- enumerateProperties.setGlobalCompletion(true);
- addCompletions(enumerateProperties(), symbolIcon, SymbolOrder);
- }
-
- if (doJsKeywordCompletion) {
- // add js keywords
- addCompletions(Scanner::keywords(), 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, keywordIcon, KeywordOrder);
- if (!doJsKeywordCompletion)
- addCompletions(qmlWordsAlsoInJs, keywordIcon, KeywordOrder);
- }
- }
-
- else if (completionOperator == QLatin1Char('.') || completionOperator == QLatin1Char('(')) {
- // Look at the expression under cursor.
- QTextCursor tc = edit->textCursor();
- 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), symbolIcon, PropertyOrder, contextFinder.isAfterOnInLhsOfBinding());
- } else
- addCompletions(enumerateProperties(value), symbolIcon, SymbolOrder);
- } else if (value && completionOperator == QLatin1Char('(') && m_startPosition == editor->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);
-
- // Recreate if necessary
- if (!m_functionArgumentWidget)
- m_functionArgumentWidget = new QmlJSEditor::Internal::FunctionArgumentWidget;
-
- QStringList signature;
- for (int i = 0; i < f->argumentCount(); ++i)
- signature.append(f->argumentName(i));
-
- m_functionArgumentWidget->showFunctionHint(functionName.trimmed(),
- signature,
- m_startPosition);
- }
-
- return -1; // We always return -1 when completing function prototypes.
- }
- }
-
- if (! m_completions.isEmpty())
- return m_startPosition;
-
- return -1;
- }
-
- if (isQmlFile && (completionOperator.isNull() || completionOperator.isSpace() || isDelimiter(completionOperator))) {
- m_completions.append(m_snippetProvider.getSnippets(this));
- }
-
- if (! m_completions.isEmpty())
- return m_startPosition;
-
- return -1;
-}
-
-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)
-{
- if (item.data.canConvert<QString>()) // snippet
- return false;
-
- return (item.text.endsWith(QLatin1String(": ")) && typedChar == QLatin1Char(':'))
- || (item.text.endsWith(QLatin1Char('.')) && typedChar == QLatin1Char('.'));
-}
-
-void CodeCompletion::complete(const TextEditor::CompletionItem &item, QChar typedChar)
-{
- Q_UNUSED(typedChar) // Currently always included in the completion item when used
-
- QString toInsert = item.text;
-
- if (QmlJSTextEditorWidget *edit = qobject_cast<QmlJSTextEditorWidget *>(m_editor->widget())) {
- if (item.data.canConvert<QString>()) {
- QTextCursor tc = edit->textCursor();
- tc.setPosition(m_startPosition, QTextCursor::KeepAnchor);
- toInsert = item.data.toString();
- edit->insertCodeSnippet(tc, toInsert);
- return;
- }
- }
-
- QString replacableChars;
- if (toInsert.endsWith(QLatin1String(": ")))
- replacableChars = QLatin1String(": ");
- else if (toInsert.endsWith(QLatin1Char('.')))
- replacableChars = QLatin1String(".");
-
- int replacedLength = 0;
-
- // Avoid inserting characters that are already there
- for (int i = 0; i < replacableChars.length(); ++i) {
- const QChar a = replacableChars.at(i);
- const QChar b = m_editor->characterAt(m_editor->position() + i);
- if (a == b)
- ++replacedLength;
- else
- break;
- }
-
- const int length = m_editor->position() - m_startPosition + replacedLength;
- m_editor->setCursorPosition(m_startPosition);
- m_editor->replace(length, toInsert);
-
- if (toInsert.endsWith(QLatin1Char('.')))
- m_restartCompletion = true;
- if (item.data.canConvert<FileNameCompletion>() && item.data.value<FileNameCompletion>().isDirectory)
- m_restartCompletion = true;
-}
-
-bool CodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)
-{
- if (completionItems.count() == 1) {
- const TextEditor::CompletionItem item = completionItems.first();
-
- if (!item.data.canConvert<QString>()) {
- complete(item, QChar());
- return true;
- }
- }
-
- return TextEditor::ICompletionCollector::partiallyComplete(completionItems);
-}
-
-void CodeCompletion::cleanup()
-{
- m_editor = 0;
- m_startPosition = 0;
- m_completions.clear();
-}
-
-static bool qmlCompletionItemLessThan(const TextEditor::CompletionItem &l, const TextEditor::CompletionItem &r)
-{
- if (l.order != r.order)
- return l.order > r.order;
- else if (l.text.isEmpty())
- return true;
- else if (r.text.isEmpty())
- return false;
- else if (l.data.isValid() != r.data.isValid())
- return l.data.isValid();
- else if (l.text.at(0).isUpper() && r.text.at(0).isLower())
- return false;
- else if (l.text.at(0).isLower() && r.text.at(0).isUpper())
- return true;
-
- return l.text < r.text;
-}
-
-void CodeCompletion::sortCompletion(QList<TextEditor::CompletionItem> &completionItems)
-{
- qStableSort(completionItems.begin(), completionItems.end(), qmlCompletionItemLessThan);
-}
-
-QList<TextEditor::CompletionItem> CodeCompletion::getCompletions()
-{
- QList<TextEditor::CompletionItem> completionItems;
-
- completions(&completionItems);
-
- sortCompletion(completionItems);
-
- // 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;
-}
diff --git a/src/plugins/qmljseditor/qmljscodecompletion.h b/src/plugins/qmljseditor/qmljscodecompletion.h
deleted file mode 100644
index ba3083448c..0000000000
--- a/src/plugins/qmljseditor/qmljscodecompletion.h
+++ /dev/null
@@ -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
diff --git a/src/plugins/qmljseditor/qmljscompletionassist.cpp b/src/plugins/qmljseditor/qmljscompletionassist.cpp
new file mode 100644
index 0000000000..6de4e82549
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljscompletionassist.cpp
@@ -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());
+}
diff --git a/src/plugins/qmljseditor/qmljscompletionassist.h b/src/plugins/qmljseditor/qmljscompletionassist.h
new file mode 100644
index 0000000000..3826f0507c
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljscompletionassist.h
@@ -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
diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp
index 65824f2329..a85e4b0e0f 100644
--- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp
+++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp
@@ -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)
+
+QList<QmlJSQuickFixOperation::Ptr> ComponentFromObjectDef::match(
+ const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface)
{
- const int pos = state.currentFile().cursor().position();
+ const int pos = interface->currentFile().cursor().position();
- QList<Node *> path = state.semanticInfo().astPath(pos);
+ 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));
}
}
}
diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h
index ccab5b05e2..0467621246 100644
--- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h
+++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h
@@ -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
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index 41f9646955..017ae2b80c 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -35,12 +35,13 @@
#include "qmljseditorconstants.h"
#include "qmljshighlighter.h"
#include "qmljseditorplugin.h"
-#include "qmljsquickfix.h"
#include "qmloutlinemodel.h"
#include "qmljsfindreferences.h"
#include "qmljssemantichighlighter.h"
#include "qmljsindenter.h"
#include "qmljsautocompleter.h"
+#include "qmljscompletionassist.h"
+#include "qmljsquickfixassist.h"
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljsevaluate.h>
@@ -70,6 +71,8 @@
#include <texteditor/syntaxhighlighter.h>
#include <texteditor/refactoroverlay.h>
#include <texteditor/tooltip/tooltip.h>
+#include <texteditor/codeassist/genericproposal.h>
+#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <qmldesigner/qmldesignerconstants.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <utils/changeset.h>
@@ -78,6 +81,7 @@
#include <QtCore/QFileInfo>
#include <QtCore/QSignalMapper>
#include <QtCore/QTimer>
+#include <QtCore/QScopedPointer>
#include <QtGui/QMenu>
#include <QtGui/QComboBox>
@@ -1347,20 +1351,29 @@ void QmlJSTextEditorWidget::contextMenuEvent(QContextMenuEvent *e)
connect(a, SIGNAL(triggered()), this, SLOT(renameIdUnderCursor()));
}
- // Add other refactoring actions:
- QmlJSQuickFixCollector *quickFixCollector = QmlJSEditorPlugin::instance()->quickFixCollector();
QSignalMapper mapper;
connect(&mapper, SIGNAL(mapped(int)), this, SLOT(performQuickFix(int)));
-
if (! isOutdated()) {
- if (quickFixCollector->startCompletion(editor()) != -1) {
- m_quickFixes = quickFixCollector->quickFixes();
-
- for (int index = 0; index < m_quickFixes.size(); ++index) {
- TextEditor::QuickFixOperation::Ptr op = m_quickFixes.at(index);
- QAction *action = refactoringMenu->addAction(op->description());
- mapper.setMapping(action, index);
- connect(action, SIGNAL(triggered()), &mapper, SLOT(map()));
+ TextEditor::IAssistInterface *interface =
+ createAssistInterface(TextEditor::QuickFix, TextEditor::ExplicitlyInvoked);
+ if (interface) {
+ QScopedPointer<TextEditor::IAssistProcessor> processor(
+ QmlJSEditorPlugin::instance()->quickFixAssistProvider()->createProcessor());
+ QScopedPointer<TextEditor::IAssistProposal> proposal(processor->perform(interface));
+ if (!proposal.isNull()) {
+ TextEditor::BasicProposalItemListModel *model =
+ static_cast<TextEditor::BasicProposalItemListModel *>(proposal->model());
+ for (int index = 0; index < model->size(); ++index) {
+ TextEditor::BasicProposalItem *item =
+ static_cast<TextEditor::BasicProposalItem *>(model->proposalItem(index));
+ TextEditor::QuickFixOperation::Ptr op =
+ item->data().value<TextEditor::QuickFixOperation::Ptr>();
+ m_quickFixes.append(op);
+ QAction *action = refactoringMenu->addAction(op->description());
+ mapper.setMapping(action, index);
+ connect(action, SIGNAL(triggered()), &mapper, SLOT(map()));
+ }
+ delete model;
}
}
}
@@ -1380,7 +1393,6 @@ void QmlJSTextEditorWidget::contextMenuEvent(QContextMenuEvent *e)
menu->exec(e->globalPos());
menu->deleteLater();
- quickFixCollector->cleanup();
m_quickFixes.clear();
}
@@ -1578,3 +1590,19 @@ SemanticHighlighterSource QmlJSTextEditorWidget::currentSource(bool force)
source.force = force;
return source;
}
+
+TextEditor::IAssistInterface *QmlJSTextEditorWidget::createAssistInterface(
+ TextEditor::AssistKind assistKind,
+ TextEditor::AssistReason reason) const
+{
+ if (assistKind == TextEditor::Completion) {
+ return new QmlJSCompletionAssistInterface(document(),
+ position(),
+ editor()->file(),
+ reason,
+ m_semanticInfo);
+ } else if (assistKind == TextEditor::QuickFix) {
+ return new QmlJSQuickFixAssistInterface(const_cast<QmlJSTextEditorWidget *>(this), reason);
+ }
+ return 0;
+}
diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h
index 6eb3bc15db..dabe5bf295 100644
--- a/src/plugins/qmljseditor/qmljseditor.h
+++ b/src/plugins/qmljseditor/qmljseditor.h
@@ -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();
diff --git a/src/plugins/qmljseditor/qmljseditor.pro b/src/plugins/qmljseditor/qmljseditor.pro
index 6d08513810..b52dcfc679 100644
--- a/src/plugins/qmljseditor/qmljseditor.pro
+++ b/src/plugins/qmljseditor/qmljseditor.pro
@@ -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
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp
index 3aebceee46..e18c8e6e4e 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.cpp
+++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp
@@ -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)
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.h b/src/plugins/qmljseditor/qmljseditorplugin.h
index 5451ab3155..18f43d2333 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.h
+++ b/src/plugins/qmljseditor/qmljseditorplugin.h
@@ -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;
};
diff --git a/src/plugins/qmljseditor/qmljshoverhandler.h b/src/plugins/qmljseditor/qmljshoverhandler.h
index 1146ae3cb4..b0a411fa55 100644
--- a/src/plugins/qmljseditor/qmljshoverhandler.h
+++ b/src/plugins/qmljseditor/qmljshoverhandler.h
@@ -56,8 +56,6 @@ class QmlJSTextEditorWidget;
namespace Internal {
-class SemanticInfo;
-
class HoverHandler : public TextEditor::BaseHoverHandler
{
Q_OBJECT
diff --git a/src/plugins/qmljseditor/qmljsquickfix.cpp b/src/plugins/qmljseditor/qmljsquickfix.cpp
index 3e8115d2f1..f00a0eddd1 100644
--- a/src/plugins/qmljseditor/qmljsquickfix.cpp
+++ b/src/plugins/qmljseditor/qmljsquickfix.cpp
@@ -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;
-}
diff --git a/src/plugins/qmljseditor/qmljsquickfix.h b/src/plugins/qmljseditor/qmljsquickfix.h
index ca5dd5ce51..7529814829 100644
--- a/src/plugins/qmljseditor/qmljsquickfix.h
+++ b/src/plugins/qmljseditor/qmljsquickfix.h
@@ -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
diff --git a/src/plugins/qmljseditor/qmljsquickfixassist.cpp b/src/plugins/qmljseditor/qmljsquickfixassist.cpp
new file mode 100644
index 0000000000..99a60eaa68
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljsquickfixassist.cpp
@@ -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;
+}
diff --git a/src/plugins/qmljseditor/qmljsquickfixassist.h b/src/plugins/qmljseditor/qmljsquickfixassist.h
new file mode 100644
index 0000000000..3427cb1b41
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljsquickfixassist.h
@@ -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
diff --git a/src/plugins/qmljseditor/qmljsquickfixes.cpp b/src/plugins/qmljseditor/qmljsquickfixes.cpp
index 9650617e8b..54c6820c3c 100644
--- a/src/plugins/qmljseditor/qmljsquickfixes.cpp
+++ b/src/plugins/qmljseditor/qmljsquickfixes.cpp
@@ -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);
diff --git a/src/plugins/qmljseditor/qmljsreuse.cpp b/src/plugins/qmljseditor/qmljsreuse.cpp
new file mode 100644
index 0000000000..a60b0f4f56
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljsreuse.cpp
@@ -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
diff --git a/src/plugins/qmljseditor/qmljsreuse.h b/src/plugins/qmljseditor/qmljsreuse.h
new file mode 100644
index 0000000000..0b5cf1f9e8
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljsreuse.h
@@ -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
diff --git a/src/plugins/qt4projectmanager/profilecompletion.cpp b/src/plugins/qt4projectmanager/profilecompletion.cpp
deleted file mode 100644
index c8015c78a2..0000000000
--- a/src/plugins/qt4projectmanager/profilecompletion.cpp
+++ /dev/null
@@ -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()
-{
-}
diff --git a/src/plugins/qt4projectmanager/profilecompletion.h b/src/plugins/qt4projectmanager/profilecompletion.h
deleted file mode 100644
index 47f6646b0d..0000000000
--- a/src/plugins/qt4projectmanager/profilecompletion.h
+++ /dev/null
@@ -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
diff --git a/src/plugins/qt4projectmanager/profilecompletionassist.cpp b/src/plugins/qt4projectmanager/profilecompletionassist.cpp
new file mode 100644
index 0000000000..2d6b25fb01
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profilecompletionassist.cpp
@@ -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;
+}
diff --git a/src/plugins/qt4projectmanager/profilecompletionassist.h b/src/plugins/qt4projectmanager/profilecompletionassist.h
new file mode 100644
index 0000000000..0569a57281
--- /dev/null
+++ b/src/plugins/qt4projectmanager/profilecompletionassist.h
@@ -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
diff --git a/src/plugins/qt4projectmanager/profileeditorfactory.cpp b/src/plugins/qt4projectmanager/profileeditorfactory.cpp
index 00052b1d8e..95fc5aa40a 100644
--- a/src/plugins/qt4projectmanager/profileeditorfactory.cpp
+++ b/src/plugins/qt4projectmanager/profileeditorfactory.cpp
@@ -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>
diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.pro b/src/plugins/qt4projectmanager/qt4projectmanager.pro
index 436f4500e1..86da78e4bb 100644
--- a/src/plugins/qt4projectmanager/qt4projectmanager.pro
+++ b/src/plugins/qt4projectmanager/qt4projectmanager.pro
@@ -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 \
diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
index feb220c2d7..c75d409c97 100644
--- a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
+++ b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
@@ -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;
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp
index f4dc040e2a..211c7a8d98 100644
--- a/src/plugins/texteditor/basetexteditor.cpp
+++ b/src/plugins/texteditor/basetexteditor.cpp
@@ -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);
+}
diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h
index 083cbceae3..dd8e141a04 100644
--- a/src/plugins/texteditor/basetexteditor.h
+++ b/src/plugins/texteditor/basetexteditor.h
@@ -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
diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h
index d5d05061c4..189e587424 100644
--- a/src/plugins/texteditor/basetexteditor_p.h
+++ b/src/plugins/texteditor/basetexteditor_p.h
@@ -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;
diff --git a/src/plugins/texteditor/codeassist/assistenums.h b/src/plugins/texteditor/codeassist/assistenums.h
new file mode 100644
index 0000000000..5bfd760eea
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/assistenums.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/basicproposalitem.cpp b/src/plugins/texteditor/codeassist/basicproposalitem.cpp
new file mode 100644
index 0000000000..f1d0045f19
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/basicproposalitem.cpp
@@ -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();
+}
diff --git a/src/plugins/texteditor/codeassist/basicproposalitem.h b/src/plugins/texteditor/codeassist/basicproposalitem.h
new file mode 100644
index 0000000000..4478fb8fb2
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/basicproposalitem.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/basicproposalitemlistmodel.cpp b/src/plugins/texteditor/codeassist/basicproposalitemlistmodel.cpp
new file mode 100644
index 0000000000..ae34da69f6
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/basicproposalitemlistmodel.cpp
@@ -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());
+}
diff --git a/src/plugins/texteditor/codeassist/basicproposalitemlistmodel.h b/src/plugins/texteditor/codeassist/basicproposalitemlistmodel.h
new file mode 100644
index 0000000000..482279a9a2
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/basicproposalitemlistmodel.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp
new file mode 100644
index 0000000000..e59b6e426e
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/codeassistant.cpp
@@ -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"
diff --git a/src/plugins/cppeditor/cppquickfixcollector.h b/src/plugins/texteditor/codeassist/codeassistant.h
index 1e45088595..ec7eb00f9a 100644
--- a/src/plugins/cppeditor/cppquickfixcollector.h
+++ b/src/plugins/texteditor/codeassist/codeassistant.h
@@ -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();
+
+ void configure(BaseTextEditor *textEditor);
- virtual bool supportsEditor(TextEditor::ITextEditor *editor) const;
- virtual TextEditor::QuickFixState *initializeCompletion(TextEditor::BaseTextEditorWidget *editor);
+ void process();
+ void notifyChange();
+ bool hasContext() const;
+ void destroyContext();
- virtual QList<TextEditor::QuickFixFactory *> quickFixFactories() const;
+ void invoke(AssistKind assistKind, IAssistProvider *provider = 0);
- /// Registers all quick-fixes in this plug-in as auto-released objects.
- static void registerQuickFixes(ExtensionSystem::IPlugin *plugIn);
+private:
+ QScopedPointer<CodeAssistantPrivate> m_d;
};
-} // namespace Internal
-} // namespace CppEditor
+} //TextEditor
-#endif // QUICKFIXCOLLECTOR_H
+#endif // CODEASSISTANT_H
diff --git a/src/plugins/texteditor/codeassist/completionassistprovider.cpp b/src/plugins/texteditor/codeassist/completionassistprovider.cpp
new file mode 100644
index 0000000000..d9d0e9ab48
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/completionassistprovider.cpp
@@ -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('_');
+}
diff --git a/src/plugins/texteditor/codeassist/completionassistprovider.h b/src/plugins/texteditor/codeassist/completionassistprovider.h
new file mode 100644
index 0000000000..9b51dce606
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/completionassistprovider.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/defaultassistinterface.cpp b/src/plugins/texteditor/codeassist/defaultassistinterface.cpp
new file mode 100644
index 0000000000..1bd9f46a50
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/defaultassistinterface.cpp
@@ -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;
+}
diff --git a/src/plugins/texteditor/codeassist/defaultassistinterface.h b/src/plugins/texteditor/codeassist/defaultassistinterface.h
new file mode 100644
index 0000000000..af4bfe1d60
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/defaultassistinterface.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/functionhintproposal.cpp b/src/plugins/texteditor/codeassist/functionhintproposal.cpp
new file mode 100644
index 0000000000..66e095bff5
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/functionhintproposal.cpp
@@ -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;
+}
diff --git a/src/plugins/texteditor/codeassist/functionhintproposal.h b/src/plugins/texteditor/codeassist/functionhintproposal.h
new file mode 100644
index 0000000000..950ac81e05
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/functionhintproposal.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/functionhintproposalwidget.cpp b/src/plugins/texteditor/codeassist/functionhintproposalwidget.cpp
new file mode 100644
index 0000000000..5dcde3de40
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/functionhintproposalwidget.cpp
@@ -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
diff --git a/src/plugins/texteditor/codeassist/functionhintproposalwidget.h b/src/plugins/texteditor/codeassist/functionhintproposalwidget.h
new file mode 100644
index 0000000000..bd60293d1b
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/functionhintproposalwidget.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/genericproposal.cpp b/src/plugins/texteditor/codeassist/genericproposal.cpp
new file mode 100644
index 0000000000..f652aa408e
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/genericproposal.cpp
@@ -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;
+}
diff --git a/src/plugins/texteditor/codeassist/genericproposal.h b/src/plugins/texteditor/codeassist/genericproposal.h
new file mode 100644
index 0000000000..682350e36f
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/genericproposal.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.
+**
+**************************************************************************/
+
+#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
diff --git a/src/plugins/texteditor/codeassist/genericproposalwidget.cpp b/src/plugins/texteditor/codeassist/genericproposalwidget.cpp
new file mode 100644
index 0000000000..96ec69c848
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/genericproposalwidget.cpp
@@ -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
diff --git a/src/plugins/texteditor/codeassist/genericproposalwidget.h b/src/plugins/texteditor/codeassist/genericproposalwidget.h
new file mode 100644
index 0000000000..a765d413dc
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/genericproposalwidget.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/iassistinterface.cpp b/src/plugins/texteditor/codeassist/iassistinterface.cpp
new file mode 100644
index 0000000000..0fa73257ca
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistinterface.cpp
@@ -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.
+*/
diff --git a/src/plugins/texteditor/codeassist/iassistinterface.h b/src/plugins/texteditor/codeassist/iassistinterface.h
new file mode 100644
index 0000000000..49ab63605b
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistinterface.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/iassistprocessor.cpp b/src/plugins/texteditor/codeassist/iassistprocessor.cpp
new file mode 100644
index 0000000000..fff1c7ff7a
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistprocessor.cpp
@@ -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()
+*/
diff --git a/src/plugins/texteditor/codeassist/iassistprocessor.h b/src/plugins/texteditor/codeassist/iassistprocessor.h
new file mode 100644
index 0000000000..43cbb4e7ff
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistprocessor.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/iassistproposal.cpp b/src/plugins/texteditor/codeassist/iassistproposal.cpp
new file mode 100644
index 0000000000..ba7a2fd514
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistproposal.cpp
@@ -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.
+*/
diff --git a/src/plugins/texteditor/codeassist/iassistproposal.h b/src/plugins/texteditor/codeassist/iassistproposal.h
new file mode 100644
index 0000000000..efacbc4abb
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistproposal.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/iassistproposalitem.cpp b/src/plugins/texteditor/codeassist/iassistproposalitem.cpp
new file mode 100644
index 0000000000..33d09d4c01
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistproposalitem.cpp
@@ -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.
+*/
diff --git a/src/plugins/texteditor/codeassist/iassistproposalitem.h b/src/plugins/texteditor/codeassist/iassistproposalitem.h
new file mode 100644
index 0000000000..319a934463
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistproposalitem.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/iassistproposalmodel.cpp b/src/plugins/texteditor/codeassist/iassistproposalmodel.cpp
new file mode 100644
index 0000000000..6222d5695e
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistproposalmodel.cpp
@@ -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()
+{}
diff --git a/src/plugins/texteditor/codeassist/iassistproposalmodel.h b/src/plugins/texteditor/codeassist/iassistproposalmodel.h
new file mode 100644
index 0000000000..e017f8da97
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistproposalmodel.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/iassistproposalwidget.cpp b/src/plugins/texteditor/codeassist/iassistproposalwidget.cpp
new file mode 100644
index 0000000000..9c7cfef193
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistproposalwidget.cpp
@@ -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.
+*/
diff --git a/src/plugins/texteditor/codeassist/iassistproposalwidget.h b/src/plugins/texteditor/codeassist/iassistproposalwidget.h
new file mode 100644
index 0000000000..1a9d866363
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistproposalwidget.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/iassistprovider.cpp b/src/plugins/texteditor/codeassist/iassistprovider.cpp
new file mode 100644
index 0000000000..4e4cc8dccd
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/iassistprovider.cpp
@@ -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.
+*/
diff --git a/src/plugins/texteditor/completionsupport.h b/src/plugins/texteditor/codeassist/iassistprovider.h
index c4787ba04e..88d04c6486 100644
--- a/src/plugins/texteditor/completionsupport.h
+++ b/src/plugins/texteditor/codeassist/iassistprovider.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.cpp b/src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.cpp
new file mode 100644
index 0000000000..1f0a9ab2d7
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.cpp
@@ -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()
+{}
diff --git a/src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.h b/src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.h
new file mode 100644
index 0000000000..b56fadf0d1
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/igenericproposalmodel.cpp b/src/plugins/texteditor/codeassist/igenericproposalmodel.cpp
new file mode 100644
index 0000000000..5bf0bfcf08
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/igenericproposalmodel.cpp
@@ -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()
+{}
diff --git a/src/plugins/texteditor/codeassist/igenericproposalmodel.h b/src/plugins/texteditor/codeassist/igenericproposalmodel.h
new file mode 100644
index 0000000000..a6f6699728
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/igenericproposalmodel.h
@@ -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
diff --git a/src/plugins/texteditor/codeassist/quickfixassistprocessor.cpp b/src/plugins/texteditor/codeassist/quickfixassistprocessor.cpp
new file mode 100644
index 0000000000..83618d243a
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/quickfixassistprocessor.cpp
@@ -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;
+}
diff --git a/src/plugins/texteditor/codeassist/quickfixassistprocessor.h b/src/plugins/texteditor/codeassist/quickfixassistprocessor.h
new file mode 100644
index 0000000000..c855907d86
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/quickfixassistprocessor.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.
+**
+**************************************************************************/
+
+#ifndef QUICKFIXASSISTPROCESSOR_H
+#define QUICKFIXASSISTPROCESSOR_H
+
+#include "iassistprocessor.h"
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT QuickFixAssistProcessor : public IAssistProcessor
+{
+public:
+ QuickFixAssistProcessor();
+ virtual ~QuickFixAssistProcessor();
+
+ virtual const IAssistProvider *provider() const = 0;
+ virtual IAssistProposal *perform(const IAssistInterface *interface);
+};
+
+} // TextEditor
+
+#endif // QUICKFIXASSISTPROCESSOR_H
diff --git a/src/plugins/texteditor/codeassist/quickfixassistprovider.cpp b/src/plugins/texteditor/codeassist/quickfixassistprovider.cpp
new file mode 100644
index 0000000000..d87b51e882
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/quickfixassistprovider.cpp
@@ -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.
+**
+**************************************************************************/
+
+#include "quickfixassistprovider.h"
+
+using namespace TextEditor;
+
+QuickFixAssistProvider::QuickFixAssistProvider()
+{}
+
+QuickFixAssistProvider::~QuickFixAssistProvider()
+{}
+
+QList<QuickFixFactory *> QuickFixAssistProvider::quickFixFactories() const
+{
+ return QList<QuickFixFactory *>();
+}
diff --git a/src/plugins/texteditor/codeassist/quickfixassistprovider.h b/src/plugins/texteditor/codeassist/quickfixassistprovider.h
new file mode 100644
index 0000000000..3e16fc6b19
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/quickfixassistprovider.h
@@ -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 QUICKFIXASSISTPROVIDER_H
+#define QUICKFIXASSISTPROVIDER_H
+
+#include "iassistprovider.h"
+
+#include <QtCore/QList>
+
+namespace TextEditor {
+
+class QuickFixFactory;
+
+class TEXTEDITOR_EXPORT QuickFixAssistProvider : public IAssistProvider
+{
+ Q_OBJECT
+
+public:
+ QuickFixAssistProvider();
+ virtual ~QuickFixAssistProvider();
+
+ virtual QList<QuickFixFactory *> quickFixFactories() const;
+};
+
+} // TextEditor
+
+#endif // QUICKFIXASSISTPROVIDER_H
diff --git a/src/plugins/texteditor/codeassist/runner.cpp b/src/plugins/texteditor/codeassist/runner.cpp
new file mode 100644
index 0000000000..a6afedcc16
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/runner.cpp
@@ -0,0 +1,88 @@
+/**************************************************************************
+**
+** 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 "runner.h"
+#include "iassistprocessor.h"
+#include "iassistproposal.h"
+#include "iassistinterface.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+ProcessorRunner::ProcessorRunner()
+ : m_processor(0)
+ , m_interface(0)
+ , m_discardProposal(false)
+ , m_proposal(0)
+{}
+
+ProcessorRunner::~ProcessorRunner()
+{
+ delete m_processor;
+ if (m_discardProposal)
+ delete m_proposal;
+}
+
+void ProcessorRunner::setProcessor(IAssistProcessor *computer)
+{
+ m_processor = computer;
+}
+
+void ProcessorRunner::run()
+{
+ m_proposal = m_processor->perform(m_interface);
+}
+
+IAssistProposal *ProcessorRunner::proposal() const
+{
+ return m_proposal;
+}
+
+void ProcessorRunner::setReason(AssistReason reason)
+{
+ m_reason = reason;
+}
+
+AssistReason ProcessorRunner::reason() const
+{
+ return m_reason;
+}
+
+void ProcessorRunner::setDiscardProposal(bool discard)
+{
+ m_discardProposal = discard;
+}
+
+void ProcessorRunner::setAssistInterface(IAssistInterface *interface)
+{
+ m_interface = interface;
+}
diff --git a/src/plugins/texteditor/codeassist/runner.h b/src/plugins/texteditor/codeassist/runner.h
new file mode 100644
index 0000000000..175733639f
--- /dev/null
+++ b/src/plugins/texteditor/codeassist/runner.h
@@ -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 PROCESSORRUNNER_H
+#define PROCESSORRUNNER_H
+
+#include "iassistproposalwidget.h"
+
+#include <QtCore/QThread>
+
+namespace TextEditor {
+
+class IAssistProcessor;
+class IAssistProposal;
+class IAssistInterface;
+
+namespace Internal {
+
+class ProcessorRunner : public QThread
+{
+ Q_OBJECT
+
+public:
+ ProcessorRunner();
+ virtual ~ProcessorRunner();
+
+ void setProcessor(IAssistProcessor *processor); // Takes ownership of the processor.
+ void setAssistInterface(IAssistInterface *interface);
+ void setDiscardProposal(bool discard);
+
+ // @TODO: Not really necessary...
+ void setReason(AssistReason reason);
+ AssistReason reason() const;
+
+ virtual void run();
+
+ IAssistProposal *proposal() const;
+
+private:
+ IAssistProcessor *m_processor;
+ IAssistInterface *m_interface;
+ bool m_discardProposal;
+ IAssistProposal *m_proposal;
+ AssistReason m_reason;
+};
+
+} // Internal
+} // TextEditor
+
+#endif // PROCESSORRUNNER_H
diff --git a/src/plugins/texteditor/completionsettings.h b/src/plugins/texteditor/completionsettings.h
index c72d5eb842..16c2d03a71 100644
--- a/src/plugins/texteditor/completionsettings.h
+++ b/src/plugins/texteditor/completionsettings.h
@@ -48,9 +48,9 @@ enum CaseSensitivity {
};
enum CompletionTrigger {
- ManualCompletion,
- TriggeredCompletion,
- AutomaticCompletion
+ ManualCompletion, // Display proposal only when explicitly invoked by the user.
+ TriggeredCompletion, // When triggered by the user or upon contextual activation characters.
+ AutomaticCompletion // The above plus an automatic trigger when the editor is "idle".
};
/**
diff --git a/src/plugins/texteditor/completionsupport.cpp b/src/plugins/texteditor/completionsupport.cpp
deleted file mode 100644
index fa33e0ea35..0000000000
--- a/src/plugins/texteditor/completionsupport.cpp
+++ /dev/null
@@ -1,243 +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 "completionsupport.h"
-#include "completionwidget.h"
-#include "icompletioncollector.h"
-
-#include <coreplugin/icore.h>
-#include <extensionsystem/pluginmanager.h>
-#include <texteditor/itexteditor.h>
-#include <texteditor/completionsettings.h>
-#include <utils/qtcassert.h>
-
-#include <QtCore/QString>
-#include <QtCore/QList>
-
-namespace TextEditor {
-
-CompletionSupport *CompletionSupport::instance()
-{
- static CompletionSupport *m_instance = 0;
- if (!m_instance)
- m_instance = new CompletionSupport;
- return m_instance;
-}
-
-class CompletionSupportPrivate : public QObject
-{
- Q_OBJECT
-
-public:
- explicit CompletionSupportPrivate(CompletionSupport *support);
-
-private slots:
- void performCompletion(const TextEditor::CompletionItem &item);
- void cleanupCompletions();
-
-public:
- QList<CompletionItem> getCompletions() const;
- void complete(ITextEditor *editor, CompletionPolicy policy, bool forced);
-
- CompletionSupport *m_support;
- Internal::CompletionWidget *m_completionList;
- int m_startPosition;
- bool m_checkCompletionTrigger; // Whether to check for completion trigger after cleanup
- ITextEditor *m_editor;
- const QList<ICompletionCollector *> m_completionCollectors;
- ICompletionCollector *m_completionCollector;
- CompletionPolicy m_policy;
-};
-
-CompletionSupportPrivate::CompletionSupportPrivate(CompletionSupport *support) :
- m_support(support),
- m_completionList(0),
- m_startPosition(0),
- m_checkCompletionTrigger(false),
- m_editor(0),
- m_completionCollectors(ExtensionSystem::PluginManager::instance()
- ->getObjects<ICompletionCollector>()),
- m_completionCollector(0),
- m_policy(SemanticCompletion)
-{
-}
-
-QList<CompletionItem> CompletionSupportPrivate::getCompletions() const
-{
- if (m_completionCollector)
- return m_completionCollector->getCompletions();
- return QList<CompletionItem>();
-}
-
-
-CompletionSupport::CompletionSupport()
- : QObject(Core::ICore::instance()),
- d(new CompletionSupportPrivate(this))
-{
-}
-
-CompletionSupport::~CompletionSupport()
-{
-}
-
-void CompletionSupportPrivate::performCompletion(const CompletionItem &item)
-{
- item.collector->complete(item, m_completionList->typedChar());
- m_checkCompletionTrigger = true;
-}
-
-void CompletionSupportPrivate::cleanupCompletions()
-{
- if (m_completionList)
- disconnect(m_completionList, SIGNAL(destroyed(QObject*)),
- this, SLOT(cleanupCompletions()));
-
- if (m_checkCompletionTrigger)
- m_checkCompletionTrigger = m_completionCollector->shouldRestartCompletion();
-
- m_completionList = 0;
- m_completionCollector->cleanup();
-
- if (m_checkCompletionTrigger) {
- m_checkCompletionTrigger = false;
-
- // Only check for completion trigger when some text was entered
- if (m_editor->position() > m_startPosition)
- complete(m_editor, m_policy, false);
- }
-}
-
-bool CompletionSupport::isActive() const
-{
- return d->m_completionList != 0;
-}
-
-CompletionPolicy CompletionSupport::policy() const
-{
- return d->m_policy;
-}
-
-void CompletionSupport::complete(ITextEditor *editor, CompletionPolicy policy, bool forced)
-{
- d->complete(editor, policy, forced);
-}
-
-void CompletionSupportPrivate::complete(ITextEditor *editor, CompletionPolicy policy, bool forced)
-{
- m_completionCollector = 0;
-
- foreach (ICompletionCollector *collector, m_completionCollectors) {
- QTC_ASSERT(collector, continue);
- if (collector->supportsEditor(editor)
- && collector->supportsPolicy(policy)) {
- m_policy = policy;
- m_completionCollector = collector;
- break;
- }
- }
-
- if (!m_completionCollector)
- return;
-
- m_editor = editor;
- QList<CompletionItem> completionItems;
-
- int currentIndex = 0;
-
- if (!m_completionList) {
- if (!forced) {
- const CompletionSettings &completionSettings = m_completionCollector->completionSettings();
- if (completionSettings.m_completionTrigger == ManualCompletion)
- return;
- if (!m_completionCollector->triggersCompletion(editor))
- return;
- }
-
- m_startPosition = m_completionCollector->startCompletion(editor);
- completionItems = getCompletions();
-
- QTC_ASSERT(!(m_startPosition == -1 && completionItems.size() > 0), return);
-
- if (completionItems.isEmpty()) {
- cleanupCompletions();
- return;
- }
-
- m_completionList = new Internal::CompletionWidget(m_support, editor);
-
- connect(m_completionList, SIGNAL(itemSelected(TextEditor::CompletionItem)),
- this, SLOT(performCompletion(TextEditor::CompletionItem)));
- connect(m_completionList, SIGNAL(completionListClosed()),
- this, SLOT(cleanupCompletions()));
-
- // Make sure to clean up the completions if the list is destroyed without
- // emitting completionListClosed (can happen when no focus out event is received,
- // for example when switching applications on the Mac)
- connect(m_completionList, SIGNAL(destroyed(QObject*)),
- this, SLOT(cleanupCompletions()));
- } else {
- completionItems = getCompletions();
-
- if (completionItems.isEmpty()) {
- m_completionList->closeList();
- return;
- }
-
- if (m_completionList->explicitlySelected()) {
- const int originalIndex = m_completionList->currentCompletionItem().originalIndex;
-
- for (int index = 0; index < completionItems.size(); ++index) {
- if (completionItems.at(index).originalIndex == originalIndex) {
- currentIndex = index;
- break;
- }
- }
- }
- }
-
- m_completionList->setCompletionItems(completionItems);
-
- if (currentIndex)
- m_completionList->setCurrentIndex(currentIndex);
-
- // Partially complete when completion was forced
- if (forced && m_completionCollector->partiallyComplete(completionItems)) {
- m_checkCompletionTrigger = true;
- m_completionList->closeList();
- } else {
- m_completionList->showCompletions(m_startPosition);
- }
-}
-
-} // namespace TextEditor
-
-#include "completionsupport.moc"
diff --git a/src/plugins/texteditor/completionwidget.cpp b/src/plugins/texteditor/completionwidget.cpp
deleted file mode 100644
index 3b82d61010..0000000000
--- a/src/plugins/texteditor/completionwidget.cpp
+++ /dev/null
@@ -1,499 +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 "completionwidget.h"
-#include "completionsupport.h"
-#include "icompletioncollector.h"
-
-#include <texteditor/itexteditor.h>
-
-#include <utils/faketooltip.h>
-#include <utils/qtcassert.h>
-
-#include <QtCore/QEvent>
-#include <QtGui/QApplication>
-#include <QtGui/QDesktopWidget>
-#include <QtGui/QKeyEvent>
-#include <QtGui/QVBoxLayout>
-#include <QtGui/QScrollBar>
-#include <QtGui/QLabel>
-#include <QtGui/QStylePainter>
-#include <QtGui/QToolTip>
-
-#include <limits.h>
-
-using namespace TextEditor;
-using namespace TextEditor::Internal;
-
-#define NUMBER_OF_VISIBLE_ITEMS 10
-
-namespace TextEditor {
-namespace Internal {
-
-class AutoCompletionModel : public QAbstractListModel
-{
-public:
- AutoCompletionModel(QObject *parent);
-
- inline const CompletionItem &itemAt(const QModelIndex &index) const
- { return m_items.at(index.row()); }
-
- void setItems(const QList<CompletionItem> &items);
-
- int rowCount(const QModelIndex &parent = QModelIndex()) const;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-
-private:
- QList<CompletionItem> m_items;
-};
-
-
-class CompletionInfoFrame : public Utils::FakeToolTip
-{
-public:
- CompletionInfoFrame(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;
-};
-
-
-} // namespace Internal
-} // namespace TextEditor
-
-
-AutoCompletionModel::AutoCompletionModel(QObject *parent)
- : QAbstractListModel(parent)
-{
-}
-
-void AutoCompletionModel::setItems(const QList<CompletionItem> &items)
-{
- m_items = items;
- reset();
-}
-
-int AutoCompletionModel::rowCount(const QModelIndex &) const
-{
- return m_items.count();
-}
-
-QVariant AutoCompletionModel::data(const QModelIndex &index, int role) const
-{
- if (index.row() >= m_items.count())
- return QVariant();
-
- if (role == Qt::DisplayRole) {
- return itemAt(index).text;
- } else if (role == Qt::DecorationRole) {
- return itemAt(index).icon;
- } else if (role == Qt::WhatsThisRole) {
- return itemAt(index).details;
- }
-
- return QVariant();
-}
-
-
-CompletionWidget::CompletionWidget(CompletionSupport *support,
- ITextEditor *editor)
- : QFrame(0, Qt::Popup),
- m_support(support),
- m_editor(editor),
- m_completionListView(new CompletionListView(support, editor, this))
-{
- // We disable the frame on this list view and use a QFrame around it instead.
- // This improves the look with QGTKStyle.
-#ifndef Q_WS_MAC
- setFrameStyle(m_completionListView->frameStyle());
-#endif
- m_completionListView->setFrameStyle(QFrame::NoFrame);
-
- setObjectName(QLatin1String("m_popupFrame"));
- setAttribute(Qt::WA_DeleteOnClose);
- setMinimumSize(1, 1);
- setFont(editor->widget()->font());
-
- QVBoxLayout *layout = new QVBoxLayout(this);
- layout->setMargin(0);
-
- layout->addWidget(m_completionListView);
- setFocusProxy(m_completionListView);
-
- connect(m_completionListView, SIGNAL(itemSelected(TextEditor::CompletionItem)),
- this, SIGNAL(itemSelected(TextEditor::CompletionItem)));
- connect(m_completionListView, SIGNAL(completionListClosed()),
- this, SIGNAL(completionListClosed()));
- connect(m_completionListView, SIGNAL(activated(QModelIndex)),
- SLOT(closeList(QModelIndex)));
- connect(editor, SIGNAL(contentsChangedBecauseOfUndo()),
- this, SLOT(closeList()));
-}
-
-CompletionWidget::~CompletionWidget()
-{
-}
-
-void CompletionWidget::setCompletionItems(const QList<TextEditor::CompletionItem> &completionitems)
-{
- m_completionListView->setCompletionItems(completionitems);
-}
-
-void CompletionWidget::closeList(const QModelIndex &index)
-{
- m_completionListView->closeList(index);
- close();
-}
-
-void CompletionWidget::showCompletions(int startPos)
-{
- ensurePolished();
- updatePositionAndSize(startPos);
- show();
- setFocus();
-}
-
-QChar CompletionWidget::typedChar() const
-{
- return m_completionListView->m_typedChar;
-}
-
-CompletionItem CompletionWidget::currentCompletionItem() const
-{
- return m_completionListView->currentCompletionItem();
-}
-
-bool CompletionWidget::explicitlySelected() const
-{
- return m_completionListView->explicitlySelected();
-}
-
-void CompletionWidget::setCurrentIndex(int index)
-{
- m_completionListView->setCurrentIndex(m_completionListView->model()->index(index, 0));
-}
-
-void CompletionWidget::updatePositionAndSize(int startPos)
-{
- // Determine size by calculating the space of the visible items
- QAbstractItemModel *model = m_completionListView->model();
- int visibleItems = model->rowCount();
- if (visibleItems > NUMBER_OF_VISIBLE_ITEMS)
- visibleItems = NUMBER_OF_VISIBLE_ITEMS;
-
- const QStyleOptionViewItem &option = m_completionListView->viewOptions();
-
- QSize shint;
- for (int i = 0; i < visibleItems; ++i) {
- QSize tmp = m_completionListView->itemDelegate()->sizeHint(option, model->index(i, 0));
- if (shint.width() < tmp.width())
- shint = tmp;
- }
-
- const int fw = frameWidth();
- const int width = shint.width() + fw * 2 + 30;
- const int height = shint.height() * visibleItems + fw * 2;
-
- // Determine the position, keeping the popup on the screen
- const QRect cursorRect = m_editor->cursorRect(startPos);
- const QDesktopWidget *desktop = QApplication::desktop();
-
- QWidget *editorWidget = m_editor->widget();
-
-#ifdef Q_WS_MAC
- const QRect screen = desktop->availableGeometry(desktop->screenNumber(editorWidget));
-#else
- const QRect screen = desktop->screenGeometry(desktop->screenNumber(editorWidget));
-#endif
-
- QPoint pos = cursorRect.bottomLeft();
- pos.rx() -= 16 + fw; // Space for the icons
-
- if (pos.y() + height > screen.bottom())
- pos.setY(cursorRect.top() - height);
-
- if (pos.x() + width > screen.right())
- pos.setX(screen.right() - width);
-
- setGeometry(pos.x(), pos.y(), width, height);
-}
-
-CompletionListView::CompletionListView(CompletionSupport *support,
- ITextEditor *editor, CompletionWidget *completionWidget)
- : QListView(completionWidget),
- m_blockFocusOut(false),
- m_editor(editor),
- m_editorWidget(editor->widget()),
- m_completionWidget(completionWidget),
- m_model(new AutoCompletionModel(this)),
- m_support(support),
- m_explicitlySelected(false)
-{
- QTC_ASSERT(m_editorWidget, return);
-
- m_infoTimer.setInterval(1000);
- m_infoTimer.setSingleShot(true);
- connect(&m_infoTimer, SIGNAL(timeout()), SLOT(maybeShowInfoTip()));
-
- setAttribute(Qt::WA_MacShowFocusRect, false);
- setUniformItemSizes(true);
- setSelectionBehavior(QAbstractItemView::SelectItems);
- setSelectionMode(QAbstractItemView::SingleSelection);
- setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- setMinimumSize(1, 1);
- setModel(m_model);
-#ifdef Q_WS_MAC
- if (horizontalScrollBar())
- horizontalScrollBar()->setAttribute(Qt::WA_MacMiniSize);
- if (verticalScrollBar())
- verticalScrollBar()->setAttribute(Qt::WA_MacMiniSize);
-#endif
-}
-
-CompletionListView::~CompletionListView()
-{
-}
-
-CompletionItem CompletionListView::currentCompletionItem() const
-{
- int row = currentIndex().row();
- if (row >= 0 && row < m_model->rowCount())
- return m_model->itemAt(currentIndex());
-
- return CompletionItem();
-}
-
-bool CompletionListView::explicitlySelected() const
-{
- return m_explicitlySelected;
-}
-
-void CompletionListView::maybeShowInfoTip()
-{
- QModelIndex current = currentIndex();
- if (!current.isValid())
- return;
- 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 CompletionInfoFrame(this);
-
-
- QRect r = rectForIndex(current);
- m_infoFrame->move(
- (parentWidget()->mapToGlobal(
- parentWidget()->rect().topRight())).x() + 3,
- mapToGlobal(r.topRight()).y() - verticalOffset()
- );
- m_infoFrame->setText(infoTip);
- m_infoFrame->adjustSize();
- m_infoFrame->show();
- m_infoFrame->raise();
-
- m_infoTimer.setInterval(0);
-}
-
-void CompletionListView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
-{
- QListView::currentChanged(current, previous);
- m_infoTimer.start();
-}
-
-
-bool CompletionListView::event(QEvent *e)
-{
- if (m_blockFocusOut)
- return QListView::event(e);
-
- bool forwardKeys = true;
- if (e->type() == QEvent::FocusOut) {
- QModelIndex index;
-#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.
- index = currentIndex();
- }
-#endif
- m_completionWidget->closeList(index);
- if (m_infoFrame)
- 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:
- // select next/previous completion
- if (ke->modifiers() == Qt::ControlModifier)
- {
- e->accept();
- int change = (ke->key() == Qt::Key_N) ? 1 : -1;
- int nrows = model()->rowCount();
- int row = currentIndex().row();
- int newRow = (row + change + nrows) % nrows;
- if (newRow == row + change || !ke->isAutoRepeat())
- setCurrentIndex(m_model->index(newRow));
- return true;
- }
- }
- } else if (e->type() == QEvent::KeyPress) {
- QKeyEvent *ke = static_cast<QKeyEvent *>(e);
- switch (ke->key()) {
- case Qt::Key_N:
- case Qt::Key_P:
- // select next/previous completion - so don't pass on to editor
- if (ke->modifiers() == Qt::ControlModifier)
- forwardKeys = false;
- break;
-
- case Qt::Key_Escape:
- m_completionWidget->closeList();
- return true;
-
- case Qt::Key_Right:
- case Qt::Key_Left:
- case Qt::Key_Home:
- case Qt::Key_End:
- // We want these navigation keys to work in the editor, so forward them
- break;
-
- case Qt::Key_Tab:
- case Qt::Key_Return:
- //independently from style, accept current entry if return is pressed
- if (qApp->focusWidget() == this)
- m_completionWidget->closeList(currentIndex());
- return true;
-
- case Qt::Key_Up:
- m_explicitlySelected = true;
- if (!ke->isAutoRepeat()
- && currentIndex().row() == 0) {
- setCurrentIndex(model()->index(model()->rowCount()-1, 0));
- return true;
- }
- forwardKeys = false;
- break;
-
- case Qt::Key_Down:
- m_explicitlySelected = true;
- if (!ke->isAutoRepeat()
- && currentIndex().row() == model()->rowCount()-1) {
- setCurrentIndex(model()->index(0, 0));
- return true;
- }
- forwardKeys = false;
- break;
-
- case Qt::Key_Enter:
- case Qt::Key_PageDown:
- case Qt::Key_PageUp:
- forwardKeys = false;
- break;
-
- default:
- // if a key is forwarded, completion widget is re-opened and selected item is reset to first,
- // so only forward keys that insert text and refine the completed item
- forwardKeys = !ke->text().isEmpty();
- break;
- }
-
- const CompletionPolicy policy = m_support->policy();
- if (forwardKeys && policy != QuickFixCompletion) {
- if (ke->text().length() == 1 && currentIndex().isValid() && qApp->focusWidget() == this) {
- QChar typedChar = ke->text().at(0);
- const CompletionItem &item = m_model->itemAt(currentIndex());
- if (item.collector->typedCharCompletes(item, typedChar)) {
- m_typedChar = typedChar;
- m_completionWidget->closeList(currentIndex());
- return true;
- }
- }
-
- m_blockFocusOut = true;
- QApplication::sendEvent(m_editorWidget, e);
- m_blockFocusOut = false;
-
- // Have the completion support update the list of items
- m_support->complete(m_editor, policy, false);
-
- return true;
- }
- }
- return QListView::event(e);
-}
-
-void CompletionListView::keyboardSearch(const QString &search)
-{
- Q_UNUSED(search)
-}
-
-void CompletionListView::setCompletionItems(const QList<TextEditor::CompletionItem> &completionItems)
-{
- m_model->setItems(completionItems);
- setCurrentIndex(m_model->index(0)); // Select the first item
-}
-
-void CompletionListView::closeList(const QModelIndex &index)
-{
- m_blockFocusOut = true;
-
- if (index.isValid())
- emit itemSelected(m_model->itemAt(index));
-
- emit completionListClosed();
-
- m_blockFocusOut = false;
-}
diff --git a/src/plugins/texteditor/completionwidget.h b/src/plugins/texteditor/completionwidget.h
deleted file mode 100644
index 2cd7af27f5..0000000000
--- a/src/plugins/texteditor/completionwidget.h
+++ /dev/null
@@ -1,136 +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 COMPLETIONWIDGET_H
-#define COMPLETIONWIDGET_H
-
-#include <QtGui/QListView>
-#include <QtCore/QPointer>
-#include <QtCore/QTimer>
-
-namespace TextEditor {
-
-class CompletionItem;
-class ITextEditor;
-class CompletionSupport;
-
-namespace Internal {
-
-class AutoCompletionModel;
-class CompletionListView;
-class CompletionInfoFrame;
-
-/* The completion widget is responsible for showing a list of possible completions.
- It is only used by the CompletionSupport.
- */
-class CompletionWidget : public QFrame
-{
- Q_OBJECT
-
-public:
- CompletionWidget(CompletionSupport *support, ITextEditor *editor);
- ~CompletionWidget();
-
- void setCompletionItems(const QList<TextEditor::CompletionItem> &completionitems);
- void showCompletions(int startPos);
-
- QChar typedChar() const;
- CompletionItem currentCompletionItem() const;
-
- void setCurrentIndex(int index);
- bool explicitlySelected() const;
-
-signals:
- void itemSelected(const TextEditor::CompletionItem &item);
- void completionListClosed();
-
-public slots:
- void closeList(const QModelIndex &index = QModelIndex());
-
-private:
- void updatePositionAndSize(int startPos);
-
-private:
- CompletionSupport *m_support;
- ITextEditor *m_editor;
- CompletionListView *m_completionListView;
-};
-
-class CompletionListView : public QListView
-{
- Q_OBJECT
-
-public:
- ~CompletionListView();
-
- CompletionItem currentCompletionItem() const;
- bool explicitlySelected() const;
-
-signals:
- void itemSelected(const TextEditor::CompletionItem &item);
- void completionListClosed();
-
-protected:
- bool event(QEvent *e);
-
- void currentChanged(const QModelIndex &current, const QModelIndex &previous);
-
-private:
- friend class CompletionWidget;
-
- CompletionListView(CompletionSupport *support, ITextEditor *editor, CompletionWidget *completionWidget);
-
- void setCompletionItems(const QList<TextEditor::CompletionItem> &completionitems);
- void keyboardSearch(const QString &search);
- void closeList(const QModelIndex &index);
-
-private slots:
- void maybeShowInfoTip();
-
-private:
- bool m_blockFocusOut;
- ITextEditor *m_editor;
- QWidget *m_editorWidget;
- CompletionWidget *m_completionWidget;
- AutoCompletionModel *m_model;
- CompletionSupport *m_support;
- QPointer<CompletionInfoFrame> m_infoFrame;
- QTimer m_infoTimer;
- QChar m_typedChar;
- bool m_explicitlySelected;
-};
-
-} // namespace Internal
-} // namespace TextEditor
-
-#endif // COMPLETIONWIDGET_H
-
diff --git a/src/plugins/texteditor/convenience.cpp b/src/plugins/texteditor/convenience.cpp
new file mode 100644
index 0000000000..3facb9ef63
--- /dev/null
+++ b/src/plugins/texteditor/convenience.cpp
@@ -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.
+**
+**************************************************************************/
+
+#include "convenience.h"
+
+#include <QtGui/QTextDocument>
+#include <QtGui/QTextBlock>
+
+namespace TextEditor {
+namespace Convenience {
+
+bool convertPosition(const QTextDocument *document, int pos, int *line, int *column)
+{
+ QTextBlock block = document->findBlock(pos);
+ if (!block.isValid()) {
+ (*line) = -1;
+ (*column) = -1;
+ return false;
+ } else {
+ (*line) = block.blockNumber() + 1;
+ (*column) = pos - block.position();
+ return true;
+ }
+}
+
+QString textAt(QTextCursor tc, int pos, int length)
+{
+ if (pos < 0)
+ pos = 0;
+ tc.movePosition(QTextCursor::End);
+ if (pos + length > tc.position())
+ length = tc.position() - pos;
+
+ tc.setPosition(pos);
+ tc.setPosition(pos + length, QTextCursor::KeepAnchor);
+
+ return tc.selectedText();
+}
+
+} // Util
+} // TextEditor
diff --git a/src/plugins/texteditor/convenience.h b/src/plugins/texteditor/convenience.h
new file mode 100644
index 0000000000..e7ae14f57b
--- /dev/null
+++ b/src/plugins/texteditor/convenience.h
@@ -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 BASETEXTEDITORUTIL_H
+#define BASETEXTEDITORUTIL_H
+
+#include "texteditor_global.h"
+
+QT_BEGIN_NAMESPACE
+class QTextDocument;
+QT_END_NAMESPACE
+
+#include <QtCore/QString>
+#include <QtGui/QTextCursor>
+
+namespace TextEditor {
+namespace Convenience {
+
+TEXTEDITOR_EXPORT bool convertPosition(const QTextDocument *document,
+ int pos,
+ int *line, int *column);
+
+TEXTEDITOR_EXPORT QString textAt(QTextCursor tc, int pos, int length);
+
+} // Util
+} // TextEditor
+
+#endif // BASETEXTEDITORUTIL_H
diff --git a/src/plugins/texteditor/icompletioncollector.cpp b/src/plugins/texteditor/icompletioncollector.cpp
deleted file mode 100644
index 0d16966700..0000000000
--- a/src/plugins/texteditor/icompletioncollector.cpp
+++ /dev/null
@@ -1,218 +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 "icompletioncollector.h"
-
-#include "completionsettings.h"
-#include "itexteditor.h"
-
-#include <QtCore/QRegExp>
-#include <algorithm>
-
-using namespace TextEditor;
-using namespace TextEditor::Internal;
-
-namespace TextEditor {
-namespace Internal {
-
-class ICompletionCollectorPrivate
-{
-public:
- CompletionSettings m_completionSettings;
-};
-
-} // namespace Internal
-} // namespace TextEditor
-
-bool ICompletionCollector::compareChar(const QChar &l, const QChar &r)
-{
- if (l == QLatin1Char('_'))
- return false;
- else if (r == QLatin1Char('_'))
- return true;
- else
- return l < r;
-}
-
-bool ICompletionCollector::lessThan(const QString &l, const QString &r)
-{
- return std::lexicographical_compare(l.begin(), l.end(),
- r.begin(), r.end(),
- compareChar);
-}
-
-bool ICompletionCollector::completionItemLessThan(const CompletionItem &i1, const CompletionItem &i2)
-{
- // The order is case-insensitive in principle, but case-sensitive when this would otherwise mean equality
- const QString lower1 = i1.text.toLower();
- const QString lower2 = i2.text.toLower();
- if (lower1 == lower2)
- return lessThan(i1.text, i2.text);
- else
- return lessThan(lower1, lower2);
-}
-
-ICompletionCollector::ICompletionCollector(QObject *parent)
- : QObject(parent)
- , m_d(new Internal::ICompletionCollectorPrivate)
-{
-}
-
-ICompletionCollector::~ICompletionCollector()
-{
- delete m_d;
-}
-
-void ICompletionCollector::setCompletionSettings(const CompletionSettings &settings)
-{
- m_d->m_completionSettings = settings;
-}
-
-const CompletionSettings &ICompletionCollector::completionSettings() const
-{
- return m_d->m_completionSettings;
-}
-
-QList<CompletionItem> ICompletionCollector::getCompletions()
-{
- QList<CompletionItem> completionItems;
-
- completions(&completionItems);
-
- qStableSort(completionItems.begin(), completionItems.end(), completionItemLessThan);
-
- // Remove duplicates
- QString lastKey;
- QList<CompletionItem> uniquelist;
-
- foreach (const CompletionItem &item, completionItems) {
- if (item.text != lastKey) {
- uniquelist.append(item);
- lastKey = item.text;
- } else {
- uniquelist.last().duplicateCount++;
- }
- }
-
- return uniquelist;
-}
-
-bool ICompletionCollector::partiallyComplete(const QList<TextEditor::CompletionItem> &items)
-{
- if (! m_d->m_completionSettings.m_partiallyComplete)
- return false;
- if (items.size() >= 100)
- return false;
-
- QList<TextEditor::CompletionItem> completionItems = items;
- sortCompletion(completionItems);
-
- // Compute common prefix
- QString firstKey = completionItems.first().text;
- QString lastKey = completionItems.last().text;
- const int length = qMin(firstKey.length(), lastKey.length());
- firstKey.truncate(length);
- lastKey.truncate(length);
-
- while (firstKey != lastKey) {
- firstKey.chop(1);
- lastKey.chop(1);
- }
-
- if (ITextEditor *ed = editor()) {
- const int typedLength = ed->position() - startPosition();
- if (!firstKey.isEmpty() && firstKey.length() > typedLength) {
- ed->setCursorPosition(startPosition());
- ed->replace(typedLength, firstKey);
- }
- }
-
- return false;
-}
-
-void ICompletionCollector::sortCompletion(QList<TextEditor::CompletionItem> &completionItems)
-{
- qStableSort(completionItems.begin(), completionItems.end(),
- &ICompletionCollector::completionItemLessThan);
-}
-
-void ICompletionCollector::filter(const QList<TextEditor::CompletionItem> &items,
- QList<TextEditor::CompletionItem> *filteredItems,
- const QString &key)
-{
- const TextEditor::CaseSensitivity caseSensitivity = m_d->m_completionSettings.m_caseSensitivity;
-
- /*
- * 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.
- */
- QString keyRegExp;
- keyRegExp += QLatin1Char('^');
- bool first = true;
- const QLatin1String wordContinuation("[a-z0-9_]*");
- foreach (const QChar &c, key) {
- 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);
-
- foreach (const TextEditor::CompletionItem &item, items)
- if (regExp.indexIn(item.text) == 0)
- filteredItems->append(item);
-}
-
-bool ICompletionCollector::shouldRestartCompletion()
-{
- return true;
-}
diff --git a/src/plugins/texteditor/icompletioncollector.h b/src/plugins/texteditor/icompletioncollector.h
deleted file mode 100644
index 71bf1993ed..0000000000
--- a/src/plugins/texteditor/icompletioncollector.h
+++ /dev/null
@@ -1,204 +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 COMPLETIONCOLLECTORINTERFACE_H
-#define COMPLETIONCOLLECTORINTERFACE_H
-
-#include "texteditor_global.h"
-
-#include <QtCore/QObject>
-#include <QtCore/QVariant>
-#include <QtGui/QIcon>
-
-namespace TextEditor {
-
-namespace Internal {
-class ICompletionCollectorPrivate;
-}
-
-class ICompletionCollector;
-class ITextEditor;
-class CompletionSettings;
-
-enum CompletionPolicy
-{
- QuickFixCompletion, // Used for "Quick Fix" operation.
- TextCompletion, // Plain word completion.
- SemanticCompletion // Completion using code models.
-};
-
-class CompletionItem
-{
-public:
- CompletionItem(ICompletionCollector *collector = 0)
- : duplicateCount(0),
- order(0),
- originalIndex(0),
- collector(collector),
- isSnippet(false)
- { }
-
- bool isValid() const
- { return collector != 0; }
-
- QString text;
- QString details;
- QIcon icon;
- QVariant data;
- int duplicateCount;
- int order;
- int originalIndex;
- ICompletionCollector *collector;
- bool isSnippet;
-};
-
-/* Defines the interface to completion collectors. A completion collector tells
- * the completion support code when a completion is triggered and provides the
- * list of possible completions. It keeps an internal state so that it can be
- * polled for the list of completions, which is reset with a call to reset.
- */
-class TEXTEDITOR_EXPORT ICompletionCollector : public QObject
-{
- Q_OBJECT
-public:
- ICompletionCollector(QObject *parent = 0);
- virtual ~ICompletionCollector();
-
- const CompletionSettings &completionSettings() const;
-
- virtual QList<CompletionItem> getCompletions();
- virtual bool shouldRestartCompletion();
-
- /* Returns the current active ITextEditor */
- virtual ITextEditor *editor() const = 0;
- virtual int startPosition() const = 0;
-
- /*
- * Returns true if this completion collector can be used with the given editor.
- */
- virtual bool supportsEditor(ITextEditor *editor) const = 0;
-
- /*
- * Returns true if this completion collector supports the given completion policy.
- */
- virtual bool supportsPolicy(CompletionPolicy policy) const = 0;
-
- /* 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(ITextEditor *editor) = 0;
-
- // returns starting position
- virtual int startCompletion(ITextEditor *editor) = 0;
-
- /* This method should add all the completions it wants to show into the list,
- * based on the given cursor position.
- */
- virtual void completions(QList<CompletionItem> *completions) = 0;
-
- /**
- * This method should return true when the given typed character should cause
- * the selected completion item to be completed.
- */
- virtual bool typedCharCompletes(const CompletionItem &item, QChar typedChar) = 0;
-
- /**
- * 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 CompletionItem &item, QChar typedChar) = 0;
-
- /* 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 void sortCompletion(QList<TextEditor::CompletionItem> &completionItems);
-
- /* Called when it's safe to clean up the completion items.
- */
- virtual void cleanup() = 0;
-
- // helpers
-
- void filter(const QList<TextEditor::CompletionItem> &items,
- QList<TextEditor::CompletionItem> *filteredItems,
- const QString &key);
-
-public slots:
- void setCompletionSettings(const TextEditor::CompletionSettings &);
-
-protected:
- static bool compareChar(const QChar &item, const QChar &other);
- static bool lessThan(const QString &item, const QString &other);
- static bool completionItemLessThan(const CompletionItem &item, const CompletionItem &other);
-
-private:
- Internal::ICompletionCollectorPrivate *m_d;
-};
-
-class TEXTEDITOR_EXPORT IQuickFixCollector : public ICompletionCollector
-{
- Q_OBJECT
-
-public:
- IQuickFixCollector(QObject *parent = 0) : ICompletionCollector(parent) {}
- virtual ~IQuickFixCollector() {}
-
- virtual bool typedCharCompletes(const CompletionItem &, QChar)
- { return false; }
-
- virtual void fix(const TextEditor::CompletionItem &item) = 0;
-
- virtual void complete(const CompletionItem &item, QChar typedChar)
- {
- Q_UNUSED(typedChar)
- fix(item);
- }
-
- virtual bool triggersCompletion(TextEditor::ITextEditor *)
- { return false; }
-
- virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &)
- { return false; }
-};
-
-
-} // namespace TextEditor
-
-#endif // COMPLETIONCOLLECTORINTERFACE_H
diff --git a/src/plugins/texteditor/quickfix.cpp b/src/plugins/texteditor/quickfix.cpp
index 8db6ebb7e8..6ca695b5ea 100644
--- a/src/plugins/texteditor/quickfix.cpp
+++ b/src/plugins/texteditor/quickfix.cpp
@@ -31,32 +31,9 @@
**************************************************************************/
#include "quickfix.h"
-#include "basetexteditor.h"
-
-#include <coreplugin/ifile.h>
-#include <extensionsystem/pluginmanager.h>
-#include <QtGui/QApplication>
-#include <QtGui/QTextBlock>
-
-#include <QtCore/QDebug>
using namespace TextEditor;
-QuickFixState::QuickFixState(TextEditor::BaseTextEditorWidget *editor)
- : _editor(editor)
-{
-}
-
-QuickFixState::~QuickFixState()
-{
-}
-
-TextEditor::BaseTextEditorWidget *QuickFixState::editor() const
-{
- return _editor;
-}
-
-
QuickFixOperation::QuickFixOperation(int priority)
{
setPriority(priority);
@@ -86,8 +63,6 @@ void QuickFixOperation::setDescription(const QString &description)
_description = description;
}
-
-
QuickFixFactory::QuickFixFactory(QObject *parent)
: QObject(parent)
{
@@ -96,91 +71,3 @@ QuickFixFactory::QuickFixFactory(QObject *parent)
QuickFixFactory::~QuickFixFactory()
{
}
-
-QuickFixCollector::QuickFixCollector()
- : m_editor(0)
-{
-}
-
-QuickFixCollector::~QuickFixCollector()
-{
-}
-
-TextEditor::ITextEditor *QuickFixCollector::editor() const
-{
- return m_editor;
-}
-
-int QuickFixCollector::startPosition() const
-{
- return m_editor->position();
-}
-
-bool QuickFixCollector::triggersCompletion(TextEditor::ITextEditor *)
-{
- return false;
-}
-
-int QuickFixCollector::startCompletion(TextEditor::ITextEditor *editable)
-{
- Q_ASSERT(editable != 0);
-
- m_editor = editable;
- TextEditor::BaseTextEditorWidget *editor = qobject_cast<TextEditor::BaseTextEditorWidget *>(editable->widget());
- Q_ASSERT(editor != 0);
-
- if (TextEditor::QuickFixState *state = initializeCompletion(editor)) {
- QMap<int, QList<QuickFixOperation::Ptr> > matchedOps;
-
- foreach (QuickFixFactory *factory, quickFixFactories()) {
- QList<QuickFixOperation::Ptr> ops = factory->matchingOperations(state);
-
- foreach (QuickFixOperation::Ptr op, ops) {
- const int priority = op->priority();
- if (priority != -1)
- matchedOps[priority].append(op);
- }
- }
-
- QMapIterator<int, QList<TextEditor::QuickFixOperation::Ptr> > it(matchedOps);
- it.toBack();
- if (it.hasPrevious()) {
- it.previous();
- m_quickFixes = it.value();
- }
-
- delete state;
-
- if (! m_quickFixes.isEmpty())
- return editable->position();
- }
-
- return -1;
-}
-
-void QuickFixCollector::completions(QList<TextEditor::CompletionItem> *quickFixItems)
-{
- for (int i = 0; i < m_quickFixes.size(); ++i) {
- TextEditor::QuickFixOperation::Ptr op = m_quickFixes.at(i);
-
- TextEditor::CompletionItem item(this);
- item.text = op->description();
- item.data = QVariant::fromValue(i);
- quickFixItems->append(item);
- }
-}
-
-void QuickFixCollector::fix(const TextEditor::CompletionItem &item)
-{
- const int index = item.data.toInt();
-
- if (index < m_quickFixes.size()) {
- TextEditor::QuickFixOperation::Ptr quickFix = m_quickFixes.at(index);
- quickFix->perform();
- }
-}
-
-void QuickFixCollector::cleanup()
-{
- m_quickFixes.clear();
-}
diff --git a/src/plugins/texteditor/quickfix.h b/src/plugins/texteditor/quickfix.h
index 869c351891..dc97ef43c7 100644
--- a/src/plugins/texteditor/quickfix.h
+++ b/src/plugins/texteditor/quickfix.h
@@ -34,31 +34,14 @@
#define TEXTEDITORQUICKFIX_H
#include "texteditor_global.h"
-#include "icompletioncollector.h"
+#include <QtCore/QString>
+#include <QtCore/QMetaType>
#include <QtCore/QSharedPointer>
namespace TextEditor {
-class BaseTextEditorWidget;
-
-/*!
- State of the editor on which the QuickFixFactory and the QuickFixOperation work.
-
- This class contains a reference
- */
-class TEXTEDITOR_EXPORT QuickFixState
-{
-public:
- /// Creates a new state object for the given text editor.
- QuickFixState(TextEditor::BaseTextEditorWidget *editor);
- virtual ~QuickFixState();
-
- TextEditor::BaseTextEditorWidget *editor() const;
-
-private:
- TextEditor::BaseTextEditorWidget *_editor;
-};
+class IAssistInterface;
/*!
Class to perform a single quick-fix.
@@ -127,58 +110,14 @@ class TEXTEDITOR_EXPORT QuickFixFactory: public QObject
public:
QuickFixFactory(QObject *parent = 0);
- virtual ~QuickFixFactory() = 0;
+ virtual ~QuickFixFactory();
- /*!
- \returns A list of operations which can be performed for the given state.
- */
- virtual QList<QuickFixOperation::Ptr> matchingOperations(QuickFixState *state) = 0;
-};
-
-/*!
- A completion collector which will use the QuickFixFactory classes to generate
- quickfixes for the given editor.
-
- All QuickFixFactory instances returned by #quickFixFactories are queried for
- possible quick-fix operations. The operations(s) with the highest priority are
- stored, and can be queried by calling #quickFixes .
- */
-class TEXTEDITOR_EXPORT QuickFixCollector: public TextEditor::IQuickFixCollector
-{
- Q_OBJECT
-
-public:
- QuickFixCollector();
- virtual ~QuickFixCollector();
-
- QList<TextEditor::QuickFixOperation::Ptr> quickFixes() const
- { return m_quickFixes; }
-
- virtual TextEditor::ITextEditor *editor() const;
- virtual int startPosition() const;
- virtual bool triggersCompletion(TextEditor::ITextEditor *editor);
- virtual int startCompletion(TextEditor::ITextEditor *editor);
- virtual void completions(QList<TextEditor::CompletionItem> *completions);
-
- virtual bool supportsPolicy(TextEditor::CompletionPolicy policy) const
- { return policy == TextEditor::QuickFixCompletion; }
-
- /// See IQuickFixCollector::fix
- virtual void fix(const TextEditor::CompletionItem &item);
-
- /// See ICompletionCollector::cleanup .
- virtual void cleanup();
-
- /// Called from #startCompletion to create a QuickFixState .
- virtual TextEditor::QuickFixState *initializeCompletion(BaseTextEditorWidget *editable) = 0;
-
- virtual QList<QuickFixFactory *> quickFixFactories() const = 0;
-
-private:
- TextEditor::ITextEditor *m_editor;
- QList<QuickFixOperation::Ptr> m_quickFixes;
+ virtual QList<QuickFixOperation::Ptr>
+ matchingOperations(const QSharedPointer<const IAssistInterface> &interface) = 0;
};
} // namespace TextEditor
+Q_DECLARE_METATYPE(TextEditor::QuickFixOperation::Ptr)
+
#endif // TEXTEDITORQUICKFIX_H
diff --git a/src/plugins/texteditor/snippets/snippetcollector.cpp b/src/plugins/texteditor/snippets/snippetassistcollector.cpp
index d2ae70e4cc..b6a27e69ab 100644
--- a/src/plugins/texteditor/snippets/snippetcollector.cpp
+++ b/src/plugins/texteditor/snippets/snippetassistcollector.cpp
@@ -30,18 +30,18 @@
**
**************************************************************************/
-#include "snippetcollector.h"
+#include "snippetassistcollector.h"
#include "snippetscollection.h"
#include <texteditor/texteditorconstants.h>
+#include <texteditor/codeassist/basicproposalitem.h>
using namespace TextEditor;
using namespace Internal;
namespace {
-void appendSnippets(ICompletionCollector *collector,
- QList<CompletionItem> *completionItems,
+void appendSnippets(QList<BasicProposalItem *> *items,
const QString &groupId,
const QIcon &icon,
int order)
@@ -50,30 +50,32 @@ void appendSnippets(ICompletionCollector *collector,
const int size = collection->totalActiveSnippets(groupId);
for (int i = 0; i < size; ++i) {
const Snippet &snippet = collection->snippet(i, groupId);
- CompletionItem item(collector);
- item.text = snippet.trigger() + QLatin1Char(' ') + snippet.complement();
- item.data = snippet.content();
- item.details = snippet.generateTip();
- item.icon = icon;
- item.order = order;
- item.isSnippet = true;
- completionItems->append(item);
+ BasicProposalItem *item = new BasicProposalItem;
+ item->setText(snippet.trigger() + QLatin1Char(' ') + snippet.complement());
+ item->setData(snippet.content());
+ item->setDetail(snippet.generateTip());
+ item->setIcon(icon);
+ item->setOrder(order);
+ items->append(item);
}
}
} // anonymous
-SnippetCollector::SnippetCollector(const QString &groupId, const QIcon &icon, int order) :
- m_groupId(groupId), m_icon(icon), m_order(order)
+
+SnippetAssistCollector::SnippetAssistCollector(const QString &groupId, const QIcon &icon, int order)
+ : m_groupId(groupId)
+ , m_icon(icon)
+ , m_order(order)
{}
-SnippetCollector::~SnippetCollector()
+SnippetAssistCollector::~SnippetAssistCollector()
{}
-QList<CompletionItem> SnippetCollector::getSnippets(ICompletionCollector *collector) const
+QList<BasicProposalItem *> SnippetAssistCollector::collect() const
{
- QList<CompletionItem> completionItems;
- appendSnippets(collector, &completionItems, m_groupId, m_icon, m_order);
- appendSnippets(collector, &completionItems, Constants::TEXT_SNIPPET_GROUP_ID, m_icon, m_order);
- return completionItems;
+ QList<BasicProposalItem *> snippets;
+ appendSnippets(&snippets, m_groupId, m_icon, m_order);
+ appendSnippets(&snippets, Constants::TEXT_SNIPPET_GROUP_ID, m_icon, m_order);
+ return snippets;
}
diff --git a/src/plugins/texteditor/snippets/snippetcollector.h b/src/plugins/texteditor/snippets/snippetassistcollector.h
index f07d192a73..942ca9371f 100644
--- a/src/plugins/texteditor/snippets/snippetcollector.h
+++ b/src/plugins/texteditor/snippets/snippetassistcollector.h
@@ -30,11 +30,10 @@
**
**************************************************************************/
-#ifndef SNIPPETPROVIDER_H
-#define SNIPPETPROVIDER_H
+#ifndef SNIPPETASSISTCOLLECTOR_H
+#define SNIPPETASSISTCOLLECTOR_H
#include <texteditor/texteditor_global.h>
-#include <texteditor/icompletioncollector.h>
#include <QtCore/QString>
#include <QtCore/QList>
@@ -42,13 +41,15 @@
namespace TextEditor {
-class TEXTEDITOR_EXPORT SnippetCollector
+class BasicProposalItem;
+
+class TEXTEDITOR_EXPORT SnippetAssistCollector
{
public:
- SnippetCollector(const QString &groupId, const QIcon &icon, int order = 0);
- ~SnippetCollector();
+ SnippetAssistCollector(const QString &groupId, const QIcon &icon, int order = 0);
+ ~SnippetAssistCollector();
- QList<CompletionItem> getSnippets(ICompletionCollector *collector) const;
+ QList<BasicProposalItem *> collect() const;
private:
QString m_groupId;
@@ -58,4 +59,4 @@ private:
} // TextEditor
-#endif // SNIPPETPROVIDER_H
+#endif // SNIPPETASSISTCOLLECTOR_H
diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro
index 51558f8ed2..2056ae391e 100644
--- a/src/plugins/texteditor/texteditor.pro
+++ b/src/plugins/texteditor/texteditor.pro
@@ -6,7 +6,8 @@ include(../../qtcreatorplugin.pri)
include(texteditor_dependencies.pri)
INCLUDEPATH += generichighlighter \
tooltip \
- snippets
+ snippets \
+ codeassist
SOURCES += texteditorplugin.cpp \
textfilewizard.cpp \
plaintexteditor.cpp \
@@ -16,9 +17,6 @@ SOURCES += texteditorplugin.cpp \
behaviorsettings.cpp \
behaviorsettingspage.cpp \
texteditoractionhandler.cpp \
- icompletioncollector.cpp \
- completionsupport.cpp \
- completionwidget.cpp \
fontsettingspage.cpp \
tabsettings.cpp \
storagesettings.cpp \
@@ -76,10 +74,32 @@ SOURCES += texteditorplugin.cpp \
snippets/snippetscollection.cpp \
snippets/snippetssettings.cpp \
snippets/isnippetprovider.cpp \
- snippets/snippetcollector.cpp \
snippets/plaintextsnippetprovider.cpp \
behaviorsettingswidget.cpp \
- extraencodingsettings.cpp
+ extraencodingsettings.cpp \
+ codeassist/functionhintproposalwidget.cpp \
+ codeassist/ifunctionhintproposalmodel.cpp \
+ codeassist/functionhintproposal.cpp \
+ codeassist/iassistprovider.cpp \
+ codeassist/iassistproposal.cpp \
+ codeassist/iassistprocessor.cpp \
+ codeassist/iassistproposalwidget.cpp \
+ codeassist/codeassistant.cpp \
+ snippets/snippetassistcollector.cpp \
+ codeassist/iassistinterface.cpp \
+ codeassist/defaultassistinterface.cpp \
+ codeassist/iassistproposalitem.cpp \
+ convenience.cpp \
+ codeassist/runner.cpp \
+ codeassist/completionassistprovider.cpp \
+ codeassist/igenericproposalmodel.cpp \
+ codeassist/quickfixassistprovider.cpp \
+ codeassist/quickfixassistprocessor.cpp \
+ codeassist/genericproposal.cpp \
+ codeassist/genericproposalwidget.cpp \
+ codeassist/basicproposalitem.cpp \
+ codeassist/basicproposalitemlistmodel.cpp \
+ codeassist/iassistproposalmodel.cpp
HEADERS += texteditorplugin.h \
textfilewizard.h \
@@ -89,12 +109,9 @@ HEADERS += texteditorplugin.h \
basetextdocument.h \
behaviorsettings.h \
behaviorsettingspage.h \
- completionsupport.h \
- completionwidget.h \
basetexteditor.h \
texteditoractionhandler.h \
fontsettingspage.h \
- icompletioncollector.h \
texteditorconstants.h \
tabsettings.h \
storagesettings.h \
@@ -160,10 +177,33 @@ HEADERS += texteditorplugin.h \
snippets/reuse.h \
snippets/snippetssettings.h \
snippets/isnippetprovider.h \
- snippets/snippetcollector.h \
snippets/plaintextsnippetprovider.h \
behaviorsettingswidget.h \
- extraencodingsettings.h
+ extraencodingsettings.h \
+ codeassist/functionhintproposalwidget.h \
+ codeassist/ifunctionhintproposalmodel.h \
+ codeassist/functionhintproposal.h \
+ codeassist/iassistprovider.h \
+ codeassist/iassistprocessor.h \
+ codeassist/iassistproposalwidget.h \
+ codeassist/iassistproposal.h \
+ codeassist/codeassistant.h \
+ snippets/snippetassistcollector.h \
+ codeassist/iassistinterface.h \
+ codeassist/defaultassistinterface.h \
+ codeassist/iassistproposalitem.h \
+ convenience.h \
+ codeassist/assistenums.h \
+ codeassist/runner.h \
+ codeassist/completionassistprovider.h \
+ codeassist/igenericproposalmodel.h \
+ codeassist/quickfixassistprovider.h \
+ codeassist/quickfixassistprocessor.h \
+ codeassist/genericproposal.h \
+ codeassist/genericproposalwidget.h \
+ codeassist/basicproposalitem.h \
+ codeassist/basicproposalitemlistmodel.h \
+ codeassist/iassistproposalmodel.h
FORMS += \
displaysettingspage.ui \
diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp
index a3b9ef8cc1..b4388e7d03 100644
--- a/src/plugins/texteditor/texteditorplugin.cpp
+++ b/src/plugins/texteditor/texteditorplugin.cpp
@@ -32,7 +32,6 @@
#include "texteditorplugin.h"
-#include "completionsupport.h"
#include "findinfiles.h"
#include "findincurrentfile.h"
#include "fontsettings.h"
@@ -46,6 +45,7 @@
#include "manager.h"
#include "outlinefactory.h"
#include "snippets/plaintextsnippetprovider.h"
+#include "codeassist/assistenums.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
@@ -215,17 +215,15 @@ void TextEditorPlugin::initializeEditor(PlainTextEditorWidget *editor)
void TextEditorPlugin::invokeCompletion()
{
Core::IEditor *iface = Core::EditorManager::instance()->currentEditor();
- ITextEditor *editor = qobject_cast<ITextEditor *>(iface);
- if (editor)
- CompletionSupport::instance()->complete(editor, SemanticCompletion, true);
+ if (BaseTextEditorWidget *w = qobject_cast<BaseTextEditorWidget *>(iface->widget()))
+ w->invokeAssist(Completion);
}
void TextEditorPlugin::invokeQuickFix()
{
Core::IEditor *iface = Core::EditorManager::instance()->currentEditor();
- ITextEditor *editor = qobject_cast<ITextEditor *>(iface);
- if (editor)
- CompletionSupport::instance()->complete(editor, QuickFixCompletion, true);
+ if (BaseTextEditorWidget *w = qobject_cast<BaseTextEditorWidget *>(iface->widget()))
+ w->invokeAssist(QuickFix);
}
void TextEditorPlugin::updateSearchResultsFont(const FontSettings &settings)