CPlusPlus: CppEditor: refactor overview model

Introduce abstract model to be able to use clang
based version of it in follow up patches.
Fix warnings and modernize source code a little.
Move OverviewModel to CppTools.

Change-Id: Idcc9bf03cad047026a456bd01063597a1eb95147
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-02-01 15:47:22 +01:00
parent 9a7e7f7d42
commit c6d4308ccd
11 changed files with 206 additions and 145 deletions

View File

@@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2018 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.
**
****************************************************************************/
#pragma once
#include "cpptools_global.h"
#include <utils/dropsupport.h>
#include <QAbstractItemModel>
#include <QSharedPointer>
namespace CPlusPlus {
class Document;
class Symbol;
}
namespace CppTools {
class CPPTOOLS_EXPORT AbstractOverviewModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum Role {
FileNameRole = Qt::UserRole + 1,
LineNumberRole
};
AbstractOverviewModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {}
virtual QSharedPointer<CPlusPlus::Document> document() const
{
return {};
}
virtual CPlusPlus::Symbol *symbolFromIndex(const QModelIndex &) const
{
return {};
}
virtual void rebuild(QSharedPointer<CPlusPlus::Document>) {}
Qt::ItemFlags flags(const QModelIndex &index) const override
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
}
Qt::DropActions supportedDragActions() const override
{
return Qt::MoveAction;
}
QStringList mimeTypes() const override
{
return Utils::DropSupport::mimeTypesForFilePaths();
}
QMimeData *mimeData(const QModelIndexList &indexes) const override
{
auto mimeData = new Utils::DropMimeData;
foreach (const QModelIndex &index, indexes) {
const QVariant fileName = data(index, FileNameRole);
if (!fileName.canConvert<QString>())
continue;
const QVariant lineNumber = data(index, LineNumberRole);
if (!lineNumber.canConvert<unsigned>())
continue;
mimeData->addFile(fileName.toString(), static_cast<int>(lineNumber.value<unsigned>()));
}
return mimeData;
}
};
} // namespace CppTools

View File

@@ -25,14 +25,15 @@
#include "cppeditoroutline.h"
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cpptoolsreuse.h>
#include <cpptools/cpptoolssettings.h>
#include "cppmodelmanager.h"
#include "cppoverviewmodel.h"
#include "cpptoolsreuse.h"
#include "cpptoolssettings.h"
#include <texteditor/texteditor.h>
#include <texteditor/textdocument.h>
#include <coreplugin/editormanager/editormanager.h>
#include <cplusplus/OverviewModel.h>
#include <utils/treeviewcombobox.h>
#include <QAction>
@@ -56,14 +57,13 @@ class OverviewProxyModel : public QSortFilterProxyModel
Q_OBJECT
public:
OverviewProxyModel(CPlusPlus::OverviewModel *sourceModel, QObject *parent)
OverviewProxyModel(CppTools::AbstractOverviewModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
, m_sourceModel(sourceModel)
{
setSourceModel(m_sourceModel);
}
bool filterAcceptsRow(int sourceRow,const QModelIndex &sourceParent) const
bool filterAcceptsRow(int sourceRow,const QModelIndex &sourceParent) const override
{
// Ignore generated symbols, e.g. by macro expansion (Q_OBJECT)
const QModelIndex sourceIndex = m_sourceModel->index(sourceRow, 0, sourceParent);
@@ -74,12 +74,12 @@ public:
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
}
private:
CPlusPlus::OverviewModel *m_sourceModel;
CppTools::AbstractOverviewModel *m_sourceModel;
};
QTimer *newSingleShotTimer(QObject *parent, int msInternal, const QString &objectName)
{
QTimer *timer = new QTimer(parent);
auto *timer = new QTimer(parent);
timer->setObjectName(objectName);
timer->setSingleShot(true);
timer->setInterval(msInternal);
@@ -94,9 +94,11 @@ CppEditorOutline::CppEditorOutline(TextEditor::TextEditorWidget *editorWidget)
: QObject(editorWidget)
, m_editorWidget(editorWidget)
, m_combo(new Utils::TreeViewComboBox)
, m_model(new CPlusPlus::OverviewModel(this))
, m_proxyModel(new OverviewProxyModel(m_model, this))
{
m_model = new CppTools::OverviewModel(this);
m_proxyModel = new OverviewProxyModel(m_model, this);
m_proxyModel->setSourceModel(m_model);
// Set up proxy model
if (CppTools::CppToolsSettings::instance()->sortedEditorDocumentOutline())
m_proxyModel->sort(0, Qt::AscendingOrder);
@@ -163,7 +165,7 @@ void CppEditorOutline::setSorted(bool sort)
}
}
CPlusPlus::OverviewModel *CppEditorOutline::model() const
CppTools::AbstractOverviewModel *CppEditorOutline::model() const
{
return m_model;
}
@@ -194,7 +196,8 @@ void CppEditorOutline::updateNow()
if (!document)
return;
if (document->editorRevision() != (unsigned) m_editorWidget->document()->revision()) {
if (document->editorRevision()
!= static_cast<unsigned>(m_editorWidget->document()->revision())) {
m_updateTimer->start();
return;
}
@@ -212,11 +215,12 @@ void CppEditorOutline::updateIndex()
void CppEditorOutline::updateIndexNow()
{
if (!m_model->document())
const CPlusPlus::Document::Ptr document = m_model->document();
if (!document)
return;
const unsigned revision = m_editorWidget->document()->revision();
if (m_model->document()->editorRevision() != revision) {
const auto revision = static_cast<unsigned>(m_editorWidget->document()->revision());
if (document->editorRevision() != revision) {
m_updateIndexTimer->start();
return;
}
@@ -253,7 +257,7 @@ void CppEditorOutline::gotoSymbolInEditor()
Core::EditorManager::cutForwardNavigationHistory();
Core::EditorManager::addCurrentPositionToNavigationHistory();
m_editorWidget->gotoLine(link.targetLine, link.targetColumn, true, true);
m_editorWidget->activateEditor();
emit m_editorWidget->activateEditor();
}
QModelIndex CppEditorOutline::indexForPosition(int line, int column,

View File

@@ -27,6 +27,8 @@
#include "cpptools_global.h"
#include "abstractoverviewmodel.h"
#include <QModelIndex>
#include <QObject>
@@ -36,7 +38,6 @@ class QSortFilterProxyModel;
class QTimer;
QT_END_NAMESPACE
namespace CPlusPlus { class OverviewModel; }
namespace TextEditor { class TextEditorWidget; }
namespace Utils { class TreeViewComboBox; }
@@ -51,7 +52,7 @@ public:
void update();
CPlusPlus::OverviewModel *model() const;
AbstractOverviewModel *model() const;
QModelIndex modelIndex();
QWidget *widget() const; // Must be deleted by client.
@@ -79,7 +80,7 @@ private:
TextEditor::TextEditorWidget *m_editorWidget;
Utils::TreeViewComboBox *m_combo; // Not owned
CPlusPlus::OverviewModel *m_model;
AbstractOverviewModel *m_model;
QSortFilterProxyModel *m_proxyModel;
QModelIndex m_modelIndex;
QAction *m_sortAction;

View File

@@ -0,0 +1,253 @@
/****************************************************************************
**
** 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 "cppoverviewmodel.h"
#include <cplusplus/Icons.h>
#include <cplusplus/Literals.h>
#include <cplusplus/Overview.h>
#include <cplusplus/Scope.h>
#include <cplusplus/Symbols.h>
#include <utils/dropsupport.h>
using namespace CPlusPlus;
namespace CppTools {
OverviewModel::OverviewModel(QObject *parent)
: AbstractOverviewModel(parent)
{ }
OverviewModel::~OverviewModel()
{ }
bool OverviewModel::hasDocument() const
{
return _cppDocument;
}
Document::Ptr OverviewModel::document() const
{
return _cppDocument;
}
unsigned OverviewModel::globalSymbolCount() const
{
unsigned count = 0;
if (_cppDocument)
count += _cppDocument->globalSymbolCount();
return count;
}
Symbol *OverviewModel::globalSymbolAt(unsigned index) const
{ return _cppDocument->globalSymbolAt(index); }
QModelIndex OverviewModel::index(int row, int column, const QModelIndex &parent) const
{
if (!parent.isValid()) {
if (row == 0) // account for no symbol item
return createIndex(row, column);
Symbol *symbol = globalSymbolAt(static_cast<unsigned>(row-1)); // account for no symbol item
return createIndex(row, column, symbol);
} else {
Symbol *parentSymbol = static_cast<Symbol *>(
parent.internalPointer());
Q_ASSERT(parentSymbol);
if (Template *t = parentSymbol->asTemplate())
if (Symbol *templateParentSymbol = t->declaration())
parentSymbol = templateParentSymbol;
Scope *scope = parentSymbol->asScope();
Q_ASSERT(scope != nullptr);
return createIndex(row, 0, scope->memberAt(static_cast<unsigned>(row)));
}
}
QModelIndex OverviewModel::parent(const QModelIndex &child) const
{
Symbol *symbol = static_cast<Symbol *>(child.internalPointer());
if (!symbol) // account for no symbol item
return QModelIndex();
if (Scope *scope = symbol->enclosingScope()) {
if (scope->isTemplate() && scope->enclosingScope())
scope = scope->enclosingScope();
if (scope->enclosingScope()) {
QModelIndex index;
if (scope->enclosingScope() && scope->enclosingScope()->enclosingScope()) // the parent doesn't have a parent
index = createIndex(static_cast<int>(scope->index()), 0, scope);
else //+1 to account for no symbol item
index = createIndex(static_cast<int>(scope->index() + 1), 0, scope);
return index;
}
}
return QModelIndex();
}
int OverviewModel::rowCount(const QModelIndex &parent) const
{
if (hasDocument()) {
if (!parent.isValid()) {
return static_cast<int>(globalSymbolCount() + 1); // account for no symbol item
} else {
if (!parent.parent().isValid() && parent.row() == 0) // account for no symbol item
return 0;
Symbol *parentSymbol = static_cast<Symbol *>(
parent.internalPointer());
Q_ASSERT(parentSymbol);
if (Template *t = parentSymbol->asTemplate())
if (Symbol *templateParentSymbol = t->declaration())
parentSymbol = templateParentSymbol;
if (Scope *parentScope = parentSymbol->asScope()) {
if (!parentScope->isFunction() && !parentScope->isObjCMethod())
return static_cast<int>(parentScope->memberCount());
}
return 0;
}
}
if (!parent.isValid())
return 1; // account for no symbol item
return 0;
}
int OverviewModel::columnCount(const QModelIndex &) const
{
return 1;
}
QVariant OverviewModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
// account for no symbol item
if (!index.parent().isValid() && index.row() == 0) {
switch (role) {
case Qt::DisplayRole:
if (rowCount() > 1)
return tr("<Select Symbol>");
else
return tr("<No Symbols>");
default:
return QVariant();
} //switch
}
switch (role) {
case Qt::DisplayRole: {
Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
QString name = _overview.prettyName(symbol->name());
if (name.isEmpty())
name = QLatin1String("anonymous");
if (symbol->isObjCForwardClassDeclaration())
name = QLatin1String("@class ") + name;
if (symbol->isObjCForwardProtocolDeclaration() || symbol->isObjCProtocol())
name = QLatin1String("@protocol ") + name;
if (symbol->isObjCClass()) {
ObjCClass *clazz = symbol->asObjCClass();
if (clazz->isInterface())
name = QLatin1String("@interface ") + name;
else
name = QLatin1String("@implementation ") + name;
if (clazz->isCategory()) {
name += QLatin1String(" (") + _overview.prettyName(clazz->categoryName())
+ QLatin1Char(')');
}
}
if (symbol->isObjCPropertyDeclaration())
name = QLatin1String("@property ") + name;
if (Template *t = symbol->asTemplate())
if (Symbol *templateDeclaration = t->declaration()) {
QStringList parameters;
parameters.reserve(static_cast<int>(t->templateParameterCount()));
for (unsigned i = 0; i < t->templateParameterCount(); ++i)
parameters.append(_overview.prettyName(t->templateParameterAt(i)->name()));
name += QLatin1Char('<') + parameters.join(QLatin1String(", ")) + QLatin1Char('>');
symbol = templateDeclaration;
}
if (symbol->isObjCMethod()) {
ObjCMethod *method = symbol->asObjCMethod();
if (method->isStatic())
name = QLatin1Char('+') + name;
else
name = QLatin1Char('-') + name;
} else if (! symbol->isScope() || symbol->isFunction()) {
QString type = _overview.prettyType(symbol->type());
if (Function *f = symbol->type()->asFunctionType()) {
name += type;
type = _overview.prettyType(f->returnType());
}
if (! type.isEmpty())
name += QLatin1String(": ") + type;
}
return name;
}
case Qt::EditRole: {
Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
QString name = _overview.prettyName(symbol->name());
if (name.isEmpty())
name = QLatin1String("anonymous");
return name;
}
case Qt::DecorationRole: {
Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
return Icons::iconForSymbol(symbol);
}
case FileNameRole: {
Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
return QString::fromUtf8(symbol->fileName(), static_cast<int>(symbol->fileNameLength()));
}
case LineNumberRole: {
Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
return symbol->line();
}
default:
return QVariant();
} // switch
}
Symbol *OverviewModel::symbolFromIndex(const QModelIndex &index) const
{
return static_cast<Symbol *>(index.internalPointer());
}
void OverviewModel::rebuild(Document::Ptr doc)
{
beginResetModel();
_cppDocument = doc;
endResetModel();
}
} // namespace CppTools

View File

@@ -0,0 +1,65 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#pragma once
#include "abstractoverviewmodel.h"
#include <cplusplus/CppDocument.h>
#include <cplusplus/Overview.h>
namespace CppTools {
class CPPTOOLS_EXPORT OverviewModel : public AbstractOverviewModel
{
Q_OBJECT
public:
OverviewModel(QObject *parent = nullptr);
~OverviewModel() override;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
CPlusPlus::Document::Ptr document() const override;
CPlusPlus::Symbol *symbolFromIndex(const QModelIndex &index) const override;
void rebuild(CPlusPlus::Document::Ptr doc) override;
private:
bool hasDocument() const;
unsigned globalSymbolCount() const;
CPlusPlus::Symbol *globalSymbolAt(unsigned index) const;
private:
CPlusPlus::Document::Ptr _cppDocument;
CPlusPlus::Overview _overview;
};
} // namespace CppTools

View File

@@ -4,6 +4,7 @@ include(../../qtcreatorplugin.pri)
HEADERS += \
abstracteditorsupport.h \
abstractoverviewmodel.h \
baseeditordocumentparser.h \
baseeditordocumentprocessor.h \
builtincursorinfo.h \
@@ -47,6 +48,7 @@ HEADERS += \
cppmodelmanager.h \
cppmodelmanagersupport.h \
cppmodelmanagersupportinternal.h \
cppoverviewmodel.h \
cpppointerdeclarationformatter.h \
cppprojectfile.h \
cppprojectupdater.h \
@@ -142,6 +144,7 @@ SOURCES += \
cppmodelmanager.cpp \
cppmodelmanagersupport.cpp \
cppmodelmanagersupportinternal.cpp \
cppoverviewmodel.cpp \
cpppointerdeclarationformatter.cpp \
cppprojectfile.cpp \
cppprojectupdater.cpp \

View File

@@ -30,6 +30,7 @@ Project {
files: [
"abstracteditorsupport.cpp",
"abstracteditorsupport.h",
"abstractoverviewmodel.h",
"baseeditordocumentparser.cpp",
"baseeditordocumentparser.h",
"baseeditordocumentprocessor.cpp",
@@ -121,6 +122,8 @@ Project {
"cppmodelmanagersupport.h",
"cppmodelmanagersupportinternal.cpp",
"cppmodelmanagersupportinternal.h",
"cppoverviewmodel.cpp",
"cppoverviewmodel.h",
"cpppointerdeclarationformatter.cpp",
"cpppointerdeclarationformatter.h",
"cppprojectfile.cpp",