Skip to content
Snippets Groups Projects
completionsupport.cpp 7.13 KiB
Newer Older
/**************************************************************************
con's avatar
con committed
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
**
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
**
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
** GNU Lesser General Public License Usage
** Alternatively, 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.
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
**
**************************************************************************/
hjk's avatar
hjk committed

con's avatar
con committed
#include "completionsupport.h"
#include "completionwidget.h"
#include "icompletioncollector.h"

#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
con's avatar
con committed
#include <texteditor/itexteditable.h>
#include <texteditor/completionsettings.h>
hjk's avatar
hjk committed
#include <utils/qtcassert.h>
con's avatar
con committed

#include <QtCore/QString>
#include <QtCore/QList>
con's avatar
con committed

namespace TextEditor {
con's avatar
con committed

CompletionSupport *CompletionSupport::instance()
con's avatar
con committed
{
    static CompletionSupport *m_instance = 0;
    if (!m_instance)
        m_instance = new CompletionSupport;
con's avatar
con committed
    return m_instance;
}

class CompletionSupportPrivate {
public:
    CompletionSupportPrivate();

    Internal::CompletionWidget *m_completionList;
    int m_startPosition;
    bool m_checkCompletionTrigger;          // Whether to check for completion trigger after cleanup
    ITextEditable *m_editor;
    const QList<ICompletionCollector *> m_completionCollectors;
    ICompletionCollector *m_completionCollector;
};

CompletionSupportPrivate::CompletionSupportPrivate() :
    m_completionList(0),
    m_startPosition(0),
    m_checkCompletionTrigger(false),
    m_editor(0),
    m_completionCollectors(ExtensionSystem::PluginManager::instance()
                           ->getObjects<ICompletionCollector>()),
    m_completionCollector(0)
{
}

CompletionSupport::CompletionSupport() :
    QObject(Core::ICore::instance()), d(new CompletionSupportPrivate)
{
}

CompletionSupport::~CompletionSupport()
con's avatar
con committed
{
}

void CompletionSupport::performCompletion(const CompletionItem &item)
{
    item.collector->complete(item, d->m_completionList->typedChar());
    d->m_checkCompletionTrigger = true;
con's avatar
con committed
}

void CompletionSupport::cleanupCompletions()
{
    if (d->m_completionList)
        disconnect(d->m_completionList, SIGNAL(destroyed(QObject*)),
con's avatar
con committed
                   this, SLOT(cleanupCompletions()));

    if (d->m_checkCompletionTrigger)
        d->m_checkCompletionTrigger = d->m_completionCollector->shouldRestartCompletion();
    d->m_completionList = 0;
    d->m_completionCollector->cleanup();
con's avatar
con committed

    if (d->m_checkCompletionTrigger) {
        d->m_checkCompletionTrigger = false;
con's avatar
con committed

        // Only check for completion trigger when some text was entered
        if (d->m_editor->position() > d->m_startPosition)
            autoComplete(d->m_editor, false);
con's avatar
con committed
    }
}

bool CompletionSupport::isActive() const
{
    return d->m_completionList != 0;
con's avatar
con committed
void CompletionSupport::autoComplete(ITextEditable *editor, bool forced)
{
    autoComplete_helper(editor, forced, /*quickFix = */ false);
}

void CompletionSupport::quickFix(ITextEditable *editor)
{
    autoComplete_helper(editor,
                        /*forced = */ true,
                        /*quickFix = */ true);
}

void CompletionSupport::autoComplete_helper(ITextEditable *editor, bool forced,
                                            bool quickFix)
con's avatar
con committed
{
    d->m_completionCollector = 0;
    foreach (ICompletionCollector *collector, d->m_completionCollectors) {
        if (quickFix)
            collector = qobject_cast<IQuickFixCollector *>(collector);

        if (collector && collector->supportsEditor(editor)) {
            d->m_completionCollector = collector;
    if (!d->m_completionCollector)
con's avatar
con committed
        return;

    d->m_editor = editor;
con's avatar
con committed
    QList<CompletionItem> completionItems;

    int currentIndex = 0;

    if (!d->m_completionList) {
            const CompletionSettings &completionSettings = d->m_completionCollector->completionSettings();
            if (completionSettings.m_completionTrigger == ManualCompletion)
                return;
            if (!d->m_completionCollector->triggersCompletion(editor))
con's avatar
con committed

        d->m_startPosition = d->m_completionCollector->startCompletion(editor);
con's avatar
con committed
        completionItems = getCompletions();

        QTC_ASSERT(!(d->m_startPosition == -1 && completionItems.size() > 0), return);
con's avatar
con committed

        if (completionItems.isEmpty()) {
            cleanupCompletions();
            return;
        }

        d->m_completionList = new Internal::CompletionWidget(this, editor);
        d->m_completionList->setQuickFix(quickFix);
con's avatar
con committed

        connect(d->m_completionList, SIGNAL(itemSelected(TextEditor::CompletionItem)),
con's avatar
con committed
                this, SLOT(performCompletion(TextEditor::CompletionItem)));
        connect(d->m_completionList, SIGNAL(completionListClosed()),
con's avatar
con committed
                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(d->m_completionList, SIGNAL(destroyed(QObject*)),
con's avatar
con committed
                this, SLOT(cleanupCompletions()));
    } else {
        completionItems = getCompletions();

        if (completionItems.isEmpty()) {
            d->m_completionList->closeList();
con's avatar
con committed
            return;
        }
        if (d->m_completionList->explicitlySelected()) {
            const int originalIndex = d->m_completionList->currentCompletionItem().originalIndex;

            for (int index = 0; index < completionItems.size(); ++index) {
                if (completionItems.at(index).originalIndex == originalIndex) {
                    currentIndex = index;
                    break;
                }
            }
        }
con's avatar
con committed
    }

    d->m_completionList->setCompletionItems(completionItems);
con's avatar
con committed

    if (currentIndex)
        d->m_completionList->setCurrentIndex(currentIndex);
con's avatar
con committed
    // Partially complete when completion was forced
    if (forced && d->m_completionCollector->partiallyComplete(completionItems)) {
        d->m_checkCompletionTrigger = true;
        d->m_completionList->closeList();
con's avatar
con committed
    } else {
        d->m_completionList->showCompletions(d->m_startPosition);
con's avatar
con committed
    }
}

QList<CompletionItem> CompletionSupport::getCompletions() const
{
    if (d->m_completionCollector)
        return d->m_completionCollector->getCompletions();
con's avatar
con committed

con's avatar
con committed
}

} // namespace TextEditor