/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of Qt Creator. ** ** 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. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "cppcodemodelinspectordialog.h" #include "cppeditor.h" #include "ui_cppcodemodelinspectordialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace CppTools; namespace { // --- Utils -------------------------------------------------------------------------------------- QString toString(bool value) { return value ? QLatin1String("Yes") : QLatin1String("No"); } QString toString(unsigned value) { return QString::number(value); } QString toString(const QDateTime &dateTime) { return dateTime.toString(QLatin1String("hh:mm:ss dd.MM.yy")); } QString toString(CPlusPlus::Document::CheckMode checkMode) { #define CASE_CHECKMODE(x) case CPlusPlus::Document::x: return QLatin1String(#x) switch (checkMode) { CASE_CHECKMODE(Unchecked); CASE_CHECKMODE(FullCheck); CASE_CHECKMODE(FastCheck); // no default to get a compiler warning if anything is added } #undef CASE_CHECKMODE return QString(); } QString toString(CPlusPlus::Document::DiagnosticMessage::Level level) { #define CASE_LEVEL(x) case CPlusPlus::Document::DiagnosticMessage::x: return QLatin1String(#x) switch (level) { CASE_LEVEL(Warning); CASE_LEVEL(Error); CASE_LEVEL(Fatal); // no default to get a compiler warning if anything is added } #undef CASE_LEVEL return QString(); } QString toString(ProjectPart::CVersion cVersion) { #define CASE_CVERSION(x) case ProjectPart::x: return QLatin1String(#x) switch (cVersion) { CASE_CVERSION(C89); CASE_CVERSION(C99); CASE_CVERSION(C11); // no default to get a compiler warning if anything is added } #undef CASE_CVERSION return QString(); } QString toString(ProjectPart::CXXVersion cxxVersion) { #define CASE_CXXVERSION(x) case ProjectPart::x: return QLatin1String(#x) switch (cxxVersion) { CASE_CXXVERSION(CXX98); CASE_CXXVERSION(CXX11); // no default to get a compiler warning if anything is added } #undef CASE_CXXVERSION return QString(); } QString toString(ProjectPart::CXXExtensions cxxExtension) { QString result; #define CASE_CXXEXTENSION(ext) if (cxxExtension & ProjectPart::ext) \ result += QLatin1String(#ext ", "); CASE_CXXEXTENSION(NoExtensions); CASE_CXXEXTENSION(GnuExtensions); CASE_CXXEXTENSION(MicrosoftExtensions); CASE_CXXEXTENSION(BorlandExtensions); CASE_CXXEXTENSION(OpenMPExtensions); #undef CASE_CXXEXTENSION if (result.endsWith(QLatin1String(", "))) result.chop(2); return result; } QString toString(ProjectPart::QtVersion qtVersion) { #define CASE_QTVERSION(x) case ProjectPart::x: return QLatin1String(#x) switch (qtVersion) { CASE_QTVERSION(UnknownQt); CASE_QTVERSION(NoQt); CASE_QTVERSION(Qt4); CASE_QTVERSION(Qt5); // no default to get a compiler warning if anything is added } #undef CASE_QTVERSION return QString(); } QString toString(const QList &projectFiles) { QStringList filesList; foreach (const ProjectFile &projectFile, projectFiles) filesList << QDir::toNativeSeparators(projectFile.path); qSort(filesList); return filesList.join(QLatin1String("\n")); } QString toString(ProjectFile::Kind kind) { #define CASE_PROFECTFILEKIND(x) case ProjectFile::x: return QLatin1String(#x) switch (kind) { CASE_PROFECTFILEKIND(Unclassified); CASE_PROFECTFILEKIND(CHeader); CASE_PROFECTFILEKIND(CSource); CASE_PROFECTFILEKIND(CXXHeader); CASE_PROFECTFILEKIND(CXXSource); CASE_PROFECTFILEKIND(ObjCHeader); CASE_PROFECTFILEKIND(ObjCSource); CASE_PROFECTFILEKIND(ObjCXXHeader); CASE_PROFECTFILEKIND(ObjCXXSource); CASE_PROFECTFILEKIND(CudaSource); CASE_PROFECTFILEKIND(OpenCLSource); // no default to get a compiler warning if anything is added } #undef CASE_PROFECTFILEKIND return QString(); } QString toString(CPlusPlus::Kind kind) { using namespace CPlusPlus; #define TOKEN(x) case x: return QLatin1String(#x) #define TOKEN_AND_ALIASES(x,y) case x: return QLatin1String(#x "/" #y) switch (kind) { TOKEN(T_EOF_SYMBOL); TOKEN(T_ERROR); TOKEN(T_CPP_COMMENT); TOKEN(T_CPP_DOXY_COMMENT); TOKEN(T_COMMENT); TOKEN(T_DOXY_COMMENT); TOKEN(T_IDENTIFIER); TOKEN(T_NUMERIC_LITERAL); TOKEN(T_CHAR_LITERAL); TOKEN(T_WIDE_CHAR_LITERAL); TOKEN(T_UTF16_CHAR_LITERAL); TOKEN(T_UTF32_CHAR_LITERAL); TOKEN(T_STRING_LITERAL); TOKEN(T_WIDE_STRING_LITERAL); TOKEN(T_UTF8_STRING_LITERAL); TOKEN(T_UTF16_STRING_LITERAL); TOKEN(T_UTF32_STRING_LITERAL); TOKEN(T_RAW_STRING_LITERAL); TOKEN(T_RAW_WIDE_STRING_LITERAL); TOKEN(T_RAW_UTF8_STRING_LITERAL); TOKEN(T_RAW_UTF16_STRING_LITERAL); TOKEN(T_RAW_UTF32_STRING_LITERAL); TOKEN(T_AT_STRING_LITERAL); TOKEN(T_ANGLE_STRING_LITERAL); TOKEN_AND_ALIASES(T_AMPER, T_BITAND); TOKEN_AND_ALIASES(T_AMPER_AMPER, T_AND); TOKEN_AND_ALIASES(T_AMPER_EQUAL, T_AND_EQ); TOKEN(T_ARROW); TOKEN(T_ARROW_STAR); TOKEN_AND_ALIASES(T_CARET, T_XOR); TOKEN_AND_ALIASES(T_CARET_EQUAL, T_XOR_EQ); TOKEN(T_COLON); TOKEN(T_COLON_COLON); TOKEN(T_COMMA); TOKEN(T_SLASH); TOKEN(T_SLASH_EQUAL); TOKEN(T_DOT); TOKEN(T_DOT_DOT_DOT); TOKEN(T_DOT_STAR); TOKEN(T_EQUAL); TOKEN(T_EQUAL_EQUAL); TOKEN_AND_ALIASES(T_EXCLAIM, T_NOT); TOKEN_AND_ALIASES(T_EXCLAIM_EQUAL, T_NOT_EQ); TOKEN(T_GREATER); TOKEN(T_GREATER_EQUAL); TOKEN(T_GREATER_GREATER); TOKEN(T_GREATER_GREATER_EQUAL); TOKEN(T_LBRACE); TOKEN(T_LBRACKET); TOKEN(T_LESS); TOKEN(T_LESS_EQUAL); TOKEN(T_LESS_LESS); TOKEN(T_LESS_LESS_EQUAL); TOKEN(T_LPAREN); TOKEN(T_MINUS); TOKEN(T_MINUS_EQUAL); TOKEN(T_MINUS_MINUS); TOKEN(T_PERCENT); TOKEN(T_PERCENT_EQUAL); TOKEN_AND_ALIASES(T_PIPE, T_BITOR); TOKEN_AND_ALIASES(T_PIPE_EQUAL, T_OR_EQ); TOKEN_AND_ALIASES(T_PIPE_PIPE, T_OR); TOKEN(T_PLUS); TOKEN(T_PLUS_EQUAL); TOKEN(T_PLUS_PLUS); TOKEN(T_POUND); TOKEN(T_POUND_POUND); TOKEN(T_QUESTION); TOKEN(T_RBRACE); TOKEN(T_RBRACKET); TOKEN(T_RPAREN); TOKEN(T_SEMICOLON); TOKEN(T_STAR); TOKEN(T_STAR_EQUAL); TOKEN_AND_ALIASES(T_TILDE, T_COMPL); TOKEN(T_TILDE_EQUAL); TOKEN(T_ALIGNAS); TOKEN(T_ALIGNOF); TOKEN_AND_ALIASES(T_ASM, T___ASM/T___ASM__); TOKEN(T_AUTO); TOKEN(T_BOOL); TOKEN(T_BREAK); TOKEN(T_CASE); TOKEN(T_CATCH); TOKEN(T_CHAR); TOKEN(T_CHAR16_T); TOKEN(T_CHAR32_T); TOKEN(T_CLASS); TOKEN_AND_ALIASES(T_CONST, T___CONST/T___CONST__); TOKEN(T_CONST_CAST); TOKEN(T_CONSTEXPR); TOKEN(T_CONTINUE); TOKEN_AND_ALIASES(T_DECLTYPE, T___DECLTYPE); TOKEN(T_DEFAULT); TOKEN(T_DELETE); TOKEN(T_DO); TOKEN(T_DOUBLE); TOKEN(T_DYNAMIC_CAST); TOKEN(T_ELSE); TOKEN(T_ENUM); TOKEN(T_EXPLICIT); TOKEN(T_EXPORT); TOKEN(T_EXTERN); TOKEN(T_FALSE); TOKEN(T_FLOAT); TOKEN(T_FOR); TOKEN(T_FRIEND); TOKEN(T_GOTO); TOKEN(T_IF); TOKEN_AND_ALIASES(T_INLINE, T___INLINE/T___INLINE__); TOKEN(T_INT); TOKEN(T_LONG); TOKEN(T_MUTABLE); TOKEN(T_NAMESPACE); TOKEN(T_NEW); TOKEN(T_NOEXCEPT); TOKEN(T_NULLPTR); TOKEN(T_OPERATOR); TOKEN(T_PRIVATE); TOKEN(T_PROTECTED); TOKEN(T_PUBLIC); TOKEN(T_REGISTER); TOKEN(T_REINTERPRET_CAST); TOKEN(T_RETURN); TOKEN(T_SHORT); TOKEN(T_SIGNED); TOKEN(T_SIZEOF); TOKEN(T_STATIC); TOKEN(T_STATIC_ASSERT); TOKEN(T_STATIC_CAST); TOKEN(T_STRUCT); TOKEN(T_SWITCH); TOKEN(T_TEMPLATE); TOKEN(T_THIS); TOKEN(T_THREAD_LOCAL); TOKEN(T_THROW); TOKEN(T_TRUE); TOKEN(T_TRY); TOKEN(T_TYPEDEF); TOKEN(T_TYPEID); TOKEN(T_TYPENAME); TOKEN(T_UNION); TOKEN(T_UNSIGNED); TOKEN(T_USING); TOKEN(T_VIRTUAL); TOKEN(T_VOID); TOKEN_AND_ALIASES(T_VOLATILE, T___VOLATILE/T___VOLATILE__); TOKEN(T_WCHAR_T); TOKEN(T_WHILE); TOKEN_AND_ALIASES(T___ATTRIBUTE__, T___ATTRIBUTE); TOKEN(T___THREAD); TOKEN_AND_ALIASES(T___TYPEOF__, T_TYPEOF/T___TYPEOF); TOKEN(T_AT_CATCH); TOKEN(T_AT_CLASS); TOKEN(T_AT_COMPATIBILITY_ALIAS); TOKEN(T_AT_DEFS); TOKEN(T_AT_DYNAMIC); TOKEN(T_AT_ENCODE); TOKEN(T_AT_END); TOKEN(T_AT_FINALLY); TOKEN(T_AT_IMPLEMENTATION); TOKEN(T_AT_INTERFACE); TOKEN(T_AT_NOT_KEYWORD); TOKEN(T_AT_OPTIONAL); TOKEN(T_AT_PACKAGE); TOKEN(T_AT_PRIVATE); TOKEN(T_AT_PROPERTY); TOKEN(T_AT_PROTECTED); TOKEN(T_AT_PROTOCOL); TOKEN(T_AT_PUBLIC); TOKEN(T_AT_REQUIRED); TOKEN(T_AT_SELECTOR); TOKEN(T_AT_SYNCHRONIZED); TOKEN(T_AT_SYNTHESIZE); TOKEN(T_AT_THROW); TOKEN(T_AT_TRY); TOKEN(T_EMIT); TOKEN(T_SIGNAL); TOKEN(T_SLOT); TOKEN(T_Q_SIGNAL); TOKEN(T_Q_SLOT); TOKEN(T_Q_SIGNALS); TOKEN(T_Q_SLOTS); TOKEN(T_Q_FOREACH); TOKEN(T_Q_D); TOKEN(T_Q_Q); TOKEN(T_Q_INVOKABLE); TOKEN(T_Q_PROPERTY); TOKEN(T_Q_PRIVATE_PROPERTY); TOKEN(T_Q_INTERFACES); TOKEN(T_Q_EMIT); TOKEN(T_Q_ENUMS); TOKEN(T_Q_FLAGS); TOKEN(T_Q_PRIVATE_SLOT); TOKEN(T_Q_DECLARE_INTERFACE); TOKEN(T_Q_OBJECT); TOKEN(T_Q_GADGET); // no default to get a compiler warning if anything is added } #undef TOKEN #undef TOKEN_AND_ALIASES return QString(); } QString partsForFile(const QString &fileName) { const QList parts = CppModelManagerInterface::instance()->projectPart(fileName); QString result; foreach (const ProjectPart::Ptr &part, parts) result += part->displayName + QLatin1Char(','); if (result.endsWith(QLatin1Char(','))) result.chop(1); return result; } QString unresolvedFileNameWithDelimiters(const CPlusPlus::Document::Include &include) { const QString unresolvedFileName = include.unresolvedFileName(); if (include.type() == CPlusPlus::Client::IncludeLocal) return QLatin1Char('"') + unresolvedFileName + QLatin1Char('"'); return QLatin1Char('<') + unresolvedFileName + QLatin1Char('>'); } QString pathListToString(const QStringList &pathList) { QStringList result; foreach (const QString &path, pathList) result << QDir::toNativeSeparators(path); return result.join(QLatin1String("\n")); } QList snapshotToList(const CPlusPlus::Snapshot &snapshot) { QList documents; CPlusPlus::Snapshot::const_iterator it = snapshot.begin(), end = snapshot.end(); for (; it != end; ++it) documents.append(it.value()); return documents; } template void resizeColumns(QTreeView *view) { for (int column = 0; column < T::ColumnCount - 1; ++column) view->resizeColumnToContents(column); } TextEditor::BaseTextEditor *currentEditor() { return qobject_cast(Core::EditorManager::currentEditor()); } QString fileInCurrentEditor() { if (TextEditor::BaseTextEditor *editor = currentEditor()) return editor->document()->filePath(); return QString(); } class DepthFinder : public CPlusPlus::SymbolVisitor { public: DepthFinder() : m_symbol(0), m_depth(-1), m_foundDepth(-1), m_stop(false) {} int operator()(const CPlusPlus::Document::Ptr &document, CPlusPlus::Symbol *symbol) { m_symbol = symbol; accept(document->globalNamespace()); return m_foundDepth; } bool preVisit(CPlusPlus::Symbol *symbol) { if (m_stop) return false; if (symbol->asScope()) { ++m_depth; if (symbol == m_symbol) { m_foundDepth = m_depth; m_stop = true; } return true; } return false; } void postVisit(CPlusPlus::Symbol *symbol) { if (symbol->asScope()) --m_depth; } private: CPlusPlus::Symbol *m_symbol; int m_depth; int m_foundDepth; bool m_stop; }; class CppCodeModelInspectorDumper { public: explicit CppCodeModelInspectorDumper(const CPlusPlus::Snapshot &globalSnapshot); ~CppCodeModelInspectorDumper(); void dumpProjectInfos(const QList &projectInfos); void dumpSnapshot(const CPlusPlus::Snapshot &snapshot, const QString &title, bool isGlobalSnapshot = false); void dumpWorkingCopy(const CppModelManagerInterface::WorkingCopy &workingCopy); private: void dumpDocuments(const QList &documents, bool skipDetails = false); static QByteArray indent(int level); CPlusPlus::Snapshot m_globalSnapshot; QFile m_logFile; QTextStream m_out; }; CppCodeModelInspectorDumper::CppCodeModelInspectorDumper(const CPlusPlus::Snapshot &globalSnapshot) : m_globalSnapshot(globalSnapshot), m_out(stderr) { const QString logFileName = QDir::tempPath() + QString::fromLatin1("/qtc-codemodelinspection.txt"); m_logFile.setFileName(logFileName); if (m_logFile.open(QIODevice::WriteOnly | QIODevice::Text)) { m_out << "Code model inspection log file is \"" << QDir::toNativeSeparators(logFileName) << "\".\n"; m_out.setDevice(&m_logFile); } m_out << "*** START Code Model Inspection Report for "; QString ideRevision; #ifdef IDE_REVISION ideRevision = QLatin1String(" from revision ") + QString::fromLatin1(Core::Constants::IDE_REVISION_STR).left(10); #endif m_out << Core::ICore::versionString() << ideRevision << "\n"; m_out << "Note: This file contains vim fold markers (\"{{{n\"). " "Make use of them via \":set foldmethod=marker\".\n"; } CppCodeModelInspectorDumper::~CppCodeModelInspectorDumper() { m_out << "*** END Code Model Inspection Report\n"; } void CppCodeModelInspectorDumper::dumpProjectInfos( const QList &projectInfos) { const QByteArray i1 = indent(1); const QByteArray i2 = indent(2); const QByteArray i3 = indent(3); const QByteArray i4 = indent(4); m_out << "Projects loaded: " << projectInfos.size() << "{{{1\n"; foreach (const CppModelManagerInterface::ProjectInfo &info, projectInfos) { const QPointer project = info.project(); m_out << i1 << "Project " << project->displayName() << " (" << project->projectFilePath() << "){{{2\n"; const QList projectParts = info.projectParts(); foreach (const ProjectPart::Ptr &part, projectParts) { QString projectName = QLatin1String(""); QString projectFilePath = QLatin1String(""); if (ProjectExplorer::Project *project = part->project) { projectName = project->displayName(); projectFilePath = project->projectFilePath(); } m_out << i2 << "Project Part \"" << part->projectFile << "\"{{{3\n"; m_out << i3 << "Project Part Name: " << part->displayName << "\n"; m_out << i3 << "Project Name : " << projectName << "\n"; m_out << i3 << "Project File : " << projectFilePath << "\n"; m_out << i3 << "C Version : " << toString(part->cVersion) << "\n"; m_out << i3 << "CXX Version : " << toString(part->cxxVersion) << "\n"; m_out << i3 << "CXX Extensions : " << toString(part->cxxExtensions) << "\n"; m_out << i3 << "Qt Version : " << toString(part->qtVersion) << "\n"; if (!part->files.isEmpty()) { m_out << i3 << "Files:{{{4\n"; foreach (const ProjectFile &projectFile, part->files) { m_out << i4 << toString(projectFile.kind) << ": " << projectFile.path << "\n"; } } if (!part->toolchainDefines.isEmpty()) { m_out << i3 << "Toolchain Defines:{{{4\n"; const QList defineLines = part->toolchainDefines.split('\n'); foreach (const QByteArray &defineLine, defineLines) m_out << i4 << defineLine << "\n"; } if (!part->projectDefines.isEmpty()) { m_out << i3 << "Project Defines:{{{4\n"; const QList defineLines = part->projectDefines.split('\n'); foreach (const QByteArray &defineLine, defineLines) m_out << i4 << defineLine << "\n"; } if (!part->includePaths.isEmpty()) { m_out << i3 << "Include Paths:{{{4\n"; foreach (const QString &includePath, part->includePaths) m_out << i4 << includePath << "\n"; } if (!part->frameworkPaths.isEmpty()) { m_out << i3 << "Framework Paths:{{{4\n"; foreach (const QString &frameworkPath, part->frameworkPaths) m_out << i4 << frameworkPath << "\n"; } if (!part->precompiledHeaders.isEmpty()) { m_out << i3 << "Precompiled Headers:{{{4\n"; foreach (const QString &precompiledHeader, part->precompiledHeaders) m_out << i4 << precompiledHeader << "\n"; } } // for part } // for project Info } void CppCodeModelInspectorDumper::dumpSnapshot(const CPlusPlus::Snapshot &snapshot, const QString &title, bool isGlobalSnapshot) { m_out << "Snapshot \"" << title << "\"{{{1\n"; const QByteArray i1 = indent(1); const QList documents = snapshotToList(snapshot); if (isGlobalSnapshot) { if (!documents.isEmpty()) { m_out << i1 << "Globally-Shared documents{{{2\n"; dumpDocuments(documents, false); } } else { // Divide into shared and not shared QList globallyShared; QList notGloballyShared; foreach (const CPlusPlus::Document::Ptr &document, documents) { CPlusPlus::Document::Ptr globalDocument = m_globalSnapshot.document(document->fileName()); if (globalDocument && globalDocument->fingerprint() == document->fingerprint()) globallyShared.append(document); else notGloballyShared.append(document); } if (!notGloballyShared.isEmpty()) { m_out << i1 << "Not-Globally-Shared documents:{{{2\n"; dumpDocuments(notGloballyShared); } if (!globallyShared.isEmpty()) { m_out << i1 << "Globally-Shared documents{{{2\n"; dumpDocuments(globallyShared, true); } } } void CppCodeModelInspectorDumper::dumpWorkingCopy( const CppModelManagerInterface::WorkingCopy &workingCopy) { m_out << "Working Copy contains " << workingCopy.size() << " entries{{{1\n"; const QByteArray i1 = indent(1); QHashIterator > it = workingCopy.iterator(); while (it.hasNext()) { it.next(); const QString filePath = it.key(); unsigned sourcRevision = it.value().second; m_out << i1 << "rev=" << sourcRevision << ", " << filePath << "\n"; } } void CppCodeModelInspectorDumper::dumpDocuments(const QList &documents, bool skipDetails) { const QByteArray i2 = indent(2); const QByteArray i3 = indent(3); const QByteArray i4 = indent(4); foreach (const CPlusPlus::Document::Ptr &document, documents) { if (skipDetails) { m_out << i2 << "\"" << document->fileName() << "\"\n"; continue; } m_out << i2 << "Document \"" << document->fileName() << "\"{{{3\n"; m_out << i3 << "Last Modified : " << toString(document->lastModified()) << "\n"; m_out << i3 << "Revision : " << toString(document->revision()) << "\n"; m_out << i3 << "Editor Revision: " << toString(document->editorRevision()) << "\n"; m_out << i3 << "Check Mode : " << toString(document->checkMode()) << "\n"; m_out << i3 << "Tokenized : " << toString(document->isTokenized()) << "\n"; m_out << i3 << "Parsed : " << toString(document->isParsed()) << "\n"; m_out << i3 << "Project Parts : " << partsForFile(document->fileName()) << "\n"; const QList includes = document->unresolvedIncludes() + document->resolvedIncludes(); if (!includes.isEmpty()) { m_out << i3 << "Includes:{{{4\n"; foreach (const CPlusPlus::Document::Include &include, includes) { m_out << i4 << "at line " << include.line() << ": " << unresolvedFileNameWithDelimiters(include) << " ==> " << include.resolvedFileName() << "\n"; } } const QList diagnosticMessages = document->diagnosticMessages(); if (!diagnosticMessages.isEmpty()) { m_out << i3 << "Diagnostic Messages:{{{4\n"; foreach (const CPlusPlus::Document::DiagnosticMessage &msg, diagnosticMessages) { const CPlusPlus::Document::DiagnosticMessage::Level level = static_cast(msg.level()); m_out << i4 << "at " << msg.line() << ":" << msg.column() << ", " << toString(level) << ": " << msg.text() << "\n"; } } const QList macroDefinitions = document->definedMacros(); if (!macroDefinitions.isEmpty()) { m_out << i3 << "(Un)Defined Macros:{{{4\n"; foreach (const CPlusPlus::Macro ¯o, macroDefinitions) m_out << i4 << "at line " << macro.line() << ": " << macro.toString() << "\n"; } const QList macroUses = document->macroUses(); if (!macroUses.isEmpty()) { m_out << i3 << "Macro Uses:{{{4\n"; foreach (const CPlusPlus::Document::MacroUse &use, macroUses) { const QString type = use.isFunctionLike() ? QLatin1String("function-like") : QLatin1String("object-like"); m_out << i4 << "at line " << use.beginLine() << ", " << QString::fromUtf8(use.macro().name()) << ", begin=" << use.begin() << ", end=" << use.end() << ", " << type << ", args=" << use.arguments().size() << "\n"; } } const QString source = QString::fromUtf8(document->utf8Source()); if (!source.isEmpty()) { m_out << i4 << "Source:{{{4\n"; m_out << source; m_out << "\n<< 1) indent += basicIndent; return indent; } } // anonymous namespace namespace CppEditor { namespace Internal { // --- FilterableView ----------------------------------------------------------------------------- class FilterableView : public QWidget { Q_OBJECT public: FilterableView(QWidget *parent); void setModel(QAbstractItemModel *model); QItemSelectionModel *selectionModel() const; void selectIndex(const QModelIndex &index); void resizeColumns(int columnCount); signals: void filterChanged(const QString &filterText); public slots: void clearFilter(); private: QTreeView *view; QLineEdit *lineEdit; }; FilterableView::FilterableView(QWidget *parent) : QWidget(parent) { view = new QTreeView(this); view->setAlternatingRowColors(true); view->setTextElideMode(Qt::ElideMiddle); view->setSortingEnabled(true); lineEdit = new QLineEdit(this); lineEdit->setPlaceholderText(QLatin1String("File Path")); QObject::connect(lineEdit, SIGNAL(textChanged(QString)), SIGNAL(filterChanged(QString))); QLabel *label = new QLabel(QLatin1String("&Filter:"), this); label->setBuddy(lineEdit); QPushButton *clearButton = new QPushButton(QLatin1String("&Clear"), this); QObject::connect(clearButton, SIGNAL(clicked()), SLOT(clearFilter())); QHBoxLayout *filterBarLayout = new QHBoxLayout(); filterBarLayout->addWidget(label); filterBarLayout->addWidget(lineEdit); filterBarLayout->addWidget(clearButton); QVBoxLayout *mainLayout = new QVBoxLayout(); mainLayout->addWidget(view); mainLayout->addLayout(filterBarLayout); setLayout(mainLayout); } void FilterableView::setModel(QAbstractItemModel *model) { view->setModel(model); } QItemSelectionModel *FilterableView::selectionModel() const { return view->selectionModel(); } void FilterableView::selectIndex(const QModelIndex &index) { if (index.isValid()) { view->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } } void FilterableView::resizeColumns(int columnCount) { for (int column = 0; column < columnCount - 1; ++column) view->resizeColumnToContents(column); } void FilterableView::clearFilter() { lineEdit->clear(); } // --- KeyValueModel ------------------------------------------------------------------------------ class KeyValueModel : public QAbstractListModel { Q_OBJECT public: typedef QList > Table; KeyValueModel(QObject *parent); void configure(const Table &table); void clear(); enum Columns { KeyColumn, ValueColumn, ColumnCount }; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: Table m_table; }; KeyValueModel::KeyValueModel(QObject *parent) : QAbstractListModel(parent) { } void KeyValueModel::configure(const Table &table) { emit layoutAboutToBeChanged(); m_table = table; emit layoutChanged(); } void KeyValueModel::clear() { emit layoutAboutToBeChanged(); m_table.clear(); emit layoutChanged(); } int KeyValueModel::rowCount(const QModelIndex &/*parent*/) const { return m_table.size(); } int KeyValueModel::columnCount(const QModelIndex &/*parent*/) const { return KeyValueModel::ColumnCount; } QVariant KeyValueModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { const int row = index.row(); const int column = index.column(); if (column == KeyColumn) { return m_table.at(row).first; } else if (column == ValueColumn) { return m_table.at(row).second; } } return QVariant(); } QVariant KeyValueModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case KeyColumn: return QLatin1String("Key"); case ValueColumn: return QLatin1String("Value"); default: return QVariant(); } } return QVariant(); } // --- SnapshotModel ------------------------------------------------------------------------------ class SnapshotModel : public QAbstractListModel { Q_OBJECT public: SnapshotModel(QObject *parent); void configure(const CPlusPlus::Snapshot &snapshot); void setGlobalSnapshot(const CPlusPlus::Snapshot &snapshot); QModelIndex indexForDocument(const QString &filePath); enum Columns { SymbolCountColumn, SharedColumn, FilePathColumn, ColumnCount }; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: QList m_documents; CPlusPlus::Snapshot m_globalSnapshot; }; SnapshotModel::SnapshotModel(QObject *parent) : QAbstractListModel(parent) { } void SnapshotModel::configure(const CPlusPlus::Snapshot &snapshot) { emit layoutAboutToBeChanged(); m_documents = snapshotToList(snapshot); emit layoutChanged(); } void SnapshotModel::setGlobalSnapshot(const CPlusPlus::Snapshot &snapshot) { m_globalSnapshot = snapshot; } QModelIndex SnapshotModel::indexForDocument(const QString &filePath) { for (int i = 0, total = m_documents.size(); i < total; ++i) { const CPlusPlus::Document::Ptr document = m_documents.at(i); if (document->fileName() == filePath) return index(i, FilePathColumn); } return QModelIndex(); } int SnapshotModel::rowCount(const QModelIndex &/*parent*/) const { return m_documents.size(); } int SnapshotModel::columnCount(const QModelIndex &/*parent*/) const { return SnapshotModel::ColumnCount; } QVariant SnapshotModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { const int column = index.column(); CPlusPlus::Document::Ptr document = m_documents.at(index.row()); if (column == SymbolCountColumn) { return document->control()->symbolCount(); } else if (column == SharedColumn) { CPlusPlus::Document::Ptr globalDocument = m_globalSnapshot.document(document->fileName()); const bool isShared = globalDocument && globalDocument->fingerprint() == document->fingerprint(); return toString(isShared); } else if (column == FilePathColumn) { return QDir::toNativeSeparators(document->fileName()); } } return QVariant(); } QVariant SnapshotModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case SymbolCountColumn: return QLatin1String("Symbols"); case SharedColumn: return QLatin1String("Shared"); case FilePathColumn: return QLatin1String("File Path"); default: return QVariant(); } } return QVariant(); } // --- IncludesModel ------------------------------------------------------------------------------ static bool includesSorter(const CPlusPlus::Document::Include &i1, const CPlusPlus::Document::Include &i2) { return i1.line() < i2.line(); } class IncludesModel : public QAbstractListModel { Q_OBJECT public: IncludesModel(QObject *parent); void configure(const QList &includes); void clear(); enum Columns { ResolvedOrNotColumn, LineNumberColumn, FilePathsColumn, ColumnCount }; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: QList m_includes; }; IncludesModel::IncludesModel(QObject *parent) : QAbstractListModel(parent) { } void IncludesModel::configure(const QList &includes) { emit layoutAboutToBeChanged(); m_includes = includes; qStableSort(m_includes.begin(), m_includes.end(), includesSorter); emit layoutChanged(); } void IncludesModel::clear() { emit layoutAboutToBeChanged(); m_includes.clear(); emit layoutChanged(); } int IncludesModel::rowCount(const QModelIndex &/*parent*/) const { return m_includes.size(); } int IncludesModel::columnCount(const QModelIndex &/*parent*/) const { return IncludesModel::ColumnCount; } QVariant IncludesModel::data(const QModelIndex &index, int role) const { if (role != Qt::DisplayRole && role != Qt::ForegroundRole) return QVariant(); static const QBrush greenBrush(QColor(0, 139, 69)); static const QBrush redBrush(QColor(205, 38, 38)); const CPlusPlus::Document::Include include = m_includes.at(index.row()); const QString resolvedFileName = QDir::toNativeSeparators(include.resolvedFileName()); const bool isResolved = !resolvedFileName.isEmpty(); if (role == Qt::DisplayRole) { const int column = index.column(); if (column == ResolvedOrNotColumn) { return toString(isResolved); } else if (column == LineNumberColumn) { return include.line(); } else if (column == FilePathsColumn) { return QVariant(unresolvedFileNameWithDelimiters(include) + QLatin1String(" --> ") + resolvedFileName); } } else if (role == Qt::ForegroundRole) { return isResolved ? greenBrush : redBrush; } return QVariant(); } QVariant IncludesModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case ResolvedOrNotColumn: return QLatin1String("Resolved"); case LineNumberColumn: return QLatin1String("Line"); case FilePathsColumn: return QLatin1String("File Paths"); default: return QVariant(); } } return QVariant(); } // --- DiagnosticMessagesModel -------------------------------------------------------------------- static bool diagnosticMessagesModelSorter(const CPlusPlus::Document::DiagnosticMessage &m1, const CPlusPlus::Document::DiagnosticMessage &m2) { return m1.line() < m2.line(); } class DiagnosticMessagesModel : public QAbstractListModel { Q_OBJECT public: DiagnosticMessagesModel(QObject *parent); void configure(const QList &messages); void clear(); enum Columns { LevelColumn, LineColumnNumberColumn, MessageColumn, ColumnCount }; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: QList m_messages; }; DiagnosticMessagesModel::DiagnosticMessagesModel(QObject *parent) : QAbstractListModel(parent) { } void DiagnosticMessagesModel::configure( const QList &messages) { emit layoutAboutToBeChanged(); m_messages = messages; qStableSort(m_messages.begin(), m_messages.end(), diagnosticMessagesModelSorter); emit layoutChanged(); } void DiagnosticMessagesModel::clear() { emit layoutAboutToBeChanged(); m_messages.clear(); emit layoutChanged(); } int DiagnosticMessagesModel::rowCount(const QModelIndex &/*parent*/) const { return m_messages.size(); } int DiagnosticMessagesModel::columnCount(const QModelIndex &/*parent*/) const { return DiagnosticMessagesModel::ColumnCount; } QVariant DiagnosticMessagesModel::data(const QModelIndex &index, int role) const { if (role != Qt::DisplayRole && role != Qt::ForegroundRole) return QVariant(); static const QBrush yellowOrangeBrush(QColor(237, 145, 33)); static const QBrush redBrush(QColor(205, 38, 38)); static const QBrush darkRedBrushQColor(QColor(139, 0, 0)); const CPlusPlus::Document::DiagnosticMessage message = m_messages.at(index.row()); const CPlusPlus::Document::DiagnosticMessage::Level level = static_cast(message.level()); if (role == Qt::DisplayRole) { const int column = index.column(); if (column == LevelColumn) { return toString(level); } else if (column == LineColumnNumberColumn) { return QVariant(QString::number(message.line()) + QLatin1Char(':') + QString::number(message.column())); } else if (column == MessageColumn) { return message.text(); } } else if (role == Qt::ForegroundRole) { switch (level) { case CPlusPlus::Document::DiagnosticMessage::Warning: return yellowOrangeBrush; case CPlusPlus::Document::DiagnosticMessage::Error: return redBrush; case CPlusPlus::Document::DiagnosticMessage::Fatal: return darkRedBrushQColor; default: return QVariant(); } } return QVariant(); } QVariant DiagnosticMessagesModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case LevelColumn: return QLatin1String("Level"); case LineColumnNumberColumn: return QLatin1String("Line:Column"); case MessageColumn: return QLatin1String("Message"); default: return QVariant(); } } return QVariant(); } // --- MacrosModel -------------------------------------------------------------------------------- class MacrosModel : public QAbstractListModel { Q_OBJECT public: MacrosModel(QObject *parent); void configure(const QList ¯os); void clear(); enum Columns { LineNumberColumn, MacroColumn, ColumnCount }; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: QList m_macros; }; MacrosModel::MacrosModel(QObject *parent) : QAbstractListModel(parent) { } void MacrosModel::configure(const QList ¯os) { emit layoutAboutToBeChanged(); m_macros = macros; emit layoutChanged(); } void MacrosModel::clear() { emit layoutAboutToBeChanged(); m_macros.clear(); emit layoutChanged(); } int MacrosModel::rowCount(const QModelIndex &/*parent*/) const { return m_macros.size(); } int MacrosModel::columnCount(const QModelIndex &/*parent*/) const { return MacrosModel::ColumnCount; } QVariant MacrosModel::data(const QModelIndex &index, int role) const { const int column = index.column(); if (role == Qt::DisplayRole || (role == Qt::ToolTipRole && column == MacroColumn)) { const CPlusPlus::Macro macro = m_macros.at(index.row()); if (column == LineNumberColumn) return macro.line(); else if (column == MacroColumn) return macro.toString(); } else if (role == Qt::TextAlignmentRole) { return Qt::AlignTop + Qt::AlignLeft; } return QVariant(); } QVariant MacrosModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case LineNumberColumn: return QLatin1String("Line"); case MacroColumn: return QLatin1String("Macro"); default: return QVariant(); } } return QVariant(); } // --- SymbolsModel ------------------------------------------------------------------------------- class SymbolsModel : public QAbstractItemModel { Q_OBJECT public: SymbolsModel(QObject *parent); void configure(const CPlusPlus::Document::Ptr &document); void clear(); enum Columns { SymbolColumn, LineNumberColumn, ColumnCount }; QModelIndex index(int row, int column, const QModelIndex &parent) const; QModelIndex parent(const QModelIndex &child) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: CPlusPlus::Document::Ptr m_document; }; SymbolsModel::SymbolsModel(QObject *parent) : QAbstractItemModel(parent) { } void SymbolsModel::configure(const CPlusPlus::Document::Ptr &document) { QTC_CHECK(document); emit layoutAboutToBeChanged(); m_document = document; emit layoutChanged(); } void SymbolsModel::clear() { emit layoutAboutToBeChanged(); m_document.clear(); emit layoutChanged(); } static CPlusPlus::Symbol *indexToSymbol(const QModelIndex &index) { if (CPlusPlus::Symbol *symbol = static_cast(index.internalPointer())) return symbol; return 0; } static CPlusPlus::Scope *indexToScope(const QModelIndex &index) { if (CPlusPlus::Symbol *symbol = indexToSymbol(index)) return symbol->asScope(); return 0; } QModelIndex SymbolsModel::index(int row, int column, const QModelIndex &parent) const { CPlusPlus::Scope *scope = 0; if (parent.isValid()) scope = indexToScope(parent); else if (m_document) scope = m_document->globalNamespace(); if (scope) { if ((unsigned)row < scope->memberCount()) return createIndex(row, column, scope->memberAt(row)); } return QModelIndex(); } QModelIndex SymbolsModel::parent(const QModelIndex &child) const { if (!child.isValid()) return QModelIndex(); if (CPlusPlus::Symbol *symbol = indexToSymbol(child)) { if (CPlusPlus::Scope *scope = symbol->enclosingScope()) { const int row = DepthFinder()(m_document, scope); return createIndex(row, 0, scope); } } return QModelIndex(); } int SymbolsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { if (CPlusPlus::Scope *scope = indexToScope(parent)) return scope->memberCount(); } else { if (m_document) return m_document->globalNamespace()->memberCount(); } return 0; } int SymbolsModel::columnCount(const QModelIndex &) const { return ColumnCount; } QVariant SymbolsModel::data(const QModelIndex &index, int role) const { const int column = index.column(); if (role == Qt::DisplayRole) { CPlusPlus::Symbol *symbol = indexToSymbol(index); if (!symbol) return QVariant(); if (column == LineNumberColumn) { return symbol->line(); } else if (column == SymbolColumn) { QString name = CPlusPlus::Overview().prettyName(symbol->name()); if (name.isEmpty()) name = QLatin1String(""); return name; } } return QVariant(); } QVariant SymbolsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case SymbolColumn: return QLatin1String("Symbol"); case LineNumberColumn: return QLatin1String("Line"); default: return QVariant(); } } return QVariant(); } // --- TokensModel -------------------------------------------------------------------------------- class TokensModel : public QAbstractListModel { Q_OBJECT public: TokensModel(QObject *parent); void configure(CPlusPlus::TranslationUnit *translationUnit); void clear(); enum Columns { SpelledColumn, KindColumn, IndexColumn, OffsetColumn, LineColumnNumberColumn, LengthColumn, GeneratedColumn, ExpandedColumn, WhiteSpaceColumn, NewlineColumn, ColumnCount }; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: struct TokenInfo { CPlusPlus::Token token; unsigned line; unsigned column; }; QList m_tokenInfos; }; TokensModel::TokensModel(QObject *parent) : QAbstractListModel(parent) { } void TokensModel::configure(CPlusPlus::TranslationUnit *translationUnit) { if (!translationUnit) return; emit layoutAboutToBeChanged(); m_tokenInfos.clear(); for (int i = 0, total = translationUnit->tokenCount(); i < total; ++i) { TokenInfo info; info.token = translationUnit->tokenAt(i); translationUnit->getPosition(info.token.offset, &info.line, &info.column); m_tokenInfos.append(info); } emit layoutChanged(); } void TokensModel::clear() { emit layoutAboutToBeChanged(); m_tokenInfos.clear(); emit layoutChanged(); } int TokensModel::rowCount(const QModelIndex &/*parent*/) const { return m_tokenInfos.size(); } int TokensModel::columnCount(const QModelIndex &/*parent*/) const { return TokensModel::ColumnCount; } QVariant TokensModel::data(const QModelIndex &index, int role) const { const int column = index.column(); if (role == Qt::DisplayRole) { const TokenInfo info = m_tokenInfos.at(index.row()); const CPlusPlus::Token token = info.token; if (column == SpelledColumn) return QString::fromUtf8(token.spell()); else if (column == KindColumn) return toString(static_cast(token.kind())); else if (column == IndexColumn) return index.row(); else if (column == OffsetColumn) return token.offset; else if (column == LineColumnNumberColumn) return QString::fromLatin1("%1:%2").arg(toString(info.line), toString(info.column)); else if (column == LengthColumn) return toString(token.length()); else if (column == GeneratedColumn) return toString(token.generated()); else if (column == ExpandedColumn) return toString(token.expanded()); else if (column == WhiteSpaceColumn) return toString(token.whitespace()); else if (column == NewlineColumn) return toString(token.newline()); } else if (role == Qt::TextAlignmentRole) { return Qt::AlignTop + Qt::AlignLeft; } return QVariant(); } QVariant TokensModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case SpelledColumn: return QLatin1String("Spelled"); case KindColumn: return QLatin1String("Kind"); case IndexColumn: return QLatin1String("Index"); case OffsetColumn: return QLatin1String("Offset"); case LineColumnNumberColumn: return QLatin1String("Line:Column"); case LengthColumn: return QLatin1String("Length"); case GeneratedColumn: return QLatin1String("Generated"); case ExpandedColumn: return QLatin1String("Expanded"); case WhiteSpaceColumn: return QLatin1String("Whitespace"); case NewlineColumn: return QLatin1String("Newline"); default: return QVariant(); } } return QVariant(); } // --- ProjectPartsModel -------------------------------------------------------------------------- class ProjectPartsModel : public QAbstractListModel { Q_OBJECT public: ProjectPartsModel(QObject *parent); void configure(const QList &projectInfos, const ProjectPart::Ptr ¤tEditorsProjectPart); QModelIndex indexForCurrentEditorsProjectPart() const; ProjectPart::Ptr projectPartForProjectFile(const QString &projectFilePath) const; enum Columns { PartNameColumn, PartFilePathColumn, ColumnCount }; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: QList m_projectPartsList; int m_currentEditorsProjectPartIndex; }; ProjectPartsModel::ProjectPartsModel(QObject *parent) : QAbstractListModel(parent), m_currentEditorsProjectPartIndex(-1) { } void ProjectPartsModel::configure(const QList &projectInfos, const ProjectPart::Ptr ¤tEditorsProjectPart) { emit layoutAboutToBeChanged(); m_projectPartsList.clear(); foreach (const CppModelManagerInterface::ProjectInfo &info, projectInfos) { foreach (const ProjectPart::Ptr &projectPart, info.projectParts()) { if (!m_projectPartsList.contains(projectPart)) { m_projectPartsList << projectPart; if (projectPart == currentEditorsProjectPart) m_currentEditorsProjectPartIndex = m_projectPartsList.size() - 1; } } } emit layoutChanged(); } QModelIndex ProjectPartsModel::indexForCurrentEditorsProjectPart() const { if (m_currentEditorsProjectPartIndex == -1) return QModelIndex(); return createIndex(m_currentEditorsProjectPartIndex, PartFilePathColumn); } ProjectPart::Ptr ProjectPartsModel::projectPartForProjectFile(const QString &projectFilePath) const { foreach (const ProjectPart::Ptr &part, m_projectPartsList) { if (part->projectFile == projectFilePath) return part; } return ProjectPart::Ptr(); } int ProjectPartsModel::rowCount(const QModelIndex &/*parent*/) const { return m_projectPartsList.size(); } int ProjectPartsModel::columnCount(const QModelIndex &/*parent*/) const { return ProjectPartsModel::ColumnCount; } QVariant ProjectPartsModel::data(const QModelIndex &index, int role) const { const int row = index.row(); if (role == Qt::DisplayRole) { const int column = index.column(); if (column == PartNameColumn) return m_projectPartsList.at(row)->displayName; else if (column == PartFilePathColumn) return QDir::toNativeSeparators(m_projectPartsList.at(row)->projectFile); } return QVariant(); } QVariant ProjectPartsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case PartNameColumn: return QLatin1String("Name"); case PartFilePathColumn: return QLatin1String("Project File Path"); default: return QVariant(); } } return QVariant(); } // --- WorkingCopyModel --------------------------------------------------------------------------- class WorkingCopyModel : public QAbstractListModel { Q_OBJECT public: WorkingCopyModel(QObject *parent); void configure(const CppModelManagerInterface::WorkingCopy &workingCopy); QModelIndex indexForFile(const QString &filePath); enum Columns { RevisionColumn, FilePathColumn, ColumnCount }; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: struct WorkingCopyEntry { WorkingCopyEntry(const QString &filePath, const QByteArray &source, unsigned revision) : filePath(filePath), source(source), revision(revision) {} QString filePath; QByteArray source; unsigned revision; }; QList m_workingCopyList; }; WorkingCopyModel::WorkingCopyModel(QObject *parent) : QAbstractListModel(parent) { } void WorkingCopyModel::configure(const CppModelManagerInterface::WorkingCopy &workingCopy) { emit layoutAboutToBeChanged(); m_workingCopyList.clear(); QHashIterator > it = workingCopy.iterator(); while (it.hasNext()) { it.next(); m_workingCopyList << WorkingCopyEntry(it.key(), it.value().first, it.value().second); } emit layoutChanged(); } QModelIndex WorkingCopyModel::indexForFile(const QString &filePath) { for (int i = 0, total = m_workingCopyList.size(); i < total; ++i) { const WorkingCopyEntry entry = m_workingCopyList.at(i); if (entry.filePath == filePath) return index(i, FilePathColumn); } return QModelIndex(); } int WorkingCopyModel::rowCount(const QModelIndex &/*parent*/) const { return m_workingCopyList.size(); } int WorkingCopyModel::columnCount(const QModelIndex &/*parent*/) const { return WorkingCopyModel::ColumnCount; } QVariant WorkingCopyModel::data(const QModelIndex &index, int role) const { const int row = index.row(); if (role == Qt::DisplayRole) { const int column = index.column(); if (column == RevisionColumn) return m_workingCopyList.at(row).revision; else if (column == FilePathColumn) return m_workingCopyList.at(row).filePath; } else if (role == Qt::UserRole) { return m_workingCopyList.at(row).source; } return QVariant(); } QVariant WorkingCopyModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case RevisionColumn: return QLatin1String("Revision"); case FilePathColumn: return QLatin1String("File Path"); default: return QVariant(); } } return QVariant(); } // --- SnapshotInfo ------------------------------------------------------------------------------- class SnapshotInfo { public: enum Type { GlobalSnapshot, EditorSnapshot }; SnapshotInfo(const CPlusPlus::Snapshot &snapshot, Type type) : snapshot(snapshot), type(type) {} CPlusPlus::Snapshot snapshot; Type type; }; // --- CppCodeModelInspectorDialog ---------------------------------------------------------------- CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent) : QDialog(parent) , m_ui(new Ui::CppCodeModelInspectorDialog) , m_snapshotInfos(new QList()) , m_snapshotView(new FilterableView(this)) , m_snapshotModel(new SnapshotModel(this)) , m_proxySnapshotModel(new QSortFilterProxyModel(this)) , m_docGenericInfoModel(new KeyValueModel(this)) , m_docIncludesModel(new IncludesModel(this)) , m_docDiagnosticMessagesModel(new DiagnosticMessagesModel(this)) , m_docMacrosModel(new MacrosModel(this)) , m_docSymbolsModel(new SymbolsModel(this)) , m_docTokensModel(new TokensModel(this)) , m_projectPartsView(new FilterableView(this)) , m_projectPartsModel(new ProjectPartsModel(this)) , m_proxyProjectPartsModel(new QSortFilterProxyModel(this)) , m_partGenericInfoModel(new KeyValueModel(this)) , m_workingCopyView(new FilterableView(this)) , m_workingCopyModel(new WorkingCopyModel(this)) , m_proxyWorkingCopyModel(new QSortFilterProxyModel(this)) { m_ui->setupUi(this); m_ui->snapshotSelectorAndViewLayout->addWidget(m_snapshotView); m_ui->projectPartsSplitter->insertWidget(0, m_projectPartsView); m_ui->workingCopySplitter->insertWidget(0, m_workingCopyView); setAttribute(Qt::WA_DeleteOnClose); connect(Core::ICore::instance(), SIGNAL(coreAboutToClose()), SLOT(close())); m_proxySnapshotModel->setSourceModel(m_snapshotModel); m_proxySnapshotModel->setFilterKeyColumn(SnapshotModel::FilePathColumn); m_snapshotView->setModel(m_proxySnapshotModel); m_ui->docGeneralView->setModel(m_docGenericInfoModel); m_ui->docIncludesView->setModel(m_docIncludesModel); m_ui->docDiagnosticMessagesView->setModel(m_docDiagnosticMessagesModel); m_ui->docDefinedMacrosView->setModel(m_docMacrosModel); m_ui->docSymbolsView->setModel(m_docSymbolsModel); m_ui->docTokensView->setModel(m_docTokensModel); m_proxyProjectPartsModel->setSourceModel(m_projectPartsModel); m_proxyProjectPartsModel->setFilterKeyColumn(ProjectPartsModel::PartFilePathColumn); m_projectPartsView->setModel(m_proxyProjectPartsModel); m_ui->partGeneralView->setModel(m_partGenericInfoModel); m_proxyWorkingCopyModel->setSourceModel(m_workingCopyModel); m_proxyWorkingCopyModel->setFilterKeyColumn(WorkingCopyModel::FilePathColumn); m_workingCopyView->setModel(m_proxyWorkingCopyModel); connect(m_snapshotView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex ,QModelIndex)), SLOT(onDocumentSelected(QModelIndex, QModelIndex))); connect(m_snapshotView, SIGNAL(filterChanged(QString)), SLOT(onSnapshotFilterChanged(QString))); connect(m_ui->snapshotSelector, SIGNAL(currentIndexChanged(int)), SLOT(onSnapshotSelected(int))); connect(m_ui->docSymbolsView, SIGNAL(expanded(QModelIndex)), SLOT(onSymbolsViewExpandedOrCollapsed(QModelIndex))); connect(m_ui->docSymbolsView, SIGNAL(collapsed(QModelIndex)), SLOT(onSymbolsViewExpandedOrCollapsed(QModelIndex))); connect(m_projectPartsView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex ,QModelIndex)), SLOT(onProjectPartSelected(QModelIndex, QModelIndex))); connect(m_projectPartsView, SIGNAL(filterChanged(QString)), SLOT(onProjectPartFilterChanged(QString))); connect(m_workingCopyView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex ,QModelIndex)), SLOT(onWorkingCopyDocumentSelected(QModelIndex, QModelIndex))); connect(m_workingCopyView, SIGNAL(filterChanged(QString)), SLOT(onWorkingCopyFilterChanged(QString))); connect(m_ui->refreshButton, SIGNAL(clicked()), SLOT(onRefreshRequested())); connect(m_ui->closeButton, SIGNAL(clicked()), SLOT(close())); refresh(); } CppCodeModelInspectorDialog::~CppCodeModelInspectorDialog() { delete m_snapshotInfos; delete m_ui; } void CppCodeModelInspectorDialog::onRefreshRequested() { refresh(); } void CppCodeModelInspectorDialog::onSnapshotFilterChanged(const QString &pattern) { m_proxySnapshotModel->setFilterWildcard(pattern); } void CppCodeModelInspectorDialog::onSnapshotSelected(int row) { if (row < 0 || row >= m_snapshotInfos->size()) return; m_snapshotView->clearFilter(); const SnapshotInfo info = m_snapshotInfos->at(row); m_snapshotModel->configure(info.snapshot); m_snapshotView->resizeColumns(SnapshotModel::ColumnCount); if (info.type == SnapshotInfo::GlobalSnapshot) { // Select first document const QModelIndex index = m_proxySnapshotModel->index(0, SnapshotModel::FilePathColumn); m_snapshotView->selectIndex(index); } else if (info.type == SnapshotInfo::EditorSnapshot) { // Select first document, unless we can find the editor document QModelIndex index = m_snapshotModel->indexForDocument(fileInCurrentEditor()); index = m_proxySnapshotModel->mapFromSource(index); if (!index.isValid()) index = m_proxySnapshotModel->index(0, SnapshotModel::FilePathColumn); m_snapshotView->selectIndex(index); } } void CppCodeModelInspectorDialog::onDocumentSelected(const QModelIndex ¤t, const QModelIndex &) { if (current.isValid()) { const QModelIndex index = m_proxySnapshotModel->index(current.row(), SnapshotModel::FilePathColumn); const QString filePath = QDir::fromNativeSeparators( m_proxySnapshotModel->data(index, Qt::DisplayRole).toString()); const SnapshotInfo info = m_snapshotInfos->at(m_ui->snapshotSelector->currentIndex()); updateDocumentData(info.snapshot.document(filePath)); } else { clearDocumentData(); } } void CppCodeModelInspectorDialog::onSymbolsViewExpandedOrCollapsed(const QModelIndex &) { resizeColumns(m_ui->docSymbolsView); } void CppCodeModelInspectorDialog::onProjectPartFilterChanged(const QString &pattern) { m_proxyProjectPartsModel->setFilterWildcard(pattern); } void CppCodeModelInspectorDialog::onProjectPartSelected(const QModelIndex ¤t, const QModelIndex &) { if (current.isValid()) { QModelIndex index = m_proxyProjectPartsModel->mapToSource(current); if (index.isValid()) { index = m_projectPartsModel->index(index.row(), ProjectPartsModel::PartFilePathColumn); const QString projectFilePath = QDir::fromNativeSeparators( m_projectPartsModel->data(index, Qt::DisplayRole).toString()); updateProjectPartData(m_projectPartsModel->projectPartForProjectFile(projectFilePath)); } } else { clearProjectPartData(); } } void CppCodeModelInspectorDialog::onWorkingCopyFilterChanged(const QString &pattern) { m_proxyWorkingCopyModel->setFilterWildcard(pattern); } void CppCodeModelInspectorDialog::onWorkingCopyDocumentSelected(const QModelIndex ¤t, const QModelIndex &) { if (current.isValid()) { const QModelIndex index = m_proxyWorkingCopyModel->mapToSource(current); if (index.isValid()) { const QString source = QString::fromUtf8(m_workingCopyModel->data(index, Qt::UserRole).toByteArray()); m_ui->workingCopySourceEdit->setPlainText(source); } } else { m_ui->workingCopySourceEdit->setPlainText(QString()); } } void CppCodeModelInspectorDialog::refresh() { CppModelManagerInterface *cmm = CppModelManagerInterface::instance(); const int oldSnapshotIndex = m_ui->snapshotSelector->currentIndex(); const bool selectEditorRelevant = m_ui->selectEditorRelevantEntriesAfterRefreshCheckBox->isChecked(); // Snapshots and Documents m_snapshotInfos->clear(); m_ui->snapshotSelector->clear(); const CPlusPlus::Snapshot globalSnapshot = cmm->snapshot(); CppCodeModelInspectorDumper dumper(globalSnapshot); m_snapshotModel->setGlobalSnapshot(globalSnapshot); m_snapshotInfos->append(SnapshotInfo(globalSnapshot, SnapshotInfo::GlobalSnapshot)); const QString globalSnapshotTitle = QString::fromLatin1("Global/Indexing Snapshot (%1 Documents)").arg(globalSnapshot.size()); m_ui->snapshotSelector->addItem(globalSnapshotTitle); dumper.dumpSnapshot(globalSnapshot, globalSnapshotTitle, /*isGlobalSnapshot=*/ true); TextEditor::BaseTextEditor *editor = currentEditor(); CppEditorSupport *editorSupport = 0; if (editor) { editorSupport = cmm->cppEditorSupport(editor); if (editorSupport) { const CPlusPlus::Snapshot editorSnapshot = editorSupport->snapshotUpdater()->snapshot(); m_snapshotInfos->append(SnapshotInfo(editorSnapshot, SnapshotInfo::EditorSnapshot)); const QString editorSnapshotTitle = QString::fromLatin1("Current Editor's Snapshot (%1 Documents)") .arg(editorSnapshot.size()); dumper.dumpSnapshot(editorSnapshot, editorSnapshotTitle); m_ui->snapshotSelector->addItem(editorSnapshotTitle); } CppEditor::Internal::CPPEditorWidget *cppEditorWidget = qobject_cast(editor->editorWidget()); if (cppEditorWidget) { SemanticInfo semanticInfo = cppEditorWidget->semanticInfo(); CPlusPlus::Snapshot snapshot; // Add semantic info snapshot snapshot = semanticInfo.snapshot; m_snapshotInfos->append(SnapshotInfo(snapshot, SnapshotInfo::EditorSnapshot)); m_ui->snapshotSelector->addItem( QString::fromLatin1("Current Editor's Semantic Info Snapshot (%1 Documents)") .arg(snapshot.size())); // Add a pseudo snapshot containing only the semantic info document since this document // is not part of the semantic snapshot. snapshot = CPlusPlus::Snapshot(); snapshot.insert(cppEditorWidget->semanticInfo().doc); m_snapshotInfos->append(SnapshotInfo(snapshot, SnapshotInfo::EditorSnapshot)); const QString snapshotTitle = QString::fromLatin1("Current Editor's Pseudo Snapshot with Semantic Info Document (%1 Documents)") .arg(snapshot.size()); dumper.dumpSnapshot(snapshot, snapshotTitle); m_ui->snapshotSelector->addItem(snapshotTitle); } } int snapshotIndex = 0; if (selectEditorRelevant) { for (int i = 0, total = m_snapshotInfos->size(); i < total; ++i) { const SnapshotInfo info = m_snapshotInfos->at(i); if (info.type == SnapshotInfo::EditorSnapshot) { snapshotIndex = i; break; } } } else if (oldSnapshotIndex < m_snapshotInfos->size()) { snapshotIndex = oldSnapshotIndex; } m_ui->snapshotSelector->setCurrentIndex(snapshotIndex); onSnapshotSelected(snapshotIndex); // Project Parts const ProjectPart::Ptr editorsProjectPart = editorSupport ? editorSupport->snapshotUpdater()->currentProjectPart() : ProjectPart::Ptr(); const QList projectInfos = cmm->projectInfos(); dumper.dumpProjectInfos(projectInfos); m_projectPartsModel->configure(projectInfos, editorsProjectPart); m_projectPartsView->resizeColumns(ProjectPartsModel::ColumnCount); QModelIndex index = m_proxyProjectPartsModel->index(0, ProjectPartsModel::PartFilePathColumn); if (index.isValid()) { if (selectEditorRelevant && editorsProjectPart) { QModelIndex editorPartIndex = m_projectPartsModel->indexForCurrentEditorsProjectPart(); editorPartIndex = m_proxyProjectPartsModel->mapFromSource(editorPartIndex); if (editorPartIndex.isValid()) index = editorPartIndex; } m_projectPartsView->selectIndex(index); } // Working Copy const CppModelManagerInterface::WorkingCopy workingCopy = cmm->workingCopy(); dumper.dumpWorkingCopy(workingCopy); m_workingCopyModel->configure(workingCopy); m_workingCopyView->resizeColumns(WorkingCopyModel::ColumnCount); if (workingCopy.size() > 0) { QModelIndex index = m_proxyWorkingCopyModel->index(0, WorkingCopyModel::FilePathColumn); if (selectEditorRelevant) { const QModelIndex eindex = m_workingCopyModel->indexForFile(fileInCurrentEditor()); if (eindex.isValid()) index = m_proxyWorkingCopyModel->mapFromSource(eindex); } m_workingCopyView->selectIndex(index); } } enum DocumentTabs { DocumentGeneralTab, DocumentIncludesTab, DocumentDiagnosticsTab, DocumentDefinedMacrosTab, DocumentPreprocessedSourceTab, DocumentSymbolsTab, DocumentTokensTab }; static QString docTabName(int tabIndex, int numberOfEntries = -1) { const char *names[] = { "&General", "&Includes", "&Diagnostic Messages", "(Un)Defined &Macros", "P&reprocessed Source", "&Symbols", "&Tokens" }; QString result = QLatin1String(names[tabIndex]); if (numberOfEntries != -1) result += QString::fromLatin1(" (%1)").arg(numberOfEntries); return result; } void CppCodeModelInspectorDialog::clearDocumentData() { m_docGenericInfoModel->clear(); m_ui->docTab->setTabText(DocumentIncludesTab, docTabName(DocumentIncludesTab)); m_docIncludesModel->clear(); m_ui->docTab->setTabText(DocumentDiagnosticsTab, docTabName(DocumentDiagnosticsTab)); m_docDiagnosticMessagesModel->clear(); m_ui->docTab->setTabText(DocumentDefinedMacrosTab, docTabName(DocumentDefinedMacrosTab)); m_docMacrosModel->clear(); m_ui->docPreprocessedSourceEdit->setPlainText(QString()); m_docSymbolsModel->clear(); m_ui->docTab->setTabText(DocumentTokensTab, docTabName(DocumentTokensTab)); m_docTokensModel->clear(); } void CppCodeModelInspectorDialog::updateDocumentData(const CPlusPlus::Document::Ptr &document) { QTC_ASSERT(document, return); // General KeyValueModel::Table table = KeyValueModel::Table() << qMakePair(QString::fromLatin1("File Path"), QDir::toNativeSeparators(document->fileName())) << qMakePair(QString::fromLatin1("Last Modified"), toString(document->lastModified())) << qMakePair(QString::fromLatin1("Revision"), toString(document->revision())) << qMakePair(QString::fromLatin1("Editor Revision"), toString(document->editorRevision())) << qMakePair(QString::fromLatin1("Check Mode"), toString(document->checkMode())) << qMakePair(QString::fromLatin1("Tokenized"), toString(document->isTokenized())) << qMakePair(QString::fromLatin1("Parsed"), toString(document->isParsed())) << qMakePair(QString::fromLatin1("Project Parts"), partsForFile(document->fileName())) ; m_docGenericInfoModel->configure(table); resizeColumns(m_ui->docGeneralView); // Includes m_docIncludesModel->configure(document->resolvedIncludes() + document->unresolvedIncludes()); resizeColumns(m_ui->docIncludesView); m_ui->docTab->setTabText(DocumentIncludesTab, docTabName(DocumentIncludesTab, m_docIncludesModel->rowCount())); // Diagnostic Messages m_docDiagnosticMessagesModel->configure(document->diagnosticMessages()); resizeColumns(m_ui->docDiagnosticMessagesView); m_ui->docTab->setTabText(DocumentDiagnosticsTab, docTabName(DocumentDiagnosticsTab, m_docDiagnosticMessagesModel->rowCount())); // Macros m_docMacrosModel->configure(document->definedMacros()); resizeColumns(m_ui->docDefinedMacrosView); m_ui->docTab->setTabText(DocumentDefinedMacrosTab, docTabName(DocumentDefinedMacrosTab, m_docMacrosModel->rowCount())); // Source m_ui->docPreprocessedSourceEdit->setPlainText(QString::fromUtf8(document->utf8Source())); // Symbols m_docSymbolsModel->configure(document); resizeColumns(m_ui->docSymbolsView); // Tokens m_docTokensModel->configure(document->translationUnit()); resizeColumns(m_ui->docTokensView); m_ui->docTab->setTabText(DocumentTokensTab, docTabName(DocumentTokensTab, m_docTokensModel->rowCount())); } enum ProjectPartTabs { ProjectPartGeneralTab, ProjectPartFilesTab, ProjectPartDefinesTab, ProjectPartIncludePathsTab, ProjectPartFrameworkPathsTab, ProjectPartPrecompiledHeadersTab }; static QString partTabName(int tabIndex, int numberOfEntries = -1) { const char *names[] = { "&General", "Project &Files", "&Defines", "&Include Paths", "F&ramework Paths", "Pre&compiled Headers" }; QString result = QLatin1String(names[tabIndex]); if (numberOfEntries != -1) result += QString::fromLatin1(" (%1)").arg(numberOfEntries); return result; } void CppCodeModelInspectorDialog::clearProjectPartData() { m_partGenericInfoModel->clear(); m_ui->partProjectFilesEdit->setPlainText(QString()); m_ui->projectPartTab->setTabText(ProjectPartFilesTab, partTabName(ProjectPartFilesTab)); m_ui->partToolchainDefinesEdit->setPlainText(QString()); m_ui->partProjectDefinesEdit->setPlainText(QString()); m_ui->projectPartTab->setTabText(ProjectPartDefinesTab, partTabName(ProjectPartDefinesTab)); m_ui->partIncludePathsEdit->setPlainText(QString()); m_ui->projectPartTab->setTabText(ProjectPartIncludePathsTab, partTabName(ProjectPartIncludePathsTab)); m_ui->partFrameworkPathsEdit->setPlainText(QString()); m_ui->projectPartTab->setTabText(ProjectPartFrameworkPathsTab, partTabName(ProjectPartFrameworkPathsTab)); m_ui->partPrecompiledHeadersEdit->setPlainText(QString()); m_ui->projectPartTab->setTabText(ProjectPartPrecompiledHeadersTab, partTabName(ProjectPartPrecompiledHeadersTab)); } void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr &part) { QTC_ASSERT(part, return); // General QString projectName = QLatin1String(""); QString projectFilePath = QLatin1String(""); if (ProjectExplorer::Project *project = part->project) { projectName = project->displayName(); projectFilePath = project->projectFilePath(); } KeyValueModel::Table table = KeyValueModel::Table() << qMakePair(QString::fromLatin1("Project Part Name"), part->displayName) << qMakePair(QString::fromLatin1("Project Part File"), QDir::toNativeSeparators(part->projectFile)) << qMakePair(QString::fromLatin1("Project Name"), projectName) << qMakePair(QString::fromLatin1("Project File"), QDir::toNativeSeparators(projectFilePath)) << qMakePair(QString::fromLatin1("C Version"), toString(part->cVersion)) << qMakePair(QString::fromLatin1("CXX Version"), toString(part->cxxVersion)) << qMakePair(QString::fromLatin1("CXX Extensions"), toString(part->cxxExtensions)) << qMakePair(QString::fromLatin1("Qt Version"), toString(part->qtVersion)) ; m_partGenericInfoModel->configure(table); resizeColumns(m_ui->partGeneralView); // Project Files m_ui->partProjectFilesEdit->setPlainText(toString(part->files)); m_ui->projectPartTab->setTabText(ProjectPartFilesTab, partTabName(ProjectPartFilesTab, part->files.size())); // Defines const QList defineLines = part->toolchainDefines.split('\n') + part->projectDefines.split('\n'); int numberOfDefines = 0; foreach (const QByteArray &line, defineLines) { if (line.startsWith("#define ")) ++numberOfDefines; } m_ui->partToolchainDefinesEdit->setPlainText(QString::fromUtf8(part->toolchainDefines)); m_ui->partProjectDefinesEdit->setPlainText(QString::fromUtf8(part->projectDefines)); m_ui->projectPartTab->setTabText(ProjectPartDefinesTab, partTabName(ProjectPartDefinesTab, numberOfDefines)); // Include Paths m_ui->partIncludePathsEdit->setPlainText(pathListToString(part->includePaths)); m_ui->projectPartTab->setTabText(ProjectPartIncludePathsTab, partTabName(ProjectPartIncludePathsTab, part->includePaths.size())); // Framework Paths m_ui->partFrameworkPathsEdit->setPlainText(pathListToString(part->frameworkPaths)); m_ui->projectPartTab->setTabText(ProjectPartFrameworkPathsTab, partTabName(ProjectPartFrameworkPathsTab, part->frameworkPaths.size())); // Precompiled Headers m_ui->partPrecompiledHeadersEdit->setPlainText(pathListToString(part->precompiledHeaders)); m_ui->projectPartTab->setTabText(ProjectPartPrecompiledHeadersTab, partTabName(ProjectPartPrecompiledHeadersTab, part->precompiledHeaders.size())); } bool CppCodeModelInspectorDialog::event(QEvent *e) { if (e->type() == QEvent::ShortcutOverride) { QKeyEvent *ke = static_cast(e); if (ke->key() == Qt::Key_Escape && !ke->modifiers()) { ke->accept(); close(); return false; } } return QDialog::event(e); } } // namespace Internal } // namespace CppEditor #include "cppcodemodelinspectordialog.moc"