RedPanda-CPP/RedPandaIDE/widgets/classbrowser.cpp

353 lines
10 KiB
C++

#include "classbrowser.h"
#include "../utils.h"
#include <QDebug>
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<ClassBrowserNode *>(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<ClassBrowserNode *>(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<ClassBrowserNode *>(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<ClassBrowserNode *>(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<ClassBrowserNode *>(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<ClassBrowserNode *>(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<ClassBrowserNode *>(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<QString> includedFiles = mParser->getFileIncludes(mCurrentFile);
addMembers(includedFiles);
// Remember selection
// if fLastSelection <> '' then
// ReSelect;
}
}
}
}
void ClassBrowserModel::addChild(ClassBrowserNode *node, PStatement statement)
{
PClassBrowserNode newNode = std::make_shared<ClassBrowserNode>();
newNode->parent = node;
newNode->statement = statement;
newNode->childrenFetched = false;
node->children.append(newNode.get());
mNodes.append(newNode);
}
void ClassBrowserModel::addMembers(const QSet<QString> &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<Statement>();
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();
}
}
}