1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "cppcodemodelinspectordialog.h"
27 #include "ui_cppcodemodelinspectordialog.h"
28 #include "cppeditorwidget.h"
29 #include "cppeditordocument.h"
30 
31 #include <coreplugin/editormanager/editormanager.h>
32 #include <coreplugin/icore.h>
33 #include <cpptools/baseeditordocumentprocessor.h>
34 #include <cpptools/cppcodemodelinspectordumper.h>
35 #include <cpptools/cppmodelmanager.h>
36 #include <cpptools/cpptoolsbridge.h>
37 #include <cpptools/cppworkingcopy.h>
38 #include <projectexplorer/projectmacro.h>
39 #include <projectexplorer/project.h>
40 
41 #include <cplusplus/CppDocument.h>
42 #include <cplusplus/Overview.h>
43 #include <cplusplus/Token.h>
44 #include <utils/qtcassert.h>
45 #include <utils/fancylineedit.h>
46 
47 #include <QAbstractTableModel>
48 #include <QLabel>
49 #include <QLineEdit>
50 #include <QPushButton>
51 #include <QSortFilterProxyModel>
52 
53 #include <algorithm>
54 #include <numeric>
55 
56 using namespace CPlusPlus;
57 using namespace CppTools;
58 namespace CMI = CppCodeModelInspector;
59 
60 namespace {
61 
resizeColumns(QTreeView * view)62 template <class T> void resizeColumns(QTreeView *view)
63 {
64     for (int column = 0; column < T::ColumnCount - 1; ++column)
65         view->resizeColumnToContents(column);
66 }
67 
currentEditor()68 TextEditor::BaseTextEditor *currentEditor()
69 {
70     return qobject_cast<TextEditor::BaseTextEditor*>(Core::EditorManager::currentEditor());
71 }
72 
fileInCurrentEditor()73 QString fileInCurrentEditor()
74 {
75     if (TextEditor::BaseTextEditor *editor = currentEditor())
76         return editor->document()->filePath().toString();
77     return QString();
78 }
79 
sizePolicyWithStretchFactor(int stretchFactor)80 QSizePolicy sizePolicyWithStretchFactor(int stretchFactor)
81 {
82     QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Expanding);
83     policy.setHorizontalStretch(stretchFactor);
84     return policy;
85 }
86 
87 class DepthFinder : public SymbolVisitor {
88 public:
operator ()(const Document::Ptr & document,Symbol * symbol)89     int operator()(const Document::Ptr &document, Symbol *symbol)
90     {
91         m_symbol = symbol;
92         accept(document->globalNamespace());
93         return m_foundDepth;
94     }
95 
preVisit(Symbol * symbol)96     bool preVisit(Symbol *symbol) override
97     {
98         if (m_stop)
99             return false;
100 
101         if (symbol->asScope()) {
102             ++m_depth;
103             if (symbol == m_symbol) {
104                 m_foundDepth = m_depth;
105                 m_stop = true;
106             }
107             return true;
108         }
109 
110         return false;
111     }
112 
postVisit(Symbol * symbol)113     void postVisit(Symbol *symbol) override
114     {
115         if (symbol->asScope())
116             --m_depth;
117     }
118 
119 private:
120     Symbol *m_symbol = nullptr;
121     int m_depth = -1;
122     int m_foundDepth = -1;
123     bool m_stop = false;
124 };
125 
126 } // anonymous namespace
127 
128 namespace CppEditor {
129 namespace Internal {
130 
131 // --- FilterableView -----------------------------------------------------------------------------
132 
133 class FilterableView : public QWidget
134 {
135     Q_OBJECT
136 public:
137     FilterableView(QWidget *parent);
138 
139     void setModel(QAbstractItemModel *model);
140     QItemSelectionModel *selectionModel() const;
141     void selectIndex(const QModelIndex &index);
142     void resizeColumns(int columnCount);
143     void clearFilter();
144 
145 signals:
146     void filterChanged(const QString &filterText);
147 
148 private:
149     QTreeView *view;
150     Utils::FancyLineEdit *lineEdit;
151 };
152 
FilterableView(QWidget * parent)153 FilterableView::FilterableView(QWidget *parent)
154     : QWidget(parent)
155 {
156     view = new QTreeView(this);
157     view->setAlternatingRowColors(true);
158     view->setTextElideMode(Qt::ElideMiddle);
159     view->setSortingEnabled(true);
160 
161     lineEdit = new Utils::FancyLineEdit(this);
162     lineEdit->setFiltering(true);
163     lineEdit->setPlaceholderText(QLatin1String("File Path"));
164     QObject::connect(lineEdit, &QLineEdit::textChanged, this, &FilterableView::filterChanged);
165 
166     QLabel *label = new QLabel(QLatin1String("&Filter:"), this);
167     label->setBuddy(lineEdit);
168 
169     auto filterBarLayout = new QHBoxLayout();
170     filterBarLayout->addWidget(label);
171     filterBarLayout->addWidget(lineEdit);
172 
173     auto mainLayout = new QVBoxLayout();
174     mainLayout->addWidget(view);
175     mainLayout->addLayout(filterBarLayout);
176 
177     setLayout(mainLayout);
178 }
179 
setModel(QAbstractItemModel * model)180 void FilterableView::setModel(QAbstractItemModel *model)
181 {
182     view->setModel(model);
183 }
184 
selectionModel() const185 QItemSelectionModel *FilterableView::selectionModel() const
186 {
187     return view->selectionModel();
188 }
189 
selectIndex(const QModelIndex & index)190 void FilterableView::selectIndex(const QModelIndex &index)
191 {
192     if (index.isValid())  {
193         view->selectionModel()->setCurrentIndex(index,
194             QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
195     }
196 }
197 
resizeColumns(int columnCount)198 void FilterableView::resizeColumns(int columnCount)
199 {
200     for (int column = 0; column < columnCount - 1; ++column)
201         view->resizeColumnToContents(column);
202 }
203 
clearFilter()204 void FilterableView::clearFilter()
205 {
206     lineEdit->clear();
207 }
208 
209 // --- ProjectFilesModel --------------------------------------------------------------------------
210 
211 class ProjectFilesModel : public QAbstractListModel
212 {
213     Q_OBJECT
214 public:
215     ProjectFilesModel(QObject *parent);
216     void configure(const ProjectFiles &files);
217     void clear();
218 
219     enum Columns { FileKindColumn, FilePathColumn, ColumnCount };
220 
221     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
222     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
223     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
224     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
225 
226 private:
227     ProjectFiles m_files;
228 };
229 
ProjectFilesModel(QObject * parent)230 ProjectFilesModel::ProjectFilesModel(QObject *parent) : QAbstractListModel(parent)
231 {
232 }
233 
configure(const ProjectFiles & files)234 void ProjectFilesModel::configure(const ProjectFiles &files)
235 {
236     emit layoutAboutToBeChanged();
237     m_files = files;
238     emit layoutChanged();
239 }
240 
clear()241 void ProjectFilesModel::clear()
242 {
243     emit layoutAboutToBeChanged();
244     m_files.clear();
245     emit layoutChanged();
246 }
247 
rowCount(const QModelIndex &) const248 int ProjectFilesModel::rowCount(const QModelIndex &/*parent*/) const
249 {
250     return m_files.size();
251 }
252 
columnCount(const QModelIndex &) const253 int ProjectFilesModel::columnCount(const QModelIndex &/*parent*/) const
254 {
255     return ProjectFilesModel::ColumnCount;
256 }
257 
data(const QModelIndex & index,int role) const258 QVariant ProjectFilesModel::data(const QModelIndex &index, int role) const
259 {
260     if (role == Qt::DisplayRole) {
261         const int row = index.row();
262         const int column = index.column();
263         if (column == FileKindColumn) {
264             return CMI::Utils::toString(m_files.at(row).kind);
265         } else if (column == FilePathColumn) {
266             return m_files.at(row).path;
267         }
268     } else if (role == Qt::ForegroundRole) {
269         if (!m_files.at(index.row()).active) {
270             return QApplication::palette().color(QPalette::ColorGroup::Disabled,
271                                                  QPalette::ColorRole::Text);
272         }
273     }
274     return QVariant();
275 }
276 
headerData(int section,Qt::Orientation orientation,int role) const277 QVariant ProjectFilesModel::headerData(int section, Qt::Orientation orientation, int role) const
278 {
279     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
280         switch (section) {
281         case FileKindColumn:
282             return QLatin1String("File Kind");
283         case FilePathColumn:
284             return QLatin1String("File Path");
285         default:
286             return QVariant();
287         }
288     }
289     return QVariant();
290 }
291 
292 // --- ProjectHeaderPathModel --------------------------------------------------------------------
293 
294 class ProjectHeaderPathsModel : public QAbstractListModel
295 {
296     Q_OBJECT
297 public:
298     ProjectHeaderPathsModel(QObject *parent);
299     void configure(const ProjectExplorer::HeaderPaths &paths);
300     void clear();
301 
302     enum Columns { TypeColumn, PathColumn, ColumnCount };
303 
304     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
305     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
306     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
307     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
308 
309 private:
310     ProjectExplorer::HeaderPaths m_paths;
311 };
312 
ProjectHeaderPathsModel(QObject * parent)313 ProjectHeaderPathsModel::ProjectHeaderPathsModel(QObject *parent) : QAbstractListModel(parent)
314 {
315 }
316 
configure(const ProjectExplorer::HeaderPaths & paths)317 void ProjectHeaderPathsModel::configure(const ProjectExplorer::HeaderPaths &paths)
318 {
319     emit layoutAboutToBeChanged();
320     m_paths = paths;
321     emit layoutChanged();
322 }
323 
clear()324 void ProjectHeaderPathsModel::clear()
325 {
326     emit layoutAboutToBeChanged();
327     m_paths.clear();
328     emit layoutChanged();
329 }
330 
rowCount(const QModelIndex &) const331 int ProjectHeaderPathsModel::rowCount(const QModelIndex &/*parent*/) const
332 {
333     return m_paths.size();
334 }
335 
columnCount(const QModelIndex &) const336 int ProjectHeaderPathsModel::columnCount(const QModelIndex &/*parent*/) const
337 {
338     return ProjectFilesModel::ColumnCount;
339 }
340 
data(const QModelIndex & index,int role) const341 QVariant ProjectHeaderPathsModel::data(const QModelIndex &index, int role) const
342 {
343     if (role == Qt::DisplayRole) {
344         const int row = index.row();
345         const int column = index.column();
346         if (column == TypeColumn) {
347             return CMI::Utils::toString(m_paths.at(row).type);
348         } else if (column == PathColumn) {
349             return m_paths.at(row).path;
350         }
351     }
352     return QVariant();
353 }
354 
headerData(int section,Qt::Orientation orientation,int role) const355 QVariant ProjectHeaderPathsModel::headerData(int section, Qt::Orientation orientation, int role) const
356 {
357     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
358         switch (section) {
359         case TypeColumn:
360             return QLatin1String("Type");
361         case PathColumn:
362             return QLatin1String("Path");
363         default:
364             return QVariant();
365         }
366     }
367     return QVariant();
368 }
369 
370 // --- KeyValueModel ------------------------------------------------------------------------------
371 
372 class KeyValueModel : public QAbstractListModel
373 {
374     Q_OBJECT
375 public:
376     using Table = QList<QPair<QString, QString>>;
377 
378     KeyValueModel(QObject *parent);
379     void configure(const Table &table);
380     void clear();
381 
382     enum Columns { KeyColumn, ValueColumn, ColumnCount };
383 
384     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
385     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
386     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
387     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
388 
389 private:
390     Table m_table;
391 };
392 
KeyValueModel(QObject * parent)393 KeyValueModel::KeyValueModel(QObject *parent) : QAbstractListModel(parent)
394 {
395 }
396 
configure(const Table & table)397 void KeyValueModel::configure(const Table &table)
398 {
399     emit layoutAboutToBeChanged();
400     m_table = table;
401     emit layoutChanged();
402 }
403 
clear()404 void KeyValueModel::clear()
405 {
406     emit layoutAboutToBeChanged();
407     m_table.clear();
408     emit layoutChanged();
409 }
410 
rowCount(const QModelIndex &) const411 int KeyValueModel::rowCount(const QModelIndex &/*parent*/) const
412 {
413     return m_table.size();
414 }
415 
columnCount(const QModelIndex &) const416 int KeyValueModel::columnCount(const QModelIndex &/*parent*/) const
417 {
418     return KeyValueModel::ColumnCount;
419 }
420 
data(const QModelIndex & index,int role) const421 QVariant KeyValueModel::data(const QModelIndex &index, int role) const
422 {
423     if (role == Qt::DisplayRole) {
424         const int row = index.row();
425         const int column = index.column();
426         if (column == KeyColumn) {
427             return m_table.at(row).first;
428         } else if (column == ValueColumn) {
429             return m_table.at(row).second;
430         }
431     }
432     return QVariant();
433 }
434 
headerData(int section,Qt::Orientation orientation,int role) const435 QVariant KeyValueModel::headerData(int section, Qt::Orientation orientation, int role) const
436 {
437     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
438         switch (section) {
439         case KeyColumn:
440             return QLatin1String("Key");
441         case ValueColumn:
442             return QLatin1String("Value");
443         default:
444             return QVariant();
445         }
446     }
447     return QVariant();
448 }
449 
450 // --- SnapshotModel ------------------------------------------------------------------------------
451 
452 class SnapshotModel : public QAbstractListModel
453 {
454     Q_OBJECT
455 public:
456     SnapshotModel(QObject *parent);
457     void configure(const Snapshot &snapshot);
458     void setGlobalSnapshot(const Snapshot &snapshot);
459 
460     QModelIndex indexForDocument(const QString &filePath);
461 
462     enum Columns { SymbolCountColumn, SharedColumn, FilePathColumn, ColumnCount };
463 
464     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
465     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
466     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
467     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
468 
469 private:
470     QList<Document::Ptr> m_documents;
471     Snapshot m_globalSnapshot;
472 };
473 
SnapshotModel(QObject * parent)474 SnapshotModel::SnapshotModel(QObject *parent) : QAbstractListModel(parent)
475 {
476 }
477 
configure(const Snapshot & snapshot)478 void SnapshotModel::configure(const Snapshot &snapshot)
479 {
480     emit layoutAboutToBeChanged();
481     m_documents = CMI::Utils::snapshotToList(snapshot);
482     emit layoutChanged();
483 }
484 
setGlobalSnapshot(const Snapshot & snapshot)485 void SnapshotModel::setGlobalSnapshot(const Snapshot &snapshot)
486 {
487     m_globalSnapshot = snapshot;
488 }
489 
indexForDocument(const QString & filePath)490 QModelIndex SnapshotModel::indexForDocument(const QString &filePath)
491 {
492     for (int i = 0, total = m_documents.size(); i < total; ++i) {
493         const Document::Ptr document = m_documents.at(i);
494         if (document->fileName() == filePath)
495             return index(i, FilePathColumn);
496     }
497     return {};
498 }
499 
rowCount(const QModelIndex &) const500 int SnapshotModel::rowCount(const QModelIndex &/*parent*/) const
501 {
502     return m_documents.size();
503 }
504 
columnCount(const QModelIndex &) const505 int SnapshotModel::columnCount(const QModelIndex &/*parent*/) const
506 {
507     return SnapshotModel::ColumnCount;
508 }
509 
data(const QModelIndex & index,int role) const510 QVariant SnapshotModel::data(const QModelIndex &index, int role) const
511 {
512     if (role == Qt::DisplayRole) {
513         const int column = index.column();
514         Document::Ptr document = m_documents.at(index.row());
515         if (column == SymbolCountColumn) {
516             return document->control()->symbolCount();
517         } else if (column == SharedColumn) {
518             Document::Ptr globalDocument = m_globalSnapshot.document(document->fileName());
519             const bool isShared
520                 = globalDocument && globalDocument->fingerprint() == document->fingerprint();
521             return CMI::Utils::toString(isShared);
522         } else if (column == FilePathColumn) {
523             return QDir::toNativeSeparators(document->fileName());
524         }
525     }
526     return QVariant();
527 }
528 
headerData(int section,Qt::Orientation orientation,int role) const529 QVariant SnapshotModel::headerData(int section, Qt::Orientation orientation, int role) const
530 {
531     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
532         switch (section) {
533         case SymbolCountColumn:
534             return QLatin1String("Symbols");
535         case SharedColumn:
536             return QLatin1String("Shared");
537         case FilePathColumn:
538             return QLatin1String("File Path");
539         default:
540             return QVariant();
541         }
542     }
543     return QVariant();
544 }
545 
546 // --- IncludesModel ------------------------------------------------------------------------------
547 
includesSorter(const Document::Include & i1,const Document::Include & i2)548 static bool includesSorter(const Document::Include &i1,
549                            const Document::Include &i2)
550 {
551     return i1.line() < i2.line();
552 }
553 
554 class IncludesModel : public QAbstractListModel
555 {
556     Q_OBJECT
557 public:
558     IncludesModel(QObject *parent);
559     void configure(const QList<Document::Include> &includes);
560     void clear();
561 
562     enum Columns { ResolvedOrNotColumn, LineNumberColumn, FilePathsColumn, ColumnCount };
563 
564     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
565     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
566     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
567     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
568 
569 private:
570     QList<Document::Include> m_includes;
571 };
572 
IncludesModel(QObject * parent)573 IncludesModel::IncludesModel(QObject *parent) : QAbstractListModel(parent)
574 {
575 }
576 
configure(const QList<Document::Include> & includes)577 void IncludesModel::configure(const QList<Document::Include> &includes)
578 {
579     emit layoutAboutToBeChanged();
580     m_includes = includes;
581     std::stable_sort(m_includes.begin(), m_includes.end(), includesSorter);
582     emit layoutChanged();
583 }
584 
clear()585 void IncludesModel::clear()
586 {
587     emit layoutAboutToBeChanged();
588     m_includes.clear();
589     emit layoutChanged();
590 }
591 
rowCount(const QModelIndex &) const592 int IncludesModel::rowCount(const QModelIndex &/*parent*/) const
593 {
594     return m_includes.size();
595 }
596 
columnCount(const QModelIndex &) const597 int IncludesModel::columnCount(const QModelIndex &/*parent*/) const
598 {
599     return IncludesModel::ColumnCount;
600 }
601 
data(const QModelIndex & index,int role) const602 QVariant IncludesModel::data(const QModelIndex &index, int role) const
603 {
604     if (role != Qt::DisplayRole && role != Qt::ForegroundRole)
605         return QVariant();
606 
607     static const QBrush greenBrush(QColor(0, 139, 69));
608     static const QBrush redBrush(QColor(205, 38, 38));
609 
610     const Document::Include include = m_includes.at(index.row());
611     const QString resolvedFileName = QDir::toNativeSeparators(include.resolvedFileName());
612     const bool isResolved = !resolvedFileName.isEmpty();
613 
614     if (role == Qt::DisplayRole) {
615         const int column = index.column();
616         if (column == ResolvedOrNotColumn) {
617             return CMI::Utils::toString(isResolved);
618         } else if (column == LineNumberColumn) {
619             return include.line();
620         } else if (column == FilePathsColumn) {
621             return QVariant(CMI::Utils::unresolvedFileNameWithDelimiters(include)
622                             + QLatin1String(" --> ") + resolvedFileName);
623         }
624     } else if (role == Qt::ForegroundRole) {
625         return isResolved ? greenBrush : redBrush;
626     }
627 
628     return QVariant();
629 }
630 
headerData(int section,Qt::Orientation orientation,int role) const631 QVariant IncludesModel::headerData(int section, Qt::Orientation orientation, int role) const
632 {
633     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
634         switch (section) {
635         case ResolvedOrNotColumn:
636             return QLatin1String("Resolved");
637         case LineNumberColumn:
638             return QLatin1String("Line");
639         case FilePathsColumn:
640             return QLatin1String("File Paths");
641         default:
642             return QVariant();
643         }
644     }
645     return QVariant();
646 }
647 
648 // --- DiagnosticMessagesModel --------------------------------------------------------------------
649 
diagnosticMessagesModelSorter(const Document::DiagnosticMessage & m1,const Document::DiagnosticMessage & m2)650 static bool diagnosticMessagesModelSorter(const Document::DiagnosticMessage &m1,
651                                           const Document::DiagnosticMessage &m2)
652 {
653     return m1.line() < m2.line();
654 }
655 
656 class DiagnosticMessagesModel : public QAbstractListModel
657 {
658     Q_OBJECT
659 public:
660     DiagnosticMessagesModel(QObject *parent);
661     void configure(const QList<Document::DiagnosticMessage> &messages);
662     void clear();
663 
664     enum Columns { LevelColumn, LineColumnNumberColumn, MessageColumn, ColumnCount };
665 
666     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
667     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
668     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
669     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
670 
671 private:
672     QList<Document::DiagnosticMessage> m_messages;
673 };
674 
DiagnosticMessagesModel(QObject * parent)675 DiagnosticMessagesModel::DiagnosticMessagesModel(QObject *parent) : QAbstractListModel(parent)
676 {
677 }
678 
configure(const QList<Document::DiagnosticMessage> & messages)679 void DiagnosticMessagesModel::configure(
680         const QList<Document::DiagnosticMessage> &messages)
681 {
682     emit layoutAboutToBeChanged();
683     m_messages = messages;
684     std::stable_sort(m_messages.begin(), m_messages.end(), diagnosticMessagesModelSorter);
685     emit layoutChanged();
686 }
687 
clear()688 void DiagnosticMessagesModel::clear()
689 {
690     emit layoutAboutToBeChanged();
691     m_messages.clear();
692     emit layoutChanged();
693 }
694 
rowCount(const QModelIndex &) const695 int DiagnosticMessagesModel::rowCount(const QModelIndex &/*parent*/) const
696 {
697     return m_messages.size();
698 }
699 
columnCount(const QModelIndex &) const700 int DiagnosticMessagesModel::columnCount(const QModelIndex &/*parent*/) const
701 {
702     return DiagnosticMessagesModel::ColumnCount;
703 }
704 
data(const QModelIndex & index,int role) const705 QVariant DiagnosticMessagesModel::data(const QModelIndex &index, int role) const
706 {
707     if (role != Qt::DisplayRole && role != Qt::ForegroundRole)
708         return QVariant();
709 
710     static const QBrush yellowOrangeBrush(QColor(237, 145, 33));
711     static const QBrush redBrush(QColor(205, 38, 38));
712     static const QBrush darkRedBrushQColor(QColor(139, 0, 0));
713 
714     const Document::DiagnosticMessage message = m_messages.at(index.row());
715     const auto level = static_cast<Document::DiagnosticMessage::Level>(message.level());
716 
717     if (role == Qt::DisplayRole) {
718         const int column = index.column();
719         if (column == LevelColumn) {
720             return CMI::Utils::toString(level);
721         } else if (column == LineColumnNumberColumn) {
722             return QVariant(QString::number(message.line()) + QLatin1Char(':')
723                             + QString::number(message.column()));
724         } else if (column == MessageColumn) {
725             return message.text();
726         }
727     } else if (role == Qt::ForegroundRole) {
728         switch (level) {
729         case Document::DiagnosticMessage::Warning:
730             return yellowOrangeBrush;
731         case Document::DiagnosticMessage::Error:
732             return redBrush;
733         case Document::DiagnosticMessage::Fatal:
734             return darkRedBrushQColor;
735         default:
736             return QVariant();
737         }
738     }
739 
740     return QVariant();
741 }
742 
headerData(int section,Qt::Orientation orientation,int role) const743 QVariant DiagnosticMessagesModel::headerData(int section, Qt::Orientation orientation, int role)
744     const
745 {
746     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
747         switch (section) {
748         case LevelColumn:
749             return QLatin1String("Level");
750         case LineColumnNumberColumn:
751             return QLatin1String("Line:Column");
752         case MessageColumn:
753             return QLatin1String("Message");
754         default:
755             return QVariant();
756         }
757     }
758     return QVariant();
759 }
760 
761 // --- MacrosModel --------------------------------------------------------------------------------
762 
763 class MacrosModel : public QAbstractListModel
764 {
765     Q_OBJECT
766 public:
767     MacrosModel(QObject *parent);
768     void configure(const QList<CPlusPlus::Macro> &macros);
769     void clear();
770 
771     enum Columns { LineNumberColumn, MacroColumn, ColumnCount };
772 
773     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
774     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
775     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
776     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
777 
778 private:
779     QList<CPlusPlus::Macro> m_macros;
780 };
781 
MacrosModel(QObject * parent)782 MacrosModel::MacrosModel(QObject *parent) : QAbstractListModel(parent)
783 {
784 }
785 
configure(const QList<CPlusPlus::Macro> & macros)786 void MacrosModel::configure(const QList<CPlusPlus::Macro> &macros)
787 {
788     emit layoutAboutToBeChanged();
789     m_macros = macros;
790     emit layoutChanged();
791 }
792 
clear()793 void MacrosModel::clear()
794 {
795     emit layoutAboutToBeChanged();
796     m_macros.clear();
797     emit layoutChanged();
798 }
799 
rowCount(const QModelIndex &) const800 int MacrosModel::rowCount(const QModelIndex &/*parent*/) const
801 {
802     return m_macros.size();
803 }
804 
columnCount(const QModelIndex &) const805 int MacrosModel::columnCount(const QModelIndex &/*parent*/) const
806 {
807     return MacrosModel::ColumnCount;
808 }
809 
data(const QModelIndex & index,int role) const810 QVariant MacrosModel::data(const QModelIndex &index, int role) const
811 {
812     const int column = index.column();
813     if (role == Qt::DisplayRole || (role == Qt::ToolTipRole && column == MacroColumn)) {
814         const CPlusPlus::Macro macro = m_macros.at(index.row());
815         if (column == LineNumberColumn)
816             return macro.line();
817         else if (column == MacroColumn)
818             return macro.toString();
819     } else if (role == Qt::TextAlignmentRole) {
820         return QVariant::fromValue(Qt::AlignTop | Qt::AlignLeft);
821     }
822     return QVariant();
823 }
824 
headerData(int section,Qt::Orientation orientation,int role) const825 QVariant MacrosModel::headerData(int section, Qt::Orientation orientation, int role) const
826 {
827     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
828         switch (section) {
829         case LineNumberColumn:
830             return QLatin1String("Line");
831         case MacroColumn:
832             return QLatin1String("Macro");
833         default:
834             return QVariant();
835         }
836     }
837     return QVariant();
838 }
839 
840 // --- SymbolsModel -------------------------------------------------------------------------------
841 
842 class SymbolsModel : public QAbstractItemModel
843 {
844     Q_OBJECT
845 public:
846     SymbolsModel(QObject *parent);
847     void configure(const Document::Ptr &document);
848     void clear();
849 
850     enum Columns { SymbolColumn, LineNumberColumn, ColumnCount };
851 
852     QModelIndex index(int row, int column, const QModelIndex &parent) const override;
853     QModelIndex parent(const QModelIndex &child) const override;
854     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
855     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
856     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
857     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
858 
859 private:
860     Document::Ptr m_document;
861 };
862 
SymbolsModel(QObject * parent)863 SymbolsModel::SymbolsModel(QObject *parent) : QAbstractItemModel(parent)
864 {
865 }
866 
configure(const Document::Ptr & document)867 void SymbolsModel::configure(const Document::Ptr &document)
868 {
869     QTC_CHECK(document);
870     emit layoutAboutToBeChanged();
871     m_document = document;
872     emit layoutChanged();
873 }
874 
clear()875 void SymbolsModel::clear()
876 {
877     emit layoutAboutToBeChanged();
878     m_document.clear();
879     emit layoutChanged();
880 }
881 
indexToSymbol(const QModelIndex & index)882 static Symbol *indexToSymbol(const QModelIndex &index)
883 {
884     return static_cast<Symbol*>(index.internalPointer());
885 }
886 
indexToScope(const QModelIndex & index)887 static Scope *indexToScope(const QModelIndex &index)
888 {
889     if (Symbol *symbol = indexToSymbol(index))
890         return symbol->asScope();
891     return nullptr;
892 }
893 
index(int row,int column,const QModelIndex & parent) const894 QModelIndex SymbolsModel::index(int row, int column, const QModelIndex &parent) const
895 {
896     Scope *scope = nullptr;
897     if (parent.isValid())
898         scope = indexToScope(parent);
899     else if (m_document)
900         scope = m_document->globalNamespace();
901 
902     if (scope) {
903         if (row < scope->memberCount())
904             return createIndex(row, column, scope->memberAt(row));
905     }
906 
907     return {};
908 }
909 
parent(const QModelIndex & child) const910 QModelIndex SymbolsModel::parent(const QModelIndex &child) const
911 {
912     if (!child.isValid())
913         return {};
914 
915     if (Symbol *symbol = indexToSymbol(child)) {
916         if (Scope *scope = symbol->enclosingScope()) {
917             const int row = DepthFinder()(m_document, scope);
918             return createIndex(row, 0, scope);
919         }
920     }
921 
922     return {};
923 }
924 
rowCount(const QModelIndex & parent) const925 int SymbolsModel::rowCount(const QModelIndex &parent) const
926 {
927     if (parent.isValid()) {
928         if (Scope *scope = indexToScope(parent))
929             return scope->memberCount();
930     } else {
931         if (m_document)
932             return m_document->globalNamespace()->memberCount();
933     }
934     return 0;
935 }
936 
columnCount(const QModelIndex &) const937 int SymbolsModel::columnCount(const QModelIndex &) const
938 {
939     return ColumnCount;
940 }
941 
data(const QModelIndex & index,int role) const942 QVariant SymbolsModel::data(const QModelIndex &index, int role) const
943 {
944     const int column = index.column();
945     if (role == Qt::DisplayRole) {
946         Symbol *symbol = indexToSymbol(index);
947         if (!symbol)
948             return QVariant();
949         if (column == LineNumberColumn) {
950             return symbol->line();
951         } else if (column == SymbolColumn) {
952             QString name = Overview().prettyName(symbol->name());
953             if (name.isEmpty())
954                 name = QLatin1String(symbol->isBlock() ? "<block>" : "<no name>");
955             return name;
956         }
957     }
958     return QVariant();
959 }
960 
headerData(int section,Qt::Orientation orientation,int role) const961 QVariant SymbolsModel::headerData(int section, Qt::Orientation orientation, int role) const
962 {
963     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
964         switch (section) {
965         case SymbolColumn:
966             return QLatin1String("Symbol");
967         case LineNumberColumn:
968             return QLatin1String("Line");
969         default:
970             return QVariant();
971         }
972     }
973     return QVariant();
974 }
975 
976 // --- TokensModel --------------------------------------------------------------------------------
977 
978 class TokensModel : public QAbstractListModel
979 {
980     Q_OBJECT
981 public:
982     TokensModel(QObject *parent);
983     void configure(TranslationUnit *translationUnit);
984     void clear();
985 
986     enum Columns { SpelledColumn, KindColumn, IndexColumn, OffsetColumn, LineColumnNumberColumn,
987                    BytesAndCodePointsColumn, GeneratedColumn, ExpandedColumn, WhiteSpaceColumn,
988                    NewlineColumn, ColumnCount };
989 
990     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
991     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
992     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
993     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
994 
995 private:
996     struct TokenInfo {
997         Token token;
998         int line;
999         int column;
1000     };
1001     QList<TokenInfo> m_tokenInfos;
1002 };
1003 
TokensModel(QObject * parent)1004 TokensModel::TokensModel(QObject *parent) : QAbstractListModel(parent)
1005 {
1006 }
1007 
configure(TranslationUnit * translationUnit)1008 void TokensModel::configure(TranslationUnit *translationUnit)
1009 {
1010     if (!translationUnit)
1011         return;
1012 
1013     emit layoutAboutToBeChanged();
1014     m_tokenInfos.clear();
1015     for (int i = 0, total = translationUnit->tokenCount(); i < total; ++i) {
1016         TokenInfo info;
1017         info.token = translationUnit->tokenAt(i);
1018         translationUnit->getPosition(info.token.utf16charsBegin(), &info.line, &info.column);
1019         m_tokenInfos.append(info);
1020     }
1021     emit layoutChanged();
1022 }
1023 
clear()1024 void TokensModel::clear()
1025 {
1026     emit layoutAboutToBeChanged();
1027     m_tokenInfos.clear();
1028     emit layoutChanged();
1029 }
1030 
rowCount(const QModelIndex &) const1031 int TokensModel::rowCount(const QModelIndex &/*parent*/) const
1032 {
1033     return m_tokenInfos.size();
1034 }
1035 
columnCount(const QModelIndex &) const1036 int TokensModel::columnCount(const QModelIndex &/*parent*/) const
1037 {
1038     return TokensModel::ColumnCount;
1039 }
1040 
data(const QModelIndex & index,int role) const1041 QVariant TokensModel::data(const QModelIndex &index, int role) const
1042 {
1043     const int column = index.column();
1044     if (role == Qt::DisplayRole) {
1045         const TokenInfo info = m_tokenInfos.at(index.row());
1046         const Token token = info.token;
1047         if (column == SpelledColumn)
1048             return QString::fromUtf8(token.spell());
1049         else if (column == KindColumn)
1050             return CMI::Utils::toString(static_cast<Kind>(token.kind()));
1051         else if (column == IndexColumn)
1052             return index.row();
1053         else if (column == OffsetColumn)
1054             return token.bytesBegin();
1055         else if (column == LineColumnNumberColumn)
1056             return QString::fromLatin1("%1:%2").arg(CMI::Utils::toString(info.line),
1057                                                     CMI::Utils::toString(info.column));
1058         else if (column == BytesAndCodePointsColumn)
1059             return QString::fromLatin1("%1/%2").arg(CMI::Utils::toString(token.bytes()),
1060                                                     CMI::Utils::toString(token.utf16chars()));
1061         else if (column == GeneratedColumn)
1062             return CMI::Utils::toString(token.generated());
1063         else if (column == ExpandedColumn)
1064             return CMI::Utils::toString(token.expanded());
1065         else if (column == WhiteSpaceColumn)
1066             return CMI::Utils::toString(token.whitespace());
1067         else if (column == NewlineColumn)
1068             return CMI::Utils::toString(token.newline());
1069     } else if (role == Qt::TextAlignmentRole) {
1070         return QVariant::fromValue(Qt::AlignTop | Qt::AlignLeft);
1071     }
1072     return QVariant();
1073 }
1074 
headerData(int section,Qt::Orientation orientation,int role) const1075 QVariant TokensModel::headerData(int section, Qt::Orientation orientation, int role) const
1076 {
1077     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
1078         switch (section) {
1079         case SpelledColumn:
1080             return QLatin1String("Spelled");
1081         case KindColumn:
1082             return QLatin1String("Kind");
1083         case IndexColumn:
1084             return QLatin1String("Index");
1085         case OffsetColumn:
1086             return QLatin1String("Offset");
1087         case LineColumnNumberColumn:
1088             return QLatin1String("Line:Column");
1089         case BytesAndCodePointsColumn:
1090             return QLatin1String("Bytes/Codepoints");
1091         case GeneratedColumn:
1092             return QLatin1String("Generated");
1093         case ExpandedColumn:
1094             return QLatin1String("Expanded");
1095         case WhiteSpaceColumn:
1096             return QLatin1String("Whitespace");
1097         case NewlineColumn:
1098             return QLatin1String("Newline");
1099         default:
1100             return QVariant();
1101         }
1102     }
1103     return QVariant();
1104 }
1105 
1106 // --- ProjectPartsModel --------------------------------------------------------------------------
1107 
1108 class ProjectPartsModel : public QAbstractListModel
1109 {
1110     Q_OBJECT
1111 public:
1112     ProjectPartsModel(QObject *parent);
1113 
1114     void configure(const QList<ProjectInfo> &projectInfos,
1115                    const ProjectPart::Ptr &currentEditorsProjectPart);
1116 
1117     QModelIndex indexForCurrentEditorsProjectPart() const;
1118     ProjectPart::Ptr projectPartForProjectId(const QString &projectPartId) const;
1119 
1120     enum Columns { PartNameColumn, PartFilePathColumn, ColumnCount };
1121 
1122     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
1123     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
1124     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
1125     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
1126 
1127 private:
1128     QList<ProjectPart::Ptr> m_projectPartsList;
1129     int m_currentEditorsProjectPartIndex;
1130 };
1131 
ProjectPartsModel(QObject * parent)1132 ProjectPartsModel::ProjectPartsModel(QObject *parent)
1133     : QAbstractListModel(parent), m_currentEditorsProjectPartIndex(-1)
1134 {
1135 }
1136 
configure(const QList<ProjectInfo> & projectInfos,const ProjectPart::Ptr & currentEditorsProjectPart)1137 void ProjectPartsModel::configure(const QList<ProjectInfo> &projectInfos,
1138                                   const ProjectPart::Ptr &currentEditorsProjectPart)
1139 {
1140     emit layoutAboutToBeChanged();
1141     m_projectPartsList.clear();
1142     foreach (const ProjectInfo &info, projectInfos) {
1143         foreach (const ProjectPart::Ptr &projectPart, info.projectParts()) {
1144             if (!m_projectPartsList.contains(projectPart)) {
1145                 m_projectPartsList << projectPart;
1146                 if (projectPart == currentEditorsProjectPart)
1147                     m_currentEditorsProjectPartIndex = m_projectPartsList.size() - 1;
1148             }
1149         }
1150     }
1151     emit layoutChanged();
1152 }
1153 
indexForCurrentEditorsProjectPart() const1154 QModelIndex ProjectPartsModel::indexForCurrentEditorsProjectPart() const
1155 {
1156     if (m_currentEditorsProjectPartIndex == -1)
1157         return {};
1158     return createIndex(m_currentEditorsProjectPartIndex, PartFilePathColumn);
1159 }
1160 
projectPartForProjectId(const QString & projectPartId) const1161 ProjectPart::Ptr ProjectPartsModel::projectPartForProjectId(const QString &projectPartId) const
1162 {
1163     foreach (const ProjectPart::Ptr &part, m_projectPartsList) {
1164         if (part->id() == projectPartId)
1165             return part;
1166     }
1167     return ProjectPart::Ptr();
1168 }
1169 
rowCount(const QModelIndex &) const1170 int ProjectPartsModel::rowCount(const QModelIndex &/*parent*/) const
1171 {
1172     return m_projectPartsList.size();
1173 }
1174 
columnCount(const QModelIndex &) const1175 int ProjectPartsModel::columnCount(const QModelIndex &/*parent*/) const
1176 {
1177     return ProjectPartsModel::ColumnCount;
1178 }
1179 
data(const QModelIndex & index,int role) const1180 QVariant ProjectPartsModel::data(const QModelIndex &index, int role) const
1181 {
1182     const int row = index.row();
1183     if (role == Qt::DisplayRole) {
1184         const int column = index.column();
1185         if (column == PartNameColumn)
1186             return m_projectPartsList.at(row)->displayName;
1187         else if (column == PartFilePathColumn)
1188             return QDir::toNativeSeparators(m_projectPartsList.at(row)->projectFile);
1189     } else if (role == Qt::ForegroundRole) {
1190         if (!m_projectPartsList.at(row)->selectedForBuilding) {
1191             return QApplication::palette().color(QPalette::ColorGroup::Disabled,
1192                                                  QPalette::ColorRole::Text);
1193         }
1194     } else if (role == Qt::UserRole) {
1195         return m_projectPartsList.at(row)->id();
1196     }
1197     return QVariant();
1198 }
1199 
headerData(int section,Qt::Orientation orientation,int role) const1200 QVariant ProjectPartsModel::headerData(int section, Qt::Orientation orientation, int role) const
1201 {
1202     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
1203         switch (section) {
1204         case PartNameColumn:
1205             return QLatin1String("Name");
1206         case PartFilePathColumn:
1207             return QLatin1String("Project File Path");
1208         default:
1209             return QVariant();
1210         }
1211     }
1212     return QVariant();
1213 }
1214 
1215 // --- WorkingCopyModel ---------------------------------------------------------------------------
1216 
1217 class WorkingCopyModel : public QAbstractListModel
1218 {
1219     Q_OBJECT
1220 public:
1221     WorkingCopyModel(QObject *parent);
1222 
1223     void configure(const WorkingCopy &workingCopy);
1224     QModelIndex indexForFile(const QString &filePath);
1225 
1226     enum Columns { RevisionColumn, FilePathColumn, ColumnCount };
1227 
1228     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
1229     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
1230     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
1231     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
1232 
1233 private:
1234     struct WorkingCopyEntry {
WorkingCopyEntryCppEditor::Internal::WorkingCopyModel::WorkingCopyEntry1235         WorkingCopyEntry(const QString &filePath, const QByteArray &source, unsigned revision)
1236             : filePath(filePath), source(source), revision(revision)
1237         {}
1238 
1239         QString filePath;
1240         QByteArray source;
1241         unsigned revision;
1242     };
1243 
1244     QList<WorkingCopyEntry> m_workingCopyList;
1245 };
1246 
WorkingCopyModel(QObject * parent)1247 WorkingCopyModel::WorkingCopyModel(QObject *parent) : QAbstractListModel(parent)
1248 {
1249 }
1250 
configure(const WorkingCopy & workingCopy)1251 void WorkingCopyModel::configure(const WorkingCopy &workingCopy)
1252 {
1253     emit layoutAboutToBeChanged();
1254     m_workingCopyList.clear();
1255     const WorkingCopy::Table &elements = workingCopy.elements();
1256     for (auto it = elements.cbegin(), end = elements.cend(); it != end; ++it) {
1257         m_workingCopyList << WorkingCopyEntry(it.key().toString(), it.value().first,
1258                                               it.value().second);
1259     }
1260     emit layoutChanged();
1261 }
1262 
indexForFile(const QString & filePath)1263 QModelIndex WorkingCopyModel::indexForFile(const QString &filePath)
1264 {
1265     for (int i = 0, total = m_workingCopyList.size(); i < total; ++i) {
1266         const WorkingCopyEntry entry = m_workingCopyList.at(i);
1267         if (entry.filePath == filePath)
1268             return index(i, FilePathColumn);
1269     }
1270     return {};
1271 }
1272 
rowCount(const QModelIndex &) const1273 int WorkingCopyModel::rowCount(const QModelIndex &/*parent*/) const
1274 {
1275     return m_workingCopyList.size();
1276 }
1277 
columnCount(const QModelIndex &) const1278 int WorkingCopyModel::columnCount(const QModelIndex &/*parent*/) const
1279 {
1280     return WorkingCopyModel::ColumnCount;
1281 }
1282 
data(const QModelIndex & index,int role) const1283 QVariant WorkingCopyModel::data(const QModelIndex &index, int role) const
1284 {
1285     const int row = index.row();
1286     if (role == Qt::DisplayRole) {
1287         const int column = index.column();
1288         if (column == RevisionColumn)
1289             return m_workingCopyList.at(row).revision;
1290         else if (column == FilePathColumn)
1291             return m_workingCopyList.at(row).filePath;
1292     } else if (role == Qt::UserRole) {
1293         return m_workingCopyList.at(row).source;
1294     }
1295     return QVariant();
1296 }
1297 
headerData(int section,Qt::Orientation orientation,int role) const1298 QVariant WorkingCopyModel::headerData(int section, Qt::Orientation orientation, int role) const
1299 {
1300     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
1301         switch (section) {
1302         case RevisionColumn:
1303             return QLatin1String("Revision");
1304         case FilePathColumn:
1305             return QLatin1String("File Path");
1306         default:
1307             return QVariant();
1308         }
1309     }
1310     return QVariant();
1311 }
1312 
1313 // --- SnapshotInfo -------------------------------------------------------------------------------
1314 
1315 class SnapshotInfo
1316 {
1317 public:
1318     enum Type { GlobalSnapshot, EditorSnapshot };
SnapshotInfo(const Snapshot & snapshot,Type type)1319     SnapshotInfo(const Snapshot &snapshot, Type type)
1320         : snapshot(snapshot), type(type) {}
1321 
1322     Snapshot snapshot;
1323     Type type;
1324 };
1325 
1326 // --- CppCodeModelInspectorDialog ----------------------------------------------------------------
1327 
CppCodeModelInspectorDialog(QWidget * parent)1328 CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent)
1329     : QDialog(parent)
1330     , m_ui(new Ui::CppCodeModelInspectorDialog)
1331     , m_snapshotInfos(new QList<SnapshotInfo>())
1332     , m_snapshotView(new FilterableView(this))
1333     , m_snapshotModel(new SnapshotModel(this))
1334     , m_proxySnapshotModel(new QSortFilterProxyModel(this))
1335     , m_docGenericInfoModel(new KeyValueModel(this))
1336     , m_docIncludesModel(new IncludesModel(this))
1337     , m_docDiagnosticMessagesModel(new DiagnosticMessagesModel(this))
1338     , m_docMacrosModel(new MacrosModel(this))
1339     , m_docSymbolsModel(new SymbolsModel(this))
1340     , m_docTokensModel(new TokensModel(this))
1341     , m_projectPartsView(new FilterableView(this))
1342     , m_projectPartsModel(new ProjectPartsModel(this))
1343     , m_proxyProjectPartsModel(new QSortFilterProxyModel(this))
1344     , m_partGenericInfoModel(new KeyValueModel(this))
1345     , m_projectFilesModel(new ProjectFilesModel(this))
1346     , m_projectHeaderPathsModel(new ProjectHeaderPathsModel(this))
1347     , m_workingCopyView(new FilterableView(this))
1348     , m_workingCopyModel(new WorkingCopyModel(this))
1349     , m_proxyWorkingCopyModel(new QSortFilterProxyModel(this))
1350 {
1351     m_ui->setupUi(this);
1352     m_ui->snapshotSelectorAndViewLayout->addWidget(m_snapshotView);
1353     m_ui->projectPartsSplitter->insertWidget(0, m_projectPartsView);
1354     m_ui->workingCopySplitter->insertWidget(0, m_workingCopyView);
1355 
1356     setAttribute(Qt::WA_DeleteOnClose);
1357     connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &QWidget::close);
1358 
1359     m_ui->partGeneralView->setSizePolicy(sizePolicyWithStretchFactor(2));
1360     m_ui->partGeneralCompilerFlagsEdit->setSizePolicy(sizePolicyWithStretchFactor(1));
1361 
1362     m_proxySnapshotModel->setSourceModel(m_snapshotModel);
1363     m_proxySnapshotModel->setFilterKeyColumn(SnapshotModel::FilePathColumn);
1364     m_snapshotView->setModel(m_proxySnapshotModel);
1365     m_ui->docGeneralView->setModel(m_docGenericInfoModel);
1366     m_ui->docIncludesView->setModel(m_docIncludesModel);
1367     m_ui->docDiagnosticMessagesView->setModel(m_docDiagnosticMessagesModel);
1368     m_ui->docDefinedMacrosView->setModel(m_docMacrosModel);
1369     m_ui->docSymbolsView->setModel(m_docSymbolsModel);
1370     m_ui->docTokensView->setModel(m_docTokensModel);
1371 
1372     m_proxyProjectPartsModel->setSourceModel(m_projectPartsModel);
1373     m_proxyProjectPartsModel->setFilterKeyColumn(ProjectPartsModel::PartFilePathColumn);
1374     m_projectPartsView->setModel(m_proxyProjectPartsModel);
1375     m_ui->partGeneralView->setModel(m_partGenericInfoModel);
1376     m_ui->projectFilesView->setModel(m_projectFilesModel);
1377     m_ui->projectHeaderPathsView->setModel(m_projectHeaderPathsModel);
1378 
1379     m_proxyWorkingCopyModel->setSourceModel(m_workingCopyModel);
1380     m_proxyWorkingCopyModel->setFilterKeyColumn(WorkingCopyModel::FilePathColumn);
1381     m_workingCopyView->setModel(m_proxyWorkingCopyModel);
1382 
1383     connect(m_snapshotView->selectionModel(),
1384             &QItemSelectionModel::currentRowChanged,
1385             this, &CppCodeModelInspectorDialog::onDocumentSelected);
1386     connect(m_snapshotView, &FilterableView::filterChanged,
1387             this, &CppCodeModelInspectorDialog::onSnapshotFilterChanged);
1388     connect(m_ui->snapshotSelector,
1389             QOverload<int>::of(&QComboBox::currentIndexChanged),
1390             this, &CppCodeModelInspectorDialog::onSnapshotSelected);
1391     connect(m_ui->docSymbolsView, &QTreeView::expanded,
1392             this, &CppCodeModelInspectorDialog::onSymbolsViewExpandedOrCollapsed);
1393     connect(m_ui->docSymbolsView, &QTreeView::collapsed,
1394             this, &CppCodeModelInspectorDialog::onSymbolsViewExpandedOrCollapsed);
1395 
1396     connect(m_projectPartsView->selectionModel(),
1397             &QItemSelectionModel::currentRowChanged,
1398             this, &CppCodeModelInspectorDialog::onProjectPartSelected);
1399     connect(m_projectPartsView, &FilterableView::filterChanged,
1400             this, &CppCodeModelInspectorDialog::onProjectPartFilterChanged);
1401 
1402     connect(m_workingCopyView->selectionModel(),
1403             &QItemSelectionModel::currentRowChanged,
1404             this, &CppCodeModelInspectorDialog::onWorkingCopyDocumentSelected);
1405     connect(m_workingCopyView, &FilterableView::filterChanged,
1406             this, &CppCodeModelInspectorDialog::onWorkingCopyFilterChanged);
1407 
1408     connect(m_ui->refreshButton, &QAbstractButton::clicked, this, &CppCodeModelInspectorDialog::onRefreshRequested);
1409     connect(m_ui->closeButton, &QAbstractButton::clicked, this, &QWidget::close);
1410 
1411     refresh();
1412 }
1413 
~CppCodeModelInspectorDialog()1414 CppCodeModelInspectorDialog::~CppCodeModelInspectorDialog()
1415 {
1416     delete m_snapshotInfos;
1417     delete m_ui;
1418 }
1419 
onRefreshRequested()1420 void CppCodeModelInspectorDialog::onRefreshRequested()
1421 {
1422     refresh();
1423 }
1424 
onSnapshotFilterChanged(const QString & pattern)1425 void CppCodeModelInspectorDialog::onSnapshotFilterChanged(const QString &pattern)
1426 {
1427     m_proxySnapshotModel->setFilterWildcard(pattern);
1428 }
1429 
onSnapshotSelected(int row)1430 void CppCodeModelInspectorDialog::onSnapshotSelected(int row)
1431 {
1432     if (row < 0 || row >= m_snapshotInfos->size())
1433         return;
1434 
1435     m_snapshotView->clearFilter();
1436     const SnapshotInfo info = m_snapshotInfos->at(row);
1437     m_snapshotModel->configure(info.snapshot);
1438     m_snapshotView->resizeColumns(SnapshotModel::ColumnCount);
1439 
1440     if (info.type == SnapshotInfo::GlobalSnapshot) {
1441         // Select first document
1442         const QModelIndex index = m_proxySnapshotModel->index(0, SnapshotModel::FilePathColumn);
1443         m_snapshotView->selectIndex(index);
1444     } else if (info.type == SnapshotInfo::EditorSnapshot) {
1445         // Select first document, unless we can find the editor document
1446         QModelIndex index = m_snapshotModel->indexForDocument(fileInCurrentEditor());
1447         index = m_proxySnapshotModel->mapFromSource(index);
1448         if (!index.isValid())
1449             index = m_proxySnapshotModel->index(0, SnapshotModel::FilePathColumn);
1450         m_snapshotView->selectIndex(index);
1451     }
1452 }
1453 
onDocumentSelected(const QModelIndex & current,const QModelIndex &)1454 void CppCodeModelInspectorDialog::onDocumentSelected(const QModelIndex &current,
1455                                                      const QModelIndex &)
1456 {
1457     if (current.isValid()) {
1458         const QModelIndex index = m_proxySnapshotModel->index(current.row(),
1459                                                               SnapshotModel::FilePathColumn);
1460         const QString filePath = QDir::fromNativeSeparators(
1461             m_proxySnapshotModel->data(index, Qt::DisplayRole).toString());
1462         const SnapshotInfo info = m_snapshotInfos->at(m_ui->snapshotSelector->currentIndex());
1463         updateDocumentData(info.snapshot.document(filePath));
1464     } else {
1465         clearDocumentData();
1466     }
1467 }
1468 
onSymbolsViewExpandedOrCollapsed(const QModelIndex &)1469 void CppCodeModelInspectorDialog::onSymbolsViewExpandedOrCollapsed(const QModelIndex &)
1470 {
1471     resizeColumns<SymbolsModel>(m_ui->docSymbolsView);
1472 }
1473 
onProjectPartFilterChanged(const QString & pattern)1474 void CppCodeModelInspectorDialog::onProjectPartFilterChanged(const QString &pattern)
1475 {
1476     m_proxyProjectPartsModel->setFilterWildcard(pattern);
1477 }
1478 
onProjectPartSelected(const QModelIndex & current,const QModelIndex &)1479 void CppCodeModelInspectorDialog::onProjectPartSelected(const QModelIndex &current,
1480                                                         const QModelIndex &)
1481 {
1482     if (current.isValid()) {
1483         QModelIndex index = m_proxyProjectPartsModel->mapToSource(current);
1484         if (index.isValid()) {
1485             index = m_projectPartsModel->index(index.row(), ProjectPartsModel::PartFilePathColumn);
1486             const QString projectPartId = m_projectPartsModel->data(index, Qt::UserRole).toString();
1487             updateProjectPartData(m_projectPartsModel->projectPartForProjectId(projectPartId));
1488         }
1489     } else {
1490         clearProjectPartData();
1491     }
1492 }
1493 
onWorkingCopyFilterChanged(const QString & pattern)1494 void CppCodeModelInspectorDialog::onWorkingCopyFilterChanged(const QString &pattern)
1495 {
1496     m_proxyWorkingCopyModel->setFilterWildcard(pattern);
1497 }
1498 
onWorkingCopyDocumentSelected(const QModelIndex & current,const QModelIndex &)1499 void CppCodeModelInspectorDialog::onWorkingCopyDocumentSelected(const QModelIndex &current,
1500                                                                 const QModelIndex &)
1501 {
1502     if (current.isValid()) {
1503         const QModelIndex index = m_proxyWorkingCopyModel->mapToSource(current);
1504         if (index.isValid()) {
1505             const QString source
1506                 = QString::fromUtf8(m_workingCopyModel->data(index, Qt::UserRole).toByteArray());
1507             m_ui->workingCopySourceEdit->setPlainText(source);
1508         }
1509     } else {
1510         m_ui->workingCopySourceEdit->clear();
1511     }
1512 }
1513 
refresh()1514 void CppCodeModelInspectorDialog::refresh()
1515 {
1516     CppModelManager *cmmi = CppModelManager::instance();
1517 
1518     const int oldSnapshotIndex = m_ui->snapshotSelector->currentIndex();
1519     const bool selectEditorRelevant
1520         = m_ui->selectEditorRelevantEntriesAfterRefreshCheckBox->isChecked();
1521 
1522     // Snapshots and Documents
1523     m_snapshotInfos->clear();
1524     m_ui->snapshotSelector->clear();
1525 
1526     const Snapshot globalSnapshot = cmmi->snapshot();
1527     CppCodeModelInspector::Dumper dumper(globalSnapshot);
1528     m_snapshotModel->setGlobalSnapshot(globalSnapshot);
1529 
1530     m_snapshotInfos->append(SnapshotInfo(globalSnapshot, SnapshotInfo::GlobalSnapshot));
1531     const QString globalSnapshotTitle
1532         = QString::fromLatin1("Global/Indexing Snapshot (%1 Documents)").arg(globalSnapshot.size());
1533     m_ui->snapshotSelector->addItem(globalSnapshotTitle);
1534     dumper.dumpSnapshot(globalSnapshot, globalSnapshotTitle, /*isGlobalSnapshot=*/ true);
1535 
1536     TextEditor::BaseTextEditor *editor = currentEditor();
1537     CppTools::CppEditorDocumentHandle *cppEditorDocument = nullptr;
1538     if (editor) {
1539         const QString editorFilePath = editor->document()->filePath().toString();
1540         cppEditorDocument = cmmi->cppEditorDocument(editorFilePath);
1541         if (auto documentProcessor = CppToolsBridge::baseEditorDocumentProcessor(editorFilePath)) {
1542             const Snapshot editorSnapshot = documentProcessor->snapshot();
1543             m_snapshotInfos->append(SnapshotInfo(editorSnapshot, SnapshotInfo::EditorSnapshot));
1544             const QString editorSnapshotTitle
1545                 = QString::fromLatin1("Current Editor's Snapshot (%1 Documents)")
1546                     .arg(editorSnapshot.size());
1547             dumper.dumpSnapshot(editorSnapshot, editorSnapshotTitle);
1548             m_ui->snapshotSelector->addItem(editorSnapshotTitle);
1549         }
1550         auto cppEditorWidget = qobject_cast<CppEditorWidget *>(editor->editorWidget());
1551         if (cppEditorWidget) {
1552             SemanticInfo semanticInfo = cppEditorWidget->semanticInfo();
1553             Snapshot snapshot;
1554 
1555             // Add semantic info snapshot
1556             snapshot = semanticInfo.snapshot;
1557             m_snapshotInfos->append(SnapshotInfo(snapshot, SnapshotInfo::EditorSnapshot));
1558             m_ui->snapshotSelector->addItem(
1559                 QString::fromLatin1("Current Editor's Semantic Info Snapshot (%1 Documents)")
1560                     .arg(snapshot.size()));
1561 
1562             // Add a pseudo snapshot containing only the semantic info document since this document
1563             // is not part of the semantic snapshot.
1564             snapshot = Snapshot();
1565             snapshot.insert(cppEditorWidget->semanticInfo().doc);
1566             m_snapshotInfos->append(SnapshotInfo(snapshot, SnapshotInfo::EditorSnapshot));
1567             const QString snapshotTitle
1568                 = QString::fromLatin1("Current Editor's Pseudo Snapshot with Semantic Info Document (%1 Documents)")
1569                     .arg(snapshot.size());
1570             dumper.dumpSnapshot(snapshot, snapshotTitle);
1571             m_ui->snapshotSelector->addItem(snapshotTitle);
1572         }
1573     }
1574 
1575     int snapshotIndex = 0;
1576     if (selectEditorRelevant) {
1577         for (int i = 0, total = m_snapshotInfos->size(); i < total; ++i) {
1578             const SnapshotInfo info = m_snapshotInfos->at(i);
1579             if (info.type == SnapshotInfo::EditorSnapshot) {
1580                 snapshotIndex = i;
1581                 break;
1582             }
1583         }
1584     } else if (oldSnapshotIndex < m_snapshotInfos->size()) {
1585         snapshotIndex = oldSnapshotIndex;
1586     }
1587     m_ui->snapshotSelector->setCurrentIndex(snapshotIndex);
1588     onSnapshotSelected(snapshotIndex);
1589 
1590     // Project Parts
1591     const ProjectPart::Ptr editorsProjectPart = cppEditorDocument
1592         ? cppEditorDocument->processor()->parser()->projectPartInfo().projectPart
1593         : ProjectPart::Ptr();
1594 
1595     const QList<ProjectInfo> projectInfos = cmmi->projectInfos();
1596     dumper.dumpProjectInfos(projectInfos);
1597     m_projectPartsModel->configure(projectInfos, editorsProjectPart);
1598     m_projectPartsView->resizeColumns(ProjectPartsModel::ColumnCount);
1599     QModelIndex index = m_proxyProjectPartsModel->index(0, ProjectPartsModel::PartFilePathColumn);
1600     if (index.isValid()) {
1601         if (selectEditorRelevant && editorsProjectPart) {
1602             QModelIndex editorPartIndex = m_projectPartsModel->indexForCurrentEditorsProjectPart();
1603             editorPartIndex = m_proxyProjectPartsModel->mapFromSource(editorPartIndex);
1604             if (editorPartIndex.isValid())
1605                 index = editorPartIndex;
1606         }
1607         m_projectPartsView->selectIndex(index);
1608     }
1609 
1610     // Working Copy
1611     const WorkingCopy workingCopy = cmmi->workingCopy();
1612     dumper.dumpWorkingCopy(workingCopy);
1613     m_workingCopyModel->configure(workingCopy);
1614     m_workingCopyView->resizeColumns(WorkingCopyModel::ColumnCount);
1615     if (workingCopy.size() > 0) {
1616         QModelIndex index = m_proxyWorkingCopyModel->index(0, WorkingCopyModel::FilePathColumn);
1617         if (selectEditorRelevant) {
1618             const QModelIndex eindex = m_workingCopyModel->indexForFile(fileInCurrentEditor());
1619             if (eindex.isValid())
1620                 index = m_proxyWorkingCopyModel->mapFromSource(eindex);
1621         }
1622         m_workingCopyView->selectIndex(index);
1623     }
1624 
1625     // Merged entities
1626     dumper.dumpMergedEntities(cmmi->headerPaths(),
1627                               ProjectExplorer::Macro::toByteArray(cmmi->definedMacros()));
1628 }
1629 
1630 enum DocumentTabs {
1631     DocumentGeneralTab,
1632     DocumentIncludesTab,
1633     DocumentDiagnosticsTab,
1634     DocumentDefinedMacrosTab,
1635     DocumentPreprocessedSourceTab,
1636     DocumentSymbolsTab,
1637     DocumentTokensTab
1638 };
1639 
docTabName(int tabIndex,int numberOfEntries=-1)1640 static QString docTabName(int tabIndex, int numberOfEntries = -1)
1641 {
1642     const char *names[] = {
1643         "&General",
1644         "&Includes",
1645         "&Diagnostic Messages",
1646         "(Un)Defined &Macros",
1647         "P&reprocessed Source",
1648         "&Symbols",
1649         "&Tokens"
1650     };
1651     QString result = QLatin1String(names[tabIndex]);
1652     if (numberOfEntries != -1)
1653         result += QString::fromLatin1(" (%1)").arg(numberOfEntries);
1654     return result;
1655 }
1656 
clearDocumentData()1657 void CppCodeModelInspectorDialog::clearDocumentData()
1658 {
1659     m_docGenericInfoModel->clear();
1660 
1661     m_ui->docTab->setTabText(DocumentIncludesTab, docTabName(DocumentIncludesTab));
1662     m_docIncludesModel->clear();
1663 
1664     m_ui->docTab->setTabText(DocumentDiagnosticsTab, docTabName(DocumentDiagnosticsTab));
1665     m_docDiagnosticMessagesModel->clear();
1666 
1667     m_ui->docTab->setTabText(DocumentDefinedMacrosTab, docTabName(DocumentDefinedMacrosTab));
1668     m_docMacrosModel->clear();
1669 
1670     m_ui->docPreprocessedSourceEdit->clear();
1671 
1672     m_docSymbolsModel->clear();
1673 
1674     m_ui->docTab->setTabText(DocumentTokensTab, docTabName(DocumentTokensTab));
1675     m_docTokensModel->clear();
1676 }
1677 
updateDocumentData(const Document::Ptr & document)1678 void CppCodeModelInspectorDialog::updateDocumentData(const Document::Ptr &document)
1679 {
1680     QTC_ASSERT(document, return);
1681 
1682     // General
1683     const KeyValueModel::Table table = {
1684         {QString::fromLatin1("File Path"), QDir::toNativeSeparators(document->fileName())},
1685         {QString::fromLatin1("Last Modified"), CMI::Utils::toString(document->lastModified())},
1686         {QString::fromLatin1("Revision"), CMI::Utils::toString(document->revision())},
1687         {QString::fromLatin1("Editor Revision"), CMI::Utils::toString(document->editorRevision())},
1688         {QString::fromLatin1("Check Mode"), CMI::Utils::toString(document->checkMode())},
1689         {QString::fromLatin1("Tokenized"), CMI::Utils::toString(document->isTokenized())},
1690         {QString::fromLatin1("Parsed"), CMI::Utils::toString(document->isParsed())},
1691         {QString::fromLatin1("Project Parts"), CMI::Utils::partsForFile(document->fileName())}
1692     };
1693     m_docGenericInfoModel->configure(table);
1694     resizeColumns<KeyValueModel>(m_ui->docGeneralView);
1695 
1696     // Includes
1697     m_docIncludesModel->configure(document->resolvedIncludes() + document->unresolvedIncludes());
1698     resizeColumns<IncludesModel>(m_ui->docIncludesView);
1699     m_ui->docTab->setTabText(DocumentIncludesTab,
1700         docTabName(DocumentIncludesTab, m_docIncludesModel->rowCount()));
1701 
1702     // Diagnostic Messages
1703     m_docDiagnosticMessagesModel->configure(document->diagnosticMessages());
1704     resizeColumns<DiagnosticMessagesModel>(m_ui->docDiagnosticMessagesView);
1705     m_ui->docTab->setTabText(DocumentDiagnosticsTab,
1706         docTabName(DocumentDiagnosticsTab, m_docDiagnosticMessagesModel->rowCount()));
1707 
1708     // Macros
1709     m_docMacrosModel->configure(document->definedMacros());
1710     resizeColumns<MacrosModel>(m_ui->docDefinedMacrosView);
1711     m_ui->docTab->setTabText(DocumentDefinedMacrosTab,
1712         docTabName(DocumentDefinedMacrosTab, m_docMacrosModel->rowCount()));
1713 
1714     // Source
1715     m_ui->docPreprocessedSourceEdit->setPlainText(QString::fromUtf8(document->utf8Source()));
1716 
1717     // Symbols
1718     m_docSymbolsModel->configure(document);
1719     resizeColumns<SymbolsModel>(m_ui->docSymbolsView);
1720 
1721     // Tokens
1722     m_docTokensModel->configure(document->translationUnit());
1723     resizeColumns<TokensModel>(m_ui->docTokensView);
1724     m_ui->docTab->setTabText(DocumentTokensTab,
1725         docTabName(DocumentTokensTab, m_docTokensModel->rowCount()));
1726 }
1727 
1728 enum ProjectPartTabs {
1729     ProjectPartGeneralTab,
1730     ProjectPartFilesTab,
1731     ProjectPartDefinesTab,
1732     ProjectPartHeaderPathsTab,
1733     ProjectPartPrecompiledHeadersTab
1734 };
1735 
partTabName(int tabIndex,int numberOfEntries=-1)1736 static QString partTabName(int tabIndex, int numberOfEntries = -1)
1737 {
1738     const char *names[] = {
1739         "&General",
1740         "Project &Files",
1741         "&Defines",
1742         "&Header Paths",
1743         "Pre&compiled Headers"
1744     };
1745     QString result = QLatin1String(names[tabIndex]);
1746     if (numberOfEntries != -1)
1747         result += QString::fromLatin1(" (%1)").arg(numberOfEntries);
1748     return result;
1749 }
1750 
clearProjectPartData()1751 void CppCodeModelInspectorDialog::clearProjectPartData()
1752 {
1753     m_partGenericInfoModel->clear();
1754     m_projectFilesModel->clear();
1755     m_projectHeaderPathsModel->clear();
1756 
1757     m_ui->projectPartTab->setTabText(ProjectPartFilesTab, partTabName(ProjectPartFilesTab));
1758 
1759     m_ui->partToolchainDefinesEdit->clear();
1760     m_ui->partProjectDefinesEdit->clear();
1761     m_ui->projectPartTab->setTabText(ProjectPartDefinesTab, partTabName(ProjectPartDefinesTab));
1762 
1763     m_ui->projectPartTab->setTabText(ProjectPartHeaderPathsTab,
1764                                      partTabName(ProjectPartHeaderPathsTab));
1765 
1766     m_ui->partPrecompiledHeadersEdit->clear();
1767     m_ui->projectPartTab->setTabText(ProjectPartPrecompiledHeadersTab,
1768                                      partTabName(ProjectPartPrecompiledHeadersTab));
1769 }
1770 
defineCount(const ProjectExplorer::Macros & macros)1771 static int defineCount(const ProjectExplorer::Macros &macros)
1772 {
1773     using ProjectExplorer::Macro;
1774     return int(std::count_if(
1775                    macros.begin(),
1776                    macros.end(),
1777                    [](const Macro &macro) { return macro.type == ProjectExplorer::MacroType::Define; }));
1778 }
1779 
updateProjectPartData(const ProjectPart::Ptr & part)1780 void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr &part)
1781 {
1782     QTC_ASSERT(part, return);
1783 
1784     // General
1785     QString projectName = QLatin1String("<None>");
1786     QString projectFilePath = QLatin1String("<None>");
1787     if (ProjectExplorer::Project *project = part->project) {
1788         projectName = project->displayName();
1789         projectFilePath = project->projectFilePath().toUserOutput();
1790     }
1791     const QString callGroupId = part->callGroupId.isEmpty() ? QString::fromLatin1("<None>")
1792                                                             : part->callGroupId;
1793     const QString buildSystemTarget
1794             = part->buildSystemTarget.isEmpty() ? QString::fromLatin1("<None>")
1795                                                 : part->buildSystemTarget;
1796 
1797     const QString precompiledHeaders = part->precompiledHeaders.isEmpty()
1798             ? QString::fromLatin1("<None>")
1799             : part->precompiledHeaders.join(',');
1800 
1801     KeyValueModel::Table table = {
1802         {QString::fromLatin1("Project Part Name"), part->displayName},
1803         {QString::fromLatin1("Project Part File"), part->projectFileLocation()},
1804         {QString::fromLatin1("Project Name"), projectName},
1805         {QString::fromLatin1("Project File"), projectFilePath},
1806         {QString::fromLatin1("Callgroup Id"), callGroupId},
1807         {QString::fromLatin1("Precompiled Headers"), precompiledHeaders},
1808         {QString::fromLatin1("Selected For Building"), CMI::Utils::toString(part->selectedForBuilding)},
1809         {QString::fromLatin1("Buildsystem Target"), buildSystemTarget},
1810         {QString::fromLatin1("Build Target Type"), CMI::Utils::toString(part->buildTargetType)},
1811         {QString::fromLatin1("ToolChain Type"), part->toolchainType.toString()},
1812         {QString::fromLatin1("ToolChain Target Triple"), part->toolChainTargetTriple},
1813         {QString::fromLatin1("ToolChain Word Width"), CMI::Utils::toString(part->toolChainWordWidth)},
1814         {QString::fromLatin1("ToolChain Install Dir"), part->toolChainInstallDir.toString()},
1815         {QString::fromLatin1("Language Version"), CMI::Utils::toString(part->languageVersion)},
1816         {QString::fromLatin1("Language Extensions"), CMI::Utils::toString(part->languageExtensions)},
1817         {QString::fromLatin1("Qt Version"), CMI::Utils::toString(part->qtVersion)}
1818     };
1819     if (!part->projectConfigFile.isEmpty())
1820         table.prepend({QString::fromLatin1("Project Config File"), part->projectConfigFile});
1821     m_partGenericInfoModel->configure(table);
1822     resizeColumns<KeyValueModel>(m_ui->partGeneralView);
1823 
1824     // Compiler Flags
1825     m_ui->partGeneralCompilerFlagsEdit->setPlainText(part->compilerFlags.join("\n"));
1826 
1827     // Project Files
1828     m_projectFilesModel->configure(part->files);
1829     m_ui->projectPartTab->setTabText(ProjectPartFilesTab,
1830         partTabName(ProjectPartFilesTab, part->files.size()));
1831 
1832     int numberOfDefines = defineCount(part->toolChainMacros) + defineCount(part->projectMacros);
1833 
1834     m_ui->partToolchainDefinesEdit->setPlainText(QString::fromUtf8(ProjectExplorer::Macro::toByteArray(part->toolChainMacros)));
1835     m_ui->partProjectDefinesEdit->setPlainText(QString::fromUtf8(ProjectExplorer::Macro::toByteArray(part->projectMacros)));
1836     m_ui->projectPartTab->setTabText(ProjectPartDefinesTab,
1837         partTabName(ProjectPartDefinesTab, numberOfDefines));
1838 
1839     // Header Paths
1840     m_projectHeaderPathsModel->configure(part->headerPaths);
1841     m_ui->projectPartTab->setTabText(ProjectPartHeaderPathsTab,
1842         partTabName(ProjectPartHeaderPathsTab, part->headerPaths.size()));
1843 
1844     // Precompiled Headers
1845     m_ui->partPrecompiledHeadersEdit->setPlainText(
1846                 CMI::Utils::pathListToString(part->precompiledHeaders));
1847     m_ui->projectPartTab->setTabText(ProjectPartPrecompiledHeadersTab,
1848         partTabName(ProjectPartPrecompiledHeadersTab, part->precompiledHeaders.size()));
1849 }
1850 
event(QEvent * e)1851 bool CppCodeModelInspectorDialog::event(QEvent *e)
1852 {
1853     if (e->type() == QEvent::ShortcutOverride) {
1854         auto ke = static_cast<QKeyEvent *>(e);
1855         if (ke->key() == Qt::Key_Escape && !ke->modifiers()) {
1856             ke->accept();
1857             close();
1858             return false;
1859         }
1860     }
1861     return QDialog::event(e);
1862 }
1863 
1864 } // namespace Internal
1865 } // namespace CppEditor
1866 
1867 #include "cppcodemodelinspectordialog.moc"
1868