OSDN Git Service

New code assist API
authorLeandro Melo <leandro.melo@nokia.com>
Fri, 15 Apr 2011 14:19:23 +0000 (16:19 +0200)
committerLeandro Melo <leandro.melo@nokia.com>
Wed, 18 May 2011 08:46:20 +0000 (10:46 +0200)
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).

119 files changed:
src/plugins/cppeditor/cppcompleteswitch.cpp
src/plugins/cppeditor/cppcompleteswitch.h
src/plugins/cppeditor/cppeditor.cpp
src/plugins/cppeditor/cppeditor.h
src/plugins/cppeditor/cppeditor.pro
src/plugins/cppeditor/cppinsertdecldef.cpp
src/plugins/cppeditor/cppinsertdecldef.h
src/plugins/cppeditor/cppinsertqtpropertymembers.cpp
src/plugins/cppeditor/cppinsertqtpropertymembers.h
src/plugins/cppeditor/cppplugin.cpp
src/plugins/cppeditor/cppplugin.h
src/plugins/cppeditor/cppquickfix.cpp
src/plugins/cppeditor/cppquickfix.h
src/plugins/cppeditor/cppquickfixassistant.cpp [new file with mode: 0644]
src/plugins/cppeditor/cppquickfixassistant.h [new file with mode: 0644]
src/plugins/cppeditor/cppquickfixcollector.cpp [deleted file]
src/plugins/cppeditor/cppquickfixes.cpp
src/plugins/cpptools/cppcodecompletion.h [deleted file]
src/plugins/cpptools/cppcompletionassist.cpp [moved from src/plugins/cpptools/cppcodecompletion.cpp with 55% similarity]
src/plugins/cpptools/cppcompletionassist.h [new file with mode: 0644]
src/plugins/cpptools/cpptools.pro
src/plugins/cpptools/cpptoolsplugin.cpp
src/plugins/fakevim/fakevimplugin.cpp
src/plugins/glsleditor/glslcodecompletion.cpp [deleted file]
src/plugins/glsleditor/glslcodecompletion.h [deleted file]
src/plugins/glsleditor/glslcompletionassist.cpp [new file with mode: 0644]
src/plugins/glsleditor/glslcompletionassist.h [new file with mode: 0644]
src/plugins/glsleditor/glsleditor.cpp
src/plugins/glsleditor/glsleditor.h
src/plugins/glsleditor/glsleditor.pro
src/plugins/glsleditor/glsleditorplugin.cpp
src/plugins/glsleditor/reuse.cpp [new file with mode: 0644]
src/plugins/glsleditor/reuse.h [new file with mode: 0644]
src/plugins/qmljseditor/qmljscodecompletion.cpp [deleted file]
src/plugins/qmljseditor/qmljscodecompletion.h [deleted file]
src/plugins/qmljseditor/qmljscompletionassist.cpp [new file with mode: 0644]
src/plugins/qmljseditor/qmljscompletionassist.h [new file with mode: 0644]
src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp
src/plugins/qmljseditor/qmljscomponentfromobjectdef.h
src/plugins/qmljseditor/qmljseditor.cpp
src/plugins/qmljseditor/qmljseditor.h
src/plugins/qmljseditor/qmljseditor.pro
src/plugins/qmljseditor/qmljseditorplugin.cpp
src/plugins/qmljseditor/qmljseditorplugin.h
src/plugins/qmljseditor/qmljshoverhandler.h
src/plugins/qmljseditor/qmljsquickfix.cpp
src/plugins/qmljseditor/qmljsquickfix.h
src/plugins/qmljseditor/qmljsquickfixassist.cpp [new file with mode: 0644]
src/plugins/qmljseditor/qmljsquickfixassist.h [new file with mode: 0644]
src/plugins/qmljseditor/qmljsquickfixes.cpp
src/plugins/qmljseditor/qmljsreuse.cpp [new file with mode: 0644]
src/plugins/qmljseditor/qmljsreuse.h [new file with mode: 0644]
src/plugins/qt4projectmanager/profilecompletion.cpp [deleted file]
src/plugins/qt4projectmanager/profilecompletion.h [deleted file]
src/plugins/qt4projectmanager/profilecompletionassist.cpp [new file with mode: 0644]
src/plugins/qt4projectmanager/profilecompletionassist.h [new file with mode: 0644]
src/plugins/qt4projectmanager/profileeditorfactory.cpp
src/plugins/qt4projectmanager/qt4projectmanager.pro
src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
src/plugins/texteditor/basetexteditor.cpp
src/plugins/texteditor/basetexteditor.h
src/plugins/texteditor/basetexteditor_p.h
src/plugins/texteditor/codeassist/assistenums.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/basicproposalitem.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/basicproposalitem.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/basicproposalitemlistmodel.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/basicproposalitemlistmodel.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/codeassistant.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/codeassistant.h [moved from src/plugins/cppeditor/cppquickfixcollector.h with 62% similarity]
src/plugins/texteditor/codeassist/completionassistprovider.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/completionassistprovider.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/defaultassistinterface.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/defaultassistinterface.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/functionhintproposal.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/functionhintproposal.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/functionhintproposalwidget.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/functionhintproposalwidget.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/genericproposal.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/genericproposal.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/genericproposalwidget.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/genericproposalwidget.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistinterface.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistinterface.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistprocessor.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistprocessor.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistproposal.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistproposal.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistproposalitem.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistproposalitem.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistproposalmodel.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistproposalmodel.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistproposalwidget.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistproposalwidget.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistprovider.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/iassistprovider.h [moved from src/plugins/texteditor/completionsupport.h with 64% similarity]
src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/ifunctionhintproposalmodel.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/igenericproposalmodel.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/igenericproposalmodel.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/quickfixassistprocessor.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/quickfixassistprocessor.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/quickfixassistprovider.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/quickfixassistprovider.h [new file with mode: 0644]
src/plugins/texteditor/codeassist/runner.cpp [new file with mode: 0644]
src/plugins/texteditor/codeassist/runner.h [new file with mode: 0644]
src/plugins/texteditor/completionsettings.h
src/plugins/texteditor/completionsupport.cpp [deleted file]
src/plugins/texteditor/completionwidget.cpp [deleted file]
src/plugins/texteditor/completionwidget.h [deleted file]
src/plugins/texteditor/convenience.cpp [new file with mode: 0644]
src/plugins/texteditor/convenience.h [new file with mode: 0644]
src/plugins/texteditor/icompletioncollector.cpp [deleted file]
src/plugins/texteditor/icompletioncollector.h [deleted file]
src/plugins/texteditor/quickfix.cpp
src/plugins/texteditor/quickfix.h
src/plugins/texteditor/snippets/snippetassistcollector.cpp [moved from src/plugins/texteditor/snippets/snippetcollector.cpp with 64% similarity]
src/plugins/texteditor/snippets/snippetassistcollector.h [moved from src/plugins/texteditor/snippets/snippetcollector.h with 81% similarity]
src/plugins/texteditor/texteditor.pro
src/plugins/texteditor/texteditorplugin.cpp

index 62222ac..05ec2c4 100644 (file)
@@ -31,6 +31,7 @@
 **************************************************************************/
 
 #include "cppcompleteswitch.h"
+#include "cppquickfixassistant.h"
 
 #include <cplusplus/Overview.h>
 #include <cplusplus/TypeOfExpression.h>
@@ -102,8 +103,11 @@ public:
 class Operation: public CppQuickFixOperation
 {
 public:
-    Operation(const CppQuickFixState &state, int priority, CompoundStatementAST *compoundStatement, const QStringList &values)
-        : CppQuickFixOperation(state, priority)
+    Operation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
+              int priority,
+              CompoundStatementAST *compoundStatement,
+              const QStringList &values)
+        : CppQuickFixOperation(interface, priority)
         , compoundStatement(compoundStatement)
         , values(values)
     {
@@ -150,15 +154,15 @@ static Enum *findEnum(const QList<LookupItem> &results,
     return 0;
 }
 
-static Enum *conditionEnum(const CppQuickFixState &state,
+static Enum *conditionEnum(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
                            SwitchStatementAST *statement)
 {
     Block *block = statement->symbol;
-    Scope *scope = state.document()->scopeAt(block->line(), block->column());
+    Scope *scope = interface->semanticInfo().doc->scopeAt(block->line(), block->column());
     TypeOfExpression typeOfExpression;
-    typeOfExpression.init(state.document(), state.snapshot());
+    typeOfExpression.init(interface->semanticInfo().doc, interface->snapshot());
     const QList<LookupItem> results = typeOfExpression(statement->condition,
-                                                       state.document(),
+                                                       interface->semanticInfo().doc,
                                                        scope);
 
     return findEnum(results, typeOfExpression.context());
@@ -166,9 +170,10 @@ static Enum *conditionEnum(const CppQuickFixState &state,
 
 } // end of anonymous namespace
 
-QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(const CppQuickFixState &state)
+QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(
+    const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
 {
-    const QList<AST *> &path = state.path();
+    const QList<AST *> &path = interface->path();
 
     if (path.isEmpty())
         return noResult(); // nothing to do
@@ -178,13 +183,13 @@ QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(const CppQui
         AST *ast = path.at(depth);
         SwitchStatementAST *switchStatement = ast->asSwitchStatement();
         if (switchStatement) {
-            if (!state.isCursorOn(switchStatement->switch_token) || !switchStatement->statement)
+            if (!interface->isCursorOn(switchStatement->switch_token) || !switchStatement->statement)
                 return noResult();
             CompoundStatementAST *compoundStatement = switchStatement->statement->asCompoundStatement();
             if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;"
                 return noResult();
             // look if the condition's type is an enum
-            if (Enum *e = conditionEnum(state, switchStatement)) {
+            if (Enum *e = conditionEnum(interface, switchStatement)) {
                 // check the possible enum values
                 QStringList values;
                 Overview prettyPrint;
@@ -195,8 +200,8 @@ QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(const CppQui
                 }
                 // Get the used values
                 Block *block = switchStatement->symbol;
-                CaseStatementCollector caseValues(state.document(), state.snapshot(),
-                                                  state.document()->scopeAt(block->line(), block->column()));
+                CaseStatementCollector caseValues(interface->semanticInfo().doc, interface->snapshot(),
+                                                  interface->semanticInfo().doc->scopeAt(block->line(), block->column()));
                 QStringList usedValues = caseValues(switchStatement);
                 // save the values that would be added
                 foreach (const QString &usedValue, usedValues)
@@ -204,7 +209,7 @@ QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(const CppQui
                 if (values.isEmpty())
                     return noResult();
                 else
-                    return singleResult(new Operation(state, depth, compoundStatement, values));
+                    return singleResult(new Operation(interface, depth, compoundStatement, values));
             }
 
             return noResult();
index f1d9c9b..b0cd42c 100644 (file)
@@ -46,7 +46,8 @@ namespace Internal {
 class CompleteSwitchCaseStatement: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state);
+    virtual QList<CppQuickFixOperation::Ptr> match(
+        const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface);
 };
 
 } // namespace Internal
index 354d4ce..0e63fff 100644 (file)
 #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"
index 9250ba1..7ac1eee 100644 (file)
 #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);
 
index 95abbbd..0431b33 100644 (file)
@@ -14,7 +14,6 @@ HEADERS += cppplugin.h \
     cppeditorenums.h \
     cppeditor_global.h \
     cppclasswizard.h \
-    cppquickfix.h \
     cppchecksymbols.h \
     cppsemanticinfo.h \
     cppoutline.h \
@@ -22,12 +21,13 @@ HEADERS += cppplugin.h \
     cpplocalsymbols.h \
     cpptypehierarchy.h \
     cppelementevaluator.h \
-    cppquickfixcollector.h \
     cppqtstyleindenter.h \
     cppautocompleter.h \
     cppcompleteswitch.h \
     cppsnippetprovider.h \
-    cppinsertqtpropertymembers.h
+    cppinsertqtpropertymembers.h \
+    cppquickfixassistant.h \
+    cppquickfix.h
 
 SOURCES += cppplugin.cpp \
     cppeditor.cpp \
@@ -35,7 +35,6 @@ SOURCES += cppplugin.cpp \
     cpphoverhandler.cpp \
     cppfilewizard.cpp \
     cppclasswizard.cpp \
-    cppquickfix.cpp \
     cppquickfixes.cpp \
     cppchecksymbols.cpp \
     cppsemanticinfo.cpp \
@@ -44,12 +43,13 @@ SOURCES += cppplugin.cpp \
     cpplocalsymbols.cpp \
     cpptypehierarchy.cpp \
     cppelementevaluator.cpp \
-    cppquickfixcollector.cpp \
     cppqtstyleindenter.cpp \
     cppautocompleter.cpp \
     cppcompleteswitch.cpp \
     cppsnippetprovider.cpp \
-    cppinsertqtpropertymembers.cpp
+    cppinsertqtpropertymembers.cpp \
+    cppquickfixassistant.cpp \
+    cppquickfix.cpp
 
 RESOURCES += cppeditor.qrc
 OTHER_FILES += CppEditor.mimetypes.xml
index 10032a9..019af89 100644 (file)
@@ -31,6 +31,7 @@
 **************************************************************************/
 
 #include "cppinsertdecldef.h"
+#include "cppquickfixassistant.h"
 
 #include <CPlusPlus.h>
 #include <cplusplus/ASTPath.h>
@@ -53,11 +54,12 @@ namespace {
 class InsertDeclOperation: public CppQuickFixOperation
 {
 public:
-    InsertDeclOperation(const CppQuickFixState &state, int priority,
+    InsertDeclOperation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
+                        int priority,
                         const QString &targetFileName, const Class *targetSymbol,
                         InsertionPointLocator::AccessSpec xsSpec,
                         const QString &decl)
-        : CppQuickFixOperation(state, priority)
+        : CppQuickFixOperation(interface, priority)
         , m_targetFileName(targetFileName)
         , m_targetSymbol(targetSymbol)
         , m_xsSpec(xsSpec)
@@ -108,10 +110,11 @@ private:
 
 } // anonymous namespace
 
-QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &state)
+QList<CppQuickFixOperation::Ptr> DeclFromDef::match(
+    const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
 {
-    const QList<AST *> &path = state.path();
-    const CppRefactoringFile &file = state.currentFile();
+    const QList<AST *> &path = interface->path();
+    const CppRefactoringFile &file = interface->currentFile();
 
     FunctionDefinitionAST *funDef = 0;
     int idx = 0;
@@ -158,7 +161,7 @@ QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &stat
     if (!q->base())
         return noResult();
 
-    if (ClassOrNamespace *binding = state.context().lookupType(q->base(), enclosingScope)) {
+    if (ClassOrNamespace *binding = interface->context().lookupType(q->base(), enclosingScope)) {
         foreach (Symbol *s, binding->symbols()) {
             if (Class *matchingClass = s->asClass()) {
                 for (Symbol *s = matchingClass->find(q->identifier()); s; s = s->next()) {
@@ -177,11 +180,11 @@ QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &stat
 
                 const QString fn = QString::fromUtf8(matchingClass->fileName(),
                                                      matchingClass->fileNameLength());
-                const QString decl = generateDeclaration(state,
+                const QString decl = generateDeclaration(interface,
                                                          method,
                                                          binding);
                 return singleResult(
-                            new InsertDeclOperation(state, idx, fn, matchingClass,
+                            new InsertDeclOperation(interface, idx, fn, matchingClass,
                                                     InsertionPointLocator::Public,
                                                     decl));
             }
@@ -191,7 +194,7 @@ QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &stat
     return noResult();
 }
 
-QString DeclFromDef::generateDeclaration(const CppQuickFixState &,
+QString DeclFromDef::generateDeclaration(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &,
                                          Function *method,
                                          ClassOrNamespace *targetBinding)
 {
@@ -214,9 +217,9 @@ namespace {
 class InsertDefOperation: public CppQuickFixOperation
 {
 public:
-    InsertDefOperation(const CppQuickFixState &state, int priority,
+    InsertDefOperation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface, int priority,
                        Declaration *decl, const InsertionLocation &loc)
-        : CppQuickFixOperation(state, priority)
+        : CppQuickFixOperation(interface, priority)
         , m_decl(decl)
         , m_loc(loc)
     {
@@ -241,12 +244,12 @@ public:
 
         //--
         SubstitutionEnvironment env;
-        env.setContext(state().context());
+        env.setContext(assistInterface()->context());
         env.switchScope(m_decl->enclosingScope());
         UseQualifiedNames q;
         env.enter(&q);
 
-        Control *control = state().context().control().data();
+        Control *control = assistInterface()->context().control().data();
         FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control);
         QString name = oo(LookupContext::fullyQualifiedName(m_decl));
         //--
@@ -274,10 +277,11 @@ private:
 
 } // anonymous namespace
 
-QList<CppQuickFixOperation::Ptr> DefFromDecl::match(const CppQuickFixState &state)
+QList<CppQuickFixOperation::Ptr> DefFromDecl::match(
+    const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
 {
-    const QList<AST *> &path = state.path();
-    const CppRefactoringFile &file = state.currentFile();
+    const QList<AST *> &path = interface->path();
+    const CppRefactoringFile &file = interface->currentFile();
 
     int idx = path.size() - 1;
     for (; idx >= 0; --idx) {
@@ -292,12 +296,12 @@ QList<CppQuickFixOperation::Ptr> DefFromDecl::match(const CppQuickFixState &stat
                                 && decl->enclosingScope()->isClass()) {
                             DeclaratorAST *declarator = simpleDecl->declarator_list->value;
                             if (file.isCursorOn(declarator->core_declarator)) {
-                                CppRefactoringChanges refactoring(state.snapshot());
+                                CppRefactoringChanges refactoring(interface->snapshot());
                                 InsertionPointLocator locator(&refactoring);
                                 QList<CppQuickFixOperation::Ptr> results;
                                 foreach (const InsertionLocation &loc, locator.methodDefinition(decl)) {
                                     if (loc.isValid())
-                                        results.append(CppQuickFixOperation::Ptr(new InsertDefOperation(state, idx, decl, loc)));
+                                        results.append(CppQuickFixOperation::Ptr(new InsertDefOperation(interface, idx, decl, loc)));
                                 }
                                 return results;
                             }
index 61273cb..793640b 100644 (file)
@@ -47,10 +47,11 @@ namespace Internal {
 class DeclFromDef: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state);
+    virtual QList<CppQuickFixOperation::Ptr>
+        match(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface);
 
 protected:
-    static QString generateDeclaration(const CppQuickFixState &state,
+    static QString generateDeclaration(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
                                        CPlusPlus::Function *method,
                                        CPlusPlus::ClassOrNamespace *targetBinding);
 };
@@ -58,7 +59,8 @@ protected:
 class DefFromDecl: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state);
+    virtual QList<CppQuickFixOperation::Ptr>
+        match(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface);
 };
 
 } // namespace Internal
index 485acec..9945746 100644 (file)
@@ -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)
index 4a36a0a..785ac87 100644 (file)
@@ -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,
index 22b60e2..2612fd0 100644 (file)
 #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) {
index 5529de1..9a0946d 100644 (file)
@@ -50,6 +50,7 @@ namespace Internal {
 
 class CPPEditorWidget;
 class CppQuickFixCollector;
+class CppQuickFixAssistProvider;
 
 class CppPlugin : public ExtensionSystem::IPlugin
 {
@@ -70,7 +71,7 @@ public:
 
     bool sortedOutline() const;
 
-    CppQuickFixCollector *quickFixCollector() const;
+    CppQuickFixAssistProvider *quickFixProvider() const;
 
 signals:
     void outlineSortingChanged(bool sort);
@@ -86,8 +87,6 @@ private slots:
     void onTaskStarted(const QString &type);
     void onAllTasksFinished(const QString &type);
     void findUsages();
-    void quickFix(TextEditor::ITextEditor *editable);
-    void quickFixNow();
     void currentEditorChanged(Core::IEditor *editor);
     void openTypeHierarchy();
 
@@ -105,9 +104,8 @@ private:
     QAction *m_updateCodeModelAction;
     QAction *m_openTypeHierarchyAction;
 
-    CppQuickFixCollector *m_quickFixCollector;
+    CppQuickFixAssistProvider *m_quickFixProvider;
 
-    QTimer *m_quickFixTimer;
     QPointer<TextEditor::ITextEditor> m_currentEditor;
 };
 
index cec45fd..ae63fb4 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "cppquickfix.h"
 #include "cppeditor.h"
-#include "cppquickfixcollector.h"
+#include "cppquickfixassistant.h"
 
 #include <AST.h>
 #include <TranslationUnit.h>
@@ -58,53 +58,10 @@ using namespace TextEditor;
 using namespace CPlusPlus;
 using namespace Utils;
 
-CppQuickFixState::CppQuickFixState(TextEditor::BaseTextEditorWidget *editor)
-    : QuickFixState(editor)
-{}
-
-const QList<AST *> &CppQuickFixState::path() const
-{
-    return _path;
-}
-
-Snapshot CppQuickFixState::snapshot() const
-{
-    return _snapshot;
-}
-
-Document::Ptr CppQuickFixState::document() const
-{
-    return _semanticInfo.doc;
-}
-
-SemanticInfo CppQuickFixState::semanticInfo() const
-{
-    return _semanticInfo;
-}
-
-const LookupContext &CppQuickFixState::context() const
-{
-    return _context;
-}
-
-const CppRefactoringFile CppQuickFixState::currentFile() const
-{
-    return CppRefactoringFile(editor(), document());
-}
-
-bool CppQuickFixState::isCursorOn(unsigned tokenIndex) const
-{
-    return currentFile().isCursorOn(tokenIndex);
-}
-
-bool CppQuickFixState::isCursorOn(const CPlusPlus::AST *ast) const
-{
-    return currentFile().isCursorOn(ast);
-}
-
-CppQuickFixOperation::CppQuickFixOperation(const CppQuickFixState &state, int priority)
+CppQuickFixOperation::CppQuickFixOperation(
+        const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority)
     : QuickFixOperation(priority)
-    , _state(state)
+    , m_interface(interface)
 {}
 
 CppQuickFixOperation::~CppQuickFixOperation()
@@ -112,19 +69,21 @@ CppQuickFixOperation::~CppQuickFixOperation()
 
 void CppQuickFixOperation::perform()
 {
-    CppRefactoringChanges refactoring(_state.snapshot());
+    CppRefactoringChanges refactoring(m_interface->snapshot());
     CppRefactoringFile current = refactoring.file(fileName());
 
     performChanges(&current, &refactoring);
 }
 
-const CppQuickFixState &CppQuickFixOperation::state() const
+const CppQuickFixAssistInterface *CppQuickFixOperation::assistInterface() const
 {
-    return _state;
+    return m_interface.data();
 }
 
 QString CppQuickFixOperation::fileName() const
-{ return state().document()->fileName(); }
+{
+    return m_interface->file()->fileName();
+}
 
 CppQuickFixFactory::CppQuickFixFactory()
 {
@@ -134,12 +93,14 @@ CppQuickFixFactory::~CppQuickFixFactory()
 {
 }
 
-QList<QuickFixOperation::Ptr> CppQuickFixFactory::matchingOperations(QuickFixState *state)
+QList<QuickFixOperation::Ptr> CppQuickFixFactory::matchingOperations(
+    const QSharedPointer<const TextEditor::IAssistInterface> &interface)
 {
-    if (CppQuickFixState *cppState = static_cast<CppQuickFixState *>(state))
-        return match(*cppState);
-    else
-        return QList<TextEditor::QuickFixOperation::Ptr>();
+    QSharedPointer<const CppQuickFixAssistInterface> cppInterface =
+            interface.staticCast<const CppQuickFixAssistInterface>();
+    if (cppInterface->path().isEmpty())
+        return QList<QuickFixOperation::Ptr>();
+    return match(cppInterface);
 }
 
 QList<CppQuickFixOperation::Ptr> CppQuickFixFactory::singleResult(CppQuickFixOperation *operation)
index 034ab9e..71da104 100644 (file)
@@ -53,40 +53,17 @@ class IPlugin;
 namespace CppEditor {
 
 namespace Internal {
-class CppQuickFixCollector;
-} // namespace Internal
-
-class CPPEDITOR_EXPORT CppQuickFixState: public TextEditor::QuickFixState
-{
-    friend class Internal::CppQuickFixCollector;
-
-public:
-    CppQuickFixState(TextEditor::BaseTextEditorWidget *editor);
-
-    const QList<CPlusPlus::AST *> &path() const;
-    CPlusPlus::Snapshot snapshot() const;
-    CPlusPlus::Document::Ptr document() const;
-    CppEditor::Internal::SemanticInfo semanticInfo() const;
-    const CPlusPlus::LookupContext &context() const;
-
-    const CppTools::CppRefactoringFile currentFile() const;
-
-    bool isCursorOn(unsigned tokenIndex) const;
-    bool isCursorOn(const CPlusPlus::AST *ast) const;
-
-private:
-    QList<CPlusPlus::AST *> _path;
-    CPlusPlus::Snapshot _snapshot;
-    CppEditor::Internal::SemanticInfo _semanticInfo;
-    CPlusPlus::LookupContext _context;
-};
+class CppQuickFixAssistInterface;
+}
 
 class CPPEDITOR_EXPORT CppQuickFixOperation: public TextEditor::QuickFixOperation
 {
     Q_DISABLE_COPY(CppQuickFixOperation)
 
 public:
-    explicit CppQuickFixOperation(const CppQuickFixState &state, int priority = -1);
+    explicit CppQuickFixOperation(
+        const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
+        int priority = -1);
     virtual ~CppQuickFixOperation();
 
     virtual void perform();
@@ -97,10 +74,10 @@ protected:
 
     QString fileName() const;
 
-    const CppQuickFixState &state() const;
+    const Internal::CppQuickFixAssistInterface *assistInterface() const;
 
 private:
-    CppQuickFixState _state;
+    QSharedPointer<const Internal::CppQuickFixAssistInterface> m_interface;
 };
 
 class CPPEDITOR_EXPORT CppQuickFixFactory: public TextEditor::QuickFixFactory
@@ -111,12 +88,15 @@ public:
     CppQuickFixFactory();
     virtual ~CppQuickFixFactory();
 
-    virtual QList<TextEditor::QuickFixOperation::Ptr> matchingOperations(TextEditor::QuickFixState *state);
+    virtual QList<TextEditor::QuickFixOperation::Ptr>
+        matchingOperations(const QSharedPointer<const TextEditor::IAssistInterface> &interface);
+
     /*!
         Implement this method to match and create the appropriate
         CppQuickFixOperation objects.
      */
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state) = 0;
+    virtual QList<CppQuickFixOperation::Ptr> match(
+        const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface) = 0;
 
 protected:
     /*!
diff --git a/src/plugins/cppeditor/cppquickfixassistant.cpp b/src/plugins/cppeditor/cppquickfixassistant.cpp
new file mode 100644 (file)
index 0000000..9b998c2
--- /dev/null
@@ -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 (file)
index 0000000..f08a9ea
--- /dev/null
@@ -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 (file)
index a48f832..0000000
+++ /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
index fa7da44..1f76416 100644 (file)
@@ -35,7 +35,8 @@
 #include "cppquickfix.h"
 #include "cppinsertdecldef.h"
 #include "cppinsertqtpropertymembers.h"
-#include "cppquickfixcollector.h"
+#include "cppquickfixassistant.h"
+#include "cppcompleteswitch.h"
 
 #include <ASTVisitor.h>
 #include <AST.h>
@@ -85,17 +86,17 @@ namespace {
 class UseInverseOp: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
         QList<CppQuickFixOperation::Ptr> result;
-        const CppRefactoringFile &file = state.currentFile();
+        const CppRefactoringFile &file = interface->currentFile();
 
-        const QList<AST *> &path = state.path();
+        const QList<AST *> &path = interface->path();
         int index = path.size() - 1;
         BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
         if (! binary)
             return result;
-        if (! state.isCursorOn(binary->binary_op_token))
+        if (! interface->isCursorOn(binary->binary_op_token))
             return result;
 
         Kind invertToken;
@@ -122,7 +123,7 @@ public:
             return result;
         }
 
-        result.append(CppQuickFixOperation::Ptr(new Operation(state, index, binary, invertToken)));
+        result.append(CppQuickFixOperation::Ptr(new Operation(interface, index, binary, invertToken)));
         return result;
     }
 
@@ -136,8 +137,9 @@ private:
         QString replacement;
 
     public:
-        Operation(const CppQuickFixState &state, int priority, BinaryExpressionAST *binary, Kind invertToken)
-            : CppQuickFixOperation(state, priority)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
+            int priority, BinaryExpressionAST *binary, Kind invertToken)
+            : CppQuickFixOperation(interface, priority)
             , binary(binary), nested(0), negation(0)
         {
             Token tok;
@@ -146,12 +148,12 @@ private:
 
             // check for enclosing nested expression
             if (priority - 1 >= 0)
-                nested = state.path()[priority - 1]->asNestedExpression();
+                nested = interface->path()[priority - 1]->asNestedExpression();
 
             // check for ! before parentheses
             if (nested && priority - 2 >= 0) {
-                negation = state.path()[priority - 2]->asUnaryExpression();
-                if (negation && ! state.currentFile().tokenAt(negation->unary_op_token).is(T_EXCLAIM))
+                negation = interface->path()[priority - 2]->asUnaryExpression();
+                if (negation && ! interface->currentFile().tokenAt(negation->unary_op_token).is(T_EXCLAIM))
                     negation = 0;
             }
         }
@@ -191,17 +193,17 @@ private:
 class FlipBinaryOp: public CppQuickFixFactory
 {
 public:
-    virtual QList<QuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<QuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
         QList<QuickFixOperation::Ptr> result;
-        const QList<AST *> &path = state.path();
-        const CppRefactoringFile &file = state.currentFile();
+        const QList<AST *> &path = interface->path();
+        const CppRefactoringFile &file = interface->currentFile();
 
         int index = path.size() - 1;
         BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
         if (! binary)
             return result;
-        if (! state.isCursorOn(binary->binary_op_token))
+        if (! interface->isCursorOn(binary->binary_op_token))
             return result;
 
         Kind flipToken;
@@ -235,7 +237,7 @@ public:
             replacement = QLatin1String(tok.spell());
         }
 
-        result.append(QuickFixOperation::Ptr(new Operation(state, index, binary, replacement)));
+        result.append(QuickFixOperation::Ptr(new Operation(interface, index, binary, replacement)));
         return result;
     }
 
@@ -243,8 +245,9 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority, BinaryExpressionAST *binary, QString replacement)
-            : CppQuickFixOperation(state)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
+                  int priority, BinaryExpressionAST *binary, QString replacement)
+            : CppQuickFixOperation(interface)
             , binary(binary)
             , replacement(replacement)
         {
@@ -288,12 +291,12 @@ private:
 class RewriteLogicalAndOp: public CppQuickFixFactory
 {
 public:
-    virtual QList<QuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<QuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
         QList<QuickFixOperation::Ptr> result;
         BinaryExpressionAST *expression = 0;
-        const QList<AST *> &path = state.path();
-        const CppRefactoringFile &file = state.currentFile();
+        const QList<AST *> &path = interface->path();
+        const CppRefactoringFile &file = interface->currentFile();
 
         int index = path.size() - 1;
         for (; index != -1; --index) {
@@ -305,10 +308,10 @@ public:
         if (! expression)
             return result;
 
-        if (! state.isCursorOn(expression->binary_op_token))
+        if (! interface->isCursorOn(expression->binary_op_token))
             return result;
 
-        QSharedPointer<Operation> op(new Operation(state));
+        QSharedPointer<Operation> op(new Operation(interface));
 
         if (expression->match(op->pattern, &matcher) &&
                 file.tokenAt(op->pattern->binary_op_token).is(T_AMPER_AMPER) &&
@@ -331,8 +334,8 @@ private:
         UnaryExpressionAST *right;
         BinaryExpressionAST *pattern;
 
-        Operation(const CppQuickFixState &state)
-            : CppQuickFixOperation(state)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
+            : CppQuickFixOperation(interface)
             , mk(new ASTPatternBuilder)
         {
             left = mk->UnaryExpression();
@@ -400,12 +403,12 @@ class SplitSimpleDeclarationOp: public CppQuickFixFactory
     }
 
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
         QList<CppQuickFixOperation::Ptr> result;
         CoreDeclaratorAST *core_declarator = 0;
-        const QList<AST *> &path = state.path();
-        const CppRefactoringFile &file = state.currentFile();
+        const QList<AST *> &path = interface->path();
+        const CppRefactoringFile &file = interface->currentFile();
 
         for (int index = path.size() - 1; index != -1; --index) {
             AST *node = path.at(index);
@@ -424,12 +427,12 @@ public:
 
                     if (cursorPosition >= startOfDeclSpecifier && cursorPosition <= endOfDeclSpecifier) {
                         // the AST node under cursor is a specifier.
-                        return singleResult(new Operation(state, index, declaration));
+                        return singleResult(new Operation(interface, index, declaration));
                     }
 
-                    if (core_declarator && state.isCursorOn(core_declarator)) {
+                    if (core_declarator && interface->isCursorOn(core_declarator)) {
                         // got a core-declarator under the text cursor.
-                        return singleResult(new Operation(state, index, declaration));
+                        return singleResult(new Operation(interface, index, declaration));
                     }
                 }
 
@@ -444,8 +447,8 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority, SimpleDeclarationAST *decl)
-            : CppQuickFixOperation(state, priority)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, SimpleDeclarationAST *decl)
+            : CppQuickFixOperation(interface, priority)
             , declaration(decl)
         {
             setDescription(QApplication::translate("CppTools::QuickFix",
@@ -503,16 +506,16 @@ private:
 class AddBracesToIfOp: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
-        const QList<AST *> &path = state.path();
+        const QList<AST *> &path = interface->path();
 
         // show when we're on the 'if' of an if statement
         int index = path.size() - 1;
         IfStatementAST *ifStatement = path.at(index)->asIfStatement();
-        if (ifStatement && state.isCursorOn(ifStatement->if_token) && ifStatement->statement
+        if (ifStatement && interface->isCursorOn(ifStatement->if_token) && ifStatement->statement
             && ! ifStatement->statement->asCompoundStatement()) {
-            return singleResult(new Operation(state, index, ifStatement->statement));
+            return singleResult(new Operation(interface, index, ifStatement->statement));
         }
 
         // or if we're on the statement contained in the if
@@ -520,9 +523,9 @@ public:
         for (; index != -1; --index) {
             IfStatementAST *ifStatement = path.at(index)->asIfStatement();
             if (ifStatement && ifStatement->statement
-                && state.isCursorOn(ifStatement->statement)
+                && interface->isCursorOn(ifStatement->statement)
                 && ! ifStatement->statement->asCompoundStatement()) {
-                return singleResult(new Operation(state, index, ifStatement->statement));
+                return singleResult(new Operation(interface, index, ifStatement->statement));
             }
         }
 
@@ -536,8 +539,8 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority, StatementAST *statement)
-            : CppQuickFixOperation(state, priority)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, StatementAST *statement)
+            : CppQuickFixOperation(interface, priority)
             , _statement(statement)
         {
             setDescription(QApplication::translate("CppTools::QuickFix",
@@ -576,10 +579,10 @@ private:
 class MoveDeclarationOutOfIfOp: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
-        const QList<AST *> &path = state.path();
-        QSharedPointer<Operation> op(new Operation(state));
+        const QList<AST *> &path = interface->path();
+        QSharedPointer<Operation> op(new Operation(interface));
 
         int index = path.size() - 1;
         for (; index != -1; --index) {
@@ -590,7 +593,7 @@ public:
                     if (! op->core)
                         return noResult();
 
-                    if (state.isCursorOn(op->core)) {
+                    if (interface->isCursorOn(op->core)) {
                         QList<CppQuickFixOperation::Ptr> result;
                         op->setPriority(index);
                         result.append(op);
@@ -607,8 +610,8 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state)
-            : CppQuickFixOperation(state)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
+            : CppQuickFixOperation(interface)
         {
             setDescription(QApplication::translate("CppTools::QuickFix",
                                                    "Move Declaration out of Condition"));
@@ -653,10 +656,10 @@ private:
 class MoveDeclarationOutOfWhileOp: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
-        const QList<AST *> &path = state.path();
-        QSharedPointer<Operation> op(new Operation(state));
+        const QList<AST *> &path = interface->path();
+        QSharedPointer<Operation> op(new Operation(interface));
 
         int index = path.size() - 1;
         for (; index != -1; --index) {
@@ -674,7 +677,7 @@ public:
                     else if (! declarator->initializer)
                         return noResult();
 
-                    if (state.isCursorOn(op->core)) {
+                    if (interface->isCursorOn(op->core)) {
                         QList<CppQuickFixOperation::Ptr> result;
                         op->setPriority(index);
                         result.append(op);
@@ -691,8 +694,8 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state)
-            : CppQuickFixOperation(state)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
+            : CppQuickFixOperation(interface)
         {
             setDescription(QApplication::translate("CppTools::QuickFix",
                                                    "Move Declaration out of Condition"));
@@ -753,10 +756,10 @@ private:
 class SplitIfStatementOp: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
         IfStatementAST *pattern = 0;
-        const QList<AST *> &path = state.path();
+        const QList<AST *> &path = interface->path();
 
         int index = path.size() - 1;
         for (; index != -1; --index) {
@@ -777,7 +780,7 @@ public:
             if (! condition)
                 return noResult();
 
-            Token binaryToken = state.currentFile().tokenAt(condition->binary_op_token);
+            Token binaryToken = interface->currentFile().tokenAt(condition->binary_op_token);
 
             // only accept a chain of ||s or &&s - no mixing
             if (! splitKind) {
@@ -791,8 +794,8 @@ public:
                 return noResult();
             }
 
-            if (state.isCursorOn(condition->binary_op_token))
-                return singleResult(new Operation(state, index, pattern, condition));
+            if (interface->isCursorOn(condition->binary_op_token))
+                return singleResult(new Operation(interface, index, pattern, condition));
         }
 
         return noResult();
@@ -802,9 +805,9 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority,
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority,
                   IfStatementAST *pattern, BinaryExpressionAST *condition)
-            : CppQuickFixOperation(state, priority)
+            : CppQuickFixOperation(interface, priority)
             , pattern(pattern)
             , condition(condition)
         {
@@ -889,12 +892,12 @@ class WrapStringLiteral: public CppQuickFixFactory
 public:
     enum Type { TypeString, TypeObjCString, TypeChar, TypeNone };
 
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
         ExpressionAST *literal = 0;
         Type type = TypeNone;
-        const QList<AST *> &path = state.path();
-        const CppRefactoringFile &file = state.currentFile();
+        const QList<AST *> &path = interface->path();
+        const CppRefactoringFile &file = interface->currentFile();
 
         if (path.isEmpty())
             return noResult(); // nothing to do
@@ -932,7 +935,7 @@ public:
             if (file.charAt(file.startOf(literal)) == QLatin1Char('@'))
                 type = TypeObjCString;
         }
-        return singleResult(new Operation(state,
+        return singleResult(new Operation(interface,
                                           path.size() - 1, // very high priority
                                           type,
                                           literal));
@@ -942,9 +945,9 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority, Type type,
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, Type type,
                   ExpressionAST *literal)
-            : CppQuickFixOperation(state, priority)
+            : CppQuickFixOperation(interface, priority)
             , type(type)
             , literal(literal)
         {
@@ -996,9 +999,9 @@ class TranslateStringLiteral: public CppQuickFixFactory
 public:
     enum TranslationOption { unknown, useTr, useQCoreApplicationTranslate, useMacro };
 
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
-        const QList<AST *> &path = state.path();
+        const QList<AST *> &path = interface->path();
         // Initialize
         ExpressionAST *literal = 0;
         QString trContext;
@@ -1016,7 +1019,7 @@ public:
                 if (call->base_expression) {
                     if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
                         if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
-                            const QByteArray id(state.currentFile().tokenAt(functionName->identifier_token).identifier->chars());
+                            const QByteArray id(interface->currentFile().tokenAt(functionName->identifier_token).identifier->chars());
 
                             if (id == "tr" || id == "trUtf8"
                                     || id == "translate"
@@ -1029,7 +1032,7 @@ public:
             }
         }
 
-        QSharedPointer<Control> control = state.context().control();
+        QSharedPointer<Control> control = interface->context().control();
         const Name *trName = control->identifier("tr");
 
         // Check whether we are in a method:
@@ -1037,14 +1040,14 @@ public:
         {
             if (FunctionDefinitionAST *definition = path.at(i)->asFunctionDefinition()) {
                 Function *function = definition->symbol;
-                ClassOrNamespace *b = state.context().lookupType(function);
+                ClassOrNamespace *b = interface->context().lookupType(function);
                 if (b) {
                     // Do we have a tr method?
                     foreach(const LookupItem &r, b->find(trName)) {
                         Symbol *s = r.declaration();
                         if (s->type()->isFunctionType()) {
                             // no context required for tr
-                            return singleResult(new Operation(state, path.size() - 1, literal, useTr, trContext));
+                            return singleResult(new Operation(interface, path.size() - 1, literal, useTr, trContext));
                         }
                     }
                 }
@@ -1059,20 +1062,20 @@ public:
                 // ... or global if none available!
                 if (trContext.isEmpty())
                     trContext = QLatin1String("GLOBAL");
-                return singleResult(new Operation(state, path.size() - 1, literal, useQCoreApplicationTranslate, trContext));
+                return singleResult(new Operation(interface, path.size() - 1, literal, useQCoreApplicationTranslate, trContext));
             }
         }
 
         // We need to use Q_TRANSLATE_NOOP
-        return singleResult(new Operation(state, path.size() - 1, literal, useMacro, QLatin1String("GLOBAL")));
+        return singleResult(new Operation(interface, path.size() - 1, literal, useMacro, QLatin1String("GLOBAL")));
     }
 
 private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority, ExpressionAST *literal, TranslationOption option, const QString &context)
-            : CppQuickFixOperation(state, priority)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, ExpressionAST *literal, TranslationOption option, const QString &context)
+            : CppQuickFixOperation(interface, priority)
             , m_literal(literal)
             , m_option(option)
             , m_context(context)
@@ -1120,16 +1123,16 @@ private:
 class CStringToNSString: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
-        const CppRefactoringFile &file = state.currentFile();
+        const CppRefactoringFile &file = interface->currentFile();
 
-        if (state.editor()->mimeType() != CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
+        if (interface->editor()->mimeType() != CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
             return noResult();
 
         StringLiteralAST *stringLiteral = 0;
         CallAST *qlatin1Call = 0;
-        const QList<AST *> &path = state.path();
+        const QList<AST *> &path = interface->path();
 
         if (path.isEmpty())
             return noResult(); // nothing to do
@@ -1147,7 +1150,7 @@ public:
                 if (call->base_expression) {
                     if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
                         if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
-                            const QByteArray id(state.currentFile().tokenAt(functionName->identifier_token).identifier->chars());
+                            const QByteArray id(interface->currentFile().tokenAt(functionName->identifier_token).identifier->chars());
 
                             if (id == "QLatin1String" || id == "QLatin1Literal")
                                 qlatin1Call = call;
@@ -1157,15 +1160,15 @@ public:
             }
         }
 
-        return singleResult(new Operation(state, path.size() - 1, stringLiteral, qlatin1Call));
+        return singleResult(new Operation(interface, path.size() - 1, stringLiteral, qlatin1Call));
     }
 
 private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority, StringLiteralAST *stringLiteral, CallAST *qlatin1Call)
-            : CppQuickFixOperation(state, priority)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, StringLiteralAST *stringLiteral, CallAST *qlatin1Call)
+            : CppQuickFixOperation(interface, priority)
             , stringLiteral(stringLiteral)
             , qlatin1Call(qlatin1Call)
         {
@@ -1214,12 +1217,12 @@ private:
 class ConvertNumericLiteral: public CppQuickFixFactory
 {
 public:
-    virtual QList<QuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<QuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
         QList<QuickFixOperation::Ptr> result;
 
-        const QList<AST *> &path = state.path();
-        const CppRefactoringFile &file = state.currentFile();
+        const QList<AST *> &path = interface->path();
+        const CppRefactoringFile &file = interface->currentFile();
 
         if (path.isEmpty())
             return result; // nothing to do
@@ -1266,7 +1269,7 @@ public:
             */
             QString replacement;
             replacement.sprintf("0x%lX", value);
-            QuickFixOperation::Ptr op(new ConvertNumeric(state, start, start + numberLength, replacement));
+            QuickFixOperation::Ptr op(new ConvertNumeric(interface, start, start + numberLength, replacement));
             op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Hexadecimal"));
             op->setPriority(priority);
             result.append(op);
@@ -1284,7 +1287,7 @@ public:
                 */
                 QString replacement;
                 replacement.sprintf("0%lo", value);
-                QuickFixOperation::Ptr op(new ConvertNumeric(state, start, start + numberLength, replacement));
+                QuickFixOperation::Ptr op(new ConvertNumeric(interface, start, start + numberLength, replacement));
                 op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Octal"));
                 op->setPriority(priority);
                 result.append(op);
@@ -1303,7 +1306,7 @@ public:
                 */
                 QString replacement;
                 replacement.sprintf("%lu", value);
-                QuickFixOperation::Ptr op(new ConvertNumeric(state, start, start + numberLength, replacement));
+                QuickFixOperation::Ptr op(new ConvertNumeric(interface, start, start + numberLength, replacement));
                 op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Decimal"));
                 op->setPriority(priority);
                 result.append(op);
@@ -1317,8 +1320,9 @@ private:
     class ConvertNumeric: public CppQuickFixOperation
     {
     public:
-        ConvertNumeric(const CppQuickFixState &state, int start, int end, const QString &replacement)
-            : CppQuickFixOperation(state)
+        ConvertNumeric(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
+                       int start, int end, const QString &replacement)
+            : CppQuickFixOperation(interface)
             , start(start)
             , end(end)
             , replacement(replacement)
@@ -1345,18 +1349,18 @@ private:
 class FixForwardDeclarationOp: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
-        const QList<AST *> &path = state.path();
+        const QList<AST *> &path = interface->path();
 
         for (int index = path.size() - 1; index != -1; --index) {
             AST *ast = path.at(index);
             if (NamedTypeSpecifierAST *namedTy = ast->asNamedTypeSpecifier()) {
-                if (Symbol *fwdClass = checkName(state, namedTy->name))
-                    return singleResult(new Operation(state, index, fwdClass));
+                if (Symbol *fwdClass = checkName(interface, namedTy->name))
+                    return singleResult(new Operation(interface, index, fwdClass));
             } else if (ElaboratedTypeSpecifierAST *eTy = ast->asElaboratedTypeSpecifier()) {
-                if (Symbol *fwdClass = checkName(state, eTy->name))
-                    return singleResult(new Operation(state, index, fwdClass));
+                if (Symbol *fwdClass = checkName(interface, eTy->name))
+                    return singleResult(new Operation(interface, index, fwdClass));
             }
         }
 
@@ -1364,16 +1368,18 @@ public:
     }
 
 protected:
-    static Symbol *checkName(const CppQuickFixState &state, NameAST *ast)
+    static Symbol *checkName(const QSharedPointer<const CppQuickFixAssistInterface> &interface, NameAST *ast)
     {
-        if (ast && state.isCursorOn(ast)) {
+        if (ast && interface->isCursorOn(ast)) {
             if (const Name *name = ast->name) {
                 unsigned line, column;
-                state.document()->translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column);
+                interface->semanticInfo().doc->translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column);
 
                 Symbol *fwdClass = 0;
 
-                foreach (const LookupItem &r, state.context().lookup(name, state.document()->scopeAt(line, column))) {
+                foreach (const LookupItem &r,
+                         interface->context().lookup(name,
+                                                     interface->semanticInfo().doc->scopeAt(line, column))) {
                     if (! r.declaration())
                         continue;
                     else if (ForwardClassDeclaration *fwd = r.declaration()->asForwardClassDeclaration())
@@ -1393,8 +1399,8 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority, Symbol *fwdClass)
-            : CppQuickFixOperation(state, priority)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, Symbol *fwdClass)
+            : CppQuickFixOperation(interface, priority)
             , fwdClass(fwdClass)
         {
             setDescription(QApplication::translate("CppTools::QuickFix",
@@ -1405,13 +1411,13 @@ private:
         {
             Q_ASSERT(fwdClass != 0);
 
-            if (Class *k = state().snapshot().findMatchingClassDeclaration(fwdClass)) {
+            if (Class *k = assistInterface()->snapshot().findMatchingClassDeclaration(fwdClass)) {
                 const QString headerFile = QString::fromUtf8(k->fileName(), k->fileNameLength());
 
                 // collect the fwd headers
                 Snapshot fwdHeaders;
-                fwdHeaders.insert(state().snapshot().document(headerFile));
-                foreach (Document::Ptr doc, state().snapshot()) {
+                fwdHeaders.insert(assistInterface()->snapshot().document(headerFile));
+                foreach (Document::Ptr doc, assistInterface()->snapshot()) {
                     QFileInfo headerFileInfo(doc->fileName());
                     if (doc->globalSymbolCount() == 0 && doc->includes().size() == 1)
                         fwdHeaders.insert(doc);
@@ -1448,7 +1454,7 @@ private:
 
                 unsigned currentLine = currentFile->cursor().blockNumber() + 1;
                 unsigned bestLine = 0;
-                foreach (const Document::Include &incl, state().document()->includes()) {
+                foreach (const Document::Include &incl, assistInterface()->semanticInfo().doc->includes()) {
                     if (incl.line() < currentLine)
                         bestLine = incl.line();
                 }
@@ -1479,18 +1485,18 @@ private:
 class AddLocalDeclarationOp: public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
-        const QList<AST *> &path = state.path();
-        const CppRefactoringFile &file = state.currentFile();
+        const QList<AST *> &path = interface->path();
+        const CppRefactoringFile &file = interface->currentFile();
 
         for (int index = path.size() - 1; index != -1; --index) {
             if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) {
                 if (binary->left_expression && binary->right_expression && file.tokenAt(binary->binary_op_token).is(T_EQUAL)) {
                     IdExpressionAST *idExpr = binary->left_expression->asIdExpression();
-                    if (state.isCursorOn(binary->left_expression) && idExpr && idExpr->name->asSimpleName() != 0) {
+                    if (interface->isCursorOn(binary->left_expression) && idExpr && idExpr->name->asSimpleName() != 0) {
                         SimpleNameAST *nameAST = idExpr->name->asSimpleName();
-                        const QList<LookupItem> results = state.context().lookup(nameAST->name, file.scopeAt(nameAST->firstToken()));
+                        const QList<LookupItem> results = interface->context().lookup(nameAST->name, file.scopeAt(nameAST->firstToken()));
                         Declaration *decl = 0;
                         foreach (const LookupItem &r, results) {
                             if (! r.declaration())
@@ -1504,7 +1510,7 @@ public:
                         }
 
                         if (! decl) {
-                            return singleResult(new Operation(state, index, binary));
+                            return singleResult(new Operation(interface, index, binary));
                         }
                     }
                 }
@@ -1518,8 +1524,8 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority, BinaryExpressionAST *binaryAST)
-            : CppQuickFixOperation(state, priority)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, BinaryExpressionAST *binaryAST)
+            : CppQuickFixOperation(interface, priority)
             , binaryAST(binaryAST)
         {
             setDescription(QApplication::translate("CppTools::QuickFix", "Add Local Declaration"));
@@ -1528,7 +1534,8 @@ private:
         virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
         {
             TypeOfExpression typeOfExpression;
-            typeOfExpression.init(state().document(), state().snapshot(), state().context().bindings());
+            typeOfExpression.init(assistInterface()->semanticInfo().doc,
+                                  assistInterface()->snapshot(), assistInterface()->context().bindings());
             const QList<LookupItem> result = typeOfExpression(currentFile->textOf(binaryAST->right_expression),
                                                               currentFile->scopeAt(binaryAST->firstToken()),
                                                               TypeOfExpression::Preprocess);
@@ -1536,12 +1543,12 @@ private:
             if (! result.isEmpty()) {
 
                 SubstitutionEnvironment env;
-                env.setContext(state().context());
+                env.setContext(assistInterface()->context());
                 env.switchScope(result.first().scope());
                 UseQualifiedNames q;
                 env.enter(&q);
 
-                Control *control = state().context().control().data();
+                Control *control = assistInterface()->context().control().data();
                 FullySpecifiedType tn = rewriteType(result.first().type(), &env, control);
 
                 Overview oo;
@@ -1573,9 +1580,9 @@ private:
 class ToCamelCaseConverter : public CppQuickFixFactory
 {
 public:
-    virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
+    virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
     {
-        const QList<AST *> &path = state.path();
+        const QList<AST *> &path = interface->path();
 
         if (path.isEmpty())
             return noResult();
@@ -1597,7 +1604,7 @@ public:
             return noResult();
         for (int i = 1; i < newName.length() - 1; ++i) {
             if (Operation::isConvertibleUnderscore(newName, i))
-                return singleResult(new Operation(state, path.size() - 1, newName));
+                return singleResult(new Operation(interface, path.size() - 1, newName));
         }
 
         return noResult();
@@ -1607,8 +1614,8 @@ private:
     class Operation: public CppQuickFixOperation
     {
     public:
-        Operation(const CppQuickFixState &state, int priority, const QString &newName)
-            : CppQuickFixOperation(state, priority)
+        Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, const QString &newName)
+            : CppQuickFixOperation(interface, priority)
             , m_name(newName)
         {
             setDescription(QApplication::translate("CppTools::QuickFix",
@@ -1627,7 +1634,7 @@ private:
                     m_name[i] = m_name.at(i).toUpper();
                 }
             }
-            static_cast<CppEditor::Internal::CPPEditorWidget*>(state().editor())->renameUsagesNow(m_name);
+            static_cast<CppEditor::Internal::CPPEditorWidget*>(assistInterface()->editor())->renameUsagesNow(m_name);
         }
 
         static bool isConvertibleUnderscore(const QString &name, int pos)
@@ -1643,7 +1650,7 @@ private:
 
 } // end of anonymous namespace
 
-void CppQuickFixCollector::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
+void registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
 {
     plugIn->addAutoReleasedObject(new UseInverseOp);
     plugIn->addAutoReleasedObject(new FlipBinaryOp);
@@ -1657,11 +1664,11 @@ void CppQuickFixCollector::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
     plugIn->addAutoReleasedObject(new TranslateStringLiteral);
     plugIn->addAutoReleasedObject(new CStringToNSString);
     plugIn->addAutoReleasedObject(new ConvertNumericLiteral);
-    plugIn->addAutoReleasedObject(new Internal::CompleteSwitchCaseStatement);
+    plugIn->addAutoReleasedObject(new CompleteSwitchCaseStatement);
     plugIn->addAutoReleasedObject(new FixForwardDeclarationOp);
     plugIn->addAutoReleasedObject(new AddLocalDeclarationOp);
     plugIn->addAutoReleasedObject(new ToCamelCaseConverter);
-    plugIn->addAutoReleasedObject(new Internal::InsertQtPropertyMembers);
-    plugIn->addAutoReleasedObject(new Internal::DeclFromDef);
-    plugIn->addAutoReleasedObject(new Internal::DefFromDecl);
+    plugIn->addAutoReleasedObject(new InsertQtPropertyMembers);
+    plugIn->addAutoReleasedObject(new DeclFromDef);
+    plugIn->addAutoReleasedObject(new DefFromDecl);
 }
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
deleted file mode 100644 (file)
index 8d14095..0000000
+++ /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
similarity index 55%
rename from src/plugins/cpptools/cppcodecompletion.cpp
rename to src/plugins/cpptools/cppcompletionassist.cpp
index 5b2c309..d6e89dc 100644 (file)
 **
 **************************************************************************/
 
-#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>
 #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 {
-
-class FunctionArgumentWidget : public QLabel
-{
-    Q_OBJECT
-
-public:
-    FunctionArgumentWidget();
-    void showFunctionHint(QList<Function *> functionSymbols,
-                          const LookupContext &context,
-                          int startPosition);
-
-protected:
-    bool eventFilter(QObject *obj, QEvent *e);
-
-private slots:
-    void nextPage();
-    void previousPage();
-
-private:
-    void updateArgumentHighlight();
-    void updateHintText();
-    void placeInsideScreen();
-
-    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;
-    QList<Function *> m_items;
-    LookupContext m_context;
-};
-
-class ConvertToCompletionItem: protected NameVisitor
-{
-    // The completion collector.
-    CppCodeCompletion *_collector;
-
-    // The completion item.
-    TextEditor::CompletionItem _item;
-
-    // The current symbol.
-    Symbol *_symbol;
-
-    // The pretty printer.
-    Overview overview;
-
-public:
-    ConvertToCompletionItem(CppCodeCompletion *collector)
-        : _collector(collector),
-          _item(0),
-          _symbol(0)
-    { }
-
-    TextEditor::CompletionItem operator()(Symbol *symbol)
-    {
-        if (! symbol || ! symbol->name() || symbol->name()->isQualifiedNameId())
-            return 0;
-
-        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);
-    }
-
-protected:
-    Symbol *switchSymbol(Symbol *symbol)
-    {
-        Symbol *previousSymbol = _symbol;
-        _symbol = symbol;
-        return previousSymbol;
-    }
-
-    TextEditor::CompletionItem switchCompletionItem(TextEditor::CompletionItem item)
-    {
-        TextEditor::CompletionItem previousItem = _item;
-        _item = item;
-        return previousItem;
-    }
-
-    TextEditor::CompletionItem newCompletionItem(const Name *name)
-    {
-        TextEditor::CompletionItem item(_collector);
-        item.text = overview.prettyName(name);
-        item.icon = _collector->iconForSymbol(_symbol);
-        return item;
-    }
-
-    virtual void visit(const Identifier *name)
-    { _item = newCompletionItem(name); }
-
-    virtual void visit(const TemplateNameId *name)
-    {
-        _item = newCompletionItem(name);
-        _item.text = QLatin1String(name->identifier()->chars());
-    }
-
-    virtual void visit(const DestructorNameId *name)
-    { _item = newCompletionItem(name); }
-
-    virtual void visit(const OperatorNameId *name)
-    { _item = newCompletionItem(name); }
-
-    virtual void visit(const ConversionNameId *name)
-    { _item = newCompletionItem(name); }
-
-    virtual void visit(const QualifiedNameId *name)
-    { _item = newCompletionItem(name->name()); }
-};
-
-struct CompleteFunctionDeclaration
-{
-    explicit CompleteFunctionDeclaration(Function *f = 0)
-        : function(f)
-    {}
-
-    Function *function;
-};
-
-} // namespace Internal
-} // namespace CppTools
-
-using namespace CppTools::Internal;
-
-Q_DECLARE_METATYPE(CompleteFunctionDeclaration)
-
-
-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(QList<Function *> functionSymbols,
-                                              const LookupContext &context,
-                                              int startPosition)
-{
-    Q_ASSERT(!functionSymbols.isEmpty());
-
-    if (m_startpos == startPosition)
-        return;
-
-    m_pager->setVisible(functionSymbols.size() > 1);
-
-    m_items = functionSymbols;
-    m_context = context;
-    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;
-    }
-
-    QString str = m_editor->textAt(m_startpos, curpos - m_startpos);
-    int argnr = 0;
-    int parcount = 0;
-    SimpleLexer tokenize;
-    QList<Token> tokens = tokenize(str);
-    for (int i = 0; i < tokens.count(); ++i) {
-        const Token &tk = tokens.at(i);
-        if (tk.is(T_LPAREN))
-            ++parcount;
-        else if (tk.is(T_RPAREN))
-            --parcount;
-        else if (! parcount && tk.is(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()
-{
-    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();
-}
-
-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);
-}
-
-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")))
-{
-}
-
-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,
+int activationSequenceChar(const QChar &ch,
+                           const QChar &ch2,
+                           const QChar &ch3,
+                           unsigned *kind,
                            bool wantFunctionCall)
 {
-    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();
-
-    int start = pos;
+    int referencePosition = 0;
     int completionKind = T_EOF_SYMBOL;
-
     switch (ch.toLatin1()) {
     case '.':
         if (ch2 != QLatin1Char('.')) {
             completionKind = T_DOT;
-            --start;
+            referencePosition = 1;
         }
         break;
     case ',':
         completionKind = T_COMMA;
-        --start;
+        referencePosition = 1;
         break;
     case '(':
         if (wantFunctionCall) {
             completionKind = T_LPAREN;
-            --start;
+            referencePosition = 1;
         }
         break;
     case ':':
         if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':')) {
             completionKind = T_COLON_COLON;
-            start -= 2;
+            referencePosition = 2;
         }
         break;
     case '>':
         if (ch2 == QLatin1Char('-')) {
             completionKind = T_ARROW;
-            start -= 2;
+            referencePosition = 2;
         }
         break;
     case '*':
         if (ch2 == QLatin1Char('.')) {
             completionKind = T_DOT_STAR;
-            start -= 2;
+            referencePosition = 2;
         } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>')) {
             completionKind = T_ARROW_STAR;
-            start -= 3;
+            referencePosition = 3;
         }
         break;
     case '\\':
     case '@':
         if (ch2.isNull() || ch2.isSpace()) {
             completionKind = T_DOXY_COMMENT;
-            --start;
+            referencePosition = 1;
         }
         break;
     case '<':
         completionKind = T_ANGLE_STRING_LITERAL;
-        --start;
+        referencePosition = 1;
         break;
     case '"':
         completionKind = T_STRING_LITERAL;
-        --start;
+        referencePosition = 1;
         break;
     case '/':
         completionKind = T_SLASH;
-        --start;
+        referencePosition = 1;
         break;
     case '#':
         completionKind = T_POUND;
-        --start;
+        referencePosition = 1;
         break;
     }
 
-    if (start == pos)
-        return start;
+    if (kind)
+        *kind = completionKind;
 
-    TextEditor::BaseTextEditorWidget *edit = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget());
-    QTextCursor tc(edit->textCursor());
-    tc.setPosition(pos);
+    return referencePosition;
+}
 
-    // 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;
-        }
-    }
+} // Anonymous
 
-    if (completionKind == T_COMMA) {
-        ExpressionUnderCursor expressionUnderCursor;
-        if (expressionUnderCursor.startOfFunctionCall(tc) == -1) {
-            completionKind = T_EOF_SYMBOL;
-            start = pos;
-        }
-    }
+namespace CppTools {
+namespace Internal {
 
-    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;
-    }
-    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;
-            }
-        }
-    }
-    // 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;
-                }
-            }
-        }
+struct CompleteFunctionDeclaration
+{
+    explicit CompleteFunctionDeclaration(Function *f = 0)
+        : function(f)
+    {}
 
-        if (!include) {
-            completionKind = T_EOF_SYMBOL;
-            start = pos;
-        }
-    }
+    Function *function;
+};
 
-    if (kind)
-        *kind = completionKind;
+// ----------------------
+// CppAssistProposalModel
+// ----------------------
+class CppAssistProposalModel : public TextEditor::BasicProposalItemListModel
+{
+public:
+    CppAssistProposalModel()
+        : TextEditor::BasicProposalItemListModel()
+        , m_sortable(false)
+        , m_completionOperator(T_EOF_SYMBOL)
+        , m_replaceDotForArrow(false)
+    {}
 
-    return start;
-}
+    virtual bool isSortable() const { return m_sortable; }
+    virtual IAssistProposalItem *proposalItem(int index) const;
 
-bool CppCodeCompletion::supportsPolicy(TextEditor::CompletionPolicy policy) const
-{
-    return policy == TextEditor::SemanticCompletion;
-}
+    bool m_sortable;
+    unsigned m_completionOperator;
+    bool m_replaceDotForArrow;
+    Snapshot m_snapshot;
+};
 
-bool CppCodeCompletion::supportsEditor(TextEditor::ITextEditor *editor) const
+// ---------------------
+// CppAssistProposalItem
+// ---------------------
+class CppAssistProposalItem : public TextEditor::BasicProposalItem
 {
-    return m_manager->isCppEditor(editor);
-}
+public:
+    CppAssistProposalItem() : m_isOverloaded(false) {}
 
-TextEditor::ITextEditor *CppCodeCompletion::editor() const
-{ return m_editor; }
+    virtual bool prematurelyApplies(const QChar &c) const;
+    virtual void applyContextualContent(TextEditor::BaseTextEditor *editor,
+                                        int basePosition) const;
 
-int CppCodeCompletion::startPosition() const
-{ return m_startPosition; }
+    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; }
 
-bool CppCodeCompletion::shouldRestartCompletion()
-{ return m_shouldRestartCompletion; }
+private:
+    bool m_isOverloaded;
+    unsigned m_completionOperator;
+    mutable QChar m_typedChar;
+    Snapshot m_snapshot;
+};
 
-bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditor *editor)
-{
-    m_editor = editor;
-    m_automaticCompletion = false;
+} // Internal
+} // CppTools
 
-    const int pos = editor->position();
-    unsigned token = T_EOF_SYMBOL;
+Q_DECLARE_METATYPE(CppTools::Internal::CompleteFunctionDeclaration)
 
-    if (startOfOperator(editor, pos, &token, /*want function call=*/ true) != pos) {
-        if (token == T_POUND) {
-            int line, column;
-            editor->convertPosition(pos, &line, &column);
-            if (column != 1)
-                return false;
-        }
+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;
+}
 
-        return true;
-    } else if (completionSettings().m_completionTrigger == TextEditor::AutomaticCompletion) {
-        // Trigger completion after three characters of a name have been typed, when not editing an existing name
-        QChar characterUnderCursor = editor->characterAt(pos);
+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;
+        }
+    }
+
+    return false;
+}
+
+void CppAssistProposalItem::applyContextualContent(TextEditor::BaseTextEditor *editor,
+                                                    int basePosition) const
+{
+    Symbol *symbol = 0;
+
+    if (data().isValid())
+        symbol = data().value<Symbol *>();
+
+    QString toInsert;
+    QString extraChars;
+    int extraLength = 0;
+    int cursorOffset = 0;
+
+    bool autoParenthesesEnabled = true;
+
+    if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
+        toInsert = text();
+        extraChars += QLatin1Char(')');
+
+        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();
+
+        const CompletionSettings &completionSettings =
+                TextEditorSettings::instance()->completionSettings();
+        const bool autoInsertBrackets = completionSettings.m_autoInsertBrackets;
+
+        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
+
+                    /// ### 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('(');
+
+                    if (completionSettings.m_spaceAfterFunctionName)
+                        extraChars += QLatin1Char(' ');
+                    extraChars += QLatin1Char('(');
+                    if (m_typedChar == QLatin1Char('('))
+                        m_typedChar = QChar();
+
+                    // 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();
+                    }
+
+                    // 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.
+                    }
+                }
+            }
+        }
+
+        if (autoInsertBrackets && data().canConvert<CompleteFunctionDeclaration>()) {
+            if (m_typedChar == QLatin1Char('('))
+                m_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 (!m_typedChar.isNull()) {
+        extraChars += m_typedChar;
+        if (cursorOffset != 0)
+            --cursorOffset;
+    }
+
+    // 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;
+    }
+
+    toInsert += extraChars;
+
+    // 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);
+}
+
+// --------------------
+// CppFunctionHintModel
+// --------------------
+class CppFunctionHintModel : public TextEditor::IFunctionHintProposalModel
+{
+public:
+    CppFunctionHintModel(QList<Function *> functionSymbols)
+        : m_functionSymbols(functionSymbols)
+        , m_currentArg(-1)
+    {}
+
+    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
+{
+    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();
+
+    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;
+}
+
+int CppFunctionHintModel::activeArgument(const QString &prefix) const
+{
+    int argnr = 0;
+    int parcount = 0;
+    SimpleLexer tokenize;
+    QList<Token> tokens = tokenize(prefix);
+    for (int i = 0; i < tokens.count(); ++i) {
+        const Token &tk = tokens.at(i);
+        if (tk.is(T_LPAREN))
+            ++parcount;
+        else if (tk.is(T_RPAREN))
+            --parcount;
+        else if (! parcount && tk.is(T_COMMA))
+            ++argnr;
+    }
+
+    if (parcount < 0)
+        return -1;
+
+    if (argnr != m_currentArg)
+        m_currentArg = argnr;
+
+    return argnr;
+}
+
+// ---------------------------
+// CppCompletionAssistProvider
+// ---------------------------
+bool CppCompletionAssistProvider::supportsEditor(const QString &editorId) const
+{
+    return editorId == QLatin1String(CppEditor::Constants::CPPEDITOR_ID);
+}
+
+int CppCompletionAssistProvider::activationCharSequenceLength() const
+{
+    return 3;
+}
+
+bool CppCompletionAssistProvider::isActivationCharSequence(const QString &sequence) const
+{
+    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;
+}
+
+IAssistProcessor *CppCompletionAssistProvider::createProcessor() const
+{
+    return new CppCompletionAssistProcessor;
+}
+
+// -----------------
+// 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)
+    {}
+
+    virtual bool isCorrective() const { return m_replaceDotForArrow; }
+    virtual void makeCorrection(BaseTextEditor *editor);
+
+private:
+    bool m_replaceDotForArrow;
+};
+
+void CppAssistProposal::makeCorrection(BaseTextEditor *editor)
+{
+    editor->setCursorPosition(basePosition() - 1);
+    editor->replace(1, QLatin1String("->"));
+    moveBasePosition(1);
+}
+
+namespace {
+
+class ConvertToCompletionItem: protected NameVisitor
+{
+    // The completion item.
+    BasicProposalItem *_item;
+
+    // The current symbol.
+    Symbol *_symbol;
+
+    // The pretty printer.
+    Overview overview;
+
+public:
+    ConvertToCompletionItem()
+        : _item(0)
+        , _symbol(0)
+    { }
+
+    BasicProposalItem *operator()(Symbol *symbol)
+    {
+        if (! symbol || ! symbol->name() || symbol->name()->isQualifiedNameId())
+            return 0;
+
+        BasicProposalItem *previousItem = switchCompletionItem(0);
+        Symbol *previousSymbol = switchSymbol(symbol);
+        accept(symbol->unqualifiedName());
+        if (_item)
+            _item->setData(QVariant::fromValue(symbol));
+        (void) switchSymbol(previousSymbol);
+        return switchCompletionItem(previousItem);
+    }
+
+protected:
+    Symbol *switchSymbol(Symbol *symbol)
+    {
+        Symbol *previousSymbol = _symbol;
+        _symbol = symbol;
+        return previousSymbol;
+    }
+
+    BasicProposalItem *switchCompletionItem(BasicProposalItem *item)
+    {
+        BasicProposalItem *previousItem = _item;
+        _item = item;
+        return previousItem;
+    }
+
+    BasicProposalItem *newCompletionItem(const Name *name)
+    {
+        BasicProposalItem *item = new CppAssistProposalItem;
+        item->setText(overview.prettyName(name));
+        return item;
+    }
+
+    virtual void visit(const Identifier *name)
+    { _item = newCompletionItem(name); }
+
+    virtual void visit(const TemplateNameId *name)
+    {
+        _item = newCompletionItem(name);
+        _item->setText(QLatin1String(name->identifier()->chars()));
+    }
+
+    virtual void visit(const DestructorNameId *name)
+    { _item = newCompletionItem(name); }
+
+    virtual void visit(const OperatorNameId *name)
+    { _item = newCompletionItem(name); }
+
+    virtual void visit(const ConversionNameId *name)
+    { _item = newCompletionItem(name); }
+
+    virtual void visit(const QualifiedNameId *name)
+    { _item = newCompletionItem(name->name()); }
+};
+
+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;
+}
+
+Scope *enclosingNonTemplateScope(Symbol *symbol)
+{
+    if (symbol) {
+        if (Scope *scope = symbol->enclosingScope()) {
+            if (Template *templ = scope->asTemplate())
+                return templ->enclosingScope();
+            return scope;
+        }
+    }
+    return 0;
+}
+
+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;
+}
+
+} // 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)
+{}
+
+CppCompletionAssistProcessor::~CppCompletionAssistProcessor()
+{}
+
+IAssistProposal * CppCompletionAssistProcessor::perform(const IAssistInterface *interface)
+{
+    m_interface.reset(static_cast<const CppCompletionAssistInterface *>(interface));
+
+    if (interface->reason() != ExplicitlyInvoked && !accepts())
+        return 0;
+
+    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;
+
+    const int start = startOfOperator(pos, &token, /*want function call=*/ true);
+    if (start != pos) {
+        if (token == T_POUND) {
+            const int column = pos - m_interface->document()->findBlock(start).position();
+            if (column != 1)
+                return false;
+        }
+
+        return true;
+    } else {
+        // Trigger completion after three characters of a name have been typed, when not editing an existing name
+        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,110 +758,265 @@ 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;
+                }
+            }
+        }
+        // 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;
                     }
                 }
             }
+
+            if (!include) {
+                *kind = T_EOF_SYMBOL;
+                start = pos;
+            }
         }
     }
+
+    return start;
+}
+
+int CppCompletionAssistProcessor::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 CppCodeCompletion::tryObjCCompletion(TextEditor::BaseTextEditorWidget *edit)
+int CppCompletionAssistProcessor::startCompletionHelper()
 {
-    Q_ASSERT(edit);
+    if (m_objcEnabled) {
+        if (tryObjCCompletion())
+            return m_startPosition;
+    }
+
+    const int startOfName = findStartOfName();
+    m_startPosition = startOfName;
+    m_model->m_completionOperator = T_EOF_SYMBOL;
+
+    int endOfOperator = m_startPosition;
+
+    // Skip whitespace preceding this position
+    while (m_interface->characterAt(endOfOperator - 1).isSpace())
+        --endOfOperator;
+
+    int endOfExpression = startOfOperator(endOfOperator,
+                                          &m_model->m_completionOperator,
+                                          /*want function call =*/ true);
+
+    const Core::IFile *file = m_interface->file();
+    QString fileName = file->fileName();
+
+    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_model->m_completionOperator == T_POUND) {
+        completePreprocessor();
+        m_startPosition = startOfName;
+        return m_startPosition;
+    }
+
+    // Include completion
+    if (m_model->m_completionOperator == T_STRING_LITERAL
+        || m_model->m_completionOperator == T_ANGLE_STRING_LITERAL
+        || m_model->m_completionOperator == T_SLASH) {
+
+        QTextCursor c(m_interface->document());
+        c.setPosition(endOfExpression);
+        if (completeInclude(c))
+            m_startPosition = startOfName;
+        return m_startPosition;
+    }
+
+    ExpressionUnderCursor expressionUnderCursor;
+    QTextCursor tc(m_interface->document());
+
+    if (m_model->m_completionOperator == T_COMMA) {
+        tc.setPosition(endOfExpression);
+        const int start = expressionUnderCursor.startOfFunctionCall(tc);
+        if (start == -1) {
+            m_model->m_completionOperator = T_EOF_SYMBOL;
+            return -1;
+        }
+
+        endOfExpression = start;
+        m_startPosition = start + 1;
+        m_model->m_completionOperator = T_LPAREN;
+    }
+
+    QString expression;
+    int startOfExpression = m_interface->position();
+    tc.setPosition(endOfExpression);
+
+    if (m_model->m_completionOperator) {
+        expression = expressionUnderCursor(tc);
+        startOfExpression = endOfExpression - expression.length();
+
+        if (m_model->m_completionOperator == T_LPAREN) {
+            if (expression.endsWith(QLatin1String("SIGNAL")))
+                m_model->m_completionOperator = T_SIGNAL;
+
+            else if (expression.endsWith(QLatin1String("SLOT")))
+                m_model->m_completionOperator = T_SLOT;
+
+            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_model->m_completionOperator = T_EOF_SYMBOL;
+                m_startPosition = startOfName;
+                startOfExpression = m_interface->position();
+            }
+        }
+    } else if (expression.isEmpty()) {
+        while (startOfExpression > 0 && m_interface->characterAt(startOfExpression).isSpace())
+            --startOfExpression;
+    }
+
+    int line = 0, column = 0;
+    Convenience::convertPosition(m_interface->document(), startOfExpression, &line, &column);
+    return startCompletionInternal(fileName, line, column, expression, endOfExpression);
+}
 
-    int end = m_editor->position();
-    while (m_editor->characterAt(end).isSpace())
+bool CppCompletionAssistProcessor::tryObjCCompletion()
+{
+    int end = m_interface->position();
+    while (m_interface->characterAt(end).isSpace())
         ++end;
-    if (m_editor->characterAt(end) != QLatin1Char(']'))
+    if (m_interface->characterAt(end) != QLatin1Char(']'))
         return false;
 
-    QTextCursor tc(edit->document());
+    QTextCursor tc(m_interface->document());
     tc.setPosition(end);
     BackwardsScanner tokens(tc);
     if (tokens[tokens.startToken() - 1].isNot(T_RBRACKET))
@@ -833,22 +1027,21 @@ bool CppCodeCompletion::tryObjCCompletion(TextEditor::BaseTextEditorWidget *edit
         return false;
 
     const int startPos = tokens[start].begin() + tokens.startPosition();
-    const QString expr = m_editor->textAt(startPos, m_editor->position() - startPos);
+    const QString expr = m_interface->textAt(startPos, m_interface->position() - startPos);
 
-    const Snapshot snapshot = m_manager->snapshot();
-    Document::Ptr thisDocument = snapshot.document(m_editor->file()->fileName());
+    Document::Ptr thisDocument = m_model->m_snapshot.document(m_interface->file()->fileName());
     if (! thisDocument)
         return false;
 
-    typeOfExpression.init(thisDocument, snapshot);
+    typeOfExpression.init(thisDocument, m_model->m_snapshot);
     int line = 0, column = 0;
-    edit->convertPosition(m_editor->position(), &line, &column);
+    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, snapshot);
+    LookupContext lookupContext(thisDocument, m_model->m_snapshot);
 
     foreach (const LookupItem &item, items) {
         FullySpecifiedType ty = item.type().simplified();
@@ -870,141 +1063,168 @@ bool CppCodeCompletion::tryObjCCompletion(TextEditor::BaseTextEditorWidget *edit
     if (m_completions.isEmpty())
         return false;
 
-    m_startPosition = m_editor->position();
+    m_startPosition = m_interface->position();
     return true;
 }
 
-int CppCodeCompletion::startCompletionHelper(TextEditor::ITextEditor *editor)
+void CppCompletionAssistProcessor::addCompletionItem(const QString &text,
+                                                     const QIcon &icon,
+                                                     int order,
+                                                     const QVariant &data)
 {
-    TextEditor::BaseTextEditorWidget *edit = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget());
-    if (! edit)
-        return -1;
-
-    m_editor = editor;
+    BasicProposalItem *item = new CppAssistProposalItem;
+    item->setText(text);
+    item->setIcon(icon);
+    item->setOrder(order);
+    item->setData(data);
+    m_completions.append(item);
+}
 
-    if (m_objcEnabled) {
-        if (tryObjCCompletion(edit))
-            return m_startPosition;
+void CppCompletionAssistProcessor::addCompletionItem(CPlusPlus::Symbol *symbol)
+{
+    ConvertToCompletionItem toCompletionItem;
+    BasicProposalItem *item = toCompletionItem(symbol);
+    if (item) {
+        item->setIcon(m_icons.iconForSymbol(symbol));
+        m_completions.append(item);
     }
+}
 
-    const int startOfName = findStartOfName();
-    m_startPosition = startOfName;
-    m_completionOperator = T_EOF_SYMBOL;
-
-    int endOfOperator = m_startPosition;
-
-    // Skip whitespace preceding this position
-    while (editor->characterAt(endOfOperator - 1).isSpace())
-        --endOfOperator;
+void CppCompletionAssistProcessor::completeObjCMsgSend(CPlusPlus::ClassOrNamespace *binding,
+                                                       bool staticClassAccess)
+{
+    QList<Scope*> memberScopes;
+    foreach (Symbol *s, binding->symbols()) {
+        if (ObjCClass *c = s->asObjCClass())
+            memberScopes.append(c);
+    }
 
-    int endOfExpression = startOfOperator(editor, endOfOperator,
-                                          &m_completionOperator,
-                                          /*want function call =*/ true);
+    foreach (Scope *scope, memberScopes) {
+        for (unsigned i = 0; i < scope->memberCount(); ++i) {
+            Symbol *symbol = scope->memberAt(i);
 
-    Core::IFile *file = editor->file();
-    QString fileName = file->fileName();
+            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 (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 (!text.isEmpty())
+                        addCompletionItem(text, QIcon(), 0, QVariant::fromValue(data));
+                }
+            }
         }
-
-        return m_startPosition;
     }
+}
 
-    // Pre-processor completion
-    if (m_completionOperator == T_POUND) {
-        completePreprocessor();
-        m_startPosition = startOfName;
-        return m_startPosition;
+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);
     }
 
-    // Include completion
-    if (m_completionOperator == T_STRING_LITERAL
-        || m_completionOperator == T_ANGLE_STRING_LITERAL
-        || m_completionOperator == T_SLASH) {
-
-        QTextCursor c = edit->textCursor();
-        c.setPosition(endOfExpression);
-        if (completeInclude(c))
-            m_startPosition = startOfName;
-        return m_startPosition;
+    // 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());
     }
 
-    ExpressionUnderCursor expressionUnderCursor;
-    QTextCursor tc(edit->document());
-
-    if (m_completionOperator == T_COMMA) {
-        tc.setPosition(endOfExpression);
-        const int start = expressionUnderCursor.startOfFunctionCall(tc);
-        if (start == -1) {
-            m_completionOperator = T_EOF_SYMBOL;
-            return -1;
+    foreach (const QString &frameworkPath, m_interface->frameworkPaths()) {
+        QString realPath = frameworkPath;
+        if (!directoryPrefix.isEmpty()) {
+            realPath += QLatin1Char('/');
+            realPath += directoryPrefix;
+            realPath += QLatin1String(".framework/Headers");
         }
-
-        endOfExpression = start;
-        m_startPosition = start + 1;
-        m_completionOperator = T_LPAREN;
+        foreach (const QString &itemText, manager->includesInPath(realPath))
+            addCompletionItem(itemText, m_icons.keywordIcon());
     }
 
-    QString expression;
-    int startOfExpression = editor->position();
-    tc.setPosition(endOfExpression);
+    return !m_completions.isEmpty();
+}
 
-    if (m_completionOperator) {
-        expression = expressionUnderCursor(tc);
-        startOfExpression = endOfExpression - expression.length();
+void CppCompletionAssistProcessor::completePreprocessor()
+{
+    foreach (const QString &preprocessorCompletion, preprocessorCompletions)
+        addCompletionItem(preprocessorCompletion);
 
-        if (m_completionOperator == T_LPAREN) {
-            if (expression.endsWith(QLatin1String("SIGNAL")))
-                m_completionOperator = T_SIGNAL;
+    if (objcKeywordsWanted())
+        addCompletionItem(QLatin1String("import"));
+}
 
-            else if (expression.endsWith(QLatin1String("SLOT")))
-                m_completionOperator = T_SLOT;
+bool CppCompletionAssistProcessor::objcKeywordsWanted() const
+{
+    if (!m_objcEnabled)
+        return false;
 
-            else if (editor->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_startPosition = startOfName;
-                startOfExpression = editor->position();
-            }
-        }
-    } else if (expression.isEmpty()) {
-        while (startOfExpression > 0 && editor->characterAt(startOfExpression).isSpace())
-            --startOfExpression;
-    }
+    const Core::IFile *file = m_interface->file();
+    QString fileName = file->fileName();
 
-    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);
+    const Core::MimeDatabase *mdb = Core::ICore::instance()->mimeDatabase();
+    return mdb->findByFile(fileName).type() == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE;
 }
 
-int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditorWidget *edit,
-                                               const QString fileName,
-                                               unsigned line, unsigned column,
-                                               const QString &expr,
-                                               int endOfExpression)
+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;
@@ -1059,375 +1279,138 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditorWidget
             }
             return -1;
 
-        } else {
-            // nothing to do.
-            return -1;
-
-        }
-    }
-
-    switch (m_completionOperator) {
-    case T_LPAREN:
-        if (completeConstructorOrFunction(results, endOfExpression, false))
-            return m_startPosition;
-        break;
-
-    case T_DOT:
-    case T_ARROW:
-        if (completeMember(results))
-            return m_startPosition;
-        break;
-
-    case T_COLON_COLON:
-        if (completeScope(results))
-            return m_startPosition;
-        break;
-
-    case T_SIGNAL:
-        if (completeSignal(results))
-            return m_startPosition;
-        break;
-
-    case T_SLOT:
-        if (completeSlot(results))
-            return m_startPosition;
-        break;
-
-    default:
-        break;
-    } // end of switch
-
-    // nothing to do.
-    return -1;
-}
-
-void CppCodeCompletion::globalCompletion(Scope *currentScope)
-{
-    const LookupContext &context = typeOfExpression.context();
-
-    if (m_completionOperator == T_COLON_COLON) {
-        completeNamespace(context.globalNamespace());
-        return;
-    }
-
-    QList<ClassOrNamespace *> usingBindings;
-    ClassOrNamespace *currentBinding = 0;
-
-    for (Scope *scope = currentScope; scope; scope = scope->enclosingScope()) {
-        if (scope->isBlock()) {
-            if (ClassOrNamespace *binding = context.lookupType(scope)) {
-                for (unsigned i = 0; i < scope->memberCount(); ++i) {
-                    Symbol *member = scope->memberAt(i);
-                    if (! member->name())
-                        continue;
-                    else if (UsingNamespaceDirective *u = member->asUsingNamespaceDirective()) {
-                        if (ClassOrNamespace *b = binding->lookupType(u->name()))
-                            usingBindings.append(b);
-                    }
-                }
-            }
-        } else if (scope->isFunction() || scope->isClass() || scope->isNamespace()) {
-            currentBinding = context.lookupType(scope);
-            break;
-        }
-    }
-
-    for (Scope *scope = currentScope; scope; scope = scope->enclosingScope()) {
-        if (scope->isBlock()) {
-            for (unsigned i = 0; i < scope->memberCount(); ++i) {
-                addCompletionItem(scope->memberAt(i));
-            }
-        } else if (scope->isFunction()) {
-            Function *fun = scope->asFunction();
-            for (unsigned i = 0; i < fun->argumentCount(); ++i) {
-                addCompletionItem(fun->argumentAt(i));
-            }
-            break;
-        } else {
-            break;
-        }
-    }
-
-    for (; currentBinding; currentBinding = currentBinding->parent()) {
-        const QList<Symbol *> symbols = currentBinding->symbols();
-
-        if (! symbols.isEmpty()) {
-            if (symbols.first()->isNamespace())
-                completeNamespace(currentBinding);
-            else
-                completeClass(currentBinding);
-        }
-    }
-
-    foreach (ClassOrNamespace *b, usingBindings)
-        completeNamespace(b);
-
-    addKeywords();
-    addMacros(QLatin1String("<configuration>"), context.snapshot());
-    addMacros(context.thisDocument()->fileName(), context.snapshot());
-    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)
-{
-    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.
+        } else {
+            // nothing to do.
+            return -1;
 
-        // 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
+    switch (m_model->m_completionOperator) {
+    case T_LPAREN:
+        if (completeConstructorOrFunction(results, endOfExpression, false))
+            return m_startPosition;
+        break;
 
-        Scope *sc = context.thisDocument()->scopeAt(line, column);
+    case T_DOT:
+    case T_ARROW:
+        if (completeMember(results))
+            return m_startPosition;
+        break;
 
-        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;
+    case T_COLON_COLON:
+        if (completeScope(results))
+            return m_startPosition;
+        break;
 
-            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("();");
+    case T_SIGNAL:
+        if (completeSignal(results))
+            return m_startPosition;
+        break;
 
-            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()) {
+    case T_SLOT:
+        if (completeSlot(results))
+            return m_startPosition;
+        break;
 
-                        autocompleteSignature = true;
+    default:
+        break;
+    } // end of switch
 
-                        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;
-                            }
-                        }
-                    }
-                }
-            }
+    // nothing to do.
+    return -1;
+}
 
-            if (autocompleteSignature && !isDestructor) {
-                // set up signature autocompletion
-                foreach (Function *f, functions) {
-                    Overview overview;
-                    overview.setShowArgumentNames(true);
-                    overview.setShowDefaultArguments(false);
+void CppCompletionAssistProcessor::globalCompletion(CPlusPlus::Scope *currentScope)
+{
+    const LookupContext &context = typeOfExpression.context();
 
-                    // gets: "parameter list) cv-spec",
-                    QString completion = overview(f->type()).mid(1);
+    if (m_model->m_completionOperator == T_COLON_COLON) {
+        completeNamespace(context.globalNamespace());
+        return;
+    }
+
+    QList<ClassOrNamespace *> usingBindings;
+    ClassOrNamespace *currentBinding = 0;
 
-                    TextEditor::CompletionItem item(this);
-                    item.text = completion;
-                    item.data = QVariant::fromValue(CompleteFunctionDeclaration(f));
-                    m_completions.append(item);
+    for (Scope *scope = currentScope; scope; scope = scope->enclosingScope()) {
+        if (scope->isBlock()) {
+            if (ClassOrNamespace *binding = context.lookupType(scope)) {
+                for (unsigned i = 0; i < scope->memberCount(); ++i) {
+                    Symbol *member = scope->memberAt(i);
+                    if (! member->name())
+                        continue;
+                    else if (UsingNamespaceDirective *u = member->asUsingNamespaceDirective()) {
+                        if (ClassOrNamespace *b = binding->lookupType(u->name()))
+                            usingBindings.append(b);
+                    }
                 }
-                return true;
             }
+        } else if (scope->isFunction() || scope->isClass() || scope->isNamespace()) {
+            currentBinding = context.lookupType(scope);
+            break;
         }
     }
 
-    if (! functions.empty() && !isDestructor) {
-        // set up function call tooltip
+    for (Scope *scope = currentScope; scope; scope = scope->enclosingScope()) {
+        if (scope->isBlock()) {
+            for (unsigned i = 0; i < scope->memberCount(); ++i) {
+                addCompletionItem(scope->memberAt(i));
+            }
+        } else if (scope->isFunction()) {
+            Function *fun = scope->asFunction();
+            for (unsigned i = 0; i < fun->argumentCount(); ++i) {
+                addCompletionItem(fun->argumentAt(i));
+            }
+            break;
+        } else {
+            break;
+        }
+    }
 
-        // Recreate if necessary
-        if (!m_functionArgumentWidget)
-            m_functionArgumentWidget = new FunctionArgumentWidget;
+    for (; currentBinding; currentBinding = currentBinding->parent()) {
+        const QList<Symbol *> symbols = currentBinding->symbols();
 
-        m_functionArgumentWidget->showFunctionHint(functions,
-                                                   typeOfExpression.context(),
-                                                   m_startPosition);
+        if (! symbols.isEmpty()) {
+            if (symbols.first()->isNamespace())
+                completeNamespace(currentBinding);
+            else
+                completeClass(currentBinding);
+        }
     }
 
-    return false;
+    foreach (ClassOrNamespace *b, usingBindings)
+        completeNamespace(b);
+
+    addKeywords();
+    addMacros(QLatin1String("<configuration>"), context.snapshot());
+    addMacros(context.thisDocument()->fileName(), context.snapshot());
+    addSnippets();
 }
 
-bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults)
+bool CppCompletionAssistProcessor::completeMember(const QList<CPlusPlus::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;
+    m_completions.append(m_snippetCollector.collect());
+}
 
-    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);
-                }
-            }
-        }
-    }
+void CppCompletionAssistProcessor::addKeywords()
+{
+    int keywordLimit = T_FIRST_OBJC_AT_KEYWORD;
+    if (objcKeywordsWanted())
+        keywordLimit = T_LAST_OBJC_AT_KEYWORD + 1;
 
-    if (m_automaticCompletion && completions->size() == 1 && key == completions->first().text) {
-        completions->clear();
-    }
+    // keyword completion items.
+    for (int i = T_FIRST_KEYWORD; i < keywordLimit; ++i)
+        addCompletionItem(QLatin1String(Token::name(i)), m_icons.keywordIcon());
 }
 
-QList<TextEditor::CompletionItem> CppCodeCompletion::removeDuplicates(const QList<TextEditor::CompletionItem> &items)
+void CppCompletionAssistProcessor::addMacros(const QString &fileName, const CPlusPlus::Snapshot &snapshot)
 {
-    // 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;
-                    }
-                }
-            }
-        }
-    }
-
-    return uniquelist;
-}
+    QSet<QString> definedMacros;
 
-QList<TextEditor::CompletionItem> CppCodeCompletion::getCompletions()
-{
-    QList<TextEditor::CompletionItem> completionItems;
-    completions(&completionItems);
+    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 (file)
index 0000000..8ed0282
--- /dev/null
@@ -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
index f970e74..ca8d89c 100644 (file)
@@ -10,7 +10,6 @@ INCLUDEPATH += .
 DEFINES += CPPTOOLS_LIBRARY
 HEADERS += completionsettingspage.h \
     cppclassesfilter.h \
-    cppcodecompletion.h \
     cppcurrentdocumentfilter.h \
     cppfunctionsfilter.h \
     cppmodelmanager.h \
@@ -28,11 +27,11 @@ HEADERS += completionsettingspage.h \
     uicodecompletionsupport.h \
     insertionpointlocator.h \
     cpprefactoringchanges.h \
-    abstracteditorsupport.h
+    abstracteditorsupport.h \
+    cppcompletionassist.h
 
 SOURCES += completionsettingspage.cpp \
     cppclassesfilter.cpp \
-    cppcodecompletion.cpp \
     cppcurrentdocumentfilter.cpp \
     cppfunctionsfilter.cpp \
     cppmodelmanager.cpp \
@@ -48,7 +47,8 @@ SOURCES += completionsettingspage.cpp \
     symbolsfindfilter.cpp \
     uicodecompletionsupport.cpp \
     insertionpointlocator.cpp \
-    cpprefactoringchanges.cpp
+    cpprefactoringchanges.cpp \
+    cppcompletionassist.cpp
 
 FORMS += completionsettingspage.ui \
     cppfilesettingspage.ui
index 44f2da4..8bff1f8 100644 (file)
 #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;
 }
 
index b34d673..d65121f 100644 (file)
 #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 (file)
index 5493ad7..0000000
+++ /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 (file)
index bb3d10a..0000000
+++ /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 (file)
index 0000000..125dbad
--- /dev/null
@@ -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 (file)
index 0000000..78daea8
--- /dev/null
@@ -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
index 83c84d1..18fa552 100644 (file)
@@ -37,6 +37,7 @@
 #include "glslhighlighter.h"
 #include "glslautocompleter.h"
 #include "glslindenter.h"
+#include "glslcompletionassist.h"
 
 #include <glsl/glsllexer.h>
 #include <glsl/glslparser.h>
@@ -412,3 +413,17 @@ Document::Ptr GLSLTextEditorWidget::glslDocument() const
 {
     return m_glslDocument;
 }
+
+TextEditor::IAssistInterface *GLSLTextEditorWidget::createAssistInterface(
+    TextEditor::AssistKind kind,
+    TextEditor::AssistReason reason) const
+{
+    if (kind == TextEditor::Completion)
+        return new GLSLCompletionAssistInterface(document(),
+                                                 position(),
+                                                 editor()->file(),
+                                                 reason,
+                                                 mimeType(),
+                                                 glslDocument());
+    return BaseTextEditorWidget::createAssistInterface(kind, reason);
+}
index 8c5712d..ba228f4 100644 (file)
@@ -104,6 +104,9 @@ public:
 
     Document::Ptr glslDocument() const;
 
+    TextEditor::IAssistInterface *createAssistInterface(TextEditor::AssistKind assistKind,
+                                                        TextEditor::AssistReason reason) const;
+
 public slots:
     virtual void setFontSettings(const TextEditor::FontSettings &);
 
index be0cdf3..7a53858 100644 (file)
@@ -17,10 +17,11 @@ glsleditorfactory.h \
 glsleditorplugin.h \
 glslfilewizard.h \
 glslhighlighter.h \
-glslcodecompletion.h \
 glslautocompleter.h \
 glslindenter.h \
-glslhoverhandler.h
+glslhoverhandler.h \
+    glslcompletionassist.h \
+    reuse.h
 
 SOURCES += \
 glsleditor.cpp \
@@ -30,10 +31,11 @@ glsleditorfactory.cpp \
 glsleditorplugin.cpp \
 glslfilewizard.cpp \
 glslhighlighter.cpp \
-glslcodecompletion.cpp \
 glslautocompleter.cpp \
 glslindenter.cpp \
-glslhoverhandler.cpp
+glslhoverhandler.cpp \
+    glslcompletionassist.cpp \
+    reuse.cpp
 
 OTHER_FILES += GLSLEditor.mimetypes.xml
 RESOURCES += glsleditor.qrc
index 7e372bf..3199828 100644 (file)
@@ -34,9 +34,9 @@
 #include "glsleditor.h"
 #include "glsleditorconstants.h"
 #include "glsleditorfactory.h"
-#include "glslcodecompletion.h"
 #include "glslfilewizard.h"
 #include "glslhoverhandler.h"
+#include "glslcompletionassist.h"
 
 #include <coreplugin/icore.h>
 #include <coreplugin/coreconstants.h>
@@ -55,7 +55,6 @@
 #include <texteditor/texteditorsettings.h>
 #include <texteditor/textfilewizard.h>
 #include <texteditor/texteditoractionhandler.h>
-#include <texteditor/completionsupport.h>
 #include <utils/qtcassert.h>
 
 #include <glsl/glslengine.h>
@@ -132,8 +131,7 @@ bool GLSLEditorPlugin::initialize(const QStringList & /*arguments*/, QString *er
     m_editor = new GLSLEditorFactory(this);
     addObject(m_editor);
 
-    CodeCompletion *completion = new CodeCompletion(this);
-    addAutoReleasedObject(completion);
+    addAutoReleasedObject(new GLSLCompletionAssistProvider);
 
     m_actionHandler = new TextEditor::TextEditorActionHandler(GLSLEditor::Constants::C_GLSLEDITOR_ID,
                                                               TextEditor::TextEditorActionHandler::Format
@@ -164,12 +162,6 @@ bool GLSLEditorPlugin::initialize(const QStringList & /*arguments*/, QString *er
     cmd = am->command(TextEditor::Constants::UN_COMMENT_SELECTION);
     contextMenu->addAction(cmd);
 
-    // Set completion settings and keep them up to date
-    TextEditor::TextEditorSettings *textEditorSettings = TextEditor::TextEditorSettings::instance();
-    completion->setCompletionSettings(textEditorSettings->completionSettings());
-    connect(textEditorSettings, SIGNAL(completionSettingsChanged(TextEditor::CompletionSettings)),
-            completion, SLOT(setCompletionSettings(TextEditor::CompletionSettings)));
-
     error_message->clear();
 
     Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
diff --git a/src/plugins/glsleditor/reuse.cpp b/src/plugins/glsleditor/reuse.cpp
new file mode 100644 (file)
index 0000000..aeb8932
--- /dev/null
@@ -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 (file)
index 0000000..5fb1211
--- /dev/null
@@ -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 (file)
index 9ad60f4..0000000
+++ /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 (file)
index ba30834..0000000
+++ /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 (file)
index 0000000..6de4e82
--- /dev/null
@@ -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 (file)
index 0000000..3826f05
--- /dev/null
@@ -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
index 65824f2..a85e4b0 100644 (file)
@@ -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));
             }
         }
     }
index ccab5b0..0467621 100644 (file)
@@ -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
index 41f9646..017ae2b 100644 (file)
 #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;
+}
index 6eb3bc1..dabe5bf 100644 (file)
@@ -160,6 +160,9 @@ public:
 
     static QVector<QString> highlighterFormatCategories();
 
+    TextEditor::IAssistInterface *createAssistInterface(TextEditor::AssistKind assistKind,
+                                                        TextEditor::AssistReason reason) const;
+
 public slots:
     void forceSemanticRehighlight();
     void followSymbolUnderCursor();
index 6d08513..b52dcfc 100644 (file)
@@ -8,7 +8,6 @@ DEFINES += \
     QT_CREATOR
 
 HEADERS += \
-    qmljscodecompletion.h \
     qmljseditor.h \
     qmljseditor_global.h \
     qmljseditoractionhandler.h \
@@ -20,7 +19,6 @@ HEADERS += \
     qmljshighlighter.h \
     qmljshoverhandler.h \
     qmljspreviewrunner.h \
-    qmljsquickfix.h \
     qmljscomponentfromobjectdef.h \
     qmljsoutline.h \
     qmloutlinemodel.h \
@@ -35,10 +33,13 @@ HEADERS += \
     qmljsindenter.h \
     qmljsautocompleter.h \
     jsfilewizard.h \
-    qmljssnippetprovider.h
+    qmljssnippetprovider.h \
+    qmljsreuse.h \
+    qmljsquickfixassist.h \
+    qmljscompletionassist.h \
+    qmljsquickfix.h
 
 SOURCES += \
-    qmljscodecompletion.cpp \
     qmljseditor.cpp \
     qmljseditoractionhandler.cpp \
     qmljseditorfactory.cpp \
@@ -48,7 +49,6 @@ SOURCES += \
     qmljshighlighter.cpp \
     qmljshoverhandler.cpp \
     qmljspreviewrunner.cpp \
-    qmljsquickfix.cpp \
     qmljscomponentfromobjectdef.cpp \
     qmljsoutline.cpp \
     qmloutlinemodel.cpp \
@@ -64,7 +64,11 @@ SOURCES += \
     qmljsindenter.cpp \
     qmljsautocompleter.cpp \
     jsfilewizard.cpp \
-    qmljssnippetprovider.cpp
+    qmljssnippetprovider.cpp \
+    qmljsreuse.cpp \
+    qmljsquickfixassist.cpp \
+    qmljscompletionassist.cpp \
+    qmljsquickfix.cpp
 
 RESOURCES += qmljseditor.qrc
 OTHER_FILES += QmlJSEditor.mimetypes.xml
index 3aebcee..e18c8e6 100644 (file)
 #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)
index 5451ab3..18f43d2 100644 (file)
@@ -68,7 +68,7 @@ namespace Internal {
 
 class QmlJSEditorFactory;
 class QmlJSPreviewRunner;
-class QmlJSQuickFixCollector;
+class QmlJSQuickFixAssistProvider;
 class QmlTaskManager;
 
 class QmlJSEditorPlugin : public ExtensionSystem::IPlugin
@@ -87,7 +87,7 @@ public:
     static QmlJSEditorPlugin *instance()
     { return m_instance; }
 
-    QmlJSQuickFixCollector *quickFixCollector() const;
+    QmlJSQuickFixAssistProvider *quickFixAssistProvider() const;
 
     void initializeEditor(QmlJSEditor::QmlJSTextEditorWidget *editor);
 
@@ -97,8 +97,6 @@ public Q_SLOTS:
     void showContextPane();
 
 private Q_SLOTS:
-    void quickFix(TextEditor::ITextEditor *editable);
-    void quickFixNow();
     void currentEditorChanged(Core::IEditor *editor);
 
 private:
@@ -115,9 +113,8 @@ private:
     QmlJSEditorFactory *m_editor;
     TextEditor::TextEditorActionHandler *m_actionHandler;
 
-    QmlJSQuickFixCollector *m_quickFixCollector;
+    QmlJSQuickFixAssistProvider *m_quickFixAssistProvider;
 
-    QTimer *m_quickFixTimer;
     QPointer<TextEditor::ITextEditor> m_currentTextEditable;
     QmlTaskManager *m_qmlTaskManager;
 };
index 1146ae3..b0a411f 100644 (file)
@@ -56,8 +56,6 @@ class QmlJSTextEditorWidget;
 
 namespace Internal {
 
-class SemanticInfo;
-
 class HoverHandler : public TextEditor::BaseHoverHandler
 {
     Q_OBJECT
index 3e8115d..f00a0ed 100644 (file)
@@ -34,6 +34,7 @@
 #include "qmljscomponentfromobjectdef.h"
 #include "qmljseditor.h"
 #include "qmljs/parser/qmljsast_p.h"
+#include "qmljsquickfixassist.h"
 
 #include <extensionsystem/iplugin.h>
 #include <extensionsystem/pluginmanager.h>
@@ -50,34 +51,11 @@ using namespace QmlJSTools;
 using namespace TextEditor;
 using TextEditor::RefactoringChanges;
 
-QmlJSQuickFixState::QmlJSQuickFixState(TextEditor::BaseTextEditorWidget *editor)
-    : QuickFixState(editor)
-{
-}
-
-SemanticInfo QmlJSQuickFixState::semanticInfo() const
-{
-    return _semanticInfo;
-}
-
-Snapshot QmlJSQuickFixState::snapshot() const
-{
-    return _semanticInfo.snapshot;
-}
-
-Document::Ptr QmlJSQuickFixState::document() const
-{
-    return _semanticInfo.document;
-}
-
-const QmlJSRefactoringFile QmlJSQuickFixState::currentFile() const
-{
-    return QmlJSRefactoringFile(editor(), document());
-}
-
-QmlJSQuickFixOperation::QmlJSQuickFixOperation(const QmlJSQuickFixState &state, int priority)
+QmlJSQuickFixOperation::QmlJSQuickFixOperation(
+        const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface,
+        int priority)
     : QuickFixOperation(priority)
-    , _state(state)
+    , m_interface(interface)
 {
 }
 
@@ -88,20 +66,21 @@ QmlJSQuickFixOperation::~QmlJSQuickFixOperation()
 void QmlJSQuickFixOperation::perform()
 {
     QmlJSRefactoringChanges refactoring(ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>(),
-                                    _state.snapshot());
+                                    //_state.snapshot());
+                                        m_interface->semanticInfo().snapshot);
     QmlJSRefactoringFile current = refactoring.file(fileName());
 
     performChanges(&current, &refactoring);
 }
 
-const QmlJSQuickFixState &QmlJSQuickFixOperation::state() const
+const QmlJSQuickFixAssistInterface *QmlJSQuickFixOperation::assistInterface() const
 {
-    return _state;
+    return m_interface.data();
 }
 
 QString QmlJSQuickFixOperation::fileName() const
 {
-    return state().document()->fileName();
+    return m_interface->semanticInfo().document->fileName();
 }
 
 QmlJSQuickFixFactory::QmlJSQuickFixFactory()
@@ -112,12 +91,10 @@ QmlJSQuickFixFactory::~QmlJSQuickFixFactory()
 {
 }
 
-QList<QuickFixOperation::Ptr> QmlJSQuickFixFactory::matchingOperations(QuickFixState *state)
+QList<QuickFixOperation::Ptr> QmlJSQuickFixFactory::matchingOperations(
+    const QSharedPointer<const TextEditor::IAssistInterface> &interface)
 {
-    if (QmlJSQuickFixState *qmljsState = static_cast<QmlJSQuickFixState *>(state))
-        return match(*qmljsState);
-    else
-        return QList<TextEditor::QuickFixOperation::Ptr>();
+    return match(interface.staticCast<const QmlJSQuickFixAssistInterface>());
 }
 
 QList<QmlJSQuickFixOperation::Ptr> QmlJSQuickFixFactory::noResult()
@@ -131,49 +108,3 @@ QList<QmlJSQuickFixOperation::Ptr> QmlJSQuickFixFactory::singleResult(QmlJSQuick
     result.append(QmlJSQuickFixOperation::Ptr(operation));
     return result;
 }
-
-QmlJSQuickFixCollector::QmlJSQuickFixCollector()
-{
-}
-
-QmlJSQuickFixCollector::~QmlJSQuickFixCollector()
-{
-}
-
-bool QmlJSQuickFixCollector::supportsEditor(TextEditor::ITextEditor *editable) const
-{
-    return qobject_cast<QmlJSTextEditorWidget *>(editable->widget()) != 0;
-}
-
-bool QmlJSQuickFixCollector::supportsPolicy(TextEditor::CompletionPolicy policy) const
-{
-    return policy == TextEditor::QuickFixCompletion;
-}
-
-TextEditor::QuickFixState *QmlJSQuickFixCollector::initializeCompletion(TextEditor::BaseTextEditorWidget *editor)
-{
-    if (QmlJSTextEditorWidget *qmljsEditor = qobject_cast<QmlJSTextEditorWidget *>(editor)) {
-        const SemanticInfo info = qmljsEditor->semanticInfo();
-
-        if (! info.isValid() || qmljsEditor->isOutdated()) {
-            // outdated
-            qWarning() << "TODO: outdated semantic info, force a reparse.";
-            return 0;
-        }
-
-        QmlJSQuickFixState *state = new QmlJSQuickFixState(editor);
-        state->_semanticInfo = info;
-        return state;
-    }
-
-    return 0;
-}
-
-QList<TextEditor::QuickFixFactory *> QmlJSQuickFixCollector::quickFixFactories() const
-{
-    QList<TextEditor::QuickFixFactory *> results;
-    ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
-    foreach (QmlJSQuickFixFactory *f, pm->getObjects<QmlJSEditor::QmlJSQuickFixFactory>())
-        results.append(f);
-    return results;
-}
index ca5dd5c..7529814 100644 (file)
@@ -40,6 +40,8 @@
 #include <qmljs/qmljsdocument.h>
 #include <qmljstools/qmljsrefactoringchanges.h>
 
+#include <QtCore/QSharedPointer>
+
 namespace ExtensionSystem {
 class IPlugin;
 }
@@ -51,40 +53,12 @@ namespace QmlJS {
 namespace QmlJSEditor {
 
 namespace Internal {
-class QmlJSQuickFixCollector;
+class QmlJSQuickFixAssistInterface;
 } // namespace Internal
 
-/*!
-    Specialized QuickFixState for QML/JavaScript quick-fixes.
-
-    This specialized state for QML/JavaScript quick-fixes also holds the
-    QmlJSEditor::Internal::SemanticInfo for the document in the editor.
- */
-class QmlJSQuickFixState: public TextEditor::QuickFixState
-{
-    friend class Internal::QmlJSQuickFixCollector;
-
-public:
-    /// Creates a new state for the given editor.
-    QmlJSQuickFixState(TextEditor::BaseTextEditorWidget *editor);
-
-    SemanticInfo semanticInfo() const;
-
-    /// \returns the snapshot holding the document of the editor.
-    QmlJS::Snapshot snapshot() const;
-
-    /// \returns the document of the editor
-    QmlJS::Document::Ptr document() const;
-
-    const QmlJSTools::QmlJSRefactoringFile currentFile() const;
-
-private:
-    SemanticInfo _semanticInfo;
-};
 
 /*!
-    A quick-fix operation for the QML/JavaScript editor, which works on a
-    QmlJSQuickFixState .
+    A quick-fix operation for the QML/JavaScript editor.
  */
 class QmlJSQuickFixOperation: public TextEditor::QuickFixOperation
 {
@@ -94,13 +68,12 @@ public:
     /*!
         Creates a new QmlJSQuickFixOperation.
 
-        This operation will copy the complete state, in order to be able to perform
-        its changes later on.
-
-        \param state The state for which this operation was created.
+        \param interface The interface on which the operation is performed.
         \param priority The priority for this operation.
      */
-    explicit QmlJSQuickFixOperation(const QmlJSQuickFixState &state, int priority = -1);
+    explicit QmlJSQuickFixOperation(
+        const QSharedPointer<const Internal::QmlJSQuickFixAssistInterface> &interface,
+        int priority = -1);
     virtual ~QmlJSQuickFixOperation();
 
     virtual void perform();
@@ -111,14 +84,13 @@ protected:
     virtual void performChanges(QmlJSTools::QmlJSRefactoringFile *currentFile,
                                 QmlJSTools::QmlJSRefactoringChanges *refactoring) = 0;
 
-    /// \returns A const-reference to the state of the operation.
-    const QmlJSQuickFixState &state() const;
+    const Internal::QmlJSQuickFixAssistInterface *assistInterface() const;
 
     /// \returns The name of the file for for which this operation is invoked.
     QString fileName() const;
 
 private:
-    QmlJSQuickFixState _state;
+    QSharedPointer<const Internal::QmlJSQuickFixAssistInterface> m_interface;
 };
 
 class QmlJSQuickFixFactory: public TextEditor::QuickFixFactory
@@ -129,39 +101,20 @@ public:
     QmlJSQuickFixFactory();
     virtual ~QmlJSQuickFixFactory();
 
-    virtual QList<TextEditor::QuickFixOperation::Ptr> matchingOperations(TextEditor::QuickFixState *state);
+    virtual QList<TextEditor::QuickFixOperation::Ptr>
+        matchingOperations(const QSharedPointer<const TextEditor::IAssistInterface> &interface);
 
     /*!
         Implement this method to match and create the appropriate
         QmlJSQuickFixOperation objects.
      */
-    virtual QList<QmlJSQuickFixOperation::Ptr> match(const QmlJSQuickFixState &state) = 0;
+    virtual QList<QmlJSQuickFixOperation::Ptr> match(
+        const QSharedPointer<const Internal::QmlJSQuickFixAssistInterface> &interface) = 0;
 
     static QList<QmlJSQuickFixOperation::Ptr> noResult();
     static QList<QmlJSQuickFixOperation::Ptr> singleResult(QmlJSQuickFixOperation *operation);
 };
 
-namespace Internal {
-
-class QmlJSQuickFixCollector: public TextEditor::QuickFixCollector
-{
-    Q_OBJECT
-
-public:
-    QmlJSQuickFixCollector();
-    virtual ~QmlJSQuickFixCollector();
-
-    virtual bool supportsEditor(TextEditor::ITextEditor *editor) const;
-    virtual bool supportsPolicy(TextEditor::CompletionPolicy policy) const;
-    virtual TextEditor::QuickFixState *initializeCompletion(TextEditor::BaseTextEditorWidget *editor);
-
-    virtual QList<TextEditor::QuickFixFactory *> quickFixFactories() const;
-
-    /// Registers all quick-fixes in this plug-in as auto-released objects.
-    static void registerQuickFixes(ExtensionSystem::IPlugin *plugIn);
-};
-
-} // namespace Internal
 } // namespace QmlJSEditor
 
 #endif // QMLJSQUICKFIX_H
diff --git a/src/plugins/qmljseditor/qmljsquickfixassist.cpp b/src/plugins/qmljseditor/qmljsquickfixassist.cpp
new file mode 100644 (file)
index 0000000..99a60ea
--- /dev/null
@@ -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 (file)
index 0000000..3427cb1
--- /dev/null
@@ -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
index 9650617..54c6820 100644 (file)
@@ -33,6 +33,7 @@
 #include "qmljsquickfix.h"
 #include "qmljscomponentfromobjectdef.h"
 #include "qmljseditor.h"
+#include "qmljsquickfixassist.h"
 
 #include <extensionsystem/iplugin.h>
 #include <extensionsystem/pluginmanager.h>
@@ -64,13 +65,14 @@ namespace {
 class SplitInitializerOp: public QmlJSQuickFixFactory
 {
 public:
-    virtual QList<QmlJSQuickFixOperation::Ptr> match(const QmlJSQuickFixState &state)
+    virtual QList<QmlJSQuickFixOperation::Ptr> match(
+        const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface)
     {
         UiObjectInitializer *objectInitializer = 0;
 
-        const int pos = state.currentFile().cursor().position();
+        const int pos = interface->currentFile().cursor().position();
 
-        if (QmlJS::AST::Node *member = state.semanticInfo().declaringMember(pos)) {
+        if (QmlJS::AST::Node *member = interface->semanticInfo().declaringMember(pos)) {
             if (QmlJS::AST::UiObjectBinding *b = QmlJS::AST::cast<QmlJS::AST::UiObjectBinding *>(member)) {
                 if (b->initializer->lbraceToken.startLine == b->initializer->rbraceToken.startLine)
                     objectInitializer = b->initializer;
@@ -82,7 +84,7 @@ public:
         }
 
         if (objectInitializer)
-            return singleResult(new Operation(state, objectInitializer));
+            return singleResult(new Operation(interface, objectInitializer));
         else
             return noResult();
     }
@@ -93,8 +95,9 @@ private:
         UiObjectInitializer *_objectInitializer;
 
     public:
-        Operation(const QmlJSQuickFixState &state, UiObjectInitializer *objectInitializer)
-            : QmlJSQuickFixOperation(state, 0)
+        Operation(const QSharedPointer<const QmlJSQuickFixAssistInterface> &interface,
+                  UiObjectInitializer *objectInitializer)
+            : QmlJSQuickFixOperation(interface, 0)
             , _objectInitializer(objectInitializer)
         {
             setDescription(QApplication::translate("QmlJSEditor::QuickFix",
@@ -129,7 +132,7 @@ private:
 
 } // end of anonymous namespace
 
-void QmlJSQuickFixCollector::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
+void registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
 {
     plugIn->addAutoReleasedObject(new SplitInitializerOp);
     plugIn->addAutoReleasedObject(new ComponentFromObjectDef);
diff --git a/src/plugins/qmljseditor/qmljsreuse.cpp b/src/plugins/qmljseditor/qmljsreuse.cpp
new file mode 100644 (file)
index 0000000..a60b0f4
--- /dev/null
@@ -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 (file)
index 0000000..0b5cf1f
--- /dev/null
@@ -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 (file)
index c8015c7..0000000
+++ /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 (file)
index 47f6646..0000000
+++ /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 (file)
index 0000000..2d6b25f
--- /dev/null
@@ -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 (file)
index 0000000..0569a57
--- /dev/null
@@ -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
index 00052b1..95fc5aa 100644 (file)
@@ -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>
index 436f450..86da78e 100644 (file)
@@ -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 \
index feb220c..c75d409 100644 (file)
@@ -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;
index f4dc040..211c7a8 100644 (file)
@@ -38,7 +38,6 @@
 #include "behaviorsettings.h"
 #include "codecselector.h"
 #include "completionsettings.h"
-#include "completionsupport.h"
 #include "tabsettings.h"
 #include "texteditorconstants.h"
 #include "texteditorplugin.h"
@@ -48,6 +47,9 @@
 #include "indenter.h"
 #include "autocompleter.h"
 #include "snippet.h"
+#include "codeassistant.h"
+#include "defaultassistinterface.h"
+#include "convenience.h"
 
 #include <aggregation/aggregate.h>
 #include <coreplugin/actionmanager/actionmanager.h>
@@ -236,11 +238,6 @@ BaseTextEditorWidget::BaseTextEditorWidget(QWidget *parent)
     d->m_highlightBlocksTimer->setSingleShot(true);
     connect(d->m_highlightBlocksTimer, SIGNAL(timeout()), this, SLOT(_q_highlightBlocks()));
 
-    d->m_requestAutoCompletionTimer = new QTimer(this);
-    d->m_requestAutoCompletionTimer->setSingleShot(true);
-    d->m_requestAutoCompletionTimer->setInterval(500);
-    connect(d->m_requestAutoCompletionTimer, SIGNAL(timeout()), this, SLOT(_q_requestAutoCompletion()));
-
     d->m_animator = 0;
 
     d->m_searchResultFormat.setBackground(QColor(0xffef0b));
@@ -490,7 +487,8 @@ ITextMarkable *BaseTextEditorWidget::markableInterface() const
 BaseTextEditor *BaseTextEditorWidget::editor() const
 {
     if (!d->m_editor) {
-        d->m_editor = const_cast<BaseTextEditorWidget*>(this)->createEditor();
+        d->m_editor = const_cast<BaseTextEditorWidget *>(this)->createEditor();
+        d->m_codeAssistant->configure(d->m_editor);
         connect(this, SIGNAL(textChanged()),
                 d->m_editor, SIGNAL(contentsChanged()));
         connect(this, SIGNAL(changed()),
@@ -668,6 +666,9 @@ void BaseTextEditorWidget::editorContentsChange(int position, int charsRemoved,
 
     if (doc->isRedoAvailable())
         emit editor()->contentsChangedBecauseOfUndo();
+
+    if (charsAdded != 0 && characterAt(position + charsAdded - 1).isPrint())
+        d->m_assistRelevantContentAdded = true;
 }
 
 void BaseTextEditorWidget::slotSelectionChanged()
@@ -1535,9 +1536,7 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
 
     if (!ro
         && (e == QKeySequence::InsertParagraphSeparator
-            || (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))
-        ) {
-
+            || (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))) {
         if (d->m_snippetOverlay->isVisible()) {
             e->accept();
             d->m_snippetOverlay->hide();
@@ -1548,7 +1547,6 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
             return;
         }
 
-
         QTextCursor cursor = textCursor();
         if (d->m_inBlockSelectionMode)
             cursor.clearSelection();
@@ -1702,7 +1700,8 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
     case Qt::Key_Right:
     case Qt::Key_Left:
 #ifndef Q_WS_MAC
-        if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) {
+        if ((e->modifiers()
+             & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) {
             int diff_row = 0;
             int diff_col = 0;
             if (e->key() == Qt::Key_Up)
@@ -1833,39 +1832,8 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
     if (!ro && e->key() == Qt::Key_Delete && d->m_parenthesesMatchingEnabled)
         d->m_parenthesesMatchingTimer->start(50);
 
-
-    if (!ro && d->m_contentsChanged && !e->text().isEmpty() && e->text().at(0).isPrint()) {
-        maybeRequestAutoCompletion(e->text().at(0));
-    }
-
-}
-
-void BaseTextEditorWidget::maybeRequestAutoCompletion(const QChar &ch)
-{
-    if (ch.isLetterOrNumber() || ch == QLatin1Char('_')) {
-        if (CompletionSupport::instance()->isActive())
-            d->m_requestAutoCompletionTimer->stop();
-        else {
-            d->m_requestAutoCompletionRevision = document()->revision();
-            d->m_requestAutoCompletionPosition = position();
-            d->m_requestAutoCompletionTimer->start();
-        }
-    } else {
-        d->m_requestAutoCompletionTimer->stop();
-        CompletionSupport::instance()->complete(editor(), SemanticCompletion, false);
-    }
-}
-
-void BaseTextEditorWidget::_q_requestAutoCompletion()
-{
-    d->m_requestAutoCompletionTimer->stop();
-
-    if (CompletionSupport::instance()->isActive())
-        return;
-
-    if (d->m_requestAutoCompletionRevision == document()->revision()
-            && d->m_requestAutoCompletionPosition == position())
-        CompletionSupport::instance()->complete(editor(), SemanticCompletion, false);
+    if (!ro && d->m_contentsChanged && !e->text().isEmpty() && e->text().at(0).isPrint())
+        d->m_codeAssistant->process();
 }
 
 void BaseTextEditorWidget::insertCodeSnippet(const QTextCursor &cursor_arg, const QString &snippet)
@@ -2025,14 +1993,7 @@ int BaseTextEditorWidget::position(ITextEditor::PositionOperation posOp, int at)
 
 void BaseTextEditorWidget::convertPosition(int pos, int *line, int *column) const
 {
-    QTextBlock block = document()->findBlock(pos);
-    if (!block.isValid()) {
-        (*line) = -1;
-        (*column) = -1;
-    } else {
-        (*line) = block.blockNumber() + 1;
-        (*column) = pos - block.position();
-    }
+    Convenience::convertPosition(document(), pos, line, column);
 }
 
 QChar BaseTextEditorWidget::characterAt(int pos) const
@@ -2087,6 +2048,7 @@ BaseTextDocument *BaseTextEditorWidget::baseTextDocument() const
     return d->m_document;
 }
 
+
 void BaseTextEditorWidget::setBaseTextDocument(BaseTextDocument *doc)
 {
     if (doc) {
@@ -2403,9 +2365,8 @@ BaseTextEditorPrivate::BaseTextEditorPrivate()
     m_findScopeVerticalBlockSelectionFirstColumn(-1),
     m_findScopeVerticalBlockSelectionLastColumn(-1),
     m_highlightBlocksTimer(0),
-    m_requestAutoCompletionRevision(0),
-    m_requestAutoCompletionPosition(0),
-    m_requestAutoCompletionTimer(0),
+    m_codeAssistant(new CodeAssistant),
+    m_assistRelevantContentAdded(false),
     m_cursorBlockNumber(-1),
     m_autoCompleter(new AutoCompleter),
     m_indenter(new Indenter)
@@ -3787,6 +3748,7 @@ void BaseTextEditorWidget::extraAreaPaintEvent(QPaintEvent *e)
             const QString &number = QString::number(blockNumber + 1);
             bool selected = (
                     (selStart < block.position() + block.length()
+
                     && selEnd > block.position())
                     || (selStart == selEnd && selStart == block.position())
                     );
@@ -3961,6 +3923,7 @@ void BaseTextEditorWidget::slotCursorPositionChanged()
     } else if (d->m_contentsChanged) {
         saveCurrentCursorPositionForNavigation();
     }
+
     updateHighlights();
 }
 
@@ -5650,8 +5613,8 @@ void BaseTextEditorWidget::insertFromMimeData(const QMimeData *source)
         if (text.isEmpty())
             return;
 
-        if (CompletionSupport::instance()->isActive())
-            setFocus();
+        if (d->m_codeAssistant->hasContext())
+            d->m_codeAssistant->destroyContext();
 
         QStringList lines = text.split(QLatin1Char('\n'));
         QTextCursor cursor = textCursor();
@@ -5696,8 +5659,8 @@ void BaseTextEditorWidget::insertFromMimeData(const QMimeData *source)
     if (text.isEmpty())
         return;
 
-    if (CompletionSupport::instance()->isActive())
-        setFocus();
+    if (d->m_codeAssistant->hasContext())
+        d->m_codeAssistant->destroyContext();
 
     if (d->m_snippetOverlay->isVisible() && (text.contains(QLatin1Char('\n'))
                                              || text.contains(QLatin1Char('\t')))) {
@@ -5882,18 +5845,7 @@ QString BaseTextEditor::selectedText() const
 
 QString BaseTextEditor::textAt(int pos, int length) const
 {
-    QTextCursor c = e->textCursor();
-
-    if (pos < 0)
-        pos = 0;
-    c.movePosition(QTextCursor::End);
-    if (pos + length > c.position())
-        length = c.position() - pos;
-
-    c.setPosition(pos);
-    c.setPosition(pos + length, QTextCursor::KeepAnchor);
-
-    return c.selectedText();
+    return Convenience::textAt(e->textCursor(), pos, length);
 }
 
 void BaseTextEditor::remove(int length)
@@ -6166,3 +6118,15 @@ void BaseTextEditorWidget::inSnippetMode(bool *active)
 {
     *active = d->m_snippetOverlay->isVisible();
 }
+
+void BaseTextEditorWidget::invokeAssist(AssistKind kind, IAssistProvider *provider)
+{
+    d->m_codeAssistant->invoke(kind, provider);
+}
+
+IAssistInterface *BaseTextEditorWidget::createAssistInterface(AssistKind kind,
+                                                              AssistReason reason) const
+{
+    Q_UNUSED(kind);
+    return new DefaultAssistInterface(document(), position(), d->m_document, reason);
+}
index 083cbce..dd8e141 100644 (file)
@@ -34,7 +34,7 @@
 #define BASETEXTEDITOR_H
 
 #include "itexteditor.h"
-#include "icompletioncollector.h"
+#include "codeassist/assistenums.h"
 
 #include <find/ifindsupport.h>
 
@@ -56,6 +56,9 @@ namespace TextEditor {
 class TabSettings;
 class RefactorOverlay;
 struct RefactorMarker;
+class IAssistMonitorInterface;
+class IAssistInterface;
+class IAssistProvider;
 
 namespace Internal {
     class BaseTextEditorPrivate;
@@ -235,6 +238,11 @@ public:
 
     QPoint toolTipPosition(const QTextCursor &c) const;
 
+    void invokeAssist(AssistKind assistKind, IAssistProvider *provider = 0);
+
+    virtual IAssistInterface *createAssistInterface(AssistKind assistKind,
+                                                    AssistReason assistReason) const;
+
 public slots:
     void setDisplayName(const QString &title);
 
@@ -492,7 +500,6 @@ signals:
     void requestBlockUpdate(const QTextBlock &);
 
 private:
-    void maybeRequestAutoCompletion(const QChar &ch);
     void indentOrUnindent(bool doIndent);
     void handleHomeKey(bool anchor);
     void handleBackspaceKey();
@@ -531,9 +538,6 @@ private:
     void transformSelection(Internal::TransformationMethod method);
 
 private slots:
-    // auto completion
-    void _q_requestAutoCompletion();
-
     void handleBlockSelection(int diff_row, int diff_col);
 
     // parentheses matcher
index d5d0506..189e587 100644 (file)
@@ -54,6 +54,7 @@ namespace TextEditor {
 
 class BaseTextDocument;
 class TextEditorActionHandler;
+class CodeAssistant;
 
 namespace Internal {
 
@@ -288,9 +289,8 @@ public:
     BaseTextEditorPrivateHighlightBlocks m_highlightBlocksInfo;
     QTimer *m_highlightBlocksTimer;
 
-    int m_requestAutoCompletionRevision;
-    int m_requestAutoCompletionPosition;
-    QTimer *m_requestAutoCompletionTimer;
+    QScopedPointer<CodeAssistant> m_codeAssistant;
+    bool m_assistRelevantContentAdded;
 
     QPointer<BaseTextEditorAnimator> m_animator;
     int m_cursorBlockNumber;
diff --git a/src/plugins/texteditor/codeassist/assistenums.h b/src/plugins/texteditor/codeassist/assistenums.h
new file mode 100644 (file)
index 0000000..5bfd760
--- /dev/null
@@ -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 (file)
index 0000000..f1d0045
--- /dev/null
@@ -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 (file)
index 0000000..4478fb8
--- /dev/null
@@ -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 (file)
index 0000000..ae34da6
--- /dev/null
@@ -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 (file)
index 0000000..482279a
--- /dev/null
@@ -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 (file)
index 0000000..e59b6e4
--- /dev/null
@@ -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"
 **
 **************************************************************************/
 
-#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 (file)
index 0000000..d9d0e9a
--- /dev/null
@@ -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 (file)
index 0000000..9b51dce
--- /dev/null
@@ -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 (file)
index 0000000..1bd9f46
--- /dev/null
@@ -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 (file)
index 0000000..af4bfe1
--- /dev/null
@@ -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 (file)
index 0000000..66e095b
--- /dev/null
@@ -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 (file)
index 0000000..950ac81
--- /dev/null
@@ -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 (file)
index 0000000..5dcde3d
--- /dev/null
@@ -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 (file)
index 0000000..bd60293
--- /dev/null
@@ -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 (file)
index 0000000..f652aa4
--- /dev/null
@@ -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 (file)
index 0000000..682350e
--- /dev/null
@@ -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 (file)
index 0000000..96ec69c
--- /dev/null
@@ -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 (file)
index 0000000..a765d41
--- /dev/null
@@ -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 (file)
index 0000000..0fa7325
--- /dev/null
@@ -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 (file)
index 0000000..49ab636
--- /dev/null
@@ -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 (file)
index 0000000..fff1c7f
--- /dev/null
@@ -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 (file)
index 0000000..43cbb4e
--- /dev/null
@@ -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 (file)
index 0000000..ba7a2fd
--- /dev/null
@@ -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 (file)
index 0000000..efacbc4
--- /dev/null
@@ -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 (file)
index 0000000..33d09d4
--- /dev/null
@@ -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 (file)
index 0000000..319a934
--- /dev/null
@@ -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 (file)
index 0000000..6222d56
--- /dev/null
@@ -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 (file)
index 0000000..e017f8d
--- /dev/null
@@ -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 (file)
index 0000000..9c7cfef
--- /dev/null
@@ -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 (file)
index 0000000..1a9d866
--- /dev/null
@@ -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 (file)
index 0000000..4e4cc8d
--- /dev/null
@@ -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.
+*/
 **
 **************************************************************************/
 
-#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 (file)
index 0000000..1f0a9ab
--- /dev/null
@@ -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 (file)
index 0000000..b56fadf
--- /dev/null
@@ -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 (file)
index 0000000..5bf0bfc
--- /dev/null
@@ -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 (file)
index 0000000..a6f6699
--- /dev/null
@@ -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 (file)
index 0000000..83618d2
--- /dev/null
@@ -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 (file)
index 0000000..c855907
--- /dev/null
@@ -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 (file)
index 0000000..d87b51e
--- /dev/null
@@ -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 (file)
index 0000000..3e16fc6
--- /dev/null
@@ -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 (file)
index 0000000..a6afedc
--- /dev/null
@@ -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 (file)
index 0000000..1757336
--- /dev/null
@@ -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
index c72d5eb..16c2d03 100644 (file)
@@ -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 (file)
index fa33e0e..0000000
+++ /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 (file)
index 3b82d61..0000000
+++ /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 (file)
index 2cd7af2..0000000
+++ /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 (file)
index 0000000..3facb9e
--- /dev/null
@@ -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 (file)
index 0000000..e7ae14f
--- /dev/null
@@ -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 (file)
index 0d16966..0000000
+++ /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 (file)
index 71bf199..0000000
+++ /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
index 8db6ebb..6ca695b 100644 (file)
 **************************************************************************/
 
 #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();
-}
index 869c351..dc97ef4 100644 (file)
 #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
 **
 **************************************************************************/
 
-#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;
 }
 **
 **************************************************************************/
 
-#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>
 
 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
index 51558f8..2056ae3 100644 (file)
@@ -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 \
index a3b9ef8..b4388e7 100644 (file)
@@ -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)