[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdevplatform] /: Move assistant completion to its own KTextEditor::CompletionModel
From:       Olivier JG <olivier.jg () gmail ! com>
Date:       2015-10-11 8:40:21
Message-ID: E1ZlCB3-0004BZ-VZ () scm ! kde ! org
[Download RAW message or body]

Git commit 039caf63fa0bdd643cd5c81eaee33bb378610f59 by Olivier JG.
Committed on 11/10/2015 at 08:44.
Pushed by olivierjg into branch 'master'.

Move assistant completion to its own KTextEditor::CompletionModel

M  +0    -5    interfaces/iuicontroller.h
M  +1    -0    language/CMakeLists.txt
A  +90   -0    language/assistant/assistantcompletionmodel.cpp     [License: LGPL \
(v2)] A  +55   -0    language/assistant/assistantcompletionmodel.h     [License: LGPL \
(v2)] M  +51   -30   language/assistant/staticassistantsmanager.cpp
M  +0    -3    language/assistant/staticassistantsmanager.h
M  +0    -106  language/codecompletion/codecompletionmodel.cpp
M  +0    -3    language/codecompletion/codecompletionmodel.h
M  +0    -25   shell/uicontroller.cpp
M  +0    -2    shell/uicontroller.h

http://commits.kde.org/kdevplatform/039caf63fa0bdd643cd5c81eaee33bb378610f59

diff --git a/interfaces/iuicontroller.h b/interfaces/iuicontroller.h
index 9d5fc19..50ddb99 100644
--- a/interfaces/iuicontroller.h
+++ b/interfaces/iuicontroller.h
@@ -130,11 +130,6 @@ public:
     virtual void registerStatus(QObject* status) = 0;
 
     /**
-     * Show the assistant specified by @p assistant
-     */
-    virtual void showAssistant(const QExplicitlySharedDataPointer<IAssistant>& \
                assistant) = 0;
-
-    /**
      * This is meant to be used by IDocument subclasses to initialize the
      * Sublime::Document.
      */
diff --git a/language/CMakeLists.txt b/language/CMakeLists.txt
index d53bc2c..6c48bbc 100644
--- a/language/CMakeLists.txt
+++ b/language/CMakeLists.txt
@@ -21,6 +21,7 @@ set(KDevPlatformLanguage_LIB_SRCS
     assistant/renameassistant.cpp
     assistant/renamefileaction.cpp
     assistant/staticassistant.cpp
+    assistant/assistantcompletionmodel.cpp
 
     editor/persistentmovingrangeprivate.cpp
     editor/persistentmovingrange.cpp
diff --git a/language/assistant/assistantcompletionmodel.cpp \
b/language/assistant/assistantcompletionmodel.cpp new file mode 100644
index 0000000..78bd544
--- /dev/null
+++ b/language/assistant/assistantcompletionmodel.cpp
@@ -0,0 +1,90 @@
+/*
+   Copyright 2015 Olivier de Gaalon <olivier.jg@gmail.com>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License version 2 as published by the Free Software Foundation.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; see the file COPYING.LIB.  If not, write to
+   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.
+*/
+
+#include "assistantcompletionmodel.h"
+
+#include "staticassistantsmanager.h"
+
+#include "interfaces/iassistant.h"
+#include "interfaces/icore.h"
+#include "interfaces/ilanguagecontroller.h"
+
+namespace KDevelop {
+
+AssistantCompletionModel::AssistantCompletionModel(QObject* parent)
+    : KTextEditor::CodeCompletionModel(parent)
+{
+}
+
+void AssistantCompletionModel::executeCompletionItem(KTextEditor::View*, const \
KTextEditor::Range&, const QModelIndex& index) const +{
+    if (auto action = actionForIndex(index)) {
+        action->execute();
+    }
+}
+
+void AssistantCompletionModel::setActions(const QList<IAssistantAction::Ptr>& \
actions) +{
+    if (m_actions == actions) {
+        return;
+    }
+
+    beginResetModel();
+    m_actions = actions;
+    endResetModel();
+
+    if (rowCount()) {
+        emit hasCompletions();
+    }
+}
+
+QVariant AssistantCompletionModel::data(const QModelIndex& index, const int role) \
const +{
+    if (role == Qt::DisplayRole && index.column() == Name) {
+        if (auto action = actionForIndex(index)) {
+            return action->description();
+        }
+    } else if (role == ArgumentHintDepth) {
+        return 1;
+    }
+    return {};
+}
+
+QModelIndex AssistantCompletionModel::index(int row, int column, const QModelIndex& \
parent) const +{
+    if (!hasIndex(row, column, parent))
+        return {};
+
+    return createIndex(row, column);
+}
+
+int AssistantCompletionModel::rowCount(const QModelIndex& parent) const
+{
+    return parent.isValid() ? 0 : m_actions.size();
+}
+
+IAssistantAction* AssistantCompletionModel::actionForIndex(const QModelIndex& index) \
const +{
+    if (index.row() < 0 || index.row() >= m_actions.size()) {
+        return nullptr;
+    }
+
+    return m_actions.at(index.row()).data();
+}
+
+}
diff --git a/language/assistant/assistantcompletionmodel.h \
b/language/assistant/assistantcompletionmodel.h new file mode 100644
index 0000000..4a6836a
--- /dev/null
+++ b/language/assistant/assistantcompletionmodel.h
@@ -0,0 +1,55 @@
+/*
+   Copyright 2015 Olivier de Gaalon <olivier.jg@gmail.com>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License version 2 as published by the Free Software Foundation.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; see the file COPYING.LIB.  If not, write to
+   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.
+*/
+
+#ifndef ASSISTANTCOMPLETIONMODEL_H
+#define ASSISTANTCOMPLETIONMODEL_H
+
+#include <KTextEditor/CodeCompletionModel>
+
+#include <QExplicitlySharedDataPointer>
+
+namespace KDevelop {
+
+class IAssistantAction;
+
+class AssistantCompletionModel : public KTextEditor::CodeCompletionModel
+{
+    Q_OBJECT
+public:
+    AssistantCompletionModel(QObject* parent = {});
+
+    void setActions(const QList<QExplicitlySharedDataPointer<IAssistantAction>> \
&actions); +
+    void executeCompletionItem(KTextEditor::View* view, const KTextEditor::Range& \
word, const QModelIndex& index) const override; +
+    QVariant data(const QModelIndex& index, const int role = Qt::DisplayRole) const;
+    QModelIndex index(int row, int column, const QModelIndex& parent = \
QModelIndex()) const override; +    int rowCount(const QModelIndex& parent = \
QModelIndex()) const override; +
+signals:
+    void hasCompletions();
+
+private:
+    IAssistantAction *actionForIndex(const QModelIndex& index) const;
+
+    QList<QExplicitlySharedDataPointer<IAssistantAction>> m_actions;
+};
+
+}
+
+#endif // ASSISTANTCOMPLETIONMODEL_H
diff --git a/language/assistant/staticassistantsmanager.cpp \
b/language/assistant/staticassistantsmanager.cpp index 3aa60bf..92ca321 100644
--- a/language/assistant/staticassistantsmanager.cpp
+++ b/language/assistant/staticassistantsmanager.cpp
@@ -17,6 +17,7 @@
    Boston, MA 02110-1301, USA.
 */
 
+#include "assistantcompletionmodel.h"
 #include "staticassistantsmanager.h"
 #include "util/debug.h"
 
@@ -37,6 +38,7 @@
 
 #include <language/backgroundparser/backgroundparser.h>
 #include <language/backgroundparser/parsejob.h>
+#include <language/codecompletion/codecompletion.h>
 #include <language/duchain/problem.h>
 
 using namespace KDevelop;
@@ -54,7 +56,6 @@ struct StaticAssistantsManager::Private
     }
 
     void eventuallyStartAssistant();
-    void startAssistant(KDevelop::IAssistant::Ptr assistant);
     void checkAssistantForProblems(KDevelop::TopDUContext* top);
 
     void documentLoaded(KDevelop::IDocument*);
@@ -64,6 +65,7 @@ struct StaticAssistantsManager::Private
     void documentActivated(KDevelop::IDocument*);
     void cursorPositionChanged(KTextEditor::View*, const KTextEditor::Cursor&);
     void timeout();
+    void setActiveAssistant(const IAssistant::Ptr& assistant);
 
     StaticAssistantsManager* q;
 
@@ -74,6 +76,7 @@ struct StaticAssistantsManager::Private
     QList<StaticAssistant::Ptr> m_registeredAssistants;
     bool m_activeProblemAssistant = false;
     QTimer* m_timer;
+    AssistantCompletionModel* m_completionModel;
 
     SafeDocumentPointer m_eventualDocument;
     KTextEditor::Range m_eventualRange;
@@ -100,6 +103,20 @@ StaticAssistantsManager::StaticAssistantsManager(QObject* \
                parent)
     foreach (IDocument* document, \
ICore::self()->documentController()->openDocuments()) {  d->documentLoaded(document);
     }
+
+    d->m_completionModel = new AssistantCompletionModel(this);
+    connect(d->m_completionModel, &AssistantCompletionModel::hasCompletions, this, \
[this]{ +        if (auto view = d->m_currentView.data()) {
+            // We cannot use KTextEditor::CodeCompletionInterface::startCompletion \
for now +            // It randomly disappears and refuses to invoke in many/various \
situations +            // Would be very nice to fix this in KTextEditor, because we \
/really/ want to +            // be able to invoke completion only on the assistants \
model as we could with +            // CodeCompletionInterface::startCompletion
+            // HACK: private internal slot invocation
+            QMetaObject::invokeMethod(view, "userInvokedCompletion");
+        }
+    });
+    new KDevelop::CodeCompletion(this, d->m_completionModel, {});
 }
 
 StaticAssistantsManager::~StaticAssistantsManager()
@@ -143,9 +160,7 @@ void StaticAssistantsManager::Private::documentLoaded(IDocument* \
document)  
 void StaticAssistantsManager::hideAssistant()
 {
-    d->m_activeAssistant = QExplicitlySharedDataPointer<KDevelop::IAssistant>();
-    d->m_activeProblemAssistant = false;
-    emit activeAssistantChanged();
+    d->setActiveAssistant({});
 }
 
 void StaticAssistantsManager::Private::textInserted(Document* document, const \
Cursor& cursor, const QString& text) @@ -194,7 +209,7 @@ void \
                StaticAssistantsManager::Private::eventuallyStartAssistant()
         assistant->textChanged(view, m_eventualRange, m_eventualRemovedText);
 
         if (assistant->isUseful()) {
-            startAssistant(IAssistant::Ptr(assistant.data()));
+            setActiveAssistant(IAssistant::Ptr(assistant.data()));
             break;
         }
     }
@@ -206,30 +221,6 @@ void \
StaticAssistantsManager::Private::eventuallyStartAssistant()  \
m_eventualRemovedText.clear();  }
 
-void StaticAssistantsManager::Private::startAssistant(IAssistant::Ptr assistant)
-{
-    if (assistant == m_activeAssistant) {
-        return;
-    }
-
-    if (m_activeAssistant) {
-        m_activeAssistant->doHide();
-    }
-
-    if (!m_currentView)
-        return;
-
-    m_activeAssistant = assistant;
-    if (m_activeAssistant) {
-        connect(m_activeAssistant.data(), &IAssistant::hide, q, \
                &StaticAssistantsManager::hideAssistant, Qt::UniqueConnection);
-        ICore::self()->uiController()->showAssistant(IAssistant::Ptr(m_activeAssistant.data()));
                
-
-        m_assistantStartedAt =  m_currentView.data()->cursorPosition();
-    }
-
-    emit q->activeAssistantChanged();
-}
-
 void StaticAssistantsManager::Private::parseJobFinished(ParseJob* job)
 {
     if (job->document() != m_currentDocument) {
@@ -291,7 +282,7 @@ void \
                StaticAssistantsManager::Private::checkAssistantForProblems(TopDUContext* \
                t
         if (m_currentView && m_currentView.data()->cursorPosition().line() == \
problem->range().start.line) {  IAssistant::Ptr solution = \
problem->solutionAssistant();  if(solution) {
-                startAssistant(solution);
+                setActiveAssistant(solution);
                 m_activeProblemAssistant = true;
                 break;
             }
@@ -314,4 +305,34 @@ void StaticAssistantsManager::Private::timeout()
     }
 }
 
+void StaticAssistantsManager::Private::setActiveAssistant(const IAssistant::Ptr& \
assistant) +{
+    if (assistant == m_activeAssistant) {
+        return;
+    }
+
+    m_activeAssistant = QExplicitlySharedDataPointer<KDevelop::IAssistant>();
+
+    if (m_activeAssistant) {
+        m_activeAssistant->doHide();
+        m_activeAssistant->disconnect(q);
+        m_activeAssistant->disconnect(m_completionModel);
+    }
+
+    m_activeAssistant = assistant;
+
+    if (auto activeAssistant = m_activeAssistant.data()) {
+        auto updateActions = [=]{ \
m_completionModel->setActions(activeAssistant->actions()); }; +        \
connect(activeAssistant, &IAssistant::hide, q, \
&StaticAssistantsManager::hideAssistant); +        connect(activeAssistant, \
&IAssistant::actionsChanged, m_completionModel, updateActions); +        if \
(m_currentView) { +            m_assistantStartedAt =  \
m_currentView.data()->cursorPosition(); +            updateActions();
+        }
+    } else {
+        m_activeProblemAssistant = false;
+        m_completionModel->setActions({});
+    }
+}
+
 #include "moc_staticassistantsmanager.cpp"
diff --git a/language/assistant/staticassistantsmanager.h \
b/language/assistant/staticassistantsmanager.h index a03e03a..1cfd3fb 100644
--- a/language/assistant/staticassistantsmanager.h
+++ b/language/assistant/staticassistantsmanager.h
@@ -66,9 +66,6 @@ public:
 public slots:
     void hideAssistant();
 
-signals:
-    void activeAssistantChanged();
-
 private:
     struct Private;
     QScopedPointer<Private> const d;
diff --git a/language/codecompletion/codecompletionmodel.cpp \
b/language/codecompletion/codecompletionmodel.cpp index 4bf0c14..6ee981b 100644
--- a/language/codecompletion/codecompletionmodel.cpp
+++ b/language/codecompletion/codecompletionmodel.cpp
@@ -31,9 +31,6 @@
 #include <ktexteditor/view.h>
 #include <ktexteditor/document.h>
 
-#include <language/assistant/staticassistant.h>
-#include <language/assistant/staticassistantsmanager.h>
-
 #include "../duchain/declaration.h"
 #include "../duchain/classfunctiondeclaration.h"
 #include "../duchain/ducontext.h"
@@ -59,73 +56,6 @@ using namespace KTextEditor;
 //Multi-threaded completion creates some multi-threading related crashes, and \
sometimes shows the completions in the wrong position if the cursor was moved  // \
#define SINGLE_THREADED_COMPLETION  
-namespace {
-
-class AssistantItem : public KDevelop::CompletionTreeItem
-{
-public:
-    AssistantItem(const KDevelop::IAssistantAction::Ptr& action)
-        : CompletionTreeItem()
-        , m_action(action)
-    {
-        Q_ASSERT(action);
-    }
-
-    QVariant data(const QModelIndex& index, int role, const \
                KDevelop::CodeCompletionModel*) const override
-    {
-        switch (role) {
-        case Qt::DisplayRole:
-            if (index.column() == KTextEditor::CodeCompletionModel::Name)
-                return m_action->description();
-            break;
-        }
-        return QVariant();
-    }
-
-    int argumentHintDepth() const override
-    {
-        return 1;
-    }
-
-    void execute(KTextEditor::View*, const KTextEditor::Range&) override
-    {
-        m_action->execute();
-    }
-
-private:
-    KDevelop::IAssistantAction::Ptr m_action;
-};
-
-class AssistantGroup : public KDevelop::CompletionCustomGroupNode
-{
-public:
-    AssistantGroup(const QList<KDevelop::IAssistantAction::Ptr>& actions)
-        : CompletionCustomGroupNode(QObject::tr("Assistants"), 0)
-    {
-        for (const auto& action: actions) {
-            appendChild(KDevelop::CompletionTreeItemPointer(new \
                AssistantItem(action)));
-        }
-    }
-};
-
-KDevelop::IAssistant* activeAssistant()
-{
-    return KDevelop::ICore::self()->languageController()-> \
                staticAssistantsManager()->activeAssistant().data();
-}
-
-KDevelop::CompletionTreeElementPointer assistantActionsGroup(KDevelop::IAssistant* \
                assistant)
-{
-    if (assistant) {
-        const auto actions = assistant->actions();
-        if (!actions.isEmpty()) {
-            return KDevelop::CompletionTreeElementPointer(new \
                AssistantGroup(actions));
-        }
-    }
-    return {};
-}
-
-}
-
 namespace KDevelop {
 
 class CompletionWorkerThread : public QThread
@@ -176,10 +106,6 @@ CodeCompletionModel::CodeCompletionModel( QObject * parent )
   , m_thread(0)
 {
   qRegisterMetaType<KTextEditor::Cursor>();
-
-  connect(ICore::self()->languageController()->staticAssistantsManager(),
-          &StaticAssistantsManager::activeAssistantChanged,
-          this, &CodeCompletionModel::updateAssistantItems);
 }
 
 void CodeCompletionModel::initialize() {
@@ -219,35 +145,6 @@ KDevelop::CodeCompletionWorker* CodeCompletionModel::worker() \
const {  return m_thread->m_worker;
 }
 
-void CodeCompletionModel::updateAssistantItems()
-{
-    const auto assistant = activeAssistant();
-    disconnect(m_connection);
-    if (assistant) {
-        m_connection = connect(assistant, &IAssistant::actionsChanged,
-                               this, &CodeCompletionModel::updateAssistantItems);
-    }
-
-    const bool hasAssistantNode = !m_completionItems.isEmpty() &&
-        dynamic_cast<AssistantGroup*>(m_completionItems.last().data());
-
-    if (!assistant && !hasAssistantNode) {
-        return;
-    }
-    // KateCompletionModel will happily ignore beginRemoveRows/endRemoveRows for \
                argument hint items
-    // We use argument hints otherwise we have to hack the currently typed text into \
                the item's Name column
-    // because KateCompletionModel offers no way to force an item to skip text \
                filtering (other than arg hints)
-    // Event if we didn't, KateCompletionModel doesn't correctly balance \
                begin/endInsertRows, so... meh
-    beginResetModel();
-    if (hasAssistantNode) {
-        m_completionItems.removeLast();
-    }
-    if (auto assists = assistantActionsGroup(assistant)) {
-        m_completionItems.append(assists);
-    }
-    endResetModel();
-}
-
 void CodeCompletionModel::clear()
 {
   beginResetModel();
@@ -367,9 +264,6 @@ void CodeCompletionModel::foundDeclarations(const \
QList<QExplicitlySharedDataPoi  
   beginResetModel();
   m_completionItems = items;
-  if (auto assists = assistantActionsGroup(activeAssistant())) {
-    m_completionItems.append(assists);
-  }
   endResetModel();
 
   if(m_completionContext) {
diff --git a/language/codecompletion/codecompletionmodel.h \
b/language/codecompletion/codecompletionmodel.h index b141fa5..4b048f4 100644
--- a/language/codecompletion/codecompletionmodel.h
+++ b/language/codecompletion/codecompletionmodel.h
@@ -136,10 +136,7 @@ class KDEVPLATFORMLANGUAGE_EXPORT CodeCompletionModel : public \
KTextEditor::Code  
     CodeCompletionWorker* worker() const;
 
-    void updateAssistantItems();
-
   private:
-    QMetaObject::Connection m_connection;
     bool m_forceWaitForModel;
     bool m_fullCompletion;
     QMutex* m_mutex;
diff --git a/shell/uicontroller.cpp b/shell/uicontroller.cpp
index 1df7a96..2510267 100644
--- a/shell/uicontroller.cpp
+++ b/shell/uicontroller.cpp
@@ -718,31 +718,6 @@ void UiController::showErrorMessage(const QString& message, int \
                timeout)
     QMetaObject::invokeMethod(mw, "showErrorMessage", Q_ARG(QString, message), \
Q_ARG(int, timeout));  }
 
-void UiController::showAssistant(const KDevelop::IAssistant::Ptr& assistant)
-{
-    if(!assistant)
-        return;
-
-    Sublime::View* view = d->activeSublimeWindow->activeView();
-    if( !view )
-    {
-        qCDebug(SHELL) << "no active view in mainwindow";
-        return;
-    }
-
-    auto editorView = qobject_cast<KTextEditor::View*>(view->widget());
-    Q_ASSERT(editorView);
-    if (editorView) {
-        // TODO: See if we can use CodeCompletionInterface::startCompletion for this
-        // See if we can split the assistant actions into their own model and use \
                the model param as well
-        // That way we don't get unwanted completions when the assistant completions \
                are shown
-        if (!assistant->actions().isEmpty()) {
-            // HACK: Internal, unexposed API -- do NOT git blame this line
-            QMetaObject::invokeMethod(editorView, "userInvokedCompletion");
-        }
-    }
-}
-
 const QMap< IToolViewFactory*, Sublime::ToolDocument* >& \
UiController::factoryDocuments() const  {
     return d->factoryDocuments;
diff --git a/shell/uicontroller.h b/shell/uicontroller.h
index 06b4104..b3bc417 100644
--- a/shell/uicontroller.h
+++ b/shell/uicontroller.h
@@ -85,8 +85,6 @@ public:
     /*! @p status must implement KDevelop::IStatus */
     virtual void registerStatus(QObject* status) override;
 
-    virtual void showAssistant(const KDevelop::IAssistant::Ptr& assistant) override;
-
     virtual void showErrorMessage(const QString& message, int timeout) override;
 
     /// Returns list of available view factories together with their ToolDocuments.


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic