cpptypehierarchy.cpp 8.29 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29
30

#include "cpptypehierarchy.h"
31

32
33
34
#include "cppeditorconstants.h"
#include "cppeditor.h"
#include "cppelementevaluator.h"
35
#include "cppeditorplugin.h"
36

37
#include <coreplugin/find/treeviewfind.h>
38
#include <utils/algorithm.h>
39
#include <utils/navigationtreeview.h>
40
#include <utils/annotateditemdelegate.h>
41

42
#include <QLabel>
43
44
#include <QLatin1String>
#include <QModelIndex>
45
#include <QStackedLayout>
46
#include <QStandardItemModel>
47
#include <QVBoxLayout>
48
49

using namespace CppEditor;
50
using namespace CppEditor::Internal;
51
using namespace Utils;
52

53
54
55
56
57
58
59
60
61
62
namespace {

enum ItemRole {
    AnnotationRole = Qt::UserRole + 1,
    LinkRole
};

QStandardItem *itemForClass(const CppClass &cppClass)
{
    QStandardItem *item = new QStandardItem;
63
64
65
66
    item->setData(cppClass.name, Qt::DisplayRole);
    if (cppClass.name != cppClass.qualifiedName)
        item->setData(cppClass.qualifiedName, AnnotationRole);
    item->setData(cppClass.icon, Qt::DecorationRole);
67
    QVariant link;
68
    link.setValue(CPPEditorWidget::Link(cppClass.link));
69
70
71
72
    item->setData(link, LinkRole);
    return item;
}

73
74
75
QList<CppClass> sortClasses(const QList<CppClass> &cppClasses)
{
    QList<CppClass> sorted = cppClasses;
76
    Utils::sort(sorted, [](const CppClass &c1, const CppClass &c2) -> bool {
77
78
79
80
        const QString key1 = c1.name + QLatin1String("::") + c1.qualifiedName;
        const QString key2 = c2.name + QLatin1String("::") + c2.qualifiedName;
        return key1 < key2;
    });
81
82
83
    return sorted;
}

84
85
} // Anonymous

86
87
88
89
90
91
namespace CppEditor {
namespace Internal {

class CppClassLabel : public QLabel
{
public:
92
93
    CppClassLabel(QWidget *parent)
        : QLabel(parent)
94
95
96
97
    {}

    void setup(CppClass *cppClass)
    {
98
99
        setText(cppClass->name);
        m_link = cppClass->link;
100
101
    }

102
103
104
105
106
107
    void clear()
    {
        QLabel::clear();
        m_link = CPPEditorWidget::Link();
    }

108
109
110
private:
    void mousePressEvent(QMouseEvent *)
    {
David Schulz's avatar
David Schulz committed
111
        if (!m_link.hasValidTarget())
112
113
            return;

114
115
116
117
        Core::EditorManager::openEditorAt(m_link.targetFileName,
                                          m_link.targetLine,
                                          m_link.targetColumn,
                                          Constants::CPPEDITOR_ID);
118
119
120
121
122
    }

    CPPEditorWidget::Link m_link;
};

123
// CppTypeHierarchyWidget
124
CppTypeHierarchyWidget::CppTypeHierarchyWidget() :
125
126
127
    QWidget(0),
    m_treeView(0),
    m_model(0),
128
129
    m_delegate(0),
    m_noTypeHierarchyAvailableLabel(0)
130
{
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
    m_inspectedClass = new CppClassLabel(this);
    m_inspectedClass->setMargin(5);
    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);
    connect(m_treeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onItemClicked(QModelIndex)));

    m_noTypeHierarchyAvailableLabel = new QLabel(tr("No type hierarchy available"), this);
    m_noTypeHierarchyAvailableLabel->setAlignment(Qt::AlignCenter);
    m_noTypeHierarchyAvailableLabel->setAutoFillBackground(true);
    m_noTypeHierarchyAvailableLabel->setBackgroundRole(QPalette::Base);

149
    m_hierarchyWidget = new QWidget(this);
150
151
152
    QVBoxLayout *layout = new QVBoxLayout;
    layout->setMargin(0);
    layout->setSpacing(0);
153
    layout->addWidget(m_inspectedClass);
154
155
    layout->addWidget(Core::TreeViewFind::createSearchableWrapper(m_treeView));
    m_hierarchyWidget->setLayout(layout);
156

157
158
159
160
161
    m_stackLayout = new QStackedLayout;
    m_stackLayout->addWidget(m_hierarchyWidget);
    m_stackLayout->addWidget(m_noTypeHierarchyAvailableLabel);
    m_stackLayout->setCurrentWidget(m_noTypeHierarchyAvailableLabel);
    setLayout(m_stackLayout);
162
163

    connect(CppEditorPlugin::instance(), SIGNAL(typeHierarchyRequested()), SLOT(perform()));
164
165
166
}

CppTypeHierarchyWidget::~CppTypeHierarchyWidget()
167
{}
168
169
170

void CppTypeHierarchyWidget::perform()
{
171
172
    showNoTypeHierarchyLabel();

173
    CPPEditor *editor = qobject_cast<CPPEditor *>(Core::EditorManager::currentEditor());
174
175
    if (!editor)
        return;
176

177
178
    CPPEditorWidget *widget = qobject_cast<CPPEditorWidget *>(editor->widget());
    if (!widget)
179
180
        return;

181
    clearTypeHierarchy();
182

183
    CppElementEvaluator evaluator(widget);
184
    evaluator.setLookupBaseClasses(true);
185
    evaluator.setLookupDerivedClasses(true);
186
187
188
    evaluator.execute();
    if (evaluator.identifiedCppElement()) {
        const QSharedPointer<CppElement> &cppElement = evaluator.cppElement();
189
        CppElement *element = cppElement.data();
190
        if (CppClass *cppClass = dynamic_cast<CppClass *>(element)) {
191
            m_inspectedClass->setup(cppClass);
192
193
            QStandardItem *bases = new QStandardItem(tr("Bases"));
            m_model->invisibleRootItem()->appendRow(bases);
194
            buildHierarchy(*cppClass, bases, true, &CppClass::bases);
195
196
            QStandardItem *derived = new QStandardItem(tr("Derived"));
            m_model->invisibleRootItem()->appendRow(derived);
197
            buildHierarchy(*cppClass, derived, true, &CppClass::derived);
198
            m_treeView->expandAll();
199
200

            showTypeHierarchy();
201
        }
202
203
204
    }
}

205
206
void CppTypeHierarchyWidget::buildHierarchy(const CppClass &cppClass, QStandardItem *parent,
                                            bool isRoot, const HierarchyMember member)
207
{
208
209
210
211
    if (!isRoot) {
        QStandardItem *item = itemForClass(cppClass);
        parent->appendRow(item);
        parent = item;
212
    }
213
214
    foreach (const CppClass &klass, sortClasses(cppClass.*member))
        buildHierarchy(klass, parent, false, member);
215
216
}

217
218
void CppTypeHierarchyWidget::showNoTypeHierarchyLabel()
{
219
    m_stackLayout->setCurrentWidget(m_noTypeHierarchyAvailableLabel);
220
221
222
223
}

void CppTypeHierarchyWidget::showTypeHierarchy()
{
224
    m_stackLayout->setCurrentWidget(m_hierarchyWidget);
225
226
227
228
229
230
231
232
}

void CppTypeHierarchyWidget::clearTypeHierarchy()
{
    m_inspectedClass->clear();
    m_model->clear();
}

233
234
void CppTypeHierarchyWidget::onItemClicked(const QModelIndex &index)
{
235
236
    const TextEditor::BaseTextEditorWidget::Link link
            = index.data(LinkRole).value<TextEditor::BaseTextEditorWidget::Link>();
David Schulz's avatar
David Schulz committed
237
    if (link.hasValidTarget())
238
239
240
241
        Core::EditorManager::openEditorAt(link.targetFileName,
                                          link.targetLine,
                                          link.targetColumn,
                                          Constants::CPPEDITOR_ID);
242
243
244
245
246
}

// CppTypeHierarchyFactory
CppTypeHierarchyFactory::CppTypeHierarchyFactory()
{
247
248
249
    setDisplayName(tr("Type Hierarchy"));
    setPriority(700);
    setId(Constants::TYPE_HIERARCHY_ID);
250
251
252
253
}

Core::NavigationView CppTypeHierarchyFactory::createWidget()
{
254
255
    auto w = new CppTypeHierarchyWidget;
    w->perform();
256
    return Core::NavigationView(w);
257
}
258
259
260
261

} // namespace Internal
} // namespace CppEditor