Files
qt-creator/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp

1761 lines
58 KiB
C++
Raw Normal View History

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cppcodemodelinspectordialog.h"
#include "ui_cppcodemodelinspectordialog.h"
#include "cppeditor.h"
C++: Base parsing on editor document instead of widget This mainly takes CppEditorSupport apart. * Parsing is now invoked by CPPEditorDocument itself by listening to QTextDocument::contentsChanged(). * Upon construction and destruction CPPEditorDocument creates and deletes an EditorDocumentHandle for (un)registration in the model manager. This handle provides everything to generate the working copy and to access the editor document processor. * A CPPEditorDocument owns a BaseEditorDocumentProcessor instance that controls parsing, semantic info recalculation and the semantic highlighting for the document. This is more or less what is left from CppEditorSupport and can be considered as the backend of a CPPEditorDocument. CPPEditorDocument itself is quite small. * BuiltinEditorDocumentProcessor and ClangEditorDocumentProcessor derive from BaseEditorDocumentProcessor and implement the gaps. * Since the semantic info calculation was bound to the widget, it also calculated the local uses, which depend on the cursor position. This calculation got moved into the extracted class UseSeletionsUpdater in the cppeditor plugin, which is run once the cursor position changes or the semantic info document is updated. * Some more logic got extracted: - SemanticInfoUpdater (logic was in CppEditorSupport) - SemanticHighlighter (logic was in CppEditorSupport) * The *Parser and *Processor classes can be easily accessed by the static function get(). * CppHighlightingSupport is gone since it turned out to be useless. * The editor dependency in CompletionAssistProviders is gone since we actually only need the file path now. Change-Id: I49d3a7bd138c5ed9620123e34480772535156508 Reviewed-by: Orgad Shaneh <orgads@gmail.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
2014-08-19 15:59:29 +02:00
#include "cppeditordocument.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <cpptools/baseeditordocumentprocessor.h>
#include <cpptools/cppcodemodelinspectordumper.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cpptoolsbridge.h>
#include <cpptools/cppworkingcopy.h>
#include <projectexplorer/project.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/Overview.h>
#include <cplusplus/Token.h>
#include <utils/qtcassert.h>
#include <QAbstractTableModel>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QSortFilterProxyModel>
#include <algorithm>
using namespace CPlusPlus;
using namespace CppTools;
namespace CMI = CppCodeModelInspector;
namespace {
template <class T> void resizeColumns(QTreeView *view)
{
for (int column = 0; column < T::ColumnCount - 1; ++column)
view->resizeColumnToContents(column);
}
TextEditor::BaseTextEditor *currentEditor()
{
return qobject_cast<TextEditor::BaseTextEditor*>(Core::EditorManager::currentEditor());
}
QString fileInCurrentEditor()
{
if (TextEditor::BaseTextEditor *editor = currentEditor())
return editor->document()->filePath().toString();
return QString();
}
class DepthFinder : public SymbolVisitor {
public:
DepthFinder() : m_symbol(0), m_depth(-1), m_foundDepth(-1), m_stop(false) {}
int operator()(const Document::Ptr &document, Symbol *symbol)
{
m_symbol = symbol;
accept(document->globalNamespace());
return m_foundDepth;
}
bool preVisit(Symbol *symbol)
{
if (m_stop)
return false;
if (symbol->asScope()) {
++m_depth;
if (symbol == m_symbol) {
m_foundDepth = m_depth;
m_stop = true;
}
return true;
}
return false;
}
void postVisit(Symbol *symbol)
{
if (symbol->asScope())
--m_depth;
}
private:
Symbol *m_symbol;
int m_depth;
int m_foundDepth;
bool m_stop;
};
} // anonymous namespace
namespace CppEditor {
namespace Internal {
// --- FilterableView -----------------------------------------------------------------------------
class FilterableView : public QWidget
{
Q_OBJECT
public:
FilterableView(QWidget *parent);
void setModel(QAbstractItemModel *model);
QItemSelectionModel *selectionModel() const;
void selectIndex(const QModelIndex &index);
void resizeColumns(int columnCount);
void clearFilter();
signals:
void filterChanged(const QString &filterText);
private:
QTreeView *view;
QLineEdit *lineEdit;
};
FilterableView::FilterableView(QWidget *parent)
: QWidget(parent)
{
view = new QTreeView(this);
view->setAlternatingRowColors(true);
view->setTextElideMode(Qt::ElideMiddle);
view->setSortingEnabled(true);
lineEdit = new QLineEdit(this);
lineEdit->setPlaceholderText(QLatin1String("File Path"));
QObject::connect(lineEdit, &QLineEdit::textChanged, this, &FilterableView::filterChanged);
QLabel *label = new QLabel(QLatin1String("&Filter:"), this);
label->setBuddy(lineEdit);
QPushButton *clearButton = new QPushButton(QLatin1String("&Clear"), this);
QObject::connect(clearButton, &QAbstractButton::clicked, this, &FilterableView::clearFilter);
QHBoxLayout *filterBarLayout = new QHBoxLayout();
filterBarLayout->addWidget(label);
filterBarLayout->addWidget(lineEdit);
filterBarLayout->addWidget(clearButton);
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->addWidget(view);
mainLayout->addLayout(filterBarLayout);
setLayout(mainLayout);
}
void FilterableView::setModel(QAbstractItemModel *model)
{
view->setModel(model);
}
QItemSelectionModel *FilterableView::selectionModel() const
{
return view->selectionModel();
}
void FilterableView::selectIndex(const QModelIndex &index)
{
if (index.isValid()) {
view->selectionModel()->setCurrentIndex(index,
QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
}
}
void FilterableView::resizeColumns(int columnCount)
{
for (int column = 0; column < columnCount - 1; ++column)
view->resizeColumnToContents(column);
}
void FilterableView::clearFilter()
{
lineEdit->clear();
}
// --- ProjectFilesModel --------------------------------------------------------------------------
class ProjectFilesModel : public QAbstractListModel
{
Q_OBJECT
public:
ProjectFilesModel(QObject *parent);
void configure(const QVector<ProjectFile> &files);
void clear();
enum Columns { FileKindColumn, FilePathColumn, ColumnCount };
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
QVector<ProjectFile> m_files;
};
ProjectFilesModel::ProjectFilesModel(QObject *parent) : QAbstractListModel(parent)
{
}
void ProjectFilesModel::configure(const QVector<ProjectFile> &files)
{
emit layoutAboutToBeChanged();
m_files = files;
emit layoutChanged();
}
void ProjectFilesModel::clear()
{
emit layoutAboutToBeChanged();
m_files.clear();
emit layoutChanged();
}
int ProjectFilesModel::rowCount(const QModelIndex &/*parent*/) const
{
return m_files.size();
}
int ProjectFilesModel::columnCount(const QModelIndex &/*parent*/) const
{
return ProjectFilesModel::ColumnCount;
}
QVariant ProjectFilesModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
const int row = index.row();
const int column = index.column();
if (column == FileKindColumn) {
return CMI::Utils::toString(m_files.at(row).kind);
} else if (column == FilePathColumn) {
return m_files.at(row).path;
}
}
return QVariant();
}
QVariant ProjectFilesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case FileKindColumn:
return QLatin1String("File Kind");
case FilePathColumn:
return QLatin1String("File Path");
default:
return QVariant();
}
}
return QVariant();
}
// --- KeyValueModel ------------------------------------------------------------------------------
class KeyValueModel : public QAbstractListModel
{
Q_OBJECT
public:
typedef QList<QPair<QString, QString> > Table;
KeyValueModel(QObject *parent);
void configure(const Table &table);
void clear();
enum Columns { KeyColumn, ValueColumn, ColumnCount };
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
Table m_table;
};
KeyValueModel::KeyValueModel(QObject *parent) : QAbstractListModel(parent)
{
}
void KeyValueModel::configure(const Table &table)
{
emit layoutAboutToBeChanged();
m_table = table;
emit layoutChanged();
}
void KeyValueModel::clear()
{
emit layoutAboutToBeChanged();
m_table.clear();
emit layoutChanged();
}
int KeyValueModel::rowCount(const QModelIndex &/*parent*/) const
{
return m_table.size();
}
int KeyValueModel::columnCount(const QModelIndex &/*parent*/) const
{
return KeyValueModel::ColumnCount;
}
QVariant KeyValueModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
const int row = index.row();
const int column = index.column();
if (column == KeyColumn) {
return m_table.at(row).first;
} else if (column == ValueColumn) {
return m_table.at(row).second;
}
}
return QVariant();
}
QVariant KeyValueModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case KeyColumn:
return QLatin1String("Key");
case ValueColumn:
return QLatin1String("Value");
default:
return QVariant();
}
}
return QVariant();
}
// --- SnapshotModel ------------------------------------------------------------------------------
class SnapshotModel : public QAbstractListModel
{
Q_OBJECT
public:
SnapshotModel(QObject *parent);
void configure(const Snapshot &snapshot);
void setGlobalSnapshot(const Snapshot &snapshot);
QModelIndex indexForDocument(const QString &filePath);
enum Columns { SymbolCountColumn, SharedColumn, FilePathColumn, ColumnCount };
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
QList<Document::Ptr> m_documents;
Snapshot m_globalSnapshot;
};
SnapshotModel::SnapshotModel(QObject *parent) : QAbstractListModel(parent)
{
}
void SnapshotModel::configure(const Snapshot &snapshot)
{
emit layoutAboutToBeChanged();
m_documents = CMI::Utils::snapshotToList(snapshot);
emit layoutChanged();
}
void SnapshotModel::setGlobalSnapshot(const Snapshot &snapshot)
{
m_globalSnapshot = snapshot;
}
QModelIndex SnapshotModel::indexForDocument(const QString &filePath)
{
for (int i = 0, total = m_documents.size(); i < total; ++i) {
const Document::Ptr document = m_documents.at(i);
if (document->fileName() == filePath)
return index(i, FilePathColumn);
}
return QModelIndex();
}
int SnapshotModel::rowCount(const QModelIndex &/*parent*/) const
{
return m_documents.size();
}
int SnapshotModel::columnCount(const QModelIndex &/*parent*/) const
{
return SnapshotModel::ColumnCount;
}
QVariant SnapshotModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
const int column = index.column();
Document::Ptr document = m_documents.at(index.row());
if (column == SymbolCountColumn) {
return document->control()->symbolCount();
} else if (column == SharedColumn) {
Document::Ptr globalDocument = m_globalSnapshot.document(document->fileName());
const bool isShared
= globalDocument && globalDocument->fingerprint() == document->fingerprint();
return CMI::Utils::toString(isShared);
} else if (column == FilePathColumn) {
return QDir::toNativeSeparators(document->fileName());
}
}
return QVariant();
}
QVariant SnapshotModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case SymbolCountColumn:
return QLatin1String("Symbols");
case SharedColumn:
return QLatin1String("Shared");
case FilePathColumn:
return QLatin1String("File Path");
default:
return QVariant();
}
}
return QVariant();
}
// --- IncludesModel ------------------------------------------------------------------------------
static bool includesSorter(const Document::Include &i1,
const Document::Include &i2)
{
return i1.line() < i2.line();
}
class IncludesModel : public QAbstractListModel
{
Q_OBJECT
public:
IncludesModel(QObject *parent);
void configure(const QList<Document::Include> &includes);
void clear();
enum Columns { ResolvedOrNotColumn, LineNumberColumn, FilePathsColumn, ColumnCount };
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
QList<Document::Include> m_includes;
};
IncludesModel::IncludesModel(QObject *parent) : QAbstractListModel(parent)
{
}
void IncludesModel::configure(const QList<Document::Include> &includes)
{
emit layoutAboutToBeChanged();
m_includes = includes;
std::stable_sort(m_includes.begin(), m_includes.end(), includesSorter);
emit layoutChanged();
}
void IncludesModel::clear()
{
emit layoutAboutToBeChanged();
m_includes.clear();
emit layoutChanged();
}
int IncludesModel::rowCount(const QModelIndex &/*parent*/) const
{
return m_includes.size();
}
int IncludesModel::columnCount(const QModelIndex &/*parent*/) const
{
return IncludesModel::ColumnCount;
}
QVariant IncludesModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole && role != Qt::ForegroundRole)
return QVariant();
static const QBrush greenBrush(QColor(0, 139, 69));
static const QBrush redBrush(QColor(205, 38, 38));
const Document::Include include = m_includes.at(index.row());
const QString resolvedFileName = QDir::toNativeSeparators(include.resolvedFileName());
const bool isResolved = !resolvedFileName.isEmpty();
if (role == Qt::DisplayRole) {
const int column = index.column();
if (column == ResolvedOrNotColumn) {
return CMI::Utils::toString(isResolved);
} else if (column == LineNumberColumn) {
return include.line();
} else if (column == FilePathsColumn) {
return QVariant(CMI::Utils::unresolvedFileNameWithDelimiters(include)
+ QLatin1String(" --> ") + resolvedFileName);
}
} else if (role == Qt::ForegroundRole) {
return isResolved ? greenBrush : redBrush;
}
return QVariant();
}
QVariant IncludesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case ResolvedOrNotColumn:
return QLatin1String("Resolved");
case LineNumberColumn:
return QLatin1String("Line");
case FilePathsColumn:
return QLatin1String("File Paths");
default:
return QVariant();
}
}
return QVariant();
}
// --- DiagnosticMessagesModel --------------------------------------------------------------------
static bool diagnosticMessagesModelSorter(const Document::DiagnosticMessage &m1,
const Document::DiagnosticMessage &m2)
{
return m1.line() < m2.line();
}
class DiagnosticMessagesModel : public QAbstractListModel
{
Q_OBJECT
public:
DiagnosticMessagesModel(QObject *parent);
void configure(const QList<Document::DiagnosticMessage> &messages);
void clear();
enum Columns { LevelColumn, LineColumnNumberColumn, MessageColumn, ColumnCount };
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
QList<Document::DiagnosticMessage> m_messages;
};
DiagnosticMessagesModel::DiagnosticMessagesModel(QObject *parent) : QAbstractListModel(parent)
{
}
void DiagnosticMessagesModel::configure(
const QList<Document::DiagnosticMessage> &messages)
{
emit layoutAboutToBeChanged();
m_messages = messages;
std::stable_sort(m_messages.begin(), m_messages.end(), diagnosticMessagesModelSorter);
emit layoutChanged();
}
void DiagnosticMessagesModel::clear()
{
emit layoutAboutToBeChanged();
m_messages.clear();
emit layoutChanged();
}
int DiagnosticMessagesModel::rowCount(const QModelIndex &/*parent*/) const
{
return m_messages.size();
}
int DiagnosticMessagesModel::columnCount(const QModelIndex &/*parent*/) const
{
return DiagnosticMessagesModel::ColumnCount;
}
QVariant DiagnosticMessagesModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole && role != Qt::ForegroundRole)
return QVariant();
static const QBrush yellowOrangeBrush(QColor(237, 145, 33));
static const QBrush redBrush(QColor(205, 38, 38));
static const QBrush darkRedBrushQColor(QColor(139, 0, 0));
const Document::DiagnosticMessage message = m_messages.at(index.row());
const Document::DiagnosticMessage::Level level
= static_cast<Document::DiagnosticMessage::Level>(message.level());
if (role == Qt::DisplayRole) {
const int column = index.column();
if (column == LevelColumn) {
return CMI::Utils::toString(level);
} else if (column == LineColumnNumberColumn) {
return QVariant(QString::number(message.line()) + QLatin1Char(':')
+ QString::number(message.column()));
} else if (column == MessageColumn) {
return message.text();
}
} else if (role == Qt::ForegroundRole) {
switch (level) {
case Document::DiagnosticMessage::Warning:
return yellowOrangeBrush;
case Document::DiagnosticMessage::Error:
return redBrush;
case Document::DiagnosticMessage::Fatal:
return darkRedBrushQColor;
default:
return QVariant();
}
}
return QVariant();
}
QVariant DiagnosticMessagesModel::headerData(int section, Qt::Orientation orientation, int role)
const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case LevelColumn:
return QLatin1String("Level");
case LineColumnNumberColumn:
return QLatin1String("Line:Column");
case MessageColumn:
return QLatin1String("Message");
default:
return QVariant();
}
}
return QVariant();
}
// --- MacrosModel --------------------------------------------------------------------------------
class MacrosModel : public QAbstractListModel
{
Q_OBJECT
public:
MacrosModel(QObject *parent);
void configure(const QList<Macro> &macros);
void clear();
enum Columns { LineNumberColumn, MacroColumn, ColumnCount };
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
QList<Macro> m_macros;
};
MacrosModel::MacrosModel(QObject *parent) : QAbstractListModel(parent)
{
}
void MacrosModel::configure(const QList<Macro> &macros)
{
emit layoutAboutToBeChanged();
m_macros = macros;
emit layoutChanged();
}
void MacrosModel::clear()
{
emit layoutAboutToBeChanged();
m_macros.clear();
emit layoutChanged();
}
int MacrosModel::rowCount(const QModelIndex &/*parent*/) const
{
return m_macros.size();
}
int MacrosModel::columnCount(const QModelIndex &/*parent*/) const
{
return MacrosModel::ColumnCount;
}
QVariant MacrosModel::data(const QModelIndex &index, int role) const
{
const int column = index.column();
if (role == Qt::DisplayRole || (role == Qt::ToolTipRole && column == MacroColumn)) {
const Macro macro = m_macros.at(index.row());
if (column == LineNumberColumn)
return macro.line();
else if (column == MacroColumn)
return macro.toString();
} else if (role == Qt::TextAlignmentRole) {
return Qt::AlignTop + Qt::AlignLeft;
}
return QVariant();
}
QVariant MacrosModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case LineNumberColumn:
return QLatin1String("Line");
case MacroColumn:
return QLatin1String("Macro");
default:
return QVariant();
}
}
return QVariant();
}
// --- SymbolsModel -------------------------------------------------------------------------------
class SymbolsModel : public QAbstractItemModel
{
Q_OBJECT
public:
SymbolsModel(QObject *parent);
void configure(const Document::Ptr &document);
void clear();
enum Columns { SymbolColumn, LineNumberColumn, ColumnCount };
QModelIndex index(int row, int column, const QModelIndex &parent) const;
QModelIndex parent(const QModelIndex &child) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
Document::Ptr m_document;
};
SymbolsModel::SymbolsModel(QObject *parent) : QAbstractItemModel(parent)
{
}
void SymbolsModel::configure(const Document::Ptr &document)
{
QTC_CHECK(document);
emit layoutAboutToBeChanged();
m_document = document;
emit layoutChanged();
}
void SymbolsModel::clear()
{
emit layoutAboutToBeChanged();
m_document.clear();
emit layoutChanged();
}
static Symbol *indexToSymbol(const QModelIndex &index)
{
if (Symbol *symbol = static_cast<Symbol*>(index.internalPointer()))
return symbol;
return 0;
}
static Scope *indexToScope(const QModelIndex &index)
{
if (Symbol *symbol = indexToSymbol(index))
return symbol->asScope();
return 0;
}
QModelIndex SymbolsModel::index(int row, int column, const QModelIndex &parent) const
{
Scope *scope = 0;
if (parent.isValid())
scope = indexToScope(parent);
else if (m_document)
scope = m_document->globalNamespace();
if (scope) {
if ((unsigned)row < scope->memberCount())
return createIndex(row, column, scope->memberAt(row));
}
return QModelIndex();
}
QModelIndex SymbolsModel::parent(const QModelIndex &child) const
{
if (!child.isValid())
return QModelIndex();
if (Symbol *symbol = indexToSymbol(child)) {
if (Scope *scope = symbol->enclosingScope()) {
const int row = DepthFinder()(m_document, scope);
return createIndex(row, 0, scope);
}
}
return QModelIndex();
}
int SymbolsModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
if (Scope *scope = indexToScope(parent))
return scope->memberCount();
} else {
if (m_document)
return m_document->globalNamespace()->memberCount();
}
return 0;
}
int SymbolsModel::columnCount(const QModelIndex &) const
{
return ColumnCount;
}
QVariant SymbolsModel::data(const QModelIndex &index, int role) const
{
const int column = index.column();
if (role == Qt::DisplayRole) {
Symbol *symbol = indexToSymbol(index);
if (!symbol)
return QVariant();
if (column == LineNumberColumn) {
return symbol->line();
} else if (column == SymbolColumn) {
QString name = Overview().prettyName(symbol->name());
if (name.isEmpty())
name = QLatin1String(symbol->isBlock() ? "<block>" : "<no name>");
return name;
}
}
return QVariant();
}
QVariant SymbolsModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case SymbolColumn:
return QLatin1String("Symbol");
case LineNumberColumn:
return QLatin1String("Line");
default:
return QVariant();
}
}
return QVariant();
}
// --- TokensModel --------------------------------------------------------------------------------
class TokensModel : public QAbstractListModel
{
Q_OBJECT
public:
TokensModel(QObject *parent);
void configure(TranslationUnit *translationUnit);
void clear();
enum Columns { SpelledColumn, KindColumn, IndexColumn, OffsetColumn, LineColumnNumberColumn,
BytesAndCodePointsColumn, GeneratedColumn, ExpandedColumn, WhiteSpaceColumn,
NewlineColumn, ColumnCount };
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
struct TokenInfo {
Token token;
unsigned line;
unsigned column;
};
QList<TokenInfo> m_tokenInfos;
};
TokensModel::TokensModel(QObject *parent) : QAbstractListModel(parent)
{
}
void TokensModel::configure(TranslationUnit *translationUnit)
{
if (!translationUnit)
return;
emit layoutAboutToBeChanged();
m_tokenInfos.clear();
for (int i = 0, total = translationUnit->tokenCount(); i < total; ++i) {
TokenInfo info;
info.token = translationUnit->tokenAt(i);
translationUnit->getPosition(info.token.utf16charsBegin(), &info.line, &info.column);
m_tokenInfos.append(info);
}
emit layoutChanged();
}
void TokensModel::clear()
{
emit layoutAboutToBeChanged();
m_tokenInfos.clear();
emit layoutChanged();
}
int TokensModel::rowCount(const QModelIndex &/*parent*/) const
{
return m_tokenInfos.size();
}
int TokensModel::columnCount(const QModelIndex &/*parent*/) const
{
return TokensModel::ColumnCount;
}
QVariant TokensModel::data(const QModelIndex &index, int role) const
{
const int column = index.column();
if (role == Qt::DisplayRole) {
const TokenInfo info = m_tokenInfos.at(index.row());
const Token token = info.token;
if (column == SpelledColumn)
return QString::fromUtf8(token.spell());
else if (column == KindColumn)
return CMI::Utils::toString(static_cast<Kind>(token.kind()));
else if (column == IndexColumn)
return index.row();
else if (column == OffsetColumn)
return token.bytesBegin();
else if (column == LineColumnNumberColumn)
return QString::fromLatin1("%1:%2").arg(CMI::Utils::toString(info.line),
CMI::Utils::toString(info.column));
else if (column == BytesAndCodePointsColumn)
return QString::fromLatin1("%1/%2").arg(CMI::Utils::toString(token.bytes()),
CMI::Utils::toString(token.utf16chars()));
else if (column == GeneratedColumn)
return CMI::Utils::toString(token.generated());
else if (column == ExpandedColumn)
return CMI::Utils::toString(token.expanded());
else if (column == WhiteSpaceColumn)
return CMI::Utils::toString(token.whitespace());
else if (column == NewlineColumn)
return CMI::Utils::toString(token.newline());
} else if (role == Qt::TextAlignmentRole) {
return Qt::AlignTop + Qt::AlignLeft;
}
return QVariant();
}
QVariant TokensModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case SpelledColumn:
return QLatin1String("Spelled");
case KindColumn:
return QLatin1String("Kind");
case IndexColumn:
return QLatin1String("Index");
case OffsetColumn:
return QLatin1String("Offset");
case LineColumnNumberColumn:
return QLatin1String("Line:Column");
case BytesAndCodePointsColumn:
return QLatin1String("Bytes/Codepoints");
case GeneratedColumn:
return QLatin1String("Generated");
case ExpandedColumn:
return QLatin1String("Expanded");
case WhiteSpaceColumn:
return QLatin1String("Whitespace");
case NewlineColumn:
return QLatin1String("Newline");
default:
return QVariant();
}
}
return QVariant();
}
// --- ProjectPartsModel --------------------------------------------------------------------------
class ProjectPartsModel : public QAbstractListModel
{
Q_OBJECT
public:
ProjectPartsModel(QObject *parent);
void configure(const QList<ProjectInfo> &projectInfos,
const ProjectPart::Ptr &currentEditorsProjectPart);
QModelIndex indexForCurrentEditorsProjectPart() const;
ProjectPart::Ptr projectPartForProjectId(const QString &projectPartId) const;
enum Columns { PartNameColumn, PartFilePathColumn, ColumnCount };
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
QList<ProjectPart::Ptr> m_projectPartsList;
int m_currentEditorsProjectPartIndex;
};
ProjectPartsModel::ProjectPartsModel(QObject *parent)
: QAbstractListModel(parent), m_currentEditorsProjectPartIndex(-1)
{
}
void ProjectPartsModel::configure(const QList<ProjectInfo> &projectInfos,
const ProjectPart::Ptr &currentEditorsProjectPart)
{
emit layoutAboutToBeChanged();
m_projectPartsList.clear();
foreach (const ProjectInfo &info, projectInfos) {
foreach (const ProjectPart::Ptr &projectPart, info.projectParts()) {
if (!m_projectPartsList.contains(projectPart)) {
m_projectPartsList << projectPart;
if (projectPart == currentEditorsProjectPart)
m_currentEditorsProjectPartIndex = m_projectPartsList.size() - 1;
}
}
}
emit layoutChanged();
}
QModelIndex ProjectPartsModel::indexForCurrentEditorsProjectPart() const
{
if (m_currentEditorsProjectPartIndex == -1)
return QModelIndex();
return createIndex(m_currentEditorsProjectPartIndex, PartFilePathColumn);
}
ProjectPart::Ptr ProjectPartsModel::projectPartForProjectId(const QString &projectPartId) const
{
foreach (const ProjectPart::Ptr &part, m_projectPartsList) {
if (part->id() == projectPartId)
return part;
}
return ProjectPart::Ptr();
}
int ProjectPartsModel::rowCount(const QModelIndex &/*parent*/) const
{
return m_projectPartsList.size();
}
int ProjectPartsModel::columnCount(const QModelIndex &/*parent*/) const
{
return ProjectPartsModel::ColumnCount;
}
QVariant ProjectPartsModel::data(const QModelIndex &index, int role) const
{
const int row = index.row();
if (role == Qt::DisplayRole) {
const int column = index.column();
if (column == PartNameColumn)
return m_projectPartsList.at(row)->displayName;
else if (column == PartFilePathColumn)
return QDir::toNativeSeparators(m_projectPartsList.at(row)->projectFile);
} else if (role == Qt::UserRole) {
return m_projectPartsList.at(row)->id();
}
return QVariant();
}
QVariant ProjectPartsModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case PartNameColumn:
return QLatin1String("Name");
case PartFilePathColumn:
return QLatin1String("Project File Path");
default:
return QVariant();
}
}
return QVariant();
}
// --- WorkingCopyModel ---------------------------------------------------------------------------
class WorkingCopyModel : public QAbstractListModel
{
Q_OBJECT
public:
WorkingCopyModel(QObject *parent);
void configure(const WorkingCopy &workingCopy);
QModelIndex indexForFile(const QString &filePath);
enum Columns { RevisionColumn, FilePathColumn, ColumnCount };
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
struct WorkingCopyEntry {
WorkingCopyEntry(const QString &filePath, const QByteArray &source, unsigned revision)
: filePath(filePath), source(source), revision(revision)
{}
QString filePath;
QByteArray source;
unsigned revision;
};
QList<WorkingCopyEntry> m_workingCopyList;
};
WorkingCopyModel::WorkingCopyModel(QObject *parent) : QAbstractListModel(parent)
{
}
void WorkingCopyModel::configure(const WorkingCopy &workingCopy)
{
emit layoutAboutToBeChanged();
m_workingCopyList.clear();
QHashIterator<Utils::FileName, QPair<QByteArray, unsigned> > it = workingCopy.iterator();
while (it.hasNext()) {
it.next();
m_workingCopyList << WorkingCopyEntry(it.key().toString(), it.value().first,
it.value().second);
}
emit layoutChanged();
}
QModelIndex WorkingCopyModel::indexForFile(const QString &filePath)
{
for (int i = 0, total = m_workingCopyList.size(); i < total; ++i) {
const WorkingCopyEntry entry = m_workingCopyList.at(i);
if (entry.filePath == filePath)
return index(i, FilePathColumn);
}
return QModelIndex();
}
int WorkingCopyModel::rowCount(const QModelIndex &/*parent*/) const
{
return m_workingCopyList.size();
}
int WorkingCopyModel::columnCount(const QModelIndex &/*parent*/) const
{
return WorkingCopyModel::ColumnCount;
}
QVariant WorkingCopyModel::data(const QModelIndex &index, int role) const
{
const int row = index.row();
if (role == Qt::DisplayRole) {
const int column = index.column();
if (column == RevisionColumn)
return m_workingCopyList.at(row).revision;
else if (column == FilePathColumn)
return m_workingCopyList.at(row).filePath;
} else if (role == Qt::UserRole) {
return m_workingCopyList.at(row).source;
}
return QVariant();
}
QVariant WorkingCopyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case RevisionColumn:
return QLatin1String("Revision");
case FilePathColumn:
return QLatin1String("File Path");
default:
return QVariant();
}
}
return QVariant();
}
// --- SnapshotInfo -------------------------------------------------------------------------------
class SnapshotInfo
{
public:
enum Type { GlobalSnapshot, EditorSnapshot };
SnapshotInfo(const Snapshot &snapshot, Type type)
: snapshot(snapshot), type(type) {}
Snapshot snapshot;
Type type;
};
// --- CppCodeModelInspectorDialog ----------------------------------------------------------------
CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent)
: QDialog(parent)
, m_ui(new Ui::CppCodeModelInspectorDialog)
, m_snapshotInfos(new QList<SnapshotInfo>())
, m_snapshotView(new FilterableView(this))
, m_snapshotModel(new SnapshotModel(this))
, m_proxySnapshotModel(new QSortFilterProxyModel(this))
, m_docGenericInfoModel(new KeyValueModel(this))
, m_docIncludesModel(new IncludesModel(this))
, m_docDiagnosticMessagesModel(new DiagnosticMessagesModel(this))
, m_docMacrosModel(new MacrosModel(this))
, m_docSymbolsModel(new SymbolsModel(this))
, m_docTokensModel(new TokensModel(this))
, m_projectPartsView(new FilterableView(this))
, m_projectPartsModel(new ProjectPartsModel(this))
, m_proxyProjectPartsModel(new QSortFilterProxyModel(this))
, m_partGenericInfoModel(new KeyValueModel(this))
, m_projectFilesModel(new ProjectFilesModel(this))
, m_workingCopyView(new FilterableView(this))
, m_workingCopyModel(new WorkingCopyModel(this))
, m_proxyWorkingCopyModel(new QSortFilterProxyModel(this))
{
m_ui->setupUi(this);
m_ui->snapshotSelectorAndViewLayout->addWidget(m_snapshotView);
m_ui->projectPartsSplitter->insertWidget(0, m_projectPartsView);
m_ui->workingCopySplitter->insertWidget(0, m_workingCopyView);
setAttribute(Qt::WA_DeleteOnClose);
connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &QWidget::close);
m_proxySnapshotModel->setSourceModel(m_snapshotModel);
m_proxySnapshotModel->setFilterKeyColumn(SnapshotModel::FilePathColumn);
m_snapshotView->setModel(m_proxySnapshotModel);
m_ui->docGeneralView->setModel(m_docGenericInfoModel);
m_ui->docIncludesView->setModel(m_docIncludesModel);
m_ui->docDiagnosticMessagesView->setModel(m_docDiagnosticMessagesModel);
m_ui->docDefinedMacrosView->setModel(m_docMacrosModel);
m_ui->docSymbolsView->setModel(m_docSymbolsModel);
m_ui->docTokensView->setModel(m_docTokensModel);
m_proxyProjectPartsModel->setSourceModel(m_projectPartsModel);
m_proxyProjectPartsModel->setFilterKeyColumn(ProjectPartsModel::PartFilePathColumn);
m_projectPartsView->setModel(m_proxyProjectPartsModel);
m_ui->partGeneralView->setModel(m_partGenericInfoModel);
m_ui->projectFilesView->setModel(m_projectFilesModel);
m_proxyWorkingCopyModel->setSourceModel(m_workingCopyModel);
m_proxyWorkingCopyModel->setFilterKeyColumn(WorkingCopyModel::FilePathColumn);
m_workingCopyView->setModel(m_proxyWorkingCopyModel);
connect(m_snapshotView->selectionModel(),
&QItemSelectionModel::currentRowChanged,
this, &CppCodeModelInspectorDialog::onDocumentSelected);
connect(m_snapshotView, &FilterableView::filterChanged,
this, &CppCodeModelInspectorDialog::onSnapshotFilterChanged);
connect(m_ui->snapshotSelector,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &CppCodeModelInspectorDialog::onSnapshotSelected);
connect(m_ui->docSymbolsView, &QTreeView::expanded,
this, &CppCodeModelInspectorDialog::onSymbolsViewExpandedOrCollapsed);
connect(m_ui->docSymbolsView, &QTreeView::collapsed,
this, &CppCodeModelInspectorDialog::onSymbolsViewExpandedOrCollapsed);
connect(m_projectPartsView->selectionModel(),
&QItemSelectionModel::currentRowChanged,
this, &CppCodeModelInspectorDialog::onProjectPartSelected);
connect(m_projectPartsView, &FilterableView::filterChanged,
this, &CppCodeModelInspectorDialog::onProjectPartFilterChanged);
connect(m_workingCopyView->selectionModel(),
&QItemSelectionModel::currentRowChanged,
this, &CppCodeModelInspectorDialog::onWorkingCopyDocumentSelected);
connect(m_workingCopyView, &FilterableView::filterChanged,
this, &CppCodeModelInspectorDialog::onWorkingCopyFilterChanged);
connect(m_ui->refreshButton, &QAbstractButton::clicked, this, &CppCodeModelInspectorDialog::onRefreshRequested);
connect(m_ui->closeButton, &QAbstractButton::clicked, this, &QWidget::close);
refresh();
}
CppCodeModelInspectorDialog::~CppCodeModelInspectorDialog()
{
delete m_snapshotInfos;
delete m_ui;
}
void CppCodeModelInspectorDialog::onRefreshRequested()
{
refresh();
}
void CppCodeModelInspectorDialog::onSnapshotFilterChanged(const QString &pattern)
{
m_proxySnapshotModel->setFilterWildcard(pattern);
}
void CppCodeModelInspectorDialog::onSnapshotSelected(int row)
{
if (row < 0 || row >= m_snapshotInfos->size())
return;
m_snapshotView->clearFilter();
const SnapshotInfo info = m_snapshotInfos->at(row);
m_snapshotModel->configure(info.snapshot);
m_snapshotView->resizeColumns(SnapshotModel::ColumnCount);
if (info.type == SnapshotInfo::GlobalSnapshot) {
// Select first document
const QModelIndex index = m_proxySnapshotModel->index(0, SnapshotModel::FilePathColumn);
m_snapshotView->selectIndex(index);
} else if (info.type == SnapshotInfo::EditorSnapshot) {
// Select first document, unless we can find the editor document
QModelIndex index = m_snapshotModel->indexForDocument(fileInCurrentEditor());
index = m_proxySnapshotModel->mapFromSource(index);
if (!index.isValid())
index = m_proxySnapshotModel->index(0, SnapshotModel::FilePathColumn);
m_snapshotView->selectIndex(index);
}
}
void CppCodeModelInspectorDialog::onDocumentSelected(const QModelIndex &current,
const QModelIndex &)
{
if (current.isValid()) {
const QModelIndex index = m_proxySnapshotModel->index(current.row(),
SnapshotModel::FilePathColumn);
const QString filePath = QDir::fromNativeSeparators(
m_proxySnapshotModel->data(index, Qt::DisplayRole).toString());
const SnapshotInfo info = m_snapshotInfos->at(m_ui->snapshotSelector->currentIndex());
updateDocumentData(info.snapshot.document(filePath));
} else {
clearDocumentData();
}
}
void CppCodeModelInspectorDialog::onSymbolsViewExpandedOrCollapsed(const QModelIndex &)
{
resizeColumns<SymbolsModel>(m_ui->docSymbolsView);
}
void CppCodeModelInspectorDialog::onProjectPartFilterChanged(const QString &pattern)
{
m_proxyProjectPartsModel->setFilterWildcard(pattern);
}
void CppCodeModelInspectorDialog::onProjectPartSelected(const QModelIndex &current,
const QModelIndex &)
{
if (current.isValid()) {
QModelIndex index = m_proxyProjectPartsModel->mapToSource(current);
if (index.isValid()) {
index = m_projectPartsModel->index(index.row(), ProjectPartsModel::PartFilePathColumn);
const QString projectPartId = m_projectPartsModel->data(index, Qt::UserRole).toString();
updateProjectPartData(m_projectPartsModel->projectPartForProjectId(projectPartId));
}
} else {
clearProjectPartData();
}
}
void CppCodeModelInspectorDialog::onWorkingCopyFilterChanged(const QString &pattern)
{
m_proxyWorkingCopyModel->setFilterWildcard(pattern);
}
void CppCodeModelInspectorDialog::onWorkingCopyDocumentSelected(const QModelIndex &current,
const QModelIndex &)
{
if (current.isValid()) {
const QModelIndex index = m_proxyWorkingCopyModel->mapToSource(current);
if (index.isValid()) {
const QString source
= QString::fromUtf8(m_workingCopyModel->data(index, Qt::UserRole).toByteArray());
m_ui->workingCopySourceEdit->setPlainText(source);
}
} else {
m_ui->workingCopySourceEdit->clear();
}
}
void CppCodeModelInspectorDialog::refresh()
{
CppModelManager *cmmi = CppModelManager::instance();
const int oldSnapshotIndex = m_ui->snapshotSelector->currentIndex();
const bool selectEditorRelevant
= m_ui->selectEditorRelevantEntriesAfterRefreshCheckBox->isChecked();
// Snapshots and Documents
m_snapshotInfos->clear();
m_ui->snapshotSelector->clear();
const Snapshot globalSnapshot = cmmi->snapshot();
CppCodeModelInspector::Dumper dumper(globalSnapshot);
m_snapshotModel->setGlobalSnapshot(globalSnapshot);
m_snapshotInfos->append(SnapshotInfo(globalSnapshot, SnapshotInfo::GlobalSnapshot));
const QString globalSnapshotTitle
= QString::fromLatin1("Global/Indexing Snapshot (%1 Documents)").arg(globalSnapshot.size());
m_ui->snapshotSelector->addItem(globalSnapshotTitle);
dumper.dumpSnapshot(globalSnapshot, globalSnapshotTitle, /*isGlobalSnapshot=*/ true);
TextEditor::BaseTextEditor *editor = currentEditor();
CppTools::CppEditorDocumentHandle *cppEditorDocument = 0;
if (editor) {
const QString editorFilePath = editor->document()->filePath().toString();
cppEditorDocument = cmmi->cppEditorDocument(editorFilePath);
if (auto *documentProcessor = CppToolsBridge::baseEditorDocumentProcessor(editorFilePath)) {
const Snapshot editorSnapshot = documentProcessor->snapshot();
m_snapshotInfos->append(SnapshotInfo(editorSnapshot, SnapshotInfo::EditorSnapshot));
const QString editorSnapshotTitle
= QString::fromLatin1("Current Editor's Snapshot (%1 Documents)")
.arg(editorSnapshot.size());
dumper.dumpSnapshot(editorSnapshot, editorSnapshotTitle);
m_ui->snapshotSelector->addItem(editorSnapshotTitle);
}
CppEditorWidget *cppEditorWidget = qobject_cast<CppEditorWidget *>(editor->editorWidget());
if (cppEditorWidget) {
SemanticInfo semanticInfo = cppEditorWidget->semanticInfo();
Snapshot snapshot;
// Add semantic info snapshot
snapshot = semanticInfo.snapshot;
m_snapshotInfos->append(SnapshotInfo(snapshot, SnapshotInfo::EditorSnapshot));
m_ui->snapshotSelector->addItem(
QString::fromLatin1("Current Editor's Semantic Info Snapshot (%1 Documents)")
.arg(snapshot.size()));
// Add a pseudo snapshot containing only the semantic info document since this document
// is not part of the semantic snapshot.
snapshot = Snapshot();
snapshot.insert(cppEditorWidget->semanticInfo().doc);
m_snapshotInfos->append(SnapshotInfo(snapshot, SnapshotInfo::EditorSnapshot));
const QString snapshotTitle
= QString::fromLatin1("Current Editor's Pseudo Snapshot with Semantic Info Document (%1 Documents)")
.arg(snapshot.size());
dumper.dumpSnapshot(snapshot, snapshotTitle);
m_ui->snapshotSelector->addItem(snapshotTitle);
}
}
int snapshotIndex = 0;
if (selectEditorRelevant) {
for (int i = 0, total = m_snapshotInfos->size(); i < total; ++i) {
const SnapshotInfo info = m_snapshotInfos->at(i);
if (info.type == SnapshotInfo::EditorSnapshot) {
snapshotIndex = i;
break;
}
}
} else if (oldSnapshotIndex < m_snapshotInfos->size()) {
snapshotIndex = oldSnapshotIndex;
}
m_ui->snapshotSelector->setCurrentIndex(snapshotIndex);
onSnapshotSelected(snapshotIndex);
// Project Parts
const ProjectPart::Ptr editorsProjectPart = cppEditorDocument
? cppEditorDocument->processor()->parser()->projectPart()
: ProjectPart::Ptr();
const QList<ProjectInfo> projectInfos = cmmi->projectInfos();
dumper.dumpProjectInfos(projectInfos);
m_projectPartsModel->configure(projectInfos, editorsProjectPart);
m_projectPartsView->resizeColumns(ProjectPartsModel::ColumnCount);
QModelIndex index = m_proxyProjectPartsModel->index(0, ProjectPartsModel::PartFilePathColumn);
if (index.isValid()) {
if (selectEditorRelevant && editorsProjectPart) {
QModelIndex editorPartIndex = m_projectPartsModel->indexForCurrentEditorsProjectPart();
editorPartIndex = m_proxyProjectPartsModel->mapFromSource(editorPartIndex);
if (editorPartIndex.isValid())
index = editorPartIndex;
}
m_projectPartsView->selectIndex(index);
}
// Working Copy
const WorkingCopy workingCopy = cmmi->workingCopy();
dumper.dumpWorkingCopy(workingCopy);
m_workingCopyModel->configure(workingCopy);
m_workingCopyView->resizeColumns(WorkingCopyModel::ColumnCount);
if (workingCopy.size() > 0) {
QModelIndex index = m_proxyWorkingCopyModel->index(0, WorkingCopyModel::FilePathColumn);
if (selectEditorRelevant) {
const QModelIndex eindex = m_workingCopyModel->indexForFile(fileInCurrentEditor());
if (eindex.isValid())
index = m_proxyWorkingCopyModel->mapFromSource(eindex);
}
m_workingCopyView->selectIndex(index);
}
// Merged entities
dumper.dumpMergedEntities(cmmi->headerPaths(), cmmi->definedMacros());
}
enum DocumentTabs {
DocumentGeneralTab,
DocumentIncludesTab,
DocumentDiagnosticsTab,
DocumentDefinedMacrosTab,
DocumentPreprocessedSourceTab,
DocumentSymbolsTab,
DocumentTokensTab
};
static QString docTabName(int tabIndex, int numberOfEntries = -1)
{
const char *names[] = {
"&General",
"&Includes",
"&Diagnostic Messages",
"(Un)Defined &Macros",
"P&reprocessed Source",
"&Symbols",
"&Tokens"
};
QString result = QLatin1String(names[tabIndex]);
if (numberOfEntries != -1)
result += QString::fromLatin1(" (%1)").arg(numberOfEntries);
return result;
}
void CppCodeModelInspectorDialog::clearDocumentData()
{
m_docGenericInfoModel->clear();
m_ui->docTab->setTabText(DocumentIncludesTab, docTabName(DocumentIncludesTab));
m_docIncludesModel->clear();
m_ui->docTab->setTabText(DocumentDiagnosticsTab, docTabName(DocumentDiagnosticsTab));
m_docDiagnosticMessagesModel->clear();
m_ui->docTab->setTabText(DocumentDefinedMacrosTab, docTabName(DocumentDefinedMacrosTab));
m_docMacrosModel->clear();
m_ui->docPreprocessedSourceEdit->clear();
m_docSymbolsModel->clear();
m_ui->docTab->setTabText(DocumentTokensTab, docTabName(DocumentTokensTab));
m_docTokensModel->clear();
}
void CppCodeModelInspectorDialog::updateDocumentData(const Document::Ptr &document)
{
QTC_ASSERT(document, return);
// General
KeyValueModel::Table table = KeyValueModel::Table()
<< qMakePair(QString::fromLatin1("File Path"),
QDir::toNativeSeparators(document->fileName()))
<< qMakePair(QString::fromLatin1("Last Modified"),
CMI::Utils::toString(document->lastModified()))
<< qMakePair(QString::fromLatin1("Revision"),
CMI::Utils::toString(document->revision()))
<< qMakePair(QString::fromLatin1("Editor Revision"),
CMI::Utils::toString(document->editorRevision()))
<< qMakePair(QString::fromLatin1("Check Mode"),
CMI::Utils::toString(document->checkMode()))
<< qMakePair(QString::fromLatin1("Tokenized"),
CMI::Utils::toString(document->isTokenized()))
<< qMakePair(QString::fromLatin1("Parsed"),
CMI::Utils::toString(document->isParsed()))
<< qMakePair(QString::fromLatin1("Project Parts"),
CMI::Utils::partsForFile(document->fileName()))
;
m_docGenericInfoModel->configure(table);
resizeColumns<KeyValueModel>(m_ui->docGeneralView);
// Includes
m_docIncludesModel->configure(document->resolvedIncludes() + document->unresolvedIncludes());
resizeColumns<IncludesModel>(m_ui->docIncludesView);
m_ui->docTab->setTabText(DocumentIncludesTab,
docTabName(DocumentIncludesTab, m_docIncludesModel->rowCount()));
// Diagnostic Messages
m_docDiagnosticMessagesModel->configure(document->diagnosticMessages());
resizeColumns<DiagnosticMessagesModel>(m_ui->docDiagnosticMessagesView);
m_ui->docTab->setTabText(DocumentDiagnosticsTab,
docTabName(DocumentDiagnosticsTab, m_docDiagnosticMessagesModel->rowCount()));
// Macros
m_docMacrosModel->configure(document->definedMacros());
resizeColumns<MacrosModel>(m_ui->docDefinedMacrosView);
m_ui->docTab->setTabText(DocumentDefinedMacrosTab,
docTabName(DocumentDefinedMacrosTab, m_docMacrosModel->rowCount()));
// Source
m_ui->docPreprocessedSourceEdit->setPlainText(QString::fromUtf8(document->utf8Source()));
// Symbols
m_docSymbolsModel->configure(document);
resizeColumns<SymbolsModel>(m_ui->docSymbolsView);
// Tokens
m_docTokensModel->configure(document->translationUnit());
resizeColumns<TokensModel>(m_ui->docTokensView);
m_ui->docTab->setTabText(DocumentTokensTab,
docTabName(DocumentTokensTab, m_docTokensModel->rowCount()));
}
enum ProjectPartTabs {
ProjectPartGeneralTab,
ProjectPartFilesTab,
ProjectPartDefinesTab,
ProjectPartHeaderPathsTab,
ProjectPartPrecompiledHeadersTab
};
static QString partTabName(int tabIndex, int numberOfEntries = -1)
{
const char *names[] = {
"&General",
"Project &Files",
"&Defines",
"&Header Paths",
"Pre&compiled Headers"
};
QString result = QLatin1String(names[tabIndex]);
if (numberOfEntries != -1)
result += QString::fromLatin1(" (%1)").arg(numberOfEntries);
return result;
}
void CppCodeModelInspectorDialog::clearProjectPartData()
{
m_partGenericInfoModel->clear();
m_projectFilesModel->clear();
m_ui->projectPartTab->setTabText(ProjectPartFilesTab, partTabName(ProjectPartFilesTab));
m_ui->partToolchainDefinesEdit->clear();
m_ui->partProjectDefinesEdit->clear();
m_ui->projectPartTab->setTabText(ProjectPartDefinesTab, partTabName(ProjectPartDefinesTab));
m_ui->partHeaderPathsEdit->clear();
m_ui->projectPartTab->setTabText(ProjectPartHeaderPathsTab,
partTabName(ProjectPartHeaderPathsTab));
m_ui->partPrecompiledHeadersEdit->clear();
m_ui->projectPartTab->setTabText(ProjectPartPrecompiledHeadersTab,
partTabName(ProjectPartPrecompiledHeadersTab));
}
void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr &part)
{
QTC_ASSERT(part, return);
// General
QString projectName = QLatin1String("<None>");
QString projectFilePath = QLatin1String("<None>");
if (ProjectExplorer::Project *project = part->project) {
projectName = project->displayName();
projectFilePath = project->projectFilePath().toUserOutput();
}
KeyValueModel::Table table = KeyValueModel::Table()
<< qMakePair(QString::fromLatin1("Project Part Name"), part->displayName)
<< qMakePair(QString::fromLatin1("Project Part File"),
QDir::toNativeSeparators(part->projectFile))
<< qMakePair(QString::fromLatin1("Project Name"), projectName)
<< qMakePair(QString::fromLatin1("Project File"), projectFilePath)
<< qMakePair(QString::fromLatin1("Language Version"),
CMI::Utils::toString(part->languageVersion))
<< qMakePair(QString::fromLatin1("Language Extensions"),
CMI::Utils::toString(part->languageExtensions))
<< qMakePair(QString::fromLatin1("Qt Version"),
CMI::Utils::toString(part->qtVersion))
;
if (!part->projectConfigFile.isEmpty())
table.prepend(qMakePair(QString::fromLatin1("Project Config File"),
part->projectConfigFile));
m_partGenericInfoModel->configure(table);
resizeColumns<KeyValueModel>(m_ui->partGeneralView);
// Project Files
m_projectFilesModel->configure(part->files);
m_ui->projectPartTab->setTabText(ProjectPartFilesTab,
partTabName(ProjectPartFilesTab, part->files.size()));
// Defines
const QList<QByteArray> defineLines = part->toolchainDefines.split('\n')
+ part->projectDefines.split('\n');
int numberOfDefines = 0;
foreach (const QByteArray &line, defineLines) {
if (line.startsWith("#define "))
++numberOfDefines;
}
m_ui->partToolchainDefinesEdit->setPlainText(QString::fromUtf8(part->toolchainDefines));
m_ui->partProjectDefinesEdit->setPlainText(QString::fromUtf8(part->projectDefines));
m_ui->projectPartTab->setTabText(ProjectPartDefinesTab,
partTabName(ProjectPartDefinesTab, numberOfDefines));
// Header Paths
m_ui->partHeaderPathsEdit->setPlainText(CMI::Utils::pathListToString(part->headerPaths));
m_ui->projectPartTab->setTabText(ProjectPartHeaderPathsTab,
partTabName(ProjectPartHeaderPathsTab, part->headerPaths.size()));
// Precompiled Headers
m_ui->partPrecompiledHeadersEdit->setPlainText(
CMI::Utils::pathListToString(part->precompiledHeaders));
m_ui->projectPartTab->setTabText(ProjectPartPrecompiledHeadersTab,
partTabName(ProjectPartPrecompiledHeadersTab, part->precompiledHeaders.size()));
}
bool CppCodeModelInspectorDialog::event(QEvent *e)
{
if (e->type() == QEvent::ShortcutOverride) {
QKeyEvent *ke = static_cast<QKeyEvent *>(e);
if (ke->key() == Qt::Key_Escape && !ke->modifiers()) {
ke->accept();
close();
return false;
}
}
return QDialog::event(e);
}
} // namespace Internal
} // namespace CppEditor
#include "cppcodemodelinspectordialog.moc"