#include "classbrowser.h" #include "../utils.h" #include ClassBrowserModel::ClassBrowserModel(QObject *parent):QAbstractItemModel(parent) { mRoot = new ClassBrowserNode(); mRoot->parent = nullptr; mRoot->statement = PStatement(); mRoot->childrenFetched = true; mUpdating = false; mUpdateCount = 0; mShowInheritedMembers = false; } ClassBrowserModel::~ClassBrowserModel() { delete mRoot; } QModelIndex ClassBrowserModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row,column,parent)) return QModelIndex(); ClassBrowserNode *parentNode; if (!parent.isValid()) { // top level parentNode = mRoot; } else { parentNode = static_cast(parent.internalPointer()); } return createIndex(row,column,parentNode->children[row]); } QModelIndex ClassBrowserModel::parent(const QModelIndex &child) const { if (!child.isValid()) { return QModelIndex(); } ClassBrowserNode *childNode = static_cast(child.internalPointer()); ClassBrowserNode *parentNode = childNode->parent; if (parentNode->parent == nullptr) //it's root node return QModelIndex(); ClassBrowserNode *grandNode = parentNode->parent; int row = grandNode->children.indexOf(parentNode); return createIndex(row,0,parentNode); } bool ClassBrowserModel::hasChildren(const QModelIndex &parent) const { ClassBrowserNode *parentNode; if (!parent.isValid()) { // top level return mRoot->children.count(); } else { parentNode = static_cast(parent.internalPointer()); if (parentNode->childrenFetched) return parentNode->children.count(); if (parentNode->statement) return !parentNode->statement->children.isEmpty(); return false; } } int ClassBrowserModel::rowCount(const QModelIndex &parent) const { ClassBrowserNode *parentNode; if (!parent.isValid()) { // top level parentNode = mRoot; } else { parentNode = static_cast(parent.internalPointer()); } return parentNode->children.count(); } int ClassBrowserModel::columnCount(const QModelIndex&) const { return 1; } void ClassBrowserModel::fetchMore(const QModelIndex &parent) { if (!parent.isValid()) { // top level return; } ClassBrowserNode *parentNode = static_cast(parent.internalPointer()); if (!parentNode->childrenFetched) { parentNode->childrenFetched = true; if (parentNode->statement && !parentNode->statement->children.isEmpty()) { filterChildren(parentNode, parentNode->statement->children); beginInsertRows(parent,0,parentNode->children.count()); endInsertRows(); } } } bool ClassBrowserModel::canFetchMore(const QModelIndex &parent) const { if (!parent.isValid()) { // top level return false; } ClassBrowserNode *parentNode = static_cast(parent.internalPointer()); if (!parentNode->childrenFetched) { if (parentNode->statement && !parentNode->statement->children.isEmpty()) return true; else parentNode->childrenFetched = true; } return false; } QVariant ClassBrowserModel::data(const QModelIndex &index, int role) const { if (!index.isValid()){ return QVariant(); } ClassBrowserNode *node = static_cast(index.internalPointer()); if (!node) return QVariant(); if (role == Qt::DisplayRole) { if (node->statement) { return node->statement->command; } } return QVariant(); } const PCppParser &ClassBrowserModel::parser() const { return mParser; } void ClassBrowserModel::setParser(const PCppParser &newCppParser) { if (mParser) { disconnect(mParser.get(), &CppParser::onEndParsing, this, &ClassBrowserModel::fillStatements); } mParser = newCppParser; if (mParser) { connect(mParser.get(), &CppParser::onEndParsing, this, &ClassBrowserModel::fillStatements); } } void ClassBrowserModel::clear() { beginResetModel(); mRoot->children.clear(); mNodes.clear(); mDummyStatements.clear(); endResetModel(); } void ClassBrowserModel::fillStatements() { { QMutexLocker locker(&mMutex); if (mUpdateCount!=0 || mUpdating) return; mUpdating = true; } beginResetModel(); clear(); { auto action = finally([this]{ endResetModel(); mUpdating = false; }); if (!mParser) return; if (!mParser->enabled()) return; if (!mParser->freeze()) return; { auto action2 = finally([this]{ mParser->unFreeze(); }); QString mParserSerialId = mParser->serialId(); if (!mCurrentFile.isEmpty()) { QSet includedFiles = mParser->getFileIncludes(mCurrentFile); addMembers(includedFiles); // Remember selection // if fLastSelection <> '' then // ReSelect; } } } } void ClassBrowserModel::addChild(ClassBrowserNode *node, PStatement statement) { PClassBrowserNode newNode = std::make_shared(); newNode->parent = node; newNode->statement = statement; newNode->childrenFetched = false; node->children.append(newNode.get()); mNodes.append(newNode); } void ClassBrowserModel::addMembers(const QSet &includedFiles) { // show statements in the file PFileIncludes p = mParser->findFileIncludes(mCurrentFile); if (!p) return; filterChildren(mRoot,p->statements); } void ClassBrowserModel::filterChildren(ClassBrowserNode *node, const StatementMap &statements) { for (PStatement statement:statements) { if (statement->kind == StatementKind::skBlock) continue; if (statement->isInherited && !mShowInheritedMembers) continue; if (statement == node->statement) // prevent infinite recursion continue; if (statement->scope == StatementScope::ssLocal) continue; // if (fStatementsType = cbstProject) then begin // if not Statement^._InProject then // Continue; // if Statement^._Static and not SameText(Statement^._FileName,fCurrentFile) // and not SameText(Statement^._FileName,fCurrentFile) then // Continue; // end; // we only test and handle orphan statements in the top level (node->statement is null) PStatement parentScope = statement->parentScope.lock(); if ((parentScope!=node->statement) && (!node->statement)) { // // we only handle orphan statements when type is cbstFile // if fStatementsType <> cbstFile then // Continue; // //should not happend, just in case of error if (!parentScope) continue; // Processing the orphan statement while (statement) { //the statement's parent is in this file, so it's not a real orphan if ((parentScope->fileName==mCurrentFile) ||(parentScope->definitionFileName==mCurrentFile)) break; PStatement dummyParent = mDummyStatements.value(parentScope->fullName,PStatement()); if (dummyParent) { dummyParent->children.insert(statement->command,statement); break; } dummyParent = createDummy(parentScope); dummyParent->children.insert(statement->command,statement); //we are adding an orphan statement, just add it statement = dummyParent; parentScope = statement->parentScope.lock(); if (!parentScope) { addChild(node,statement); break; } } } else if (statement->kind == StatementKind::skNamespace) { PStatement dummy = mDummyStatements.value(statement->fullName,PStatement()); if (dummy) { for (PStatement child: statement->children) { dummy->children.insert(child->command,child); } continue; } dummy = createDummy(statement); dummy->children = statement->children; addChild(node,dummy); } else { addChild(node,statement); } } // if sortAlphabetically and sortByType then begin // filtered.Sort(@CompareByAlphaAndType); // end else if sortAlphabetically then begin // filtered.Sort(@CompareByAlpha); // end else if sortByType then begin // filtered.Sort(@CompareByType); // end; } PStatement ClassBrowserModel::createDummy(PStatement statement) { PStatement result = std::make_shared(); result->parentScope = statement->parentScope; result->command = statement->command; result->args = statement->args; result->noNameArgs = statement->noNameArgs; result->fullName = statement->fullName; result->kind = statement->kind; result->type = statement->type; result->value = statement->value; result->scope = statement->scope; result->classScope = statement->classScope; result->inProject = statement->inProject; result->inSystemHeader = statement->inSystemHeader; result->isStatic = statement->isStatic; result->isInherited = statement->isInherited; result->fileName = mCurrentFile; result->definitionFileName = mCurrentFile; result->line = 0; result->definitionLine = 0; mDummyStatements.insert(result->fullName,result); return result; } const QString &ClassBrowserModel::currentFile() const { return mCurrentFile; } void ClassBrowserModel::setCurrentFile(const QString &newCurrentFile) { mCurrentFile = newCurrentFile; } void ClassBrowserModel::beginUpdate() { mUpdateCount++; } void ClassBrowserModel::endUpdate() { mUpdateCount--; if (mUpdateCount == 0) { if (!mParser->parsing()) { this->fillStatements(); } } }