Create type hierarchy widget; Refactor code from C++ hover into a simple reusable model.

Hierarchy information removed from tooltips now.
This commit is contained in:
Leandro Melo
2010-08-13 16:38:45 +02:00
parent 761a9694f9
commit f79187ca97
15 changed files with 1236 additions and 436 deletions

View File

@@ -1755,6 +1755,9 @@ void CPPEditor::unCommentSelection()
CPPEditor::Link CPPEditor::linkToSymbol(CPlusPlus::Symbol *symbol) CPPEditor::Link CPPEditor::linkToSymbol(CPlusPlus::Symbol *symbol)
{ {
if (!symbol)
return Link();
const QString fileName = QString::fromUtf8(symbol->fileName(), const QString fileName = QString::fromUtf8(symbol->fileName(),
symbol->fileNameLength()); symbol->fileNameLength());
unsigned line = symbol->line(); unsigned line = symbol->line();

View File

@@ -180,6 +180,10 @@ public:
void setObjCEnabled(bool onoff); void setObjCEnabled(bool onoff);
bool isObjCEnabled() const; bool isObjCEnabled() const;
bool openLink(const Link &link) { return openCppEditorAt(link); }
static Link linkToSymbol(CPlusPlus::Symbol *symbol);
Q_SIGNALS: Q_SIGNALS:
void outlineModelIndexChanged(const QModelIndex &index); void outlineModelIndexChanged(const QModelIndex &index);
@@ -267,13 +271,10 @@ private:
void abortRename(); void abortRename();
Link findLinkAt(const QTextCursor &, bool resolveTarget = true); Link findLinkAt(const QTextCursor &, bool resolveTarget = true);
bool openLink(const Link &link) { return openCppEditorAt(link); }
bool openCppEditorAt(const Link &); bool openCppEditorAt(const Link &);
QModelIndex indexForPosition(int line, int column, const QModelIndex &rootIndex = QModelIndex()) const; QModelIndex indexForPosition(int line, int column, const QModelIndex &rootIndex = QModelIndex()) const;
static Link linkToSymbol(CPlusPlus::Symbol *symbol);
CppTools::CppModelManagerInterface *m_modelManager; CppTools::CppModelManagerInterface *m_modelManager;
QComboBox *m_outlineCombo; QComboBox *m_outlineCombo;

View File

@@ -20,8 +20,9 @@ HEADERS += cppplugin.h \
cppsemanticinfo.h \ cppsemanticinfo.h \
cppoutline.h \ cppoutline.h \
cppdeclfromdef.h \ cppdeclfromdef.h \
cpplocalsymbols.h cpplocalsymbols.h \
cpptypehierarchy.h \
cppelementevaluator.h
SOURCES += cppplugin.cpp \ SOURCES += cppplugin.cpp \
cppeditor.cpp \ cppeditor.cpp \
cpphighlighter.cpp \ cpphighlighter.cpp \
@@ -35,8 +36,9 @@ SOURCES += cppplugin.cpp \
cppsemanticinfo.cpp \ cppsemanticinfo.cpp \
cppoutline.cpp \ cppoutline.cpp \
cppdeclfromdef.cpp \ cppdeclfromdef.cpp \
cpplocalsymbols.cpp cpplocalsymbols.cpp \
cpptypehierarchy.cpp \
cppelementevaluator.cpp
RESOURCES += cppeditor.qrc RESOURCES += cppeditor.qrc
OTHER_FILES += CppEditor.pluginspec \
OTHER_FILES += CppEditor.pluginspec CppEditor.mimetypes.xml CppEditor.mimetypes.xml

View File

@@ -48,6 +48,9 @@ const char * const FIND_REFERENCES = "CppEditor.FindReferences";
const char * const JUMP_TO_DEFINITION = "CppEditor.JumpToDefinition"; const char * const JUMP_TO_DEFINITION = "CppEditor.JumpToDefinition";
const char * const UPDATE_CODEMODEL = "CppEditor.UpdateCodeModel"; const char * const UPDATE_CODEMODEL = "CppEditor.UpdateCodeModel";
const char * const TYPE_HIERARCHY_ID = "CppEditor.TypeHierarchy";
const char * const OPEN_TYPE_HIERARCHY = "CppEditor.OpenTypeHierarchy";
const char * const HEADER_FILE_TYPE = "CppHeaderFiles"; const char * const HEADER_FILE_TYPE = "CppHeaderFiles";
const char * const SOURCE_FILE_TYPE = "CppSourceFiles"; const char * const SOURCE_FILE_TYPE = "CppSourceFiles";

View File

@@ -0,0 +1,500 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "cppelementevaluator.h"
#include <coreplugin/ifile.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <FullySpecifiedType.h>
#include <Names.h>
#include <CoreTypes.h>
#include <Scope.h>
#include <Symbol.h>
#include <Symbols.h>
#include <cplusplus/ExpressionUnderCursor.h>
#include <cplusplus/Overview.h>
#include <cplusplus/TypeOfExpression.h>
#include <cplusplus/LookupContext.h>
#include <cplusplus/LookupItem.h>
#include <cplusplus/Icons.h>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QSet>
#include <QtCore/QQueue>
using namespace CppEditor;
using namespace Internal;
using namespace CPlusPlus;
namespace {
void moveCursorToEndOfName(QTextCursor *tc) {
QTextDocument *doc = tc->document();
if (!doc)
return;
QChar ch = doc->characterAt(tc->position());
while (ch.isLetterOrNumber() || ch == QLatin1Char('_')) {
tc->movePosition(QTextCursor::NextCharacter);
ch = doc->characterAt(tc->position());
}
}
}
CppElementEvaluator::CppElementEvaluator(CPPEditor *editor) :
m_editor(editor),
m_modelManager(CppTools::CppModelManagerInterface::instance()),
m_tc(editor->textCursor()),
m_lookupBaseClasses(false)
{}
void CppElementEvaluator::setTextCursor(const QTextCursor &tc)
{ m_tc = tc; }
void CppElementEvaluator::setLookupBaseClasses(const bool lookup)
{ m_lookupBaseClasses = lookup; }
QSharedPointer<CppElement> CppElementEvaluator::identifyCppElement()
{
m_element.clear();
evaluate();
return m_element;
}
// @todo: Consider refactoring code from CPPEditor::findLinkAt into here.
void CppElementEvaluator::evaluate()
{
if (!m_modelManager)
return;
const Snapshot &snapshot = m_modelManager->snapshot();
Document::Ptr doc = snapshot.document(m_editor->file()->fileName());
if (!doc)
return;
int line = 0;
int column = 0;
const int pos = m_tc.position();
m_editor->convertPosition(pos, &line, &column);
if (!matchDiagnosticMessage(doc, line)) {
if (!matchIncludeFile(doc, line) && !matchMacroInUse(doc, pos)) {
moveCursorToEndOfName(&m_tc);
// Fetch the expression's code
ExpressionUnderCursor expressionUnderCursor;
const QString &expression = expressionUnderCursor(m_tc);
Scope *scope = doc->scopeAt(line, column);
TypeOfExpression typeOfExpression;
typeOfExpression.init(doc, snapshot);
const QList<LookupItem> &lookupItems = typeOfExpression(expression, scope);
if (lookupItems.isEmpty())
return;
const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate.
handleLookupItemMatch(snapshot, lookupItem, typeOfExpression.context());
}
}
}
bool CppElementEvaluator::matchDiagnosticMessage(const CPlusPlus::Document::Ptr &document,
unsigned line)
{
foreach (const Document::DiagnosticMessage &m, document->diagnosticMessages()) {
if (m.line() == line) {
m_element = QSharedPointer<CppElement>(new CppDiagnosis(m));
return true;
}
}
return false;
}
bool CppElementEvaluator::matchIncludeFile(const CPlusPlus::Document::Ptr &document, unsigned line)
{
foreach (const Document::Include &includeFile, document->includes()) {
if (includeFile.line() == line) {
m_element = QSharedPointer<CppElement>(new CppInclude(includeFile));
return true;
}
}
return false;
}
bool CppElementEvaluator::matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos)
{
foreach (const Document::MacroUse &use, document->macroUses()) {
if (use.contains(pos)) {
const unsigned begin = use.begin();
const QString &name = use.macro().name();
if (pos < begin + name.length()) {
m_element = QSharedPointer<CppElement>(new CppMacro(use.macro()));
return true;
}
}
}
return false;
}
void CppElementEvaluator::handleLookupItemMatch(const Snapshot &snapshot,
const LookupItem &lookupItem,
const LookupContext &context)
{
Symbol *declaration = lookupItem.declaration();
if (!declaration) {
const QString &type = Overview().prettyType(lookupItem.type(), QString());
m_element = QSharedPointer<CppElement>(new Unknown(type));
} else {
const FullySpecifiedType &type = declaration->type();
if (declaration->isNamespace()) {
m_element = QSharedPointer<CppElement>(new CppNamespace(declaration));
} else if (declaration->isClass() || declaration->isForwardClassDeclaration()) {
if (declaration->isForwardClassDeclaration())
if (Symbol *classDeclaration = snapshot.findMatchingClassDeclaration(declaration))
declaration = classDeclaration;
CppClass *cppClass = new CppClass(declaration);
if (m_lookupBaseClasses)
cppClass->lookupBases(declaration, context);
m_element = QSharedPointer<CppElement>(cppClass);
} else if (declaration->isEnum() || declaration->scope()->isEnum()) {
m_element = QSharedPointer<CppElement>(new CppEnum(declaration));
} else if (declaration->isTypedef()) {
m_element = QSharedPointer<CppElement>(new CppTypedef(declaration));
} else if (declaration->isFunction() || (type.isValid() && type->isFunctionType())) {
m_element = QSharedPointer<CppElement>(new CppFunction(declaration));
} else if (declaration->isDeclaration() && type.isValid()) {
m_element = QSharedPointer<CppElement>(
new CppVariable(declaration, context, lookupItem.scope()));
} else {
m_element = QSharedPointer<CppElement>(new CppDeclarableElement(declaration));
}
}
}
// CppElement
CppElement::CppElement() : m_helpCategory(CppHoverHandler::HelpCandidate::Unknown)
{}
CppElement::~CppElement()
{}
void CppElement::setHelpCategory(const CppHoverHandler::HelpCandidate::Category &cat)
{ m_helpCategory = cat; }
const CppHoverHandler::HelpCandidate::Category &CppElement::helpCategory() const
{ return m_helpCategory; }
void CppElement::setHelpIdCandidates(const QStringList &candidates)
{ m_helpIdCandidates = candidates; }
void CppElement::addHelpIdCandidate(const QString &candidate)
{ m_helpIdCandidates.append(candidate); }
const QStringList &CppElement::helpIdCandidates() const
{ return m_helpIdCandidates; }
void CppElement::setHelpMark(const QString &mark)
{ m_helpMark = mark; }
const QString &CppElement::helpMark() const
{ return m_helpMark; }
void CppElement::setLink(const CPPEditor::Link &link)
{ m_link = link; }
const CPPEditor::Link &CppElement::link() const
{ return m_link; }
void CppElement::setTooltip(const QString &tooltip)
{ m_tooltip = tooltip; }
const QString &CppElement::tooltip() const
{ return m_tooltip; }
// Unknown
Unknown::Unknown(const QString &type) : CppElement(), m_type(type)
{
setTooltip(m_type);
}
Unknown::~Unknown()
{}
const QString &Unknown::type() const
{ return m_type; }
// CppDiagnosis
CppDiagnosis::CppDiagnosis(const Document::DiagnosticMessage &message) :
CppElement(), m_text(message.text())
{
setTooltip(m_text);
}
CppDiagnosis::~CppDiagnosis()
{}
const QString &CppDiagnosis::text() const
{ return m_text; }
// CppInclude
CppInclude::~CppInclude()
{}
CppInclude::CppInclude(const Document::Include &includeFile) :
CppElement(),
m_path(QDir::toNativeSeparators(includeFile.fileName())),
m_fileName(QFileInfo(includeFile.fileName()).fileName())
{
setHelpCategory(CppHoverHandler::HelpCandidate::Brief);
setHelpIdCandidates(QStringList(m_fileName));
setHelpMark(m_fileName);
setLink(CPPEditor::Link(m_path));
setTooltip(m_path);
}
const QString &CppInclude::path() const
{ return m_path; }
const QString &CppInclude::fileName() const
{ return m_fileName; }
// CppMacro
CppMacro::CppMacro(const Macro &macro) : CppElement()
{
setHelpCategory(CppHoverHandler::HelpCandidate::Macro);
setHelpIdCandidates(QStringList(macro.name()));
setHelpMark(macro.name());
setLink(CPPEditor::Link(macro.fileName(), macro.line()));
setTooltip(macro.toString());
}
CppMacro::~CppMacro()
{}
// CppDeclarableElement
CppDeclarableElement::CppDeclarableElement(Symbol *declaration) : CppElement()
{
const FullySpecifiedType &type = declaration->type();
Overview overview;
overview.setShowArgumentNames(true);
overview.setShowReturnTypes(true);
m_icon = Icons().iconForSymbol(declaration);
m_name = overview.prettyName(declaration->name());
if (declaration->scope()->isClass() ||
declaration->scope()->isNamespace() ||
declaration->scope()->isEnum()) {
m_qualifiedName = overview.prettyName(LookupContext::fullyQualifiedName(declaration));
} else {
m_qualifiedName = m_name;
}
if (declaration->isClass() ||
declaration->isNamespace() ||
declaration->isForwardClassDeclaration() ||
declaration->isEnum()) {
m_type = m_qualifiedName;
} else {
m_type = overview.prettyType(type, m_qualifiedName);
}
setTooltip(m_type);
setLink(CPPEditor::linkToSymbol(declaration));
QStringList helpIds;
helpIds << m_name << m_qualifiedName;
setHelpIdCandidates(helpIds);
setHelpMark(m_name);
}
CppDeclarableElement::~CppDeclarableElement()
{}
void CppDeclarableElement::setName(const QString &name)
{ m_name = name; }
const QString &CppDeclarableElement::name() const
{ return m_name; }
void CppDeclarableElement::setQualifiedName(const QString &name)
{ m_qualifiedName = name; }
const QString &CppDeclarableElement::qualifiedName() const
{ return m_qualifiedName; }
void CppDeclarableElement::setType(const QString &type)
{ m_type = type; }
const QString &CppDeclarableElement::type() const
{ return m_type; }
void CppDeclarableElement::setIcon(const QIcon &icon)
{ m_icon = icon; }
const QIcon &CppDeclarableElement::icon() const
{ return m_icon; }
// CppNamespace
CppNamespace::CppNamespace(Symbol *declaration) : CppDeclarableElement(declaration)
{
setHelpCategory(CppHoverHandler::HelpCandidate::ClassOrNamespace);
}
CppNamespace::~CppNamespace()
{}
// CppClass
CppClass::CppClass(Symbol *declaration) : CppDeclarableElement(declaration)
{
setHelpCategory(CppHoverHandler::HelpCandidate::ClassOrNamespace);
}
CppClass::~CppClass()
{}
void CppClass::lookupBases(Symbol *declaration, const CPlusPlus::LookupContext &context)
{
typedef QPair<ClassOrNamespace *, CppClass *> Data;
if (ClassOrNamespace *clazz = context.lookupType(declaration)) {
QSet<ClassOrNamespace *> visited;
QQueue<Data> q;
q.enqueue(qMakePair(clazz, this));
while (!q.isEmpty()) {
Data current = q.dequeue();
clazz = current.first;
visited.insert(clazz);
const QList<ClassOrNamespace *> &bases = clazz->usings();
foreach (ClassOrNamespace *baseClass, bases) {
const QList<Symbol *> &symbols = baseClass->symbols();
foreach (Symbol *symbol, symbols) {
if (symbol->isClass() && (
clazz = context.lookupType(symbol)) &&
!visited.contains(clazz)) {
CppClass baseCppClass(symbol);
CppClass *cppClass = current.second;
cppClass->m_bases.append(baseCppClass);
q.enqueue(qMakePair(clazz, &cppClass->m_bases.last()));
}
}
}
}
}
}
const QList<CppClass> &CppClass::bases() const
{ return m_bases; }
// CppFunction
CppFunction::CppFunction(Symbol *declaration) : CppDeclarableElement(declaration)
{
setHelpCategory(CppHoverHandler::HelpCandidate::Function);
const FullySpecifiedType &type = declaration->type();
// Functions marks can be found either by the main overload or signature based
// (with no argument names and no return). Help ids have no signature at all.
Overview overview;
overview.setShowDefaultArguments(false);
setHelpMark(overview.prettyType(type, name()));
overview.setShowFunctionSignatures(false);
addHelpIdCandidate(overview.prettyName(declaration->name()));
}
CppFunction::~CppFunction()
{}
// CppEnum
CppEnum::CppEnum(Symbol *declaration) : CppDeclarableElement(declaration)
{
setHelpCategory(CppHoverHandler::HelpCandidate::Enum);
if (declaration->scope()->isEnum()) {
Symbol *enumSymbol = declaration->scope()->asEnum();
Overview overview;
setHelpMark(overview.prettyName(enumSymbol->name()));
setTooltip(overview.prettyName(LookupContext::fullyQualifiedName(enumSymbol)));
}
}
CppEnum::~CppEnum()
{}
// CppTypedef
CppTypedef::CppTypedef(Symbol *declaration) :
CppDeclarableElement(declaration)
{
setHelpCategory(CppHoverHandler::HelpCandidate::Typedef);
}
CppTypedef::~CppTypedef()
{}
// CppVariable
CppVariable::CppVariable(Symbol *declaration, const LookupContext &context, Scope *scope) :
CppDeclarableElement(declaration)
{
const FullySpecifiedType &type = declaration->type();
const Name *typeName = 0;
if (type->isNamedType()) {
typeName = type->asNamedType()->name();
} else if (type->isPointerType() || type->isReferenceType()) {
FullySpecifiedType associatedType;
if (type->isPointerType())
associatedType = type->asPointerType()->elementType();
else
associatedType = type->asReferenceType()->elementType();
if (associatedType->isNamedType())
typeName = associatedType->asNamedType()->name();
}
if (typeName) {
if (ClassOrNamespace *clazz = context.lookupType(typeName, scope)) {
if (!clazz->symbols().isEmpty()) {
Overview overview;
Symbol *symbol = clazz->symbols().at(0);
const QString &name =
overview.prettyName(LookupContext::fullyQualifiedName(symbol));
setTooltip(name);
setHelpCategory(CppHoverHandler::HelpCandidate::ClassOrNamespace);
setHelpMark(name);
setHelpIdCandidates(QStringList(name));
}
}
}
}
CppVariable::~CppVariable()
{}

View File

@@ -0,0 +1,238 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef CPPHIGHLEVELMODEL_H
#define CPPHIGHLEVELMODEL_H
#include "cppeditor.h"
#include "cpphoverhandler.h"
#include <cplusplus/CppDocument.h>
#include <cplusplus/Overview.h>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QSharedPointer>
#include <QtGui/QTextCursor>
#include <QtGui/QIcon>
namespace CPlusPlus {
class LookupItem;
class LookupContext;
}
namespace CppTools {
class CppModelManagerInterface;
}
namespace CppEditor {
namespace Internal {
class CPPEditor;
class CppElement;
class CppElementEvaluator
{
public:
CppElementEvaluator(CPPEditor *editor);
void setTextCursor(const QTextCursor &tc);
void setLookupBaseClasses(const bool lookup);
QSharedPointer<CppElement> identifyCppElement();
private:
void evaluate();
bool matchDiagnosticMessage(const CPlusPlus::Document::Ptr &document, unsigned line);
bool matchIncludeFile(const CPlusPlus::Document::Ptr &document, unsigned line);
bool matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos);
void handleLookupItemMatch(const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::LookupItem &lookupItem,
const CPlusPlus::LookupContext &lookupContext);
CPPEditor *m_editor;
CppTools::CppModelManagerInterface *m_modelManager;
QTextCursor m_tc;
bool m_lookupBaseClasses;
QSharedPointer<CppElement> m_element;
};
class CppElement
{
public:
virtual ~CppElement();
const CppHoverHandler::HelpCandidate::Category &helpCategory() const;
const QStringList &helpIdCandidates() const;
const QString &helpMark() const;
const CPPEditor::Link &link() const;
const QString &tooltip() const;
protected:
CppElement();
void setHelpCategory(const CppHoverHandler::HelpCandidate::Category &category);
void setLink(const CPPEditor::Link &link);
void setTooltip(const QString &tooltip);
void setHelpIdCandidates(const QStringList &candidates);
void addHelpIdCandidate(const QString &candidate);
void setHelpMark(const QString &mark);
private:
CppHoverHandler::HelpCandidate::Category m_helpCategory;
QStringList m_helpIdCandidates;
QString m_helpMark;
CPPEditor::Link m_link;
QString m_tooltip;
};
class Unknown : public CppElement
{
public:
Unknown(const QString &type);
virtual ~Unknown();
const QString &type() const;
private:
QString m_type;
};
class CppDiagnosis : public CppElement
{
public:
CppDiagnosis(const CPlusPlus::Document::DiagnosticMessage &message);
virtual ~CppDiagnosis();
const QString &text() const;
private:
QString m_text;
};
class CppInclude : public CppElement
{
public:
CppInclude(const CPlusPlus::Document::Include &includeFile);
virtual ~CppInclude();
const QString &path() const;
const QString &fileName() const;
private:
QString m_path;
QString m_fileName;
};
class CppMacro : public CppElement
{
public:
CppMacro(const CPlusPlus::Macro &macro);
virtual ~CppMacro();
};
class CppDeclarableElement : public CppElement
{
public:
CppDeclarableElement(CPlusPlus::Symbol *declaration);
virtual ~CppDeclarableElement();
const QString &name() const;
const QString &qualifiedName() const;
const QString &type() const;
const QIcon &icon() const;
protected:
void setName(const QString &name);
void setQualifiedName(const QString &name);
void setType(const QString &type);
void setIcon(const QIcon &icon);
private:
QString m_name;
QString m_qualifiedName;
QString m_type;
QIcon m_icon;
};
class CppNamespace : public CppDeclarableElement
{
public:
CppNamespace(CPlusPlus::Symbol *declaration);
virtual ~CppNamespace();
};
class CppClass : public CppDeclarableElement
{
public:
CppClass(CPlusPlus::Symbol *declaration);
virtual ~CppClass();
void lookupBases(CPlusPlus::Symbol *declaration, const CPlusPlus::LookupContext &context);
const QList<CppClass> &bases() const;
private:
QList<CppClass> m_bases;
};
class CppFunction : public CppDeclarableElement
{
public:
CppFunction(CPlusPlus::Symbol *declaration);
virtual ~CppFunction();
};
class CppEnum : public CppDeclarableElement
{
public:
CppEnum(CPlusPlus::Symbol *declaration);
virtual ~CppEnum();
};
class CppTypedef : public CppDeclarableElement
{
public:
CppTypedef(CPlusPlus::Symbol *declaration);
virtual ~CppTypedef();
};
class CppVariable : public CppDeclarableElement
{
public:
CppVariable(CPlusPlus::Symbol *declaration,
const CPlusPlus::LookupContext &context,
CPlusPlus::Scope *scope);
virtual ~CppVariable();
};
} // namespace Internal
} // namespace CppEditor
#endif // CPPHIGHLEVELMODEL_H

View File

@@ -29,6 +29,7 @@
#include "cpphoverhandler.h" #include "cpphoverhandler.h"
#include "cppeditor.h" #include "cppeditor.h"
#include "cppelementevaluator.h"
#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
@@ -37,29 +38,9 @@
#include <texteditor/itexteditor.h> #include <texteditor/itexteditor.h>
#include <texteditor/basetexteditor.h> #include <texteditor/basetexteditor.h>
#include <FullySpecifiedType.h>
#include <Names.h>
#include <CoreTypes.h>
#include <Scope.h>
#include <Symbol.h>
#include <Symbols.h>
#include <cplusplus/ExpressionUnderCursor.h>
#include <cplusplus/Overview.h>
#include <cplusplus/TypeOfExpression.h>
#include <cplusplus/LookupContext.h>
#include <cplusplus/LookupItem.h>
#include <QtCore/QSet>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QtAlgorithms>
#include <QtCore/QStringBuilder>
#include <QtGui/QTextCursor> #include <QtGui/QTextCursor>
#include <algorithm>
using namespace CppEditor::Internal; using namespace CppEditor::Internal;
using namespace CPlusPlus;
using namespace Core; using namespace Core;
namespace { namespace {
@@ -70,73 +51,13 @@ namespace {
else else
return name.right(name.length() - index - 1); return name.right(name.length() - index - 1);
} }
void moveCursorToEndOfName(QTextCursor *tc) {
QTextDocument *doc = tc->document();
if (!doc)
return;
QChar ch = doc->characterAt(tc->position());
while (ch.isLetterOrNumber() || ch == QLatin1Char('_')) {
tc->movePosition(QTextCursor::NextCharacter);
ch = doc->characterAt(tc->position());
}
}
void buildClassHierarchyHelper(ClassOrNamespace *classSymbol,
const LookupContext &context,
const Overview &overview,
QList<QStringList> *hierarchy,
QSet<ClassOrNamespace *> *visited) {
visited->insert(classSymbol);
const QList<ClassOrNamespace *> &bases = classSymbol->usings();
foreach (ClassOrNamespace *baseClass, bases) {
const QList<Symbol *> &symbols = baseClass->symbols();
foreach (Symbol *baseSymbol, symbols) {
if (baseSymbol->isClass() && (
classSymbol = context.lookupType(baseSymbol)) &&
!visited->contains(classSymbol)) {
const QString &qualifiedName = overview.prettyName(
LookupContext::fullyQualifiedName(baseSymbol));
if (!qualifiedName.isEmpty()) {
hierarchy->back().append(qualifiedName);
buildClassHierarchyHelper(classSymbol,
context,
overview,
hierarchy,
visited);
hierarchy->append(hierarchy->back());
hierarchy->back().removeLast();
}
}
}
}
}
void buildClassHierarchy(Symbol *symbol,
const LookupContext &context,
const Overview &overview,
QList<QStringList> *hierarchy) {
if (ClassOrNamespace *classSymbol = context.lookupType(symbol)) {
hierarchy->append(QStringList());
QSet<ClassOrNamespace *> visited;
buildClassHierarchyHelper(classSymbol, context, overview, hierarchy, &visited);
hierarchy->removeLast();
}
}
struct ClassHierarchyComp
{
bool operator()(const QStringList &a, const QStringList &b)
{ return a.size() < b.size(); }
};
} }
CppHoverHandler::CppHoverHandler(QObject *parent) : BaseHoverHandler(parent), m_modelManager(0) CppHoverHandler::CppHoverHandler(QObject *parent) : BaseHoverHandler(parent)
{ {}
m_modelManager =
ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>(); CppHoverHandler::~CppHoverHandler()
} {}
bool CppHoverHandler::acceptEditor(IEditor *editor) bool CppHoverHandler::acceptEditor(IEditor *editor)
{ {
@@ -148,191 +69,25 @@ bool CppHoverHandler::acceptEditor(IEditor *editor)
void CppHoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos) void CppHoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos)
{ {
if (!m_modelManager) CPPEditor *cppEditor = qobject_cast<CPPEditor *>(editor->widget());
if (!cppEditor)
return; return;
const Snapshot &snapshot = m_modelManager->snapshot(); if (!cppEditor->extraSelectionTooltip(pos).isEmpty()) {
Document::Ptr doc = snapshot.document(editor->file()->fileName()); setToolTip(cppEditor->extraSelectionTooltip(pos));
if (!doc)
return;
int line = 0;
int column = 0;
editor->convertPosition(pos, &line, &column);
if (!matchDiagnosticMessage(doc, line)) {
if (!matchIncludeFile(doc, line) && !matchMacroInUse(doc, pos)) {
TextEditor::BaseTextEditor *baseEditor = baseTextEditor(editor);
if (!baseEditor)
return;
bool extraSelectionTooltip = false;
if (!baseEditor->extraSelectionTooltip(pos).isEmpty()) {
setToolTip(baseEditor->extraSelectionTooltip(pos));
extraSelectionTooltip = true;
}
QTextCursor tc(baseEditor->document());
tc.setPosition(pos);
moveCursorToEndOfName(&tc);
// Fetch the expression's code
ExpressionUnderCursor expressionUnderCursor;
const QString &expression = expressionUnderCursor(tc);
Scope *scope = doc->scopeAt(line, column);
TypeOfExpression typeOfExpression;
typeOfExpression.init(doc, snapshot);
const QList<LookupItem> &lookupItems = typeOfExpression(expression, scope);
if (lookupItems.isEmpty())
return;
const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate.
handleLookupItemMatch(lookupItem, typeOfExpression.context(), !extraSelectionTooltip);
}
}
}
bool CppHoverHandler::matchDiagnosticMessage(const CPlusPlus::Document::Ptr &document,
unsigned line)
{
foreach (const Document::DiagnosticMessage &m, document->diagnosticMessages()) {
if (m.line() == line) {
setToolTip(m.text());
return true;
}
}
return false;
}
bool CppHoverHandler::matchIncludeFile(const CPlusPlus::Document::Ptr &document, unsigned line)
{
foreach (const Document::Include &includeFile, document->includes()) {
if (includeFile.line() == line) {
setToolTip(QDir::toNativeSeparators(includeFile.fileName()));
const QString &fileName = QFileInfo(includeFile.fileName()).fileName();
addHelpCandidate(HelpCandidate(fileName, fileName, HelpCandidate::Brief));
return true;
}
}
return false;
}
bool CppHoverHandler::matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos)
{
foreach (const Document::MacroUse &use, document->macroUses()) {
if (use.contains(pos)) {
const unsigned begin = use.begin();
const QString &name = use.macro().name();
if (pos < begin + name.length()) {
setToolTip(use.macro().toString());
addHelpCandidate(HelpCandidate(name, name, HelpCandidate::Macro));
return true;
}
}
}
return false;
}
void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem,
const LookupContext &context,
const bool assignTooltip)
{
Symbol *matchingDeclaration = lookupItem.declaration();
FullySpecifiedType matchingType = lookupItem.type();
Overview overview;
overview.setShowArgumentNames(true);
overview.setShowReturnTypes(true);
if (!matchingDeclaration && assignTooltip) {
setToolTip(overview.prettyType(matchingType, QString()));
} else { } else {
QString name; QTextCursor tc(cppEditor->document());
if (matchingDeclaration->scope()->isClass() || tc.setPosition(pos);
matchingDeclaration->scope()->isNamespace() ||
matchingDeclaration->scope()->isEnum()) {
name.append(overview.prettyName(
LookupContext::fullyQualifiedName(matchingDeclaration)));
if (matchingDeclaration->isClass() || CppElementEvaluator evaluator(cppEditor);
matchingDeclaration->isForwardClassDeclaration()) { evaluator.setTextCursor(tc);
buildClassHierarchy(matchingDeclaration, context, overview, &m_classHierarchy); QSharedPointer<CppElement> cppElement = evaluator.identifyCppElement();
} if (!cppElement.isNull()) {
} else { setToolTip(cppElement->tooltip());
name.append(overview.prettyName(matchingDeclaration->name())); foreach (const QString &helpId, cppElement->helpIdCandidates())
} addHelpCandidate(HelpCandidate(helpId,
cppElement->helpMark(),
if (assignTooltip) { cppElement->helpCategory()));
if (matchingDeclaration->isClass() ||
matchingDeclaration->isNamespace() ||
matchingDeclaration->isForwardClassDeclaration() ||
matchingDeclaration->isEnum()) {
setToolTip(name);
} else {
setToolTip(overview.prettyType(matchingType, name));
}
}
HelpCandidate::Category helpCategory = HelpCandidate::Unknown;
if (matchingDeclaration->isNamespace() ||
matchingDeclaration->isClass() ||
matchingDeclaration->isForwardClassDeclaration()) {
helpCategory = HelpCandidate::ClassOrNamespace;
} else if (matchingDeclaration->isEnum() ||
matchingDeclaration->scope()->isEnum()) {
helpCategory = HelpCandidate::Enum;
} else if (matchingDeclaration->isTypedef()) {
helpCategory = HelpCandidate::Typedef;
} else if (matchingDeclaration->isFunction() ||
(matchingType.isValid() && matchingType->isFunctionType())){
helpCategory = HelpCandidate::Function;
} else if (matchingDeclaration->isDeclaration() && matchingType.isValid()) {
const Name *typeName = 0;
if (matchingType->isNamedType()) {
typeName = matchingType->asNamedType()->name();
} else if (matchingType->isPointerType() || matchingType->isReferenceType()) {
FullySpecifiedType type;
if (matchingType->isPointerType())
type = matchingType->asPointerType()->elementType();
else
type = matchingType->asReferenceType()->elementType();
if (type->isNamedType())
typeName = type->asNamedType()->name();
}
if (typeName) {
if (ClassOrNamespace *clazz = context.lookupType(typeName, lookupItem.scope())) {
if (!clazz->symbols().isEmpty()) {
Symbol *symbol = clazz->symbols().at(0);
matchingDeclaration = symbol;
name = overview.prettyName(LookupContext::fullyQualifiedName(symbol));
setToolTip(name);
buildClassHierarchy(symbol, context, overview, &m_classHierarchy);
helpCategory = HelpCandidate::ClassOrNamespace;
}
}
}
}
if (helpCategory != HelpCandidate::Unknown) {
QString docMark = overview.prettyName(matchingDeclaration->name());
if (matchingType.isValid() && matchingType->isFunctionType()) {
// Functions marks can be found either by the main overload or signature based
// (with no argument names and no return). Help ids have no signature at all.
overview.setShowArgumentNames(false);
overview.setShowReturnTypes(false);
docMark = overview.prettyType(matchingType, docMark);
overview.setShowFunctionSignatures(false);
const QString &functionName = overview.prettyName(matchingDeclaration->name());
addHelpCandidate(HelpCandidate(functionName, docMark, helpCategory));
} else if (matchingDeclaration->scope()->isEnum()) {
Symbol *enumSymbol = matchingDeclaration->scope()->asEnum();
docMark = overview.prettyName(enumSymbol->name());
}
addHelpCandidate(HelpCandidate(name, docMark, helpCategory));
} }
} }
} }
@@ -357,121 +112,8 @@ void CppHoverHandler::evaluateHelpCandidates()
void CppHoverHandler::decorateToolTip(TextEditor::ITextEditor *editor) void CppHoverHandler::decorateToolTip(TextEditor::ITextEditor *editor)
{ {
if (!m_classHierarchy.isEmpty())
generateDiagramTooltip(extendToolTips(editor));
else
generateNormalTooltip(extendToolTips(editor));
}
void CppHoverHandler::generateDiagramTooltip(const bool extendTooltips)
{
QString clazz = toolTip();
qSort(m_classHierarchy.begin(), m_classHierarchy.end(), ClassHierarchyComp());
// Remove duplicates (in case there are any).
m_classHierarchy.erase(std::unique(m_classHierarchy.begin(), m_classHierarchy.end()),
m_classHierarchy.end());
QStringList directBaseClasses;
foreach (const QStringList &hierarchy, m_classHierarchy) {
if (hierarchy.size() > 1)
break;
directBaseClasses.append(hierarchy.at(0));
}
QString diagram(QLatin1String("<table>"));
for (int i = 0; i < directBaseClasses.size(); ++i) {
if (i == 0) {
diagram.append(QString(
"<tr><td>%1</td><td>"
"<img src=\":/cppeditor/images/rightarrow.png\"></td>"
"<td>%2</td></tr>").arg(toolTip()).arg(directBaseClasses.at(i)));
} else {
diagram.append(QString(
"<tr><td></td><td>"
"<img src=\":/cppeditor/images/larrow.png\"></td>"
"<td>%1</td></tr>").arg(directBaseClasses.at(i)));
}
}
diagram.append(QLatin1String("</table>"));
setToolTip(diagram);
if (matchingHelpCandidate() != -1) { if (matchingHelpCandidate() != -1) {
appendToolTip(getDocContents(extendTooltips)); const QString &contents = getDocContents(extendToolTips(editor));
} else {
// Look for documented base classes. Diagram the nearest one or the nearest ones (in
// the case there are many at the same level).
int helpLevel = 0;
QList<int> baseClassesWithHelp;
for (int i = 0; i < m_classHierarchy.size(); ++i) {
const QStringList &hierarchy = m_classHierarchy.at(i);
if (helpLevel != 0 && hierarchy.size() != helpLevel)
break;
bool exists = false;
QString name = hierarchy.last();
if (helpIdExists(name)) {
exists = true;
} else {
name = removeClassNameQualification(name);
if (helpIdExists(name)) {
exists = true;
m_classHierarchy[i].last() = name;
}
}
if (exists) {
baseClassesWithHelp.append(i);
if (helpLevel == 0)
helpLevel = hierarchy.size();
}
}
if (!baseClassesWithHelp.isEmpty()) {
// Choose the first one as the help match.
QString base = m_classHierarchy.at(baseClassesWithHelp.at(0)).last();
HelpCandidate help(base, base, HelpCandidate::ClassOrNamespace);
addHelpCandidate(help);
setMatchingHelpCandidate(helpCandidates().size() - 1);
if (baseClassesWithHelp.size() == 1 && helpLevel == 1) {
appendToolTip(getDocContents(help, extendTooltips));
} else {
foreach (int hierarchyIndex, baseClassesWithHelp) {
appendToolTip(QLatin1String("<p>"));
const QStringList &hierarchy = m_classHierarchy.at(hierarchyIndex);
Q_ASSERT(helpLevel <= hierarchy.size());
// Following contents are inside tables so they are on the exact same
// alignment as the top level diagram.
diagram = QString(QLatin1String("<table><tr><td>%1</td>")).arg(clazz);
for (int i = 0; i < helpLevel; ++i) {
diagram.append(
QLatin1String("<td><img src=\":/cppeditor/images/rightarrow.png\">"
"</td><td>") %
hierarchy.at(i) %
QLatin1String("</td>"));
}
diagram.append(QLatin1String("</tr></table>"));
base = hierarchy.at(helpLevel - 1);
const QString &contents =
getDocContents(HelpCandidate(base, base, HelpCandidate::Brief), false);
if (!contents.isEmpty()) {
appendToolTip(diagram % QLatin1String("<table><tr><td>") %
contents % QLatin1String("</td></tr></table>"));
}
appendToolTip(QLatin1String("</p>"));
}
}
}
}
}
void CppHoverHandler::generateNormalTooltip(const bool extendTooltips)
{
if (matchingHelpCandidate() != -1) {
const QString &contents = getDocContents(extendTooltips);
if (!contents.isEmpty()) { if (!contents.isEmpty()) {
HelpCandidate::Category cat = helpCandidate(matchingHelpCandidate()).m_category; HelpCandidate::Category cat = helpCandidate(matchingHelpCandidate()).m_category;
if (cat == HelpCandidate::ClassOrNamespace) if (cat == HelpCandidate::ClassOrNamespace)
@@ -486,8 +128,3 @@ void CppHoverHandler::generateNormalTooltip(const bool extendTooltips)
} }
} }
} }
void CppHoverHandler::resetExtras()
{
m_classHierarchy.clear();
}

View File

@@ -30,26 +30,14 @@
#ifndef CPPHOVERHANDLER_H #ifndef CPPHOVERHANDLER_H
#define CPPHOVERHANDLER_H #define CPPHOVERHANDLER_H
#include <cplusplus/CppDocument.h>
#include <texteditor/basehoverhandler.h> #include <texteditor/basehoverhandler.h>
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QStringList>
namespace CPlusPlus {
class LookupItem;
class LookupContext;
}
namespace Core { namespace Core {
class IEditor; class IEditor;
} }
namespace CppTools {
class CppModelManagerInterface;
}
namespace TextEditor { namespace TextEditor {
class ITextEditor; class ITextEditor;
} }
@@ -62,26 +50,13 @@ class CppHoverHandler : public TextEditor::BaseHoverHandler
Q_OBJECT Q_OBJECT
public: public:
CppHoverHandler(QObject *parent = 0); CppHoverHandler(QObject *parent = 0);
virtual ~CppHoverHandler();
private: private:
virtual bool acceptEditor(Core::IEditor *editor); virtual bool acceptEditor(Core::IEditor *editor);
virtual void identifyMatch(TextEditor::ITextEditor *editor, int pos); virtual void identifyMatch(TextEditor::ITextEditor *editor, int pos);
virtual void resetExtras();
virtual void evaluateHelpCandidates(); virtual void evaluateHelpCandidates();
virtual void decorateToolTip(TextEditor::ITextEditor *editor); virtual void decorateToolTip(TextEditor::ITextEditor *editor);
bool matchDiagnosticMessage(const CPlusPlus::Document::Ptr &document, unsigned line);
bool matchIncludeFile(const CPlusPlus::Document::Ptr &document, unsigned line);
bool matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos);
void handleLookupItemMatch(const CPlusPlus::LookupItem &lookupItem,
const CPlusPlus::LookupContext &lookupContext,
const bool assignTooltip);
void generateDiagramTooltip(const bool extendTooltips);
void generateNormalTooltip(const bool extendTooltips);
CppTools::CppModelManagerInterface *m_modelManager;
QList<QStringList> m_classHierarchy;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -36,6 +36,7 @@
#include "cpphoverhandler.h" #include "cpphoverhandler.h"
#include "cppquickfix.h" #include "cppquickfix.h"
#include "cppoutline.h" #include "cppoutline.h"
#include "cpptypehierarchy.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
@@ -46,6 +47,7 @@
#include <coreplugin/actionmanager/command.h> #include <coreplugin/actionmanager/command.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/navigationwidget.h>
#include <texteditor/completionsupport.h> #include <texteditor/completionsupport.h>
#include <texteditor/fontsettings.h> #include <texteditor/fontsettings.h>
#include <texteditor/storagesettings.h> #include <texteditor/storagesettings.h>
@@ -60,6 +62,7 @@
#include <QtCore/QSettings> #include <QtCore/QSettings>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtGui/QMenu> #include <QtGui/QMenu>
@@ -139,8 +142,8 @@ CppPlugin::CppPlugin() :
m_sortedOutline(false), m_sortedOutline(false),
m_renameSymbolUnderCursorAction(0), m_renameSymbolUnderCursorAction(0),
m_findUsagesAction(0), m_findUsagesAction(0),
m_updateCodeModelAction(0) m_updateCodeModelAction(0),
m_openTypeHierarchyAction(0)
{ {
m_instance = this; m_instance = this;
@@ -205,7 +208,7 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
addAutoReleasedObject(new CppEditorFactory(this)); addAutoReleasedObject(new CppEditorFactory(this));
addAutoReleasedObject(new CppHoverHandler); addAutoReleasedObject(new CppHoverHandler);
addAutoReleasedObject(new CppOutlineWidgetFactory); addAutoReleasedObject(new CppOutlineWidgetFactory);
addAutoReleasedObject(new CppTypeHierarchyFactory);
m_quickFixCollector = new CppQuickFixCollector; m_quickFixCollector = new CppQuickFixCollector;
addAutoReleasedObject(m_quickFixCollector); addAutoReleasedObject(m_quickFixCollector);
@@ -274,6 +277,13 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
contextMenu->addAction(cmd); contextMenu->addAction(cmd);
cppToolsMenu->addAction(cmd); cppToolsMenu->addAction(cmd);
m_openTypeHierarchyAction = new QAction(tr("Open Type Hierarchy"), this);
cmd = am->registerAction(m_openTypeHierarchyAction, Constants::OPEN_TYPE_HIERARCHY, context);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+T")));
connect(m_openTypeHierarchyAction, SIGNAL(triggered()), this, SLOT(openTypeHierarchy()));
contextMenu->addAction(cmd);
cppToolsMenu->addAction(cmd);
// Update context in global context // Update context in global context
Core::Context globalContext(Core::Constants::C_GLOBAL); Core::Context globalContext(Core::Constants::C_GLOBAL);
cppToolsMenu->addAction(createSeparator(am, this, globalContext, CppEditor::Constants::SEPARATOR2)); cppToolsMenu->addAction(createSeparator(am, this, globalContext, CppEditor::Constants::SEPARATOR2));
@@ -391,6 +401,7 @@ void CppPlugin::onTaskStarted(const QString &type)
m_renameSymbolUnderCursorAction->setEnabled(false); m_renameSymbolUnderCursorAction->setEnabled(false);
m_findUsagesAction->setEnabled(false); m_findUsagesAction->setEnabled(false);
m_updateCodeModelAction->setEnabled(false); m_updateCodeModelAction->setEnabled(false);
m_openTypeHierarchyAction->setEnabled(false);
} }
} }
@@ -400,6 +411,7 @@ void CppPlugin::onAllTasksFinished(const QString &type)
m_renameSymbolUnderCursorAction->setEnabled(true); m_renameSymbolUnderCursorAction->setEnabled(true);
m_findUsagesAction->setEnabled(true); m_findUsagesAction->setEnabled(true);
m_updateCodeModelAction->setEnabled(true); m_updateCodeModelAction->setEnabled(true);
m_openTypeHierarchyAction->setEnabled(true);
} }
} }
@@ -413,4 +425,15 @@ void CppPlugin::currentEditorChanged(Core::IEditor *editor)
} }
} }
void CppPlugin::openTypeHierarchy()
{
Core::EditorManager *em = Core::EditorManager::instance();
CPPEditor *editor = qobject_cast<CPPEditor*>(em->currentEditor()->widget());
if (editor) {
Core::NavigationWidget *navigation = Core::NavigationWidget::instance();
navigation->activateSubWidget(QLatin1String(Constants::TYPE_HIERARCHY_ID));
emit typeHierarchyRequested();
}
}
Q_EXPORT_PLUGIN(CppPlugin) Q_EXPORT_PLUGIN(CppPlugin)

View File

@@ -71,6 +71,7 @@ public:
signals: signals:
void outlineSortingChanged(bool sort); void outlineSortingChanged(bool sort);
void typeHierarchyRequested();
public slots: public slots:
void setSortedOutline(bool sorted); void setSortedOutline(bool sorted);
@@ -85,6 +86,7 @@ private slots:
void quickFix(TextEditor::ITextEditable *editable); void quickFix(TextEditor::ITextEditable *editable);
void quickFixNow(); void quickFixNow();
void currentEditorChanged(Core::IEditor *editor); void currentEditorChanged(Core::IEditor *editor);
void openTypeHierarchy();
private: private:
Core::IEditor *createEditor(QWidget *parent); Core::IEditor *createEditor(QWidget *parent);
@@ -98,6 +100,7 @@ private:
QAction *m_renameSymbolUnderCursorAction; QAction *m_renameSymbolUnderCursorAction;
QAction *m_findUsagesAction; QAction *m_findUsagesAction;
QAction *m_updateCodeModelAction; QAction *m_updateCodeModelAction;
QAction *m_openTypeHierarchyAction;
CppQuickFixCollector *m_quickFixCollector; CppQuickFixCollector *m_quickFixCollector;

View File

@@ -0,0 +1,267 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "cpptypehierarchy.h"
#include "cppeditorconstants.h"
#include "cppeditor.h"
#include "cppelementevaluator.h"
#include "cppplugin.h"
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/coreconstants.h>
#include <utils/navigationtreeview.h>
#include <QtCore/QLatin1Char>
#include <QtCore/QLatin1String>
#include <QtCore/QModelIndex>
#include <QtCore/QSettings>
#include <QtGui/QVBoxLayout>
#include <QtGui/QStandardItemModel>
#include <QtGui/QFontMetrics>
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QLabel>
using namespace CppEditor;
using namespace Internal;
// CppTypeHierarchyItem
CppTypeHierarchyItem::CppTypeHierarchyItem(const CppClass &cppClass) :
QStandardItem(), m_cppClass(cppClass)
{}
CppTypeHierarchyItem::~CppTypeHierarchyItem()
{}
int CppTypeHierarchyItem::type() const
{ return UserType; }
const CppClass &CppTypeHierarchyItem::cppClass() const
{ return m_cppClass; }
// CppTypeHierarchyDelegate
CppTypeHierarchyDelegate::CppTypeHierarchyDelegate(QObject *parent) : QStyledItemDelegate(parent)
{}
CppTypeHierarchyDelegate::~CppTypeHierarchyDelegate()
{}
void CppTypeHierarchyDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (const QStyleOptionViewItemV3 *v3 =
qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option)) {
QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, v3, painter, v3->widget);
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
const QStandardItemModel *model = static_cast<const QStandardItemModel *>(index.model());
CppTypeHierarchyItem *item =
static_cast<CppTypeHierarchyItem *>(model->itemFromIndex(index));
painter->save();
const QIcon &icon = item->cppClass().icon();
const QSize &iconSize = icon.actualSize(opt.decorationSize);
QRect workingRect(opt.rect);
QRect decorationRect(workingRect.topLeft(), iconSize);
icon.paint(painter, decorationRect, opt.decorationAlignment);
workingRect.setX(workingRect.x() + iconSize.width() + 4);
QRect boundingRect;
const QString &name = item->cppClass().name() + QLatin1Char(' ');
painter->drawText(workingRect, Qt::AlignLeft, name, &boundingRect);
if (item->cppClass().name() != item->cppClass().qualifiedName()) {
QFont font(painter->font());
if (font.pointSize() > 2)
font.setPointSize(font.pointSize() - 2);
else if (font.pointSize() > 1)
font.setPointSize(font.pointSize() - 1);
font.setItalic(true);
painter->setFont(font);
QFontMetrics metrics(font);
workingRect.setX(boundingRect.x() + boundingRect.width());
workingRect.setY(boundingRect.y() + boundingRect.height() - metrics.height());
painter->drawText(workingRect, Qt::AlignLeft, item->cppClass().qualifiedName());
}
painter->restore();
} else {
QStyledItemDelegate::paint(painter, option, index);
}
}
QSize CppTypeHierarchyDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QSize size = QStyledItemDelegate::sizeHint(option, index);
size.rwidth() += 5; // Extend a bit because of the font processing.
return size;
}
// CppTypeHierarchyWidget
CppTypeHierarchyWidget::CppTypeHierarchyWidget(Core::IEditor *editor) :
QWidget(0),
m_cppEditor(0),
m_treeView(0),
m_model(0),
m_delegate(0)
{
QVBoxLayout *layout = new QVBoxLayout;
layout->setMargin(0);
layout->setSpacing(0);
if (CPPEditorEditable *cppEditable = qobject_cast<CPPEditorEditable *>(editor)) {
m_cppEditor = static_cast<CPPEditor *>(cppEditable->widget());
m_model = new QStandardItemModel;
m_treeView = new Utils::NavigationTreeView;
m_delegate = new CppTypeHierarchyDelegate;
m_treeView->setModel(m_model);
m_treeView->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_treeView->setItemDelegate(m_delegate);
layout->addWidget(m_treeView);
connect(m_treeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onItemClicked(QModelIndex)));
connect(CppPlugin::instance(), SIGNAL(typeHierarchyRequested()), this, SLOT(perform()));
} else {
QLabel *label = new QLabel(tr("No type hierarchy available"), this);
label->setAlignment(Qt::AlignCenter);
label->setAutoFillBackground(true);
label->setBackgroundRole(QPalette::Base);
layout->addWidget(label);
}
setLayout(layout);
}
CppTypeHierarchyWidget::~CppTypeHierarchyWidget()
{
delete m_model;
delete m_delegate;
}
void CppTypeHierarchyWidget::perform()
{
if (!m_cppEditor)
return;
m_model->clear();
CppElementEvaluator evaluator(m_cppEditor);
evaluator.setLookupBaseClasses(true);
QSharedPointer<CppElement> cppElement = evaluator.identifyCppElement();
if (!cppElement.isNull()) {
CppElement *element = cppElement.data();
if (CppClass *cppClass = dynamic_cast<CppClass *>(element))
buildModel(*cppClass, m_model->invisibleRootItem());
}
}
void CppTypeHierarchyWidget::buildModel(const CppClass &cppClass, QStandardItem *parent)
{
CppTypeHierarchyItem *item = new CppTypeHierarchyItem(cppClass);
parent->appendRow(item);
// The delegate retrieves data from the item directly. This is to help size hint.
const QString &display = cppClass.name() + cppClass.qualifiedName();
m_model->setData(m_model->indexFromItem(item), display, Qt::DisplayRole);
m_model->setData(m_model->indexFromItem(item), cppClass.icon(), Qt::DecorationRole);
foreach (const CppClass &cppBase, cppClass.bases())
buildModel(cppBase, item);
m_treeView->expand(m_model->indexFromItem(item));
}
void CppTypeHierarchyWidget::onItemClicked(const QModelIndex &index)
{
if (QStandardItem *item = m_model->itemFromIndex(index)) {
CppTypeHierarchyItem *cppItem = static_cast<CppTypeHierarchyItem *>(item);
m_cppEditor->openLink(cppItem->cppClass().link());
}
}
// CppTypeHierarchyStackedWidget
CppTypeHierarchyStackedWidget::CppTypeHierarchyStackedWidget(QWidget *parent) :
QStackedWidget(parent),
m_typeHiearchyWidgetInstance(
new CppTypeHierarchyWidget(Core::EditorManager::instance()->currentEditor()))
{
addWidget(m_typeHiearchyWidgetInstance);
connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
this, SLOT(editorChanged(Core::IEditor*)));
}
CppTypeHierarchyStackedWidget::~CppTypeHierarchyStackedWidget()
{
delete m_typeHiearchyWidgetInstance;
}
void CppTypeHierarchyStackedWidget::editorChanged(Core::IEditor *editor)
{
CppTypeHierarchyWidget *replacement = new CppTypeHierarchyWidget(editor);
removeWidget(m_typeHiearchyWidgetInstance);
m_typeHiearchyWidgetInstance->deleteLater();
m_typeHiearchyWidgetInstance = replacement;
addWidget(m_typeHiearchyWidgetInstance);
}
// CppTypeHierarchyFactory
CppTypeHierarchyFactory::CppTypeHierarchyFactory()
{}
CppTypeHierarchyFactory::~CppTypeHierarchyFactory()
{}
QString CppTypeHierarchyFactory::displayName() const
{
return tr("Type Hierarchy");
}
QString CppTypeHierarchyFactory::id() const
{
return QLatin1String(Constants::TYPE_HIERARCHY_ID);
}
QKeySequence CppTypeHierarchyFactory::activationSequence() const
{
return QKeySequence();
}
Core::NavigationView CppTypeHierarchyFactory::createWidget()
{
CppTypeHierarchyStackedWidget *w = new CppTypeHierarchyStackedWidget;
static_cast<CppTypeHierarchyWidget *>(w->currentWidget())->perform();
Core::NavigationView navigationView;
navigationView.widget = w;
return navigationView;
}

View File

@@ -0,0 +1,142 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef CPPTYPEHIERARCHY_H
#define CPPTYPEHIERARCHY_H
#include "cppelementevaluator.h"
#include <coreplugin/inavigationwidgetfactory.h>
#include <QtCore/QString>
#include <QtGui/QWidget>
#include <QtGui/QStackedWidget>
#include <QtGui/QStandardItem>
#include <QtGui/QStyledItemDelegate>
QT_BEGIN_NAMESPACE
class QStandardItemModel;
class QModelIndex;
class QPainter;
QT_END_NAMESPACE
namespace Core {
class IEditor;
}
namespace Utils {
class NavigationTreeView;
}
namespace CppEditor {
namespace Internal {
class CPPEditor;
class CppTypeHierarchyItem : public QStandardItem
{
public:
CppTypeHierarchyItem(const CppClass &cppClass);
virtual ~CppTypeHierarchyItem();
virtual int type() const;
const CppClass &cppClass() const;
private:
CppClass m_cppClass;
};
class CppTypeHierarchyDelegate : public QStyledItemDelegate
{
public:
CppTypeHierarchyDelegate(QObject *parent = 0);
virtual ~CppTypeHierarchyDelegate();
virtual void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
class CppTypeHierarchyWidget : public QWidget
{
Q_OBJECT
public:
CppTypeHierarchyWidget(Core::IEditor *editor);
virtual ~CppTypeHierarchyWidget();
public slots:
void perform();
private slots:
void onItemClicked(const QModelIndex &index);
private:
void buildModel(const CppClass &cppClass, QStandardItem *item);
CPPEditor *m_cppEditor;
Utils::NavigationTreeView *m_treeView;
QStandardItemModel *m_model;
CppTypeHierarchyDelegate *m_delegate;
};
// @todo: Pretty much the same design as the OutlineWidgetStack. Maybe we can generalize the
// outline factory so that it works for different widgets that support the same editor.
class CppTypeHierarchyStackedWidget : public QStackedWidget
{
Q_OBJECT
public:
CppTypeHierarchyStackedWidget(QWidget *parent = 0);
virtual ~CppTypeHierarchyStackedWidget();
public slots:
void editorChanged(Core::IEditor* editor);
private:
CppTypeHierarchyWidget *m_typeHiearchyWidgetInstance;
};
class CppTypeHierarchyFactory : public Core::INavigationWidgetFactory
{
Q_OBJECT
public:
CppTypeHierarchyFactory();
virtual ~CppTypeHierarchyFactory();
virtual QString displayName() const;
virtual QString id() const;
virtual QKeySequence activationSequence() const;
virtual Core::NavigationView createWidget();
};
} // namespace Internal
} // namespace CppEditor
#endif // CPPTYPEHIERARCHY_H

View File

@@ -95,6 +95,10 @@ void BaseHoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint
void BaseHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos) void BaseHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos)
{ {
BaseTextEditor *baseEditor = baseTextEditor(editor);
if (!baseEditor)
return;
// If the tooltip is visible and there is a help match, this match is used to update // If the tooltip is visible and there is a help match, this match is used to update
// the help id. Otherwise, let the identification process happen. // the help id. Otherwise, let the identification process happen.
if (!ToolTip::instance()->isVisible() || m_matchingHelpCandidate == -1) if (!ToolTip::instance()->isVisible() || m_matchingHelpCandidate == -1)

View File

@@ -57,19 +57,6 @@ class TEXTEDITOR_EXPORT BaseHoverHandler : public QObject
public: public:
BaseHoverHandler(QObject *parent = 0); BaseHoverHandler(QObject *parent = 0);
private slots:
void editorOpened(Core::IEditor *editor);
public slots:
void showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos);
void updateContextHelpId(TextEditor::ITextEditor *editor, int pos);
protected:
void setToolTip(const QString &tooltip);
const QString &toolTip() const;
void appendToolTip(const QString &extension);
void addF1ToToolTip();
struct HelpCandidate struct HelpCandidate
{ {
enum Category { enum Category {
@@ -94,6 +81,19 @@ protected:
Category m_category; Category m_category;
}; };
private slots:
void editorOpened(Core::IEditor *editor);
public slots:
void showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos);
void updateContextHelpId(TextEditor::ITextEditor *editor, int pos);
protected:
void setToolTip(const QString &tooltip);
const QString &toolTip() const;
void appendToolTip(const QString &extension);
void addF1ToToolTip();
void addHelpCandidate(const HelpCandidate &helpCandidate); void addHelpCandidate(const HelpCandidate &helpCandidate);
void setHelpCandidate(const HelpCandidate &helpCandidate, int index); void setHelpCandidate(const HelpCandidate &helpCandidate, int index);
const QList<HelpCandidate> &helpCandidates() const; const QList<HelpCandidate> &helpCandidates() const;

View File

@@ -463,6 +463,7 @@ protected:
static void countBrackets(QTextCursor cursor, int from, int end, QChar open, QChar close, static void countBrackets(QTextCursor cursor, int from, int end, QChar open, QChar close,
int *errors, int *stillopen); int *errors, int *stillopen);
public:
struct Link struct Link
{ {
Link(const QString &fileName = QString(), Link(const QString &fileName = QString(),
@@ -489,6 +490,7 @@ protected:
int column; // Target column int column; // Target column
}; };
protected:
/*! /*!
Reimplement this function to enable code navigation. Reimplement this function to enable code navigation.