forked from qt-creator/qt-creator
Support Outline sidebar for C++ files
This commit is contained in:
@@ -18,7 +18,8 @@ HEADERS += cppplugin.h \
|
||||
cppquickfix.h \
|
||||
cpprefactoringchanges.h \
|
||||
cppcheckundefinedsymbols.h \
|
||||
cppsemanticinfo.h
|
||||
cppsemanticinfo.h \
|
||||
cppoutline.h
|
||||
|
||||
SOURCES += cppplugin.cpp \
|
||||
cppeditor.cpp \
|
||||
@@ -29,7 +30,8 @@ SOURCES += cppplugin.cpp \
|
||||
cppquickfix.cpp \
|
||||
cpprefactoringchanges.cpp \
|
||||
cppcheckundefinedsymbols.cpp \
|
||||
cppsemanticinfo.cpp
|
||||
cppsemanticinfo.cpp \
|
||||
cppoutline.cpp
|
||||
|
||||
RESOURCES += cppeditor.qrc
|
||||
|
||||
|
||||
216
src/plugins/cppeditor/cppoutline.cpp
Normal file
216
src/plugins/cppeditor/cppoutline.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include "cppoutline.h"
|
||||
|
||||
#include <TranslationUnit.h>
|
||||
#include <Symbol.h>
|
||||
|
||||
#include <coreplugin/ifile.h>
|
||||
#include <cplusplus/OverviewModel.h>
|
||||
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
using namespace CppEditor::Internal;
|
||||
|
||||
enum {
|
||||
debug = false
|
||||
};
|
||||
|
||||
CppOutlineTreeView::CppOutlineTreeView(QWidget *parent) :
|
||||
QTreeView(parent)
|
||||
{
|
||||
// see also QmlJSOutlineTreeView
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
setUniformRowHeights(true);
|
||||
setHeaderHidden(true);
|
||||
setTextElideMode(Qt::ElideNone);
|
||||
setIndentation(20);
|
||||
setExpandsOnDoubleClick(false);
|
||||
}
|
||||
|
||||
CppOutlineFilterModel::CppOutlineFilterModel(QObject *parent) :
|
||||
QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool CppOutlineFilterModel::filterAcceptsRow(int sourceRow,
|
||||
const QModelIndex &sourceParent) const
|
||||
{
|
||||
// ignore artifical "<Select Symbol>" entry
|
||||
if (!sourceParent.isValid() && sourceRow == 0) {
|
||||
return false;
|
||||
}
|
||||
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
|
||||
}
|
||||
|
||||
|
||||
CppOutlineWidget::CppOutlineWidget(CPPEditor *editor) :
|
||||
TextEditor::IOutlineWidget(),
|
||||
m_editor(editor),
|
||||
m_treeView(new CppOutlineTreeView(this)),
|
||||
m_model(new CPlusPlus::OverviewModel(this)),
|
||||
m_proxyModel(new CppOutlineFilterModel(this)),
|
||||
m_enableCursorSync(true),
|
||||
m_blockCursorSync(false)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->setMargin(0);
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(m_treeView);
|
||||
setLayout(layout);
|
||||
|
||||
m_proxyModel->setSourceModel(m_model);
|
||||
m_treeView->setModel(m_proxyModel);
|
||||
|
||||
CppTools::CppModelManagerInterface *modelManager = CppTools::CppModelManagerInterface::instance();
|
||||
|
||||
connect(modelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
|
||||
this, SLOT(updateOutline(CPlusPlus::Document::Ptr)));
|
||||
|
||||
if (modelManager->snapshot().contains(editor->file()->fileName())) {
|
||||
updateOutline(modelManager->snapshot().document(editor->file()->fileName()));
|
||||
}
|
||||
|
||||
connect(m_editor, SIGNAL(cursorPositionChanged()),
|
||||
this, SLOT(updateSelectionInTree()));
|
||||
connect(m_treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||
this, SLOT(updateSelectionInText(QItemSelection)));
|
||||
}
|
||||
|
||||
void CppOutlineWidget::setCursorSynchronization(bool syncWithCursor)
|
||||
{
|
||||
m_enableCursorSync = syncWithCursor;
|
||||
if (m_enableCursorSync)
|
||||
updateSelectionInTree();
|
||||
}
|
||||
|
||||
void CppOutlineWidget::updateOutline(CPlusPlus::Document::Ptr document)
|
||||
{
|
||||
m_document = document;
|
||||
if (document && m_editor
|
||||
&& (document->fileName() == m_editor->file()->fileName())
|
||||
&& (document->editorRevision() == m_editor->editorRevision())) {
|
||||
if (debug)
|
||||
qDebug() << "CppOutline - rebuilding model";
|
||||
m_model->rebuild(document);
|
||||
m_treeView->expandAll();
|
||||
updateSelectionInTree();
|
||||
}
|
||||
}
|
||||
|
||||
void CppOutlineWidget::updateSelectionInTree()
|
||||
{
|
||||
if (!syncCursor())
|
||||
return;
|
||||
|
||||
int line = m_editor->textCursor().blockNumber();
|
||||
int column = m_editor->textCursor().columnNumber();
|
||||
|
||||
QModelIndex index = indexForPosition(QModelIndex(), line, column);
|
||||
QModelIndex proxyIndex = m_proxyModel->mapFromSource(index);
|
||||
|
||||
m_blockCursorSync = true;
|
||||
if (debug)
|
||||
qDebug() << "CppOutline - updating selection due to cursor move";
|
||||
|
||||
m_treeView->selectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
m_blockCursorSync = false;
|
||||
}
|
||||
|
||||
void CppOutlineWidget::updateSelectionInText(const QItemSelection &selection)
|
||||
{
|
||||
if (!syncCursor())
|
||||
return;
|
||||
|
||||
if (!selection.indexes().isEmpty()) {
|
||||
QModelIndex proxyIndex = selection.indexes().first();
|
||||
QModelIndex index = m_proxyModel->mapToSource(proxyIndex);
|
||||
CPlusPlus::Symbol *symbol = m_model->symbolFromIndex(index);
|
||||
if (symbol) {
|
||||
m_blockCursorSync = true;
|
||||
unsigned line, column;
|
||||
m_document->translationUnit()->getPosition(symbol->startOffset(), &line, &column);
|
||||
|
||||
if (debug)
|
||||
qDebug() << "CppOutline - moving cursor to" << line << column - 1;
|
||||
|
||||
// line has to be 1 based, column 0 based!
|
||||
m_editor->gotoLine(line, column - 1);
|
||||
m_blockCursorSync = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex CppOutlineWidget::indexForPosition(const QModelIndex &rootIndex, int line, int column)
|
||||
{
|
||||
QModelIndex result = rootIndex;
|
||||
|
||||
const int rowCount = m_model->rowCount(rootIndex);
|
||||
for (int row = 0; row < rowCount; ++row) {
|
||||
QModelIndex index = m_model->index(row, 0, rootIndex);
|
||||
CPlusPlus::Symbol *symbol = m_model->symbolFromIndex(index);
|
||||
if (symbol && positionInsideSymbol(line, column, symbol)) {
|
||||
// recurse to children
|
||||
result = indexForPosition(index, line, column);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CppOutlineWidget::positionInsideSymbol(unsigned cursorLine, unsigned cursorColumn, CPlusPlus::Symbol *symbol) const
|
||||
{
|
||||
if (!m_document)
|
||||
return false;
|
||||
CPlusPlus::TranslationUnit *translationUnit = m_document->translationUnit();
|
||||
|
||||
unsigned symbolStartLine = -1;
|
||||
unsigned symbolStartColumn = -1;
|
||||
|
||||
translationUnit->getPosition(symbol->startOffset(), &symbolStartLine, &symbolStartColumn);
|
||||
|
||||
// normalize to 0 based
|
||||
--symbolStartLine;
|
||||
--symbolStartColumn;
|
||||
|
||||
if (symbolStartLine < cursorLine
|
||||
|| (symbolStartLine == cursorLine && symbolStartColumn <= cursorColumn)) {
|
||||
unsigned symbolEndLine = -1;
|
||||
unsigned symbolEndColumn = -1;
|
||||
translationUnit->getPosition(symbol->endOffset(), &symbolEndLine, &symbolEndColumn);
|
||||
|
||||
// normalize to 0 based
|
||||
--symbolEndLine;
|
||||
--symbolEndColumn;
|
||||
|
||||
if (symbolEndLine > cursorLine
|
||||
|| (symbolEndLine == cursorLine && symbolEndColumn >= cursorColumn)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CppOutlineWidget::syncCursor()
|
||||
{
|
||||
return m_enableCursorSync && !m_blockCursorSync;
|
||||
}
|
||||
|
||||
bool CppOutlineWidgetFactory::supportsEditor(Core::IEditor *editor) const
|
||||
{
|
||||
if (qobject_cast<CPPEditorEditable*>(editor))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
TextEditor::IOutlineWidget *CppOutlineWidgetFactory::createWidget(Core::IEditor *editor)
|
||||
{
|
||||
CPPEditorEditable *cppEditable = qobject_cast<CPPEditorEditable*>(editor);
|
||||
CPPEditor *cppEditor = qobject_cast<CPPEditor*>(cppEditable->widget());
|
||||
Q_ASSERT(cppEditor);
|
||||
|
||||
CppOutlineWidget *widget = new CppOutlineWidget(cppEditor);
|
||||
|
||||
return widget;
|
||||
}
|
||||
72
src/plugins/cppeditor/cppoutline.h
Normal file
72
src/plugins/cppeditor/cppoutline.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef CPPOUTLINE_H
|
||||
#define CPPOUTLINE_H
|
||||
|
||||
#include "cppeditor.h"
|
||||
|
||||
#include <texteditor/ioutlinewidget.h>
|
||||
|
||||
#include <QtGui/QSortFilterProxyModel>
|
||||
#include <QtGui/QTreeView>
|
||||
|
||||
namespace CppEditor {
|
||||
namespace Internal {
|
||||
|
||||
class CppOutlineTreeView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CppOutlineTreeView(QWidget *parent);
|
||||
};
|
||||
|
||||
class CppOutlineFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CppOutlineFilterModel(QObject *parent);
|
||||
// QSortFilterProxyModel
|
||||
bool filterAcceptsRow(int sourceRow,
|
||||
const QModelIndex &sourceParent) const;
|
||||
};
|
||||
|
||||
class CppOutlineWidget : public TextEditor::IOutlineWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CppOutlineWidget(CPPEditor *editor);
|
||||
|
||||
// IOutlineWidget
|
||||
virtual void setCursorSynchronization(bool syncWithCursor);
|
||||
|
||||
private slots:
|
||||
void updateOutline(CPlusPlus::Document::Ptr document);
|
||||
void updateSelectionInTree();
|
||||
void updateSelectionInText(const QItemSelection &selection);
|
||||
|
||||
private:
|
||||
QModelIndex indexForPosition(const QModelIndex &rootIndex, int line, int column);
|
||||
bool positionInsideSymbol(unsigned cursorLine, unsigned cursorColumn, CPlusPlus::Symbol *symbol) const;
|
||||
bool syncCursor();
|
||||
|
||||
private:
|
||||
CPPEditor *m_editor;
|
||||
CppOutlineTreeView *m_treeView;
|
||||
CPlusPlus::OverviewModel *m_model;
|
||||
CppOutlineFilterModel *m_proxyModel;
|
||||
CPlusPlus::Document::Ptr m_document;
|
||||
|
||||
bool m_enableCursorSync;
|
||||
bool m_blockCursorSync;
|
||||
};
|
||||
|
||||
class CppOutlineWidgetFactory : public TextEditor::IOutlineWidgetFactory
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool supportsEditor(Core::IEditor *editor) const;
|
||||
TextEditor::IOutlineWidget *createWidget(Core::IEditor *editor);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CppEditor
|
||||
|
||||
#endif // CPPOUTLINE_H
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "cppfilewizard.h"
|
||||
#include "cpphoverhandler.h"
|
||||
#include "cppquickfix.h"
|
||||
#include "cppoutline.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/coreconstants.h>
|
||||
@@ -202,6 +203,8 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
|
||||
|
||||
addAutoReleasedObject(new CppEditorFactory(this));
|
||||
addAutoReleasedObject(new CppHoverHandler);
|
||||
addAutoReleasedObject(new CppOutlineWidgetFactory);
|
||||
|
||||
|
||||
m_quickFixCollector = new CppQuickFixCollector;
|
||||
addAutoReleasedObject(m_quickFixCollector);
|
||||
|
||||
Reference in New Issue
Block a user