cpptoolsplugin.cpp 12.4 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2 3 4
**
** This file is part of Qt Creator
**
5
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
** Commercial Usage
10
**
11 12 13 14
** 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.
15
**
16
** GNU Lesser General Public License Usage
17
**
18 19 20 21 22 23
** 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.
24
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

30
#include "cpptoolsplugin.h"
31
#include "completionsettingspage.h"
32
#include "cppfilesettingspage.h"
33
#include "cppclassesfilter.h"
con's avatar
con committed
34
#include "cppcodecompletion.h"
35
#include "cppfunctionsfilter.h"
36
#include "cppcurrentdocumentfilter.h"
con's avatar
con committed
37 38
#include "cppmodelmanager.h"
#include "cpptoolsconstants.h"
con's avatar
con committed
39
#include "cpplocatorfilter.h"
con's avatar
con committed
40

41 42
#include <extensionsystem/pluginmanager.h>

con's avatar
con committed
43 44 45 46
#include <coreplugin/icore.h>
#include <coreplugin/mimedatabase.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/uniqueidmanager.h>
47
#include <coreplugin/actionmanager/actionmanager.h>
con's avatar
con committed
48
#include <coreplugin/editormanager/editormanager.h>
49
#include <coreplugin/progressmanager/progressmanager.h>
con's avatar
con committed
50 51
#include <cppeditor/cppeditorconstants.h>

52 53 54 55 56 57 58 59
#include <QtCore/QtConcurrentRun>
#include <QtCore/QFutureSynchronizer>
#include <qtconcurrent/runextensions.h>

#include <find/ifindfilter.h>
#include <find/searchresultwindow.h>
#include <utils/filesearch.h>

60
#include <QtCore/QtPlugin>
con's avatar
con committed
61 62 63
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDebug>
64
#include <QtCore/QSettings>
con's avatar
con committed
65 66 67
#include <QtGui/QMenu>
#include <QtGui/QAction>

68 69
#include <sstream>

con's avatar
con committed
70
using namespace CppTools::Internal;
71
using namespace CPlusPlus;
con's avatar
con committed
72 73 74 75 76

enum { debug = 0 };

CppToolsPlugin *CppToolsPlugin::m_instance = 0;

77 78 79 80
CppToolsPlugin::CppToolsPlugin() :
    m_context(-1),
    m_modelManager(0),
    m_fileSettings(new CppFileSettings)
con's avatar
con committed
81 82 83 84 85 86 87 88 89 90
{
    m_instance = this;
}

CppToolsPlugin::~CppToolsPlugin()
{
    m_instance = 0;
    m_modelManager = 0; // deleted automatically
}

91
bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
con's avatar
con committed
92
{
93 94
    Q_UNUSED(arguments)
    Q_UNUSED(error)
95 96
    Core::ICore *core = Core::ICore::instance();
    Core::ActionManager *am = core->actionManager();
con's avatar
con committed
97 98 99 100

    // Objects
    m_modelManager = new CppModelManager(this);
    addAutoReleasedObject(m_modelManager);
Roberto Raggi's avatar
Roberto Raggi committed
101

102
    m_completion = new CppCodeCompletion(m_modelManager);
103
    addAutoReleasedObject(m_completion);
Roberto Raggi's avatar
Roberto Raggi committed
104 105 106

    addAutoReleasedObject(new CppQuickFixCollector(m_modelManager));

con's avatar
con committed
107
    CppLocatorFilter *quickOpenFilter = new CppLocatorFilter(m_modelManager,
108
                                                                 core->editorManager());
con's avatar
con committed
109
    addAutoReleasedObject(quickOpenFilter);
110 111
    addAutoReleasedObject(new CppClassesFilter(m_modelManager, core->editorManager()));
    addAutoReleasedObject(new CppFunctionsFilter(m_modelManager, core->editorManager()));
112
    addAutoReleasedObject(new CppCurrentDocumentFilter(m_modelManager, core->editorManager()));
113
    addAutoReleasedObject(new CompletionSettingsPage(m_completion));
114
    addAutoReleasedObject(new CppFileSettingsPage(m_fileSettings));
con's avatar
con committed
115 116

    // Menus
117 118
    Core::ActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS);
    Core::ActionContainer *mcpptools = am->createMenu(CppTools::Constants::M_TOOLS_CPP);
con's avatar
con committed
119 120 121 122 123 124
    QMenu *menu = mcpptools->menu();
    menu->setTitle(tr("&C++"));
    menu->setEnabled(true);
    mtools->addMenu(mcpptools);

    // Actions
125
    m_context = core->uniqueIDManager()->uniqueIdentifier(CppEditor::Constants::C_CPPEDITOR);
con's avatar
con committed
126 127 128
    QList<int> context = QList<int>() << m_context;

    QAction *switchAction = new QAction(tr("Switch Header/Source"), this);
con's avatar
con committed
129
    Core::Command *command = am->registerAction(switchAction, Constants::SWITCH_HEADER_SOURCE, context);
con's avatar
con committed
130 131 132 133
    command->setDefaultKeySequence(QKeySequence(Qt::Key_F4));
    mcpptools->addAction(command);
    connect(switchAction, SIGNAL(triggered()), this, SLOT(switchHeaderSource()));

134
    // Restore settings
135
    QSettings *settings = Core::ICore::instance()->settings();
136 137 138 139
    settings->beginGroup(QLatin1String("CppTools"));
    settings->beginGroup(QLatin1String("Completion"));
    const bool caseSensitive = settings->value(QLatin1String("CaseSensitive"), true).toBool();
    m_completion->setCaseSensitivity(caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
140
    m_completion->setAutoInsertBrackets(settings->value(QLatin1String("AutoInsertBraces"), true).toBool());
141
    m_completion->setPartialCompletionEnabled(settings->value(QLatin1String("PartiallyComplete"), true).toBool());
142 143 144
    settings->endGroup();
    settings->endGroup();

con's avatar
con committed
145 146 147 148 149
    return true;
}

void CppToolsPlugin::extensionsInitialized()
{
150 151 152 153 154
    // The Cpp editor plugin, which is loaded later on, registers the Cpp mime types,
    // so, apply settings here
    m_fileSettings->fromSettings(Core::ICore::instance()->settings());
    if (!m_fileSettings->applySuffixesToMimeDB())
        qWarning("Unable to apply cpp suffixes to mime database (cpp mime types not found).\n");
155 156 157 158 159

    // Initialize header suffixes
    const Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase();
    const Core::MimeType mimeType = mimeDatabase->findByType(QLatin1String("text/x-c++hdr"));
    m_modelManager->setHeaderSuffixes(mimeType.suffixes());
con's avatar
con committed
160 161
}

162 163 164
void CppToolsPlugin::shutdown()
{
    // Save settings
165
    QSettings *settings = Core::ICore::instance()->settings();
166 167 168
    settings->beginGroup(QLatin1String("CppTools"));
    settings->beginGroup(QLatin1String("Completion"));
    settings->setValue(QLatin1String("CaseSensitive"), m_completion->caseSensitivity() == Qt::CaseSensitive);
169
    settings->setValue(QLatin1String("AutoInsertBraces"), m_completion->autoInsertBrackets());
170
    settings->setValue(QLatin1String("PartiallyComplete"), m_completion->isPartialCompletionEnabled());
171 172 173 174
    settings->endGroup();
    settings->endGroup();
}

con's avatar
con committed
175 176
void CppToolsPlugin::switchHeaderSource()
{
177
    Core::EditorManager *editorManager = Core::EditorManager::instance();
178
    Core::IEditor *editor = editorManager->currentEditor();
con's avatar
con committed
179 180
    QString otherFile = correspondingHeaderOrSource(editor->file()->fileName());
    if (!otherFile.isEmpty()) {
181 182
        editorManager->openEditor(otherFile);
        editorManager->ensureEditorManagerVisible();
con's avatar
con committed
183 184 185 186 187 188 189 190 191
    }
}

QFileInfo CppToolsPlugin::findFile(const QDir &dir, const QString &name,
                                   const ProjectExplorer::Project *project) const
{
    if (debug)
        qDebug() << Q_FUNC_INFO << dir << name;

192 193
    QFileInfo fileInSameDir(dir, name);
    if (project && !fileInSameDir.isFile()) {
con's avatar
con committed
194 195 196 197 198 199 200 201 202
        QString pattern = QString(1, QLatin1Char('/'));
        pattern += name;
        const QStringList projectFiles = project->files(ProjectExplorer::Project::AllFiles);
        const QStringList::const_iterator pcend = projectFiles.constEnd();
        for (QStringList::const_iterator it = projectFiles.constBegin(); it != pcend; ++it)
            if (it->endsWith(pattern))
                return QFileInfo(*it);
        return QFileInfo();
    }
203
    return fileInSameDir;
con's avatar
con committed
204 205 206
}

// Figure out file type
207 208 209 210
enum FileType {
    HeaderFile,
    C_SourceFile,
    CPP_SourceFile,
211
    ObjectiveCPP_SourceFile,
212 213
    UnknownType
};
con's avatar
con committed
214 215 216 217 218 219 220 221 222 223 224

static inline FileType fileType(const Core::MimeDatabase *mimeDatase, const  QFileInfo & fi)
{
    const Core::MimeType mimeType = mimeDatase->findByFile(fi);
    if (!mimeType)
        return UnknownType;
    const QString typeName = mimeType.type();
    if (typeName == QLatin1String(CppTools::Constants::C_SOURCE_MIMETYPE))
        return C_SourceFile;
    if (typeName == QLatin1String(CppTools::Constants::CPP_SOURCE_MIMETYPE))
        return CPP_SourceFile;
225 226
    if (typeName == QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE))
        return ObjectiveCPP_SourceFile;
con's avatar
con committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240
    if (typeName == QLatin1String(CppTools::Constants::C_HEADER_MIMETYPE)
        || typeName == QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE))
        return HeaderFile;
    return UnknownType;
}

// Return the suffixes that should be checked when trying to find a
// source belonging to a header and vice versa
static QStringList matchingCandidateSuffixes(const Core::MimeDatabase *mimeDatase, FileType type)
{
    switch (type) {
    case UnknownType:
        break;
    case HeaderFile: // Note that C/C++ headers are undistinguishable
241 242 243
        return mimeDatase->findByType(QLatin1String(CppTools::Constants::C_SOURCE_MIMETYPE)).suffixes()
               + mimeDatase->findByType(QLatin1String(CppTools::Constants::CPP_SOURCE_MIMETYPE)).suffixes()
               + mimeDatase->findByType(QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)).suffixes();
con's avatar
con committed
244 245 246
    case C_SourceFile:
        return mimeDatase->findByType(QLatin1String(CppTools::Constants::C_HEADER_MIMETYPE)).suffixes();
    case CPP_SourceFile:
247
    case ObjectiveCPP_SourceFile:
con's avatar
con committed
248 249 250 251 252 253 254
        return mimeDatase->findByType(QLatin1String(CppTools::Constants::CPP_HEADER_MIMETYPE)).suffixes();
    }
    return QStringList();
}

QString CppToolsPlugin::correspondingHeaderOrSourceI(const QString &fileName) const
{
255
    const Core::ICore *core = Core::ICore::instance();
con's avatar
con committed
256 257
    const Core::MimeDatabase *mimeDatase = core->mimeDatabase();
    ProjectExplorer::ProjectExplorerPlugin *explorer =
258
       ProjectExplorer::ProjectExplorerPlugin::instance();
con's avatar
con committed
259 260 261 262 263 264 265 266 267 268 269 270
    ProjectExplorer::Project *project = (explorer ? explorer->currentProject() : 0);

    const QFileInfo fi(fileName);
    const FileType type = fileType(mimeDatase, fi);

    if (debug)
        qDebug() << Q_FUNC_INFO << fileName <<  type;

    if (type == UnknownType)
        return QString();

    const QDir absoluteDir = fi.absoluteDir();
271
    const QString baseName = fi.completeBaseName();
con's avatar
con committed
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
    const QStringList suffixes = matchingCandidateSuffixes(mimeDatase, type);

    const QString privateHeaderSuffix = QLatin1String("_p");
    const QChar dot = QLatin1Char('.');
    QStringList candidates;
    // Check base matches 'source.h'-> 'source.cpp' and vice versa
    const QStringList::const_iterator scend = suffixes.constEnd();
    for (QStringList::const_iterator it = suffixes.constBegin(); it != scend; ++it) {
        QString candidate = baseName;
        candidate += dot;
        candidate += *it;
        const QFileInfo candidateFi = findFile(absoluteDir, candidate, project);
        if (candidateFi.isFile())
            return candidateFi.absoluteFilePath();
    }
    if (type == HeaderFile) {
        // 'source_p.h': try 'source.cpp'
        if (baseName.endsWith(privateHeaderSuffix)) {
            QString sourceBaseName = baseName;
            sourceBaseName.truncate(sourceBaseName.size() - privateHeaderSuffix.size());
            for (QStringList::const_iterator it = suffixes.constBegin(); it != scend; ++it) {
                QString candidate = sourceBaseName;
                candidate += dot;
                candidate += *it;
                const QFileInfo candidateFi = findFile(absoluteDir, candidate, project);
                if (candidateFi.isFile())
                    return candidateFi.absoluteFilePath();
            }
        }
    } else {
        // 'source.cpp': try 'source_p.h'
        const QStringList::const_iterator scend = suffixes.constEnd();
        for (QStringList::const_iterator it = suffixes.constBegin(); it != scend; ++it) {
            QString candidate = baseName;
            candidate += privateHeaderSuffix;
            candidate += dot;
            candidate += *it;
            const QFileInfo candidateFi = findFile(absoluteDir, candidate, project);
            if (candidateFi.isFile())
                return candidateFi.absoluteFilePath();
        }
    }
    return QString();
}

QString CppToolsPlugin::correspondingHeaderOrSource(const QString &fileName) const
{
    const QString rc = correspondingHeaderOrSourceI(fileName);
    if (debug)
        qDebug() << Q_FUNC_INFO << fileName << rc;
    return rc;
}

Q_EXPORT_PLUGIN(CppToolsPlugin)