diff options
-rw-r--r-- | src/libs/utils/treemodel.h | 3 | ||||
-rw-r--r-- | src/plugins/projectexplorer/expanddata.cpp | 10 | ||||
-rw-r--r-- | src/plugins/projectexplorer/expanddata.h | 4 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projectmodels.cpp | 680 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projectmodels.h | 93 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projectnodes.cpp | 67 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projectnodes.h | 17 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projecttree.cpp | 161 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projecttree.h | 62 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projecttreewidget.cpp | 138 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projecttreewidget.h | 13 | ||||
-rw-r--r-- | src/plugins/projectexplorer/session.cpp | 16 | ||||
-rw-r--r-- | src/plugins/qmakeprojectmanager/qmakenodes.cpp | 9 |
13 files changed, 223 insertions, 1050 deletions
diff --git a/src/libs/utils/treemodel.h b/src/libs/utils/treemodel.h index 6532caaf1e..ba791c1cf8 100644 --- a/src/libs/utils/treemodel.h +++ b/src/libs/utils/treemodel.h @@ -249,13 +249,16 @@ public: explicit TreeModel(QObject *parent = 0) : BaseTreeModel(new RootItem, parent) {} explicit TreeModel(RootItem *root, QObject *parent = 0) : BaseTreeModel(root, parent) {} + using BaseTreeModel::canFetchMore; using BaseTreeModel::clear; using BaseTreeModel::columnCount; using BaseTreeModel::data; using BaseTreeModel::destroyItem; + using BaseTreeModel::fetchMore; using BaseTreeModel::hasChildren; using BaseTreeModel::index; using BaseTreeModel::indexForItem; + using BaseTreeModel::parent; using BaseTreeModel::rowCount; using BaseTreeModel::setData; using BaseTreeModel::setHeader; diff --git a/src/plugins/projectexplorer/expanddata.cpp b/src/plugins/projectexplorer/expanddata.cpp index 9e940aeb27..2322735a76 100644 --- a/src/plugins/projectexplorer/expanddata.cpp +++ b/src/plugins/projectexplorer/expanddata.cpp @@ -37,9 +37,15 @@ bool ExpandData::operator==(const ExpandData &other) const return path == other.path && displayName == other.displayName; } -QStringList ExpandData::toStringList() const +ExpandData ExpandData::fromSettings(const QVariant &v) { - return { path, displayName }; + QStringList list = v.toStringList(); + return list.size() == 2 ? ExpandData(list.at(0), list.at(1)) : ExpandData(); +} + +QVariant ExpandData::toSettings() const +{ + return QVariant::fromValue(QStringList({ path, displayName })); } int ProjectExplorer::Internal::qHash(const ExpandData &data) diff --git a/src/plugins/projectexplorer/expanddata.h b/src/plugins/projectexplorer/expanddata.h index 090007b619..9d6a656449 100644 --- a/src/plugins/projectexplorer/expanddata.h +++ b/src/plugins/projectexplorer/expanddata.h @@ -38,7 +38,9 @@ public: ExpandData() = default; ExpandData(const QString &path_, const QString &displayName_); bool operator==(const ExpandData &other) const; - QStringList toStringList() const; + + static ExpandData fromSettings(const QVariant &v); + QVariant toSettings() const; QString path; QString displayName; diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index e597e23bf7..c4fb0e6e59 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -29,6 +29,7 @@ #include "projectnodes.h" #include "projectexplorer.h" #include "projecttree.h" +#include "session.h" #include <coreplugin/fileiconprovider.h> #include <utils/algorithm.h> @@ -40,15 +41,13 @@ #include <QMimeData> #include <QLoggingCategory> +using namespace Utils; + namespace ProjectExplorer { using namespace Internal; -namespace { - -// sorting helper function - -bool sortNodes(Node *n1, Node *n2) +static bool sortNodes(const Node *n1, const Node *n2) { if (n1->priority() > n2->priority()) return true; @@ -66,78 +65,45 @@ bool sortNodes(Node *n1, Node *n2) return n1 < n2; // sort by pointer value } -} // namespace anon +static bool sortWrapperNodes(const WrapperNode *w1, const WrapperNode *w2) +{ + return sortNodes(w1->m_node, w2->m_node); +} -FlatModel::FlatModel(SessionNode *rootNode, QObject *parent) : QAbstractItemModel(parent), - m_rootNode(rootNode) +FlatModel::FlatModel(QObject *parent) + : TreeModel<WrapperNode, WrapperNode>(new WrapperNode(SessionManager::sessionNode()), parent) { + m_timer.setInterval(200); + connect(&m_timer, &QTimer::timeout, this, &FlatModel::doUpdate); + ProjectTree *tree = ProjectTree::instance(); + connect(tree, &ProjectTree::dataChanged, this, &FlatModel::update); + connect(tree, &ProjectTree::nodeUpdated, this, &FlatModel::nodeUpdated); - connect(tree, &ProjectTree::aboutToChangeShowInSimpleTree, - this, &FlatModel::aboutToShowInSimpleTreeChanged); - - connect(tree, &ProjectTree::showInSimpleTreeChanged, - this, &FlatModel::showInSimpleTreeChanged); - - connect(tree, &ProjectTree::foldersAboutToBeAdded, - this, &FlatModel::foldersAboutToBeAdded); - connect(tree, &ProjectTree::foldersAdded, - this, &FlatModel::foldersAdded); - - connect(tree, &ProjectTree::foldersAboutToBeRemoved, - this, &FlatModel::foldersAboutToBeRemoved); - connect(tree, &ProjectTree::foldersRemoved, - this, &FlatModel::foldersRemoved); - - connect(tree, &ProjectTree::filesAboutToBeAdded, - this, &FlatModel::filesAboutToBeAdded); - connect(tree, &ProjectTree::filesAdded, - this, &FlatModel::filesAdded); - - connect(tree, &ProjectTree::filesAboutToBeRemoved, - this, &FlatModel::filesAboutToBeRemoved); - connect(tree, &ProjectTree::filesRemoved, - this, &FlatModel::filesRemoved); - - connect(tree, &ProjectTree::nodeSortKeyAboutToChange, - this, &FlatModel::nodeSortKeyAboutToChange); - connect(tree, &ProjectTree::nodeSortKeyChanged, - this, &FlatModel::nodeSortKeyChanged); - - connect(tree, &ProjectTree::nodeUpdated, - this, &FlatModel::nodeUpdated); -} - -QModelIndex FlatModel::index(int row, int column, const QModelIndex &parent) const -{ - QModelIndex result; - if (!parent.isValid() && row == 0 && column == 0) { // session - result = createIndex(0, 0, m_rootNode); - } else if (parent.isValid() && column == 0) { - FolderNode *parentNode = nodeForIndex(parent)->asFolderNode(); - Q_ASSERT(parentNode); - QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode); - if (it == m_childNodes.constEnd()) { - fetchMore(parentNode); - it = m_childNodes.constFind(parentNode); - } + SessionManager *sm = SessionManager::instance(); + connect(sm, &SessionManager::projectRemoved, this, &FlatModel::update); + connect(sm, &SessionManager::startupProjectChanged, this, &FlatModel::startupProjectChanged); - if (row < it.value().size()) - result = createIndex(row, 0, it.value().at(row)); - } -// qDebug() << "index of " << row << column << parent.data(Project::FilePathRole) << " is " << result.data(Project::FilePathRole); - return result; + connect(sm, &SessionManager::sessionLoaded, this, &FlatModel::loadExpandData); + connect(sm, &SessionManager::aboutToSaveSession, this, &FlatModel::saveExpandData); + connect(sm, &SessionManager::projectAdded, this, &FlatModel::handleProjectAdded); } -QModelIndex FlatModel::parent(const QModelIndex &idx) const +void FlatModel::setView(QTreeView *view) { - QModelIndex parentIndex; - if (Node *node = nodeForIndex(idx)) { - FolderNode *parentNode = visibleFolderNode(node->parentFolderNode()); - if (parentNode) - return indexForNode(parentNode); - } - return parentIndex; + QTC_CHECK(!m_view); + m_view = view; + connect(m_view, &QTreeView::expanded, this, &FlatModel::onExpanded); + connect(m_view, &QTreeView::collapsed, this, &FlatModel::onCollapsed); +} + +void FlatModel::startupProjectChanged(Project *project) +{ + ProjectNode *projectNode = project ? project->rootProjectNode() : nullptr; + if (m_startupProject == projectNode) + return; + m_startupProject = projectNode; + layoutChanged(); } QVariant FlatModel::data(const QModelIndex &index, int role) const @@ -149,7 +115,6 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: { QString name = node->displayName(); - if (node->nodeType() == NodeType::Project && node->parentFolderNode() && node->parentFolderNode()->nodeType() == NodeType::Session) { @@ -207,7 +172,7 @@ Qt::ItemFlags FlatModel::flags(const QModelIndex &index) const // We control the only view, and that one does the checks Qt::ItemFlags f = Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsDragEnabled; if (Node *node = nodeForIndex(index)) { - if (node == m_rootNode) + if (node->asSessionNode()) return 0; // no flags for session node... if (!node->asProjectNode()) { // either folder or file node @@ -235,142 +200,116 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol return true; } -int FlatModel::rowCount(const QModelIndex &parent) const +void FlatModel::update() { - int rows = 0; - if (!parent.isValid()) { - rows = 1; - } else { - FolderNode *folderNode = nodeForIndex(parent)->asFolderNode(); - if (folderNode && m_childNodes.contains(folderNode)) - rows = m_childNodes.value(folderNode).size(); - } - return rows; + m_timer.start(300); } -int FlatModel::columnCount(const QModelIndex &/*parent*/) const +void FlatModel::doUpdate() { - return 1; + m_timer.stop(); + rebuildModel(); } -bool FlatModel::hasChildren(const QModelIndex &parent) const +void FlatModel::rebuildModel() { - if (!parent.isValid()) - return true; - - FolderNode *folderNode = nodeForIndex(parent)->asFolderNode(); - if (!folderNode) - return false; + QSet<Node *> seen; - QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(folderNode); - if (it == m_childNodes.constEnd()) { - fetchMore(folderNode); - it = m_childNodes.constFind(folderNode); + rootItem()->removeChildren(); + const QList<ProjectNode *> projectNodes = SessionManager::sessionNode()->projectNodes(); + for (ProjectNode *projectNode : projectNodes) { + if (!seen.contains(projectNode)) + addProjectNode(rootItem(), projectNode, &seen); } - return !it.value().isEmpty(); -} -bool FlatModel::canFetchMore(const QModelIndex & parent) const -{ - if (!parent.isValid()) { - return false; - } else { - if (FolderNode *folderNode = nodeForIndex(parent)->asFolderNode()) - return !m_childNodes.contains(folderNode); - else - return false; - } + forAllItems([this](WrapperNode *node) { + const QString path = node->m_node->filePath().toString(); + const QString displayName = node->m_node->displayName(); + ExpandData ed(path, displayName); + if (m_toExpand.contains(ed)) + m_view->expand(node->index()); + }); } -void FlatModel::recursiveAddFolderNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const +void FlatModel::onCollapsed(const QModelIndex &idx) { - foreach (FolderNode *folderNode, startNode->folderNodes()) { - if (folderNode && !blackList.contains(folderNode)) - recursiveAddFolderNodesImpl(folderNode, list, blackList); - } + m_toExpand.remove(expandDataForNode(nodeForIndex(idx))); } -void FlatModel::recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const +void FlatModel::onExpanded(const QModelIndex &idx) { - if (!filter(startNode)) { - if (!blackList.contains(startNode)) - list->append(startNode); - } else { - foreach (FolderNode *folderNode, startNode->folderNodes()) { - if (folderNode && !blackList.contains(folderNode)) - recursiveAddFolderNodesImpl(folderNode, list, blackList); - } - } + m_toExpand.insert(expandDataForNode(nodeForIndex(idx))); } -void FlatModel::recursiveAddFileNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const +ExpandData FlatModel::expandDataForNode(const Node *node) const { - foreach (FolderNode *subFolderNode, startNode->folderNodes()) { - if (!blackList.contains(subFolderNode)) - recursiveAddFileNodes(subFolderNode, list, blackList); - } - foreach (Node *node, startNode->fileNodes()) { - if (!blackList.contains(node) && !filter(node)) - list->append(node); - } + QTC_ASSERT(node, return ExpandData()); + const QString path = node->filePath().toString(); + const QString displayName = node->displayName(); + return ExpandData(path, displayName); } -QList<Node*> FlatModel::childNodes(FolderNode *parentNode, const QSet<Node*> &blackList) const +void FlatModel::handleProjectAdded(Project *project) { - qCDebug(logger()) << " FlatModel::childNodes for " << parentNode->filePath(); - QList<Node*> nodeList; - - if (parentNode->nodeType() == NodeType::Session) { - auto sessionNode = static_cast<SessionNode*>(parentNode); - QList<ProjectNode*> projectList = sessionNode->projectNodes(); - for (int i = 0; i < projectList.size(); ++i) { - if (!blackList.contains(projectList.at(i))) - nodeList << projectList.at(i); - } - } else { - recursiveAddFolderNodes(parentNode, &nodeList, blackList); - recursiveAddFileNodes(parentNode, &nodeList, blackList + nodeList.toSet()); + Node *node = project->rootProjectNode(); + m_toExpand.insert(expandDataForNode(node)); + if (WrapperNode *wrapper = wrapperForNode(node)) { + wrapper->forFirstLevelChildren([this](WrapperNode *child) { + m_toExpand.insert(expandDataForNode(child->m_node)); + }); } - Utils::sort(nodeList, sortNodes); - qCDebug(logger()) << " found" << nodeList.size() << "nodes"; - return nodeList; + doUpdate(); } -void FlatModel::fetchMore(FolderNode *folderNode) const +void FlatModel::loadExpandData() { - Q_ASSERT(folderNode); - Q_ASSERT(!m_childNodes.contains(folderNode)); - - QList<Node*> nodeList = childNodes(folderNode); - m_childNodes.insert(folderNode, nodeList); + const QList<QVariant> data = SessionManager::value("ProjectTree.ExpandData").value<QList<QVariant>>(); + m_toExpand = Utils::transform<QSet>(data, [](const QVariant &v) { return ExpandData::fromSettings(v); }); + m_toExpand.remove(ExpandData()); } -void FlatModel::fetchMore(const QModelIndex &parent) +void FlatModel::saveExpandData() { - FolderNode *folderNode = nodeForIndex(parent)->asFolderNode(); - Q_ASSERT(folderNode); - - fetchMore(folderNode); + // TODO if there are multiple ProjectTreeWidgets, the last one saves the data + QList<QVariant> data = Utils::transform<QList>(m_toExpand, &ExpandData::toSettings); + SessionManager::setValue(QLatin1String("ProjectTree.ExpandData"), data); } -void FlatModel::setStartupProject(ProjectNode *projectNode) +void FlatModel::addProjectNode(WrapperNode *parent, ProjectNode *projectNode, QSet<Node *> *seen) { - if (m_startupProject != projectNode) { - QModelIndex oldIndex = (m_startupProject ? indexForNode(m_startupProject) : QModelIndex()); - QModelIndex newIndex = (projectNode ? indexForNode(projectNode) : QModelIndex()); - m_startupProject = projectNode; - if (oldIndex.isValid()) - emit dataChanged(oldIndex, oldIndex); - if (newIndex.isValid()) - emit dataChanged(newIndex, newIndex); + seen->insert(projectNode); + auto node = new WrapperNode(projectNode); + parent->appendChild(node); + addFolderNode(node, projectNode, seen); + const QList<ProjectNode *> subProjectNodes = projectNode->projectNodes(); + for (ProjectNode *subProjectNode : subProjectNodes) { + if (!seen->contains(subProjectNode)) + addProjectNode(node, subProjectNode, seen); } + node->sortChildren(&sortWrapperNodes); } -void FlatModel::reset() +void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen) { - beginResetModel(); - m_childNodes.clear(); - endResetModel(); + const QList<FolderNode *> subFolderNodes = folderNode->folderNodes(); + for (FolderNode *subFolderNode : subFolderNodes) { + if (!filter(subFolderNode) && !seen->contains(subFolderNode)) { + seen->insert(subFolderNode); + auto node = new WrapperNode(subFolderNode); + parent->appendChild(node); + addFolderNode(node, subFolderNode, seen); + node->sortChildren(&sortWrapperNodes); + } else { + addFolderNode(parent, subFolderNode, seen); + } + } + const QList<FileNode *> fileNodes = folderNode->fileNodes(); + for (FileNode *fileNode : fileNodes) { + if (!filter(fileNode) && !seen->contains(fileNode)) { + seen->insert(fileNode); + parent->appendChild(new WrapperNode(fileNode)); + } + } } Qt::DropActions FlatModel::supportedDragActions() const @@ -395,32 +334,17 @@ QMimeData *FlatModel::mimeData(const QModelIndexList &indexes) const return data; } -QModelIndex FlatModel::indexForNode(const Node *node_) const +WrapperNode *FlatModel::wrapperForNode(const Node *node) const { - // We assume that we are only called for nodes that are represented - - // we use non-const pointers internally - auto node = const_cast<Node*>(node_); - if (!node) - return QModelIndex(); - - if (node == m_rootNode) - return createIndex(0, 0, m_rootNode); - - FolderNode *parentNode = visibleFolderNode(node->parentFolderNode()); + return findNonRooItem([this, node](WrapperNode *item) { + return item->m_node == node; + }); +} - // Do we have the parent mapped? - QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode); - if (it == m_childNodes.constEnd()) { - fetchMore(parentNode); - it = m_childNodes.constFind(parentNode); - } - if (it != m_childNodes.constEnd()) { - const int row = it.value().indexOf(node); - if (row != -1) - return createIndex(row, 0, node); - } - return QModelIndex(); +QModelIndex FlatModel::indexForNode(const Node *node) const +{ + WrapperNode *wrapper = wrapperForNode(node); + return wrapper ? indexForItem(wrapper) : QModelIndex(); } void FlatModel::setProjectFilterEnabled(bool filter) @@ -428,13 +352,13 @@ void FlatModel::setProjectFilterEnabled(bool filter) if (filter == m_filterProjects) return; m_filterProjects = filter; - reset(); + rebuildModel(); } void FlatModel::setGeneratedFilesFilterEnabled(bool filter) { m_filterGeneratedFiles = filter; - reset(); + rebuildModel(); } bool FlatModel::projectFilterEnabled() @@ -449,28 +373,8 @@ bool FlatModel::generatedFilesFilterEnabled() Node *FlatModel::nodeForIndex(const QModelIndex &index) const { - if (index.isValid()) - return (Node*)index.internalPointer(); - return nullptr; -} - -/* - Returns the first folder node in the ancestors - for the given node that is not filtered - out by the Flat Model. -*/ -FolderNode *FlatModel::visibleFolderNode(FolderNode *node) const -{ - if (!node) - return nullptr; - - for (FolderNode *folderNode = node; - folderNode; - folderNode = folderNode->parentFolderNode()) { - if (!filter(folderNode)) - return folderNode; - } - return nullptr; + WrapperNode *flatNode = itemForIndex(index); + return flatNode ? flatNode->m_node : nullptr; } bool FlatModel::filter(Node *node) const @@ -502,343 +406,9 @@ bool isSorted(const QList<Node *> &nodes) return true; } -/// slots and all the fun -void FlatModel::added(FolderNode* parentNode, const QList<Node*> &newNodeList) -{ - qCDebug(logger()) << "FlatModel::added" << parentNode->filePath() << newNodeList.size() << "nodes"; - QModelIndex parentIndex = indexForNode(parentNode); - // Old list - - if (newNodeList.isEmpty()) { - qCDebug(logger()) << " newNodeList empty"; - return; - } - - QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode); - if (it == m_childNodes.constEnd()) { - if (!parentIndex.isValid()) { - qCDebug(logger()) << " parent not mapped returning"; - return; - } - qCDebug(logger()) << " updated m_childNodes"; - beginInsertRows(parentIndex, 0, newNodeList.size() - 1); - m_childNodes.insert(parentNode, newNodeList); - endInsertRows(); - return; - } - QList<Node *> oldNodeList = it.value(); - - // Compare lists and emit signals, and modify m_childNodes on the fly - QList<Node *>::const_iterator oldIter = oldNodeList.constBegin(); - QList<Node *>::const_iterator newIter = newNodeList.constBegin(); - - Q_ASSERT(isSorted(oldNodeList)); - Q_ASSERT(isSorted(newNodeList)); - - QSet<Node *> emptyDifference; - emptyDifference = oldNodeList.toSet(); - emptyDifference.subtract(newNodeList.toSet()); - if (!emptyDifference.isEmpty()) { - // This should not happen... - qDebug() << "FlatModel::added, old Node list should be subset of newNode list, found files in old list which were not part of new list"; - foreach (Node *n, emptyDifference) - qDebug()<<n->filePath(); - Q_ASSERT(false); - } - - // optimization, check for old list is empty - if (oldIter == oldNodeList.constEnd()) { - // New Node List is empty, nothing added which intrest us - if (newIter == newNodeList.constEnd()) - return; - // So all we need to do is easy - beginInsertRows(parentIndex, 0, newNodeList.size() - 1); - m_childNodes.insert(parentNode, newNodeList); - endInsertRows(); - qCDebug(logger()) << " updated m_childNodes"; - return; - } - - while (true) { - // Skip all that are the same - while (*oldIter == *newIter) { - ++oldIter; - ++newIter; - if (oldIter == oldNodeList.constEnd()) { - // At end of oldNodeList, sweep up rest of newNodeList - QList<Node *>::const_iterator startOfBlock = newIter; - newIter = newNodeList.constEnd(); - int pos = oldIter - oldNodeList.constBegin(); - int count = newIter - startOfBlock; - if (count > 0) { - beginInsertRows(parentIndex, pos, pos+count-1); - while (startOfBlock != newIter) { - oldNodeList.insert(pos, *startOfBlock); - ++pos; - ++startOfBlock; - } - m_childNodes.insert(parentNode, oldNodeList); - endInsertRows(); - } - return; // Done with the lists, leave the function - } - } - - QList<Node *>::const_iterator startOfBlock = newIter; - while (*oldIter != *newIter) - ++newIter; - // startOfBlock is the first that was diffrent - // newIter points to the new position of oldIter - // newIter - startOfBlock is number of new items - // oldIter is the position where those are... - int pos = oldIter - oldNodeList.constBegin(); - int count = newIter - startOfBlock; - beginInsertRows(parentIndex, pos, pos + count - 1); - while (startOfBlock != newIter) { - oldNodeList.insert(pos, *startOfBlock); - ++pos; - ++startOfBlock; - } - m_childNodes.insert(parentNode, oldNodeList); - endInsertRows(); - oldIter = oldNodeList.constBegin() + pos; - } - qCDebug(logger()) << " updated m_childNodes"; -} - -void FlatModel::removed(FolderNode* parentNode, const QList<Node*> &newNodeList) -{ - qCDebug(logger()) << "FlatModel::removed" << parentNode->filePath() << newNodeList.size() << "nodes"; - QModelIndex parentIndex = indexForNode(parentNode); - // Old list - QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(parentNode); - if (it == m_childNodes.constEnd()) { - qCDebug(logger()) << " unmapped node"; - return; - } - - QList<Node *> oldNodeList = it.value(); - // Compare lists and emit signals, and modify m_childNodes on the fly - QList<Node *>::const_iterator oldIter = oldNodeList.constBegin(); - QList<Node *>::const_iterator newIter = newNodeList.constBegin(); - - Q_ASSERT(isSorted(newNodeList)); - - QSet<Node *> emptyDifference; - emptyDifference = newNodeList.toSet(); - emptyDifference.subtract(oldNodeList.toSet()); - if (!emptyDifference.isEmpty()) { - // This should not happen... - qDebug() << "FlatModel::removed, new Node list should be subset of oldNode list, found files in new list which were not part of old list"; - foreach (Node *n, emptyDifference) - qDebug()<<n->filePath(); - Q_ASSERT(false); - } - - // optimization, check for new list is empty - if (newIter == newNodeList.constEnd()) { - // New Node List is empty, everything removed - if (oldIter == oldNodeList.constEnd()) - return; - // So all we need to do is easy - beginRemoveRows(parentIndex, 0, oldNodeList.size() - 1); - m_childNodes.insert(parentNode, newNodeList); - endRemoveRows(); - qCDebug(logger()) << " updated m_childNodes"; - return; - } - - while (true) { - // Skip all that are the same - while (*oldIter == *newIter) { - ++oldIter; - ++newIter; - if (newIter == newNodeList.constEnd()) { - // At end of newNodeList, sweep up rest of oldNodeList - QList<Node *>::const_iterator startOfBlock = oldIter; - oldIter = oldNodeList.constEnd(); - int pos = startOfBlock - oldNodeList.constBegin(); - int count = oldIter - startOfBlock; - if (count > 0) { - beginRemoveRows(parentIndex, pos, pos+count-1); - while (startOfBlock != oldIter) { - ++startOfBlock; - oldNodeList.removeAt(pos); - } - - m_childNodes.insert(parentNode, oldNodeList); - endRemoveRows(); - } - return; // Done with the lists, leave the function - } - } - - QList<Node *>::const_iterator startOfBlock = oldIter; - while (*oldIter != *newIter) - ++oldIter; - // startOfBlock is the first that was diffrent - // oldIter points to the new position of newIter - // oldIter - startOfBlock is number of new items - // newIter is the position where those are... - int pos = startOfBlock - oldNodeList.constBegin(); - int count = oldIter - startOfBlock; - beginRemoveRows(parentIndex, pos, pos + count - 1); - while (startOfBlock != oldIter) { - ++startOfBlock; - oldNodeList.removeAt(pos); - } - m_childNodes.insert(parentNode, oldNodeList); - endRemoveRows(); - oldIter = oldNodeList.constBegin() + pos; - } - qCDebug(logger()) << " updated m_childNodes"; -} - -void FlatModel::aboutToShowInSimpleTreeChanged(FolderNode* node) -{ - if (!m_filterProjects) - return; - FolderNode *folder = visibleFolderNode(node->parentFolderNode()); - QList<Node *> newNodeList = childNodes(folder, QSet<Node *>() << node); - removed(folder, newNodeList); - - QList<Node *> staleFolders; - recursiveAddFolderNodesImpl(node, &staleFolders); - foreach (Node *n, staleFolders) - if (FolderNode *fn = n->asFolderNode()) - m_childNodes.remove(fn); -} - -void FlatModel::showInSimpleTreeChanged(FolderNode *node) -{ - if (!m_filterProjects) - return; - // we are only interested if we filter - FolderNode *folder = visibleFolderNode(node->parentFolderNode()); - QList<Node *> newNodeList = childNodes(folder); - added(folder, newNodeList); -} - -void FlatModel::foldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode*> &newFolders) -{ - qCDebug(logger()) << "FlatModel::foldersAboutToBeAdded"; - Q_UNUSED(newFolders) - m_parentFolderForChange = parentFolder; -} - -void FlatModel::foldersAdded() -{ - // First found out what the folder is that we are adding the files to - FolderNode *folderNode = visibleFolderNode(m_parentFolderForChange); - - // Now get the new list for that folder - QList<Node *> newNodeList = childNodes(folderNode); - - added(folderNode, newNodeList); -} - -void FlatModel::foldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode*> &staleFolders) -{ - QSet<Node *> blackList; - foreach (FolderNode *node, staleFolders) - blackList.insert(node); - - FolderNode *folderNode = visibleFolderNode(parentFolder); - QList<Node *> newNodeList = childNodes(folderNode, blackList); - - removed(folderNode, newNodeList); - removeFromCache(staleFolders); -} - -void FlatModel::removeFromCache(QList<FolderNode *> list) -{ - foreach (FolderNode *fn, list) { - removeFromCache(fn->folderNodes()); - m_childNodes.remove(fn); - } -} - -void FlatModel::changedSortKey(FolderNode *folderNode, Node *node) -{ - if (!m_childNodes.contains(folderNode)) - return; // The directory was not yet mapped, so there is no need to sort it. - - QList<Node *> nodes = m_childNodes.value(folderNode); - int oldIndex = nodes.indexOf(node); - - nodes.removeAt(oldIndex); - QList<Node *>::iterator newPosIt = std::lower_bound(nodes.begin(), nodes.end(), node, sortNodes); - int newIndex = newPosIt - nodes.begin(); - - if (newIndex == oldIndex) - return; - - nodes.insert(newPosIt, node); - - QModelIndex parentIndex = indexForNode(folderNode); - if (newIndex > oldIndex) - ++newIndex; // see QAbstractItemModel::beginMoveRows - beginMoveRows(parentIndex, oldIndex, oldIndex, parentIndex, newIndex); - m_childNodes[folderNode] = nodes; - endMoveRows(); -} - -void FlatModel::foldersRemoved() -{ - // Do nothing -} - -void FlatModel::filesAboutToBeAdded(FolderNode *folder, const QList<FileNode*> &newFiles) -{ - qCDebug(logger()) << "FlatModel::filesAboutToBeAdded"; - Q_UNUSED(newFiles) - m_parentFolderForChange = folder; -} - -void FlatModel::filesAdded() -{ - // First find out what the folder is that we are adding the files to - FolderNode *folderNode = visibleFolderNode(m_parentFolderForChange); - - // Now get the new List for that folder - QList<Node *> newNodeList = childNodes(folderNode); - added(folderNode, newNodeList); -} - -void FlatModel::filesAboutToBeRemoved(FolderNode *folder, const QList<FileNode*> &staleFiles) -{ - // First found out what the folder (that is the project) is that we are adding the files to - FolderNode *folderNode = visibleFolderNode(folder); - - QSet<Node *> blackList; - foreach (Node *node, staleFiles) - blackList.insert(node); - - // Now get the new List for that folder - QList<Node *> newNodeList = childNodes(folderNode, blackList); - removed(folderNode, newNodeList); -} - -void FlatModel::filesRemoved() -{ - // Do nothing -} - -void FlatModel::nodeSortKeyAboutToChange(Node *node) -{ - m_nodeForSortKeyChange = node; -} - -void FlatModel::nodeSortKeyChanged() -{ - FolderNode *folderNode = visibleFolderNode(m_nodeForSortKeyChange->parentFolderNode()); - changedSortKey(folderNode, m_nodeForSortKeyChange); -} - -void FlatModel::nodeUpdated(Node *node) +void FlatModel::nodeUpdated(Node *) { - QModelIndex idx = indexForNode(node); - emit dataChanged(idx, idx); + update(); } namespace Internal { diff --git a/src/plugins/projectexplorer/projectmodels.h b/src/plugins/projectexplorer/projectmodels.h index cfd4e5c1b8..4b466fe27c 100644 --- a/src/plugins/projectexplorer/projectmodels.h +++ b/src/plugins/projectexplorer/projectmodels.h @@ -25,51 +25,53 @@ #pragma once +#include "expanddata.h" +#include "projectnodes.h" + #include <utils/fileutils.h> +#include <utils/treemodel.h> -#include <QAbstractItemModel> +#include <QPointer> #include <QSet> +#include <QTimer> +#include <QTreeView> namespace ProjectExplorer { class Node; -class FileNode; class FolderNode; +class Project; class ProjectNode; -class SessionNode; namespace Internal { -class FlatModel : public QAbstractItemModel +class WrapperNode : public Utils::TypedTreeItem<WrapperNode> +{ +public: + explicit WrapperNode(Node *node) : m_node(node) {} + QPointer<Node> m_node; +}; + +class FlatModel : public Utils::TreeModel<WrapperNode, WrapperNode> { Q_OBJECT public: - FlatModel(SessionNode *rootNode, QObject *parent); + FlatModel(QObject *parent); + + void setView(QTreeView *view); // QAbstractItemModel - QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex &index) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; - int rowCount(const QModelIndex & parent = QModelIndex()) const override; - int columnCount(const QModelIndex & parent = QModelIndex()) const override; - bool hasChildren(const QModelIndex & parent = QModelIndex()) const override; - - bool canFetchMore(const QModelIndex & parent) const override; - void fetchMore(const QModelIndex & parent) override; - - void reset(); - Qt::DropActions supportedDragActions() const override; QStringList mimeTypes() const override; QMimeData *mimeData(const QModelIndexList &indexes) const override; - void setStartupProject(ProjectNode *projectNode); - Node *nodeForIndex(const QModelIndex &index) const; + WrapperNode *wrapperForNode(const Node *node) const; QModelIndex indexForNode(const Node *node) const; bool projectFilterEnabled(); @@ -81,53 +83,34 @@ signals: void renamed(const Utils::FileName &oldName, const Utils::FileName &newName); private: - void aboutToShowInSimpleTreeChanged(ProjectExplorer::FolderNode *node); - void showInSimpleTreeChanged(ProjectExplorer::FolderNode *node); - void foldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode*> &newFolders); - void foldersAdded(); - - void foldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode*> &staleFolders); - void foldersRemoved(); - - // files - void filesAboutToBeAdded(FolderNode *folder, const QList<FileNode*> &newFiles); - void filesAdded(); - - void filesAboutToBeRemoved(FolderNode *folder, const QList<FileNode*> &staleFiles); - void filesRemoved(); - - void nodeSortKeyAboutToChange(Node *node); - void nodeSortKeyChanged(); - + void startupProjectChanged(Project *project); void nodeUpdated(ProjectExplorer::Node *node); - void added(FolderNode* folderNode, const QList<Node*> &newNodeList); - void removed(FolderNode* parentNode, const QList<Node*> &newNodeList); - void removeFromCache(QList<FolderNode *> list); - void changedSortKey(FolderNode *folderNode, Node *node); - void fetchMore(FolderNode *foldernode) const; - - void recursiveAddFolderNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList = QSet<Node*>()) const; - void recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList = QSet<Node*>()) const; - void recursiveAddFileNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList = QSet<Node*>()) const; - QList<Node*> childNodes(FolderNode *parentNode, const QSet<Node*> &blackList = QSet<Node*>()) const; - - FolderNode *visibleFolderNode(FolderNode *node) const; - bool filter(Node *node) const; + bool filter(Node *node) const; // Returns true if node is hidden. bool m_filterProjects = false; bool m_filterGeneratedFiles = true; - SessionNode *m_rootNode; - mutable QHash<FolderNode*, QList<Node*> > m_childNodes; ProjectNode *m_startupProject = nullptr; - FolderNode *m_parentFolderForChange = nullptr; - Node *m_nodeForSortKeyChange = nullptr; - static const QLoggingCategory &logger(); - friend class FlatModelManager; + void update(); + void doUpdate(); + void rebuildModel(); + void addProjectNode(WrapperNode *parent, ProjectNode *projectNode, QSet<Node *> *seen); + void addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen); + + ExpandData expandDataForNode(const Node *node) const; + void onExpanded(const QModelIndex &idx); + void onCollapsed(const QModelIndex &idx); + void loadExpandData(); + void saveExpandData(); + void handleProjectAdded(Project *project); + + QTimer m_timer; + QTreeView *m_view = nullptr; + QSet<ExpandData> m_toExpand; }; int caseFriendlyCompare(const QString &a, const QString &b); diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index a6e6e8c3af..d2f54d02be 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -68,30 +68,21 @@ void Node::setPriority(int p) m_priority = p; } -void Node::emitNodeSortKeyAboutToChange() -{ - if (parentFolderNode()) - ProjectTree::instance()->emitNodeSortKeyAboutToChange(this); -} - -void Node::emitNodeSortKeyChanged() -{ - if (parentFolderNode()) - ProjectTree::instance()->emitNodeSortKeyChanged(this); -} - void Node::setAbsoluteFilePathAndLine(const Utils::FileName &path, int line) { if (m_filePath == path && m_line == line) return; - emitNodeSortKeyAboutToChange(); m_filePath = path; m_line = line; - emitNodeSortKeyChanged(); emitNodeUpdated(); } +Node::~Node() +{ + +} + NodeType Node::nodeType() const { return m_nodeType; @@ -186,7 +177,12 @@ void Node::setEnabled(bool enabled) void Node::emitNodeUpdated() { if (parentFolderNode()) - ProjectTree::instance()->emitNodeUpdated(this); + ProjectTree::emitNodeUpdated(this); +} + +void Node::emitTreeChanged() +{ + ProjectTree::emitDataChanged(); } Node *Node::trim(const QSet<Node *> &keepers) @@ -511,9 +507,7 @@ void FolderNode::setDisplayName(const QString &name) { if (m_displayName == name) return; - emitNodeSortKeyAboutToChange(); m_displayName = name; - emitNodeSortKeyChanged(); emitNodeUpdated(); } @@ -588,8 +582,6 @@ void FolderNode::addFileNodes(const QList<FileNode *> &files) if (files.isEmpty()) return; - ProjectTree::instance()->emitFilesAboutToBeAdded(this, files); - foreach (FileNode *file, files) { QTC_ASSERT(!file->parentFolderNode(), qDebug("File node has already a parent folder")); @@ -606,7 +598,7 @@ void FolderNode::addFileNodes(const QList<FileNode *> &files) } } - ProjectTree::instance()->emitFilesAdded(this); + ProjectTree::emitDataChanged(); } /*! @@ -627,8 +619,6 @@ void FolderNode::removeFileNodes(const QList<FileNode *> &files) QList<FileNode*> toRemove = files; Utils::sort(toRemove); - ProjectTree::instance()->emitFilesAboutToBeRemoved(this, toRemove); - auto toRemoveIter = toRemove.constBegin(); auto filesIter = m_fileNodes.begin(); for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) { @@ -641,7 +631,7 @@ void FolderNode::removeFileNodes(const QList<FileNode *> &files) filesIter = m_fileNodes.erase(filesIter); } - ProjectTree::instance()->emitFilesRemoved(this); + ProjectTree::emitDataChanged(); } /*! @@ -655,7 +645,6 @@ void FolderNode::addFolderNodes(const QList<FolderNode*> &subFolders) if (subFolders.isEmpty()) return; - ProjectTree::instance()->emitFoldersAboutToBeAdded(this, subFolders); foreach (FolderNode *folder, subFolders) { QTC_ASSERT(!folder->parentFolderNode(), qDebug("Project node has already a parent folder")); @@ -677,7 +666,7 @@ void FolderNode::addFolderNodes(const QList<FolderNode*> &subFolders) qDebug("project nodes have to be added via addProjectNodes")); } - ProjectTree::instance()->emitFoldersAdded(this); + ProjectTree::emitDataChanged(); } /*! @@ -696,8 +685,6 @@ void FolderNode::removeFolderNodes(const QList<FolderNode*> &subFolders) QList<FolderNode*> toRemove = subFolders; Utils::sort(toRemove); - ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove); - auto toRemoveIter = toRemove.constBegin(); auto folderIter = m_folderNodes.begin(); for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) { @@ -712,7 +699,7 @@ void FolderNode::removeFolderNodes(const QList<FolderNode*> &subFolders) folderIter = m_folderNodes.erase(folderIter); } - ProjectTree::instance()->emitFoldersRemoved(this); + ProjectTree::emitDataChanged(); } bool FolderNode::showInSimpleTree() const @@ -867,8 +854,6 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects) foreach (ProjectNode *projectNode, subProjects) folderNodes << projectNode; - ProjectTree::instance()->emitFoldersAboutToBeAdded(this, folderNodes); - foreach (ProjectNode *project, subProjects) { QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this, qDebug("Project node has already a parent")); @@ -876,10 +861,9 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects) m_folderNodes.append(project); m_projectNodes.append(project); } + Utils::sort(m_folderNodes); Utils::sort(m_projectNodes); - - ProjectTree::instance()->emitFoldersAdded(this); } } @@ -898,8 +882,6 @@ void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects) toRemove << projectNode; Utils::sort(toRemove); - ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove); - auto toRemoveIter = toRemove.constBegin(); auto folderIter = m_folderNodes.begin(); auto projectIter = m_projectNodes.begin(); @@ -918,8 +900,6 @@ void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects) projectIter = m_projectNodes.erase(projectIter); folderIter = m_folderNodes.erase(folderIter); } - - ProjectTree::instance()->emitFoldersRemoved(this); } } @@ -967,12 +947,6 @@ bool SessionNode::showInSimpleTree() const return true; } -void SessionNode::projectDisplayNameChanged(Node *node) -{ - ProjectTree::instance()->emitNodeSortKeyAboutToChange(node); - ProjectTree::instance()->emitNodeSortKeyChanged(node); -} - QList<ProjectNode*> SessionNode::projectNodes() const { return m_projectNodes; @@ -990,8 +964,6 @@ void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes) foreach (ProjectNode *projectNode, projectNodes) folderNodes << projectNode; - ProjectTree::instance()->emitFoldersAboutToBeAdded(this, folderNodes); - foreach (ProjectNode *project, projectNodes) { QTC_ASSERT(!project->parentFolderNode(), qDebug("Project node has already a parent folder")); @@ -1002,8 +974,6 @@ void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes) Utils::sort(m_folderNodes); Utils::sort(m_projectNodes); - - ProjectTree::instance()->emitFoldersAdded(this); } } @@ -1015,9 +985,6 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes) toRemove << projectNode; Utils::sort(toRemove); - - ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove); - auto toRemoveIter = toRemove.constBegin(); auto folderIter = m_folderNodes.begin(); auto projectIter = m_projectNodes.begin(); @@ -1035,8 +1002,6 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes) projectIter = m_projectNodes.erase(projectIter); folderIter = m_folderNodes.erase(folderIter); } - - ProjectTree::instance()->emitFoldersRemoved(this); } } diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 1dd71df02f..99e4b2ac82 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -104,8 +104,9 @@ class NodesVisitor; class SessionManager; // Documentation inside. -class PROJECTEXPLORER_EXPORT Node +class PROJECTEXPLORER_EXPORT Node : public QObject { + Q_OBJECT public: enum PriorityLevel { DefaultPriority = 0, @@ -116,7 +117,7 @@ public: DefaultProjectFilePriority = 500000 }; - virtual ~Node() = default; + virtual ~Node(); NodeType nodeType() const; int priority() const; @@ -141,6 +142,7 @@ public: void setAbsoluteFilePathAndLine(const Utils::FileName &filePath, int line); void emitNodeUpdated(); + void emitTreeChanged(); virtual Node *trim(const QSet<Node *> &keepers); @@ -161,9 +163,6 @@ protected: void setPriority(int priority); void setParentFolderNode(FolderNode *parentFolder); - void emitNodeSortKeyAboutToChange(); - void emitNodeSortKeyChanged(); - private: FolderNode *m_parentFolderNode = nullptr; Utils::FileName m_filePath; @@ -177,6 +176,7 @@ class PROJECTEXPLORER_EXPORT FileNode : public Node { public: FileNode(const Utils::FileName &filePath, const FileType fileType, bool generated, int line = -1); + FileNode(const FileNode &other) : FileNode(other.filePath(), other.fileType(), true) {} FileType fileType() const; bool isGenerated() const; @@ -255,8 +255,8 @@ public: void addFolderNodes(const QList<FolderNode*> &subFolders); void removeFolderNodes(const QList<FolderNode*> &subFolders); - FolderNode *asFolderNode() final { return this; } - const FolderNode *asFolderNode() const final { return this; } + FolderNode *asFolderNode() override { return this; } + const FolderNode *asFolderNode() const override { return this; } protected: QList<FolderNode*> m_folderNodes; @@ -330,11 +330,8 @@ public: SessionNode(); QList<ProjectAction> supportedActions(Node *node) const override; - QList<ProjectNode*> projectNodes() const; - QString addFileFilter() const override; - void accept(NodesVisitor *visitor) override; bool showInSimpleTree() const override; diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp index 376dc73d7f..1774d8ee0f 100644 --- a/src/plugins/projectexplorer/projecttree.cpp +++ b/src/plugins/projectexplorer/projecttree.cpp @@ -258,167 +258,14 @@ void ProjectTree::updateContext() void ProjectTree::emitNodeUpdated(Node *node) { - if (!isInNodeHierarchy(node)) + if (!s_instance->isInNodeHierarchy(node)) return; - emit nodeUpdated(node); + emit s_instance->nodeUpdated(node); } -void ProjectTree::emitAboutToChangeShowInSimpleTree(FolderNode *node) +void ProjectTree::emitDataChanged() { - if (!isInNodeHierarchy(node)) - return; - emit aboutToChangeShowInSimpleTree(node); -} - -void ProjectTree::emitShowInSimpleTreeChanged(FolderNode *node) -{ - if (!isInNodeHierarchy(node)) - return; - emit showInSimpleTreeChanged(node); -} - -void ProjectTree::emitFoldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode *> &newFolders) -{ - if (!isInNodeHierarchy(parentFolder)) - return; - - m_foldersAdded = newFolders; - - emit foldersAboutToBeAdded(parentFolder, newFolders); -} - -void ProjectTree::emitFoldersAdded(FolderNode *folder) -{ - if (!isInNodeHierarchy(folder)) - return; - - emit foldersAdded(); - - if (Utils::anyOf(m_projectTreeWidgets, &ProjectTreeWidget::hasFocus)) - return; - - if (!m_currentNode) { - Core::IDocument *document = Core::EditorManager::currentDocument(); - const FileName fileName = document ? document->filePath() : FileName(); - - - FindNodesForFileVisitor findNodes(fileName); - foreach (FolderNode *fn, m_foldersAdded) - fn->accept(&findNodes); - - Node *bestNode = ProjectTreeWidget::mostExpandedNode(findNodes.nodes()); - if (!bestNode) - return; - - updateFromNode(bestNode); - } - m_foldersAdded.clear(); -} - -void ProjectTree::emitFoldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode *> &staleFolders) -{ - if (!isInNodeHierarchy(parentFolder)) - return; - - Node *n = ProjectTree::currentNode(); - while (n) { - if (FolderNode *fn = n->asFolderNode()) { - if (staleFolders.contains(fn)) { - ProjectNode *pn = n->parentProjectNode(); - // Make sure the node we are switching too isn't going to be removed also - while (staleFolders.contains(pn)) - pn = pn->parentFolderNode()->parentProjectNode(); - m_resetCurrentNodeFolder = true; - break; - } - } - n = n->parentFolderNode(); - } - emit foldersAboutToBeRemoved(parentFolder, staleFolders); -} - -void ProjectTree::emitFoldersRemoved(FolderNode *folder) -{ - if (!isInNodeHierarchy(folder)) - return; - - emit foldersRemoved(); - - if (m_resetCurrentNodeFolder) { - updateFromFocus(true); - m_resetCurrentNodeFolder = false; - } -} - -void ProjectTree::emitFilesAboutToBeAdded(FolderNode *folder, const QList<FileNode *> &newFiles) -{ - if (!isInNodeHierarchy(folder)) - return; - m_filesAdded = newFiles; - emit filesAboutToBeAdded(folder, newFiles); -} - -void ProjectTree::emitFilesAdded(FolderNode *folder) -{ - if (!isInNodeHierarchy(folder)) - return; - - emit filesAdded(); - - if (Utils::anyOf(m_projectTreeWidgets, &ProjectTreeWidget::hasFocus)) - return; - - if (!m_currentNode) { - Core::IDocument *document = Core::EditorManager::currentDocument(); - const FileName fileName = document ? document->filePath() : FileName(); - - int index = Utils::indexOf(m_filesAdded, Utils::equal(&FileNode::filePath, fileName)); - - if (index == -1) - return; - - updateFromNode(m_filesAdded.at(index)); - } - m_filesAdded.clear(); -} - -void ProjectTree::emitFilesAboutToBeRemoved(FolderNode *folder, const QList<FileNode *> &staleFiles) -{ - if (!isInNodeHierarchy(folder)) - return; - - if (m_currentNode) - if (FileNode *fileNode = m_currentNode->asFileNode()) - if (staleFiles.contains(fileNode)) - m_resetCurrentNodeFile = true; - - emit filesAboutToBeRemoved(folder, staleFiles); -} - -void ProjectTree::emitFilesRemoved(FolderNode *folder) -{ - if (!isInNodeHierarchy(folder)) - return; - emit filesRemoved(); - - if (m_resetCurrentNodeFile) { - updateFromFocus(true); - m_resetCurrentNodeFile = false; - } -} - -void ProjectTree::emitNodeSortKeyAboutToChange(Node *node) -{ - if (!isInNodeHierarchy(node)) - return; - emit nodeSortKeyAboutToChange(node); -} - -void ProjectTree::emitNodeSortKeyChanged(Node *node) -{ - if (!isInNodeHierarchy(node)) - return; - emit nodeSortKeyChanged(); + instance()->dataChanged(); } void ProjectTree::collapseAll() diff --git a/src/plugins/projectexplorer/projecttree.h b/src/plugins/projectexplorer/projecttree.h index 196e280c14..e7822abc18 100644 --- a/src/plugins/projectexplorer/projecttree.h +++ b/src/plugins/projectexplorer/projecttree.h @@ -68,61 +68,14 @@ signals: // Emitted whenever the model needs to send a update signal. void nodeUpdated(ProjectExplorer::Node *node); - - // projects - void aboutToChangeShowInSimpleTree(ProjectExplorer::FolderNode*); - void showInSimpleTreeChanged(ProjectExplorer::FolderNode *node); - - // folders & projects - void foldersAboutToBeAdded(FolderNode *parentFolder, - const QList<FolderNode*> &newFolders); - void foldersAdded(); - - void foldersAboutToBeRemoved(FolderNode *parentFolder, - const QList<FolderNode*> &staleFolders); - void foldersRemoved(); - - // files - void filesAboutToBeAdded(FolderNode *folder, - const QList<FileNode*> &newFiles); - void filesAdded(); - - void filesAboutToBeRemoved(FolderNode *folder, - const QList<FileNode*> &staleFiles); - void filesRemoved(); - void nodeSortKeyAboutToChange(Node *node); - void nodeSortKeyChanged(); + void dataChanged(); void aboutToShowContextMenu(ProjectExplorer::Project *project, ProjectExplorer::Node *node); public: // for nodes to emit signals, do not call unless you are a node - void emitNodeUpdated(ProjectExplorer::Node *node); - - // projects - void emitAboutToChangeShowInSimpleTree(ProjectExplorer::FolderNode *node); - void emitShowInSimpleTreeChanged(ProjectExplorer::FolderNode *node); - - // folders & projects - void emitFoldersAboutToBeAdded(FolderNode *parentFolder, - const QList<FolderNode*> &newFolders); - void emitFoldersAdded(FolderNode *folder); - - void emitFoldersAboutToBeRemoved(FolderNode *parentFolder, - const QList<FolderNode*> &staleFolders); - void emitFoldersRemoved(FolderNode *folder); - - // files - void emitFilesAboutToBeAdded(FolderNode *folder, - const QList<FileNode*> &newFiles); - void emitFilesAdded(FolderNode *folder); - - void emitFilesAboutToBeRemoved(FolderNode *folder, - const QList<FileNode*> &staleFiles); - void emitFilesRemoved(FolderNode *folder); - void emitNodeSortKeyAboutToChange(Node *node); - void emitNodeSortKeyChanged(Node *node); - + static void emitNodeUpdated(ProjectExplorer::Node *node); + static void emitDataChanged(); void collapseAll(); private: @@ -144,14 +97,9 @@ private: private: static ProjectTree *s_instance; - QList<Internal::ProjectTreeWidget *> m_projectTreeWidgets; - Node *m_currentNode = nullptr; + QList<QPointer<Internal::ProjectTreeWidget>> m_projectTreeWidgets; + QPointer<Node> m_currentNode; Project *m_currentProject = nullptr; - QList<FileNode *> m_filesAdded; - QList<FolderNode *> m_foldersAdded; - bool m_resetCurrentNodeFolder = false; - bool m_resetCurrentNodeFile = false; - bool m_resetCurrentNodeProject = false; Internal::ProjectTreeWidget *m_focusForContextMenu = nullptr; Core::Context m_lastProjectContext; }; diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp index ba2f304c7a..387612e832 100644 --- a/src/plugins/projectexplorer/projecttreewidget.cpp +++ b/src/plugins/projectexplorer/projecttreewidget.cpp @@ -167,17 +167,15 @@ private: */ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent) { - m_model = new FlatModel(SessionManager::sessionNode(), this); - Project *pro = SessionManager::startupProject(); - if (pro) - m_model->setStartupProject(pro->rootProjectNode()); - + // We keep one instance per tree as this also manages the + // simple/non-simple etc state which is per tree. + m_model = new FlatModel(this); m_view = new ProjectTreeView; m_view->setModel(m_model); m_view->setItemDelegate(new ProjectTreeItemDelegate(this)); setFocusProxy(m_view); m_view->installEventFilter(this); - initView(); + m_model->setView(m_view); auto layout = new QVBoxLayout(); layout->addWidget(ItemViewFind::createSearchableWrapper( @@ -198,8 +196,6 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent) this, &ProjectTreeWidget::setGeneratedFilesFilter); // connections - connect(m_model, &QAbstractItemModel::modelReset, - this, &ProjectTreeWidget::initView); connect(m_model, &FlatModel::renamed, this, &ProjectTreeWidget::renamed); connect(m_view, &QAbstractItemView::activated, @@ -209,19 +205,6 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent) connect(m_view, &QWidget::customContextMenuRequested, this, &ProjectTreeWidget::showContextMenu); - SessionManager *sessionManager = SessionManager::instance(); - connect(sessionManager, &SessionManager::projectAdded, - this, &ProjectTreeWidget::handleProjectAdded); - connect(sessionManager, &SessionManager::startupProjectChanged, - this, &ProjectTreeWidget::startupProjectChanged); - - connect(sessionManager, &SessionManager::aboutToLoadSession, - this, &ProjectTreeWidget::disableAutoExpand); - connect(sessionManager, &SessionManager::sessionLoaded, - this, &ProjectTreeWidget::loadExpandData); - connect(sessionManager, &SessionManager::aboutToSaveSession, - this, &ProjectTreeWidget::saveExpandData); - m_toggleSync = new QToolButton; m_toggleSync->setIcon(Utils::Icons::LINK.icon()); m_toggleSync->setCheckable(true); @@ -230,6 +213,7 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent) connect(m_toggleSync, &QAbstractButton::clicked, this, &ProjectTreeWidget::toggleAutoSynchronization); + setCurrentItem(ProjectTree::currentNode()); setAutoSynchronization(true); m_projectTreeWidgets << this; @@ -268,14 +252,6 @@ void ProjectTreeWidget::rowsInserted(const QModelIndex &parent, int start, int e { Node *node = m_model->nodeForIndex(parent); QTC_ASSERT(node, return); - const QString path = node->filePath().toString(); - const QString displayName = node->displayName(); - - auto it = m_toExpand.find(ExpandData(path, displayName)); - if (it != m_toExpand.end()) { - m_view->expand(parent); - m_toExpand.erase(it); - } int i = start; while (i <= end) { QModelIndex idx = m_model->index(i, 0, parent); @@ -317,68 +293,6 @@ Node *ProjectTreeWidget::mostExpandedNode(const QList<Node *> &nodes) return bestNode; } -void ProjectTreeWidget::disableAutoExpand() -{ - m_autoExpand = false; -} - -void ProjectTreeWidget::loadExpandData() -{ - m_autoExpand = true; - QList<QVariant> data = SessionManager::value(QLatin1String("ProjectTree.ExpandData")).value<QList<QVariant>>(); - QSet<ExpandData> set = Utils::transform<QSet>(data, [](const QVariant &v) { - QStringList list = v.toStringList(); - if (list.size() != 2) - return ExpandData(); - return ExpandData(list.at(0), list.at(1)); - }); - - set.remove(ExpandData()); - - recursiveLoadExpandData(m_view->rootIndex(), set); - - // store remaning nodes to expand - m_toExpand = set; -} - -void ProjectTreeWidget::recursiveLoadExpandData(const QModelIndex &index, QSet<ExpandData> &data) -{ - Node *node = m_model->nodeForIndex(index); - const QString path = node->filePath().toString(); - const QString displayName = node->displayName(); - auto it = data.find(ExpandData(path, displayName)); - if (it != data.end()) { - m_view->expand(index); - data.erase(it); - int count = m_model->rowCount(index); - for (int i = 0; i < count; ++i) - recursiveLoadExpandData(index.child(i, 0), data); - } -} - -void ProjectTreeWidget::saveExpandData() -{ - QList<QVariant> data; - recursiveSaveExpandData(m_view->rootIndex(), &data); - // TODO if there are multiple ProjectTreeWidgets, the last one saves the data - SessionManager::setValue(QLatin1String("ProjectTree.ExpandData"), data); -} - -void ProjectTreeWidget::recursiveSaveExpandData(const QModelIndex &index, QList<QVariant> *data) -{ - Q_ASSERT(data); - if (m_view->isExpanded(index) || index == m_view->rootIndex()) { - // Note: We store the path+displayname of the node, which isn't unique for e.g. .pri files - // but works for most nodes - Node *node = m_model->nodeForIndex(index); - const QStringList &list = ExpandData(node->filePath().toString(), node->displayName()).toStringList(); - data->append(QVariant::fromValue(list)); - int count = m_model->rowCount(index); - for (int i = 0; i < count; ++i) - recursiveSaveExpandData(index.child(i, 0), data); - } -} - QToolButton *ProjectTreeWidget::toggleSync() { return m_toggleSync; @@ -427,9 +341,9 @@ void ProjectTreeWidget::editCurrentItem() m_view->edit(m_view->selectionModel()->currentIndex()); } - void ProjectTreeWidget::renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath) { + update(); Q_UNUSED(oldPath); if (!currentNode() || currentNode()->filePath() != newPath) { // try to find the node @@ -453,7 +367,6 @@ void ProjectTreeWidget::setCurrentItem(Node *node) } else { m_view->clearSelection(); } - } void ProjectTreeWidget::handleCurrentItemChange(const QModelIndex ¤t) @@ -491,45 +404,6 @@ void ProjectTreeWidget::showContextMenu(const QPoint &pos) ProjectTree::showContextMenu(this, m_view->mapToGlobal(pos), node); } -void ProjectTreeWidget::handleProjectAdded(Project *project) -{ - Node *node = project->rootProjectNode(); - QModelIndex idx = m_model->indexForNode(node); - if (m_autoExpand) // disabled while session restoring - m_view->setExpanded(idx, true); - m_view->setCurrentIndex(idx); - - connect(m_model, &FlatModel::rowsInserted, - this, &ProjectTreeWidget::rowsInserted); -} - -void ProjectTreeWidget::startupProjectChanged(Project *project) -{ - if (project) { - ProjectNode *node = project->rootProjectNode(); - m_model->setStartupProject(node); - } else { - m_model->setStartupProject(0); - } -} - -void ProjectTreeWidget::initView() -{ - QModelIndex sessionIndex = m_model->index(0, 0); - - // hide root folder - m_view->setRootIndex(sessionIndex); - - while (m_model->canFetchMore(sessionIndex)) - m_model->fetchMore(sessionIndex); - - // expand top level projects - for (int i = 0; i < m_model->rowCount(sessionIndex); ++i) - m_view->expand(m_model->index(i, 0, sessionIndex)); - - setCurrentItem(ProjectTree::currentNode()); -} - void ProjectTreeWidget::openItem(const QModelIndex &mainIndex) { Node *node = m_model->nodeForIndex(mainIndex); diff --git a/src/plugins/projectexplorer/projecttreewidget.h b/src/plugins/projectexplorer/projecttreewidget.h index dbda089187..2a94a29e0c 100644 --- a/src/plugins/projectexplorer/projecttreewidget.h +++ b/src/plugins/projectexplorer/projecttreewidget.h @@ -47,6 +47,7 @@ class FileNode; namespace Internal { class FlatModel; +class WrapperNode; class ProjectTreeWidget : public QWidget { @@ -78,32 +79,20 @@ private: void handleCurrentItemChange(const QModelIndex ¤t); void showContextMenu(const QPoint &pos); void openItem(const QModelIndex &mainIndex); - void handleProjectAdded(ProjectExplorer::Project *project); - void startupProjectChanged(ProjectExplorer::Project *project); - void initView(); - - void loadExpandData(); - void saveExpandData(); - void disableAutoExpand(); void setCurrentItem(ProjectExplorer::Node *node); - void recursiveLoadExpandData(const QModelIndex &index, QSet<ExpandData> &data); - void recursiveSaveExpandData(const QModelIndex &index, QList<QVariant> *data); static int expandedCount(Node *node); void rowsInserted(const QModelIndex &parent, int start, int end); void renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath); - QSet<ExpandData> m_toExpand; QTreeView *m_view = nullptr; FlatModel *m_model = nullptr; QAction *m_filterProjectsAction = nullptr; QAction *m_filterGeneratedFilesAction; QToolButton *m_toggleSync; - QModelIndex m_subIndex; QString m_modelId; bool m_autoSync = false; - bool m_autoExpand = true; Utils::FileName m_delayedRename; static QList<ProjectTreeWidget *> m_projectTreeWidgets; diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 2d789f6d83..42b36aca24 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -93,7 +93,7 @@ public: static QString windowTitleAddition(const QString &filePath); static QString sessionTitle(const QString &filePath); - std::unique_ptr<SessionNode> m_sessionNode; + SessionNode m_sessionNode; QString m_sessionName = QLatin1String("default"); bool m_virginSession = true; bool m_loadingSession = false; @@ -124,8 +124,6 @@ SessionManager::SessionManager(QObject *parent) : QObject(parent) m_instance = this; d = new SessionManagerPrivate; - d->m_sessionNode.reset(new SessionNode); - connect(ModeManager::instance(), &ModeManager::currentModeChanged, this, &SessionManager::saveActiveMode); @@ -383,13 +381,13 @@ void SessionManager::addProject(Project *pro) QTC_ASSERT(!d->m_projects.contains(pro), return); d->m_projects.append(pro); - d->m_sessionNode->addProjectNodes(QList<ProjectNode *>() << pro->rootProjectNode()); + d->m_sessionNode.addProjectNodes({ pro->rootProjectNode() }); connect(pro, &Project::fileListChanged, m_instance, &SessionManager::clearProjectFileCache); connect(pro, &Project::displayNameChanged, m_instance, [pro] { - d->m_sessionNode->projectDisplayNameChanged(pro->rootProjectNode()); + d->m_sessionNode.emitNodeUpdated(); emit m_instance->projectDisplayNameChanged(pro); }); @@ -650,11 +648,9 @@ Project *SessionManager::projectForNode(Node *node) if (!rootProjectNode) rootProjectNode = node->parentFolderNode(); - while (rootProjectNode && rootProjectNode->parentFolderNode() != d->m_sessionNode.get()) + while (rootProjectNode && rootProjectNode->parentFolderNode() != &d->m_sessionNode) rootProjectNode = rootProjectNode->parentFolderNode(); - Q_ASSERT(rootProjectNode); - return Utils::findOrDefault(d->m_projects, Utils::equal(&Project::rootProjectNode, rootProjectNode)); } @@ -742,7 +738,7 @@ void SessionManager::removeProjects(QList<Project *> remove) m_instance, &SessionManager::clearProjectFileCache); d->m_projectFileCache.remove(pro); - d->m_sessionNode->removeProjectNodes(QList<ProjectNode *>() << pro->rootProjectNode()); + d->m_sessionNode.removeProjectNodes({ pro->rootProjectNode() }); emit m_instance->projectRemoved(pro); delete pro; } @@ -1095,7 +1091,7 @@ QString SessionManager::lastSession() SessionNode *SessionManager::sessionNode() { - return d->m_sessionNode.get(); + return &d->m_sessionNode; } void SessionManager::reportProjectLoadingProgress() diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index f987c655b6..dd3b055db9 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -2083,15 +2083,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult) removeProjectNodes(projectNodes()); removeFolderNodes(folderNodes()); - bool changesShowInSimpleTree = showInSimpleTree() ^ showInSimpleTree(result->projectType); - - if (changesShowInSimpleTree) - ProjectTree::instance()->emitAboutToChangeShowInSimpleTree(this); - m_projectType = result->projectType; - - if (changesShowInSimpleTree) - ProjectTree::instance()->emitShowInSimpleTreeChanged(this); } // @@ -2232,6 +2224,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult) updateGeneratedFiles(buildDirectory); cleanupProFileReaders(); + ProjectNode::emitTreeChanged(); } void QmakeProFileNode::cleanupProFileReaders() |