/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** 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. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** **************************************************************************/ #include "cpptypehierarchy.h" #include "cppeditorconstants.h" #include "cppeditor.h" #include "cppelementevaluator.h" #include "cppplugin.h" #include #include #include #include #include #include #include #include #include #include #include using namespace CppEditor; using namespace Internal; using namespace Utils; namespace { enum ItemRole { AnnotationRole = Qt::UserRole + 1, LinkRole }; QStandardItem *itemForClass(const CppClass &cppClass) { QStandardItem *item = new QStandardItem; item->setData(cppClass.name(), Qt::DisplayRole); if (cppClass.name() != cppClass.qualifiedName()) item->setData(cppClass.qualifiedName(), AnnotationRole); item->setData(cppClass.icon(), Qt::DecorationRole); QVariant link; link.setValue(CPPEditorWidget::Link(cppClass.link())); item->setData(link, LinkRole); return item; } bool compareCppClassNames(const CppClass &c1, const CppClass &c2) { const QString key1 = c1.name() + QLatin1String("::") + c1.qualifiedName(); const QString key2 = c2.name() + QLatin1String("::") + c2.qualifiedName(); return key1 < key2; } QList sortClasses(const QList &cppClasses) { QList sorted = cppClasses; qSort(sorted.begin(), sorted.end(), compareCppClassNames); return sorted; } } // Anonymous namespace CppEditor { namespace Internal { class CppClassLabel : public QLabel { public: CppClassLabel(CPPEditorWidget *editor, QWidget *parent) : QLabel(parent), m_editor(editor) {} void setup(CppClass *cppClass) { setText(cppClass->name()); m_link = cppClass->link(); } private: void mousePressEvent(QMouseEvent *) { m_editor->openLink(m_link); } CPPEditorWidget *m_editor; CPPEditorWidget::Link m_link; }; } // namespace Internal } // namespace CppEditor // 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 (CPPEditor *cppEditor = qobject_cast(editor)) { m_cppEditor = static_cast(cppEditor->widget()); m_inspectedClass = new CppClassLabel(m_cppEditor, this); m_inspectedClass->setMargin(5); layout->addWidget(m_inspectedClass); m_model = new QStandardItemModel(this); m_treeView = new NavigationTreeView(this); m_delegate = new AnnotatedItemDelegate(this); m_delegate->setDelimiter(QLatin1String(" ")); m_delegate->setAnnotationRole(AnnotationRole); m_treeView->setModel(m_model); m_treeView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_treeView->setItemDelegate(m_delegate); m_treeView->setRootIsDecorated(false); 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() {} bool CppTypeHierarchyWidget::handleEditorChange(Core::IEditor *editor) { if (CPPEditor *cppEditor = qobject_cast(editor)) { if (m_cppEditor) { m_cppEditor = static_cast(cppEditor->widget()); return true; } } else if (!m_cppEditor) { return true; } return false; } void CppTypeHierarchyWidget::perform() { if (!m_cppEditor) return; m_model->clear(); CppElementEvaluator evaluator(m_cppEditor); evaluator.setLookupBaseClasses(true); evaluator.setLookupDerivedClasses(true); evaluator.execute(); if (evaluator.identifiedCppElement()) { const QSharedPointer &cppElement = evaluator.cppElement(); CppElement *element = cppElement.data(); if (CppClass *cppClass = dynamic_cast(element)) { m_inspectedClass->setup(cppClass); QStandardItem *bases = new QStandardItem(tr("Bases")); m_model->invisibleRootItem()->appendRow(bases); QVector v; v.push_back(*cppClass); buildBaseHierarchy(&v); m_treeView->expand(m_model->indexFromItem(bases)); QStandardItem *derived = new QStandardItem(tr("Derived")); m_model->invisibleRootItem()->appendRow(derived); foreach (const CppClass &derivedClass, sortClasses(cppClass->derived())) buildDerivedHierarchy(derivedClass, derived); } } } void CppTypeHierarchyWidget::buildBaseHierarchy(QVector *s) { const CppClass ¤t = s->back(); const QList &bases = sortClasses(current.bases()); if (!bases.isEmpty()) { foreach (const CppClass &base, bases) { s->push_back(base); buildBaseHierarchy(s); s->pop_back(); } } else { QStandardItem *parent = m_model->item(0, 0); for (int i = s->size() - 1; i > 0; --i) { QStandardItem *item = itemForClass(s->at(i)); parent->appendRow(item); m_treeView->expand(m_model->indexFromItem(parent)); parent = item; } } } void CppTypeHierarchyWidget::buildDerivedHierarchy(const CppClass &cppClass, QStandardItem *parent) { QStandardItem *item = itemForClass(cppClass); parent->appendRow(item); foreach (const CppClass &derived, sortClasses(cppClass.derived())) buildDerivedHierarchy(derived, item); m_treeView->expand(m_model->indexFromItem(parent)); } void CppTypeHierarchyWidget::onItemClicked(const QModelIndex &index) { m_cppEditor->openLink(index.data(LinkRole).value()); } // 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) { if (!m_typeHiearchyWidgetInstance->handleEditorChange(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"); } int CppTypeHierarchyFactory::priority() const { return Constants::TYPE_HIERARCHY_PRIORITY; } Core::Id CppTypeHierarchyFactory::id() const { return Core::Id(Constants::TYPE_HIERARCHY_ID); } QKeySequence CppTypeHierarchyFactory::activationSequence() const { return QKeySequence(); } Core::NavigationView CppTypeHierarchyFactory::createWidget() { CppTypeHierarchyStackedWidget *w = new CppTypeHierarchyStackedWidget; static_cast(w->currentWidget())->perform(); Core::NavigationView navigationView; navigationView.widget = w; return navigationView; }