forked from qt-creator/qt-creator
ProjectExplorer: Make the FlatModel a Utils::TreeModel
The FlatModel is essentially a proxy model keeping expansion and
filter state per ProjectTree(View). Using a Utils::TreeModel makes
it fast enough to allow recreation of the proxy structure on
structural changes simplifying the parent/child logic significantly.
The {Session,Project,Folder,File}Node hierarchy still is still primary
information and shared by all views.
Change-Id: Ic08180a19bda37908280ff30e0737d188ed93e92
Reviewed-by: Robert Loehning <robert.loehning@qt.io>
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
@@ -249,13 +249,16 @@ public:
|
|||||||
explicit TreeModel(QObject *parent = 0) : BaseTreeModel(new RootItem, parent) {}
|
explicit TreeModel(QObject *parent = 0) : BaseTreeModel(new RootItem, parent) {}
|
||||||
explicit TreeModel(RootItem *root, QObject *parent = 0) : BaseTreeModel(root, parent) {}
|
explicit TreeModel(RootItem *root, QObject *parent = 0) : BaseTreeModel(root, parent) {}
|
||||||
|
|
||||||
|
using BaseTreeModel::canFetchMore;
|
||||||
using BaseTreeModel::clear;
|
using BaseTreeModel::clear;
|
||||||
using BaseTreeModel::columnCount;
|
using BaseTreeModel::columnCount;
|
||||||
using BaseTreeModel::data;
|
using BaseTreeModel::data;
|
||||||
using BaseTreeModel::destroyItem;
|
using BaseTreeModel::destroyItem;
|
||||||
|
using BaseTreeModel::fetchMore;
|
||||||
using BaseTreeModel::hasChildren;
|
using BaseTreeModel::hasChildren;
|
||||||
using BaseTreeModel::index;
|
using BaseTreeModel::index;
|
||||||
using BaseTreeModel::indexForItem;
|
using BaseTreeModel::indexForItem;
|
||||||
|
using BaseTreeModel::parent;
|
||||||
using BaseTreeModel::rowCount;
|
using BaseTreeModel::rowCount;
|
||||||
using BaseTreeModel::setData;
|
using BaseTreeModel::setData;
|
||||||
using BaseTreeModel::setHeader;
|
using BaseTreeModel::setHeader;
|
||||||
|
|||||||
@@ -37,9 +37,15 @@ bool ExpandData::operator==(const ExpandData &other) const
|
|||||||
return path == other.path && displayName == other.displayName;
|
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)
|
int ProjectExplorer::Internal::qHash(const ExpandData &data)
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ public:
|
|||||||
ExpandData() = default;
|
ExpandData() = default;
|
||||||
ExpandData(const QString &path_, const QString &displayName_);
|
ExpandData(const QString &path_, const QString &displayName_);
|
||||||
bool operator==(const ExpandData &other) const;
|
bool operator==(const ExpandData &other) const;
|
||||||
QStringList toStringList() const;
|
|
||||||
|
static ExpandData fromSettings(const QVariant &v);
|
||||||
|
QVariant toSettings() const;
|
||||||
|
|
||||||
QString path;
|
QString path;
|
||||||
QString displayName;
|
QString displayName;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "projectnodes.h"
|
#include "projectnodes.h"
|
||||||
#include "projectexplorer.h"
|
#include "projectexplorer.h"
|
||||||
#include "projecttree.h"
|
#include "projecttree.h"
|
||||||
|
#include "session.h"
|
||||||
|
|
||||||
#include <coreplugin/fileiconprovider.h>
|
#include <coreplugin/fileiconprovider.h>
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
@@ -40,15 +41,13 @@
|
|||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
|
|
||||||
using namespace Internal;
|
using namespace Internal;
|
||||||
|
|
||||||
namespace {
|
static bool sortNodes(const Node *n1, const Node *n2)
|
||||||
|
|
||||||
// sorting helper function
|
|
||||||
|
|
||||||
bool sortNodes(Node *n1, Node *n2)
|
|
||||||
{
|
{
|
||||||
if (n1->priority() > n2->priority())
|
if (n1->priority() > n2->priority())
|
||||||
return true;
|
return true;
|
||||||
@@ -66,78 +65,45 @@ bool sortNodes(Node *n1, Node *n2)
|
|||||||
return n1 < n2; // sort by pointer value
|
return n1 < n2; // sort by pointer value
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace anon
|
static bool sortWrapperNodes(const WrapperNode *w1, const WrapperNode *w2)
|
||||||
|
|
||||||
FlatModel::FlatModel(SessionNode *rootNode, QObject *parent) : QAbstractItemModel(parent),
|
|
||||||
m_rootNode(rootNode)
|
|
||||||
{
|
{
|
||||||
|
return sortNodes(w1->m_node, w2->m_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
ProjectTree *tree = ProjectTree::instance();
|
||||||
|
connect(tree, &ProjectTree::dataChanged, this, &FlatModel::update);
|
||||||
|
connect(tree, &ProjectTree::nodeUpdated, this, &FlatModel::nodeUpdated);
|
||||||
|
|
||||||
connect(tree, &ProjectTree::aboutToChangeShowInSimpleTree,
|
SessionManager *sm = SessionManager::instance();
|
||||||
this, &FlatModel::aboutToShowInSimpleTreeChanged);
|
connect(sm, &SessionManager::projectRemoved, this, &FlatModel::update);
|
||||||
|
connect(sm, &SessionManager::startupProjectChanged, this, &FlatModel::startupProjectChanged);
|
||||||
|
|
||||||
connect(tree, &ProjectTree::showInSimpleTreeChanged,
|
connect(sm, &SessionManager::sessionLoaded, this, &FlatModel::loadExpandData);
|
||||||
this, &FlatModel::showInSimpleTreeChanged);
|
connect(sm, &SessionManager::aboutToSaveSession, this, &FlatModel::saveExpandData);
|
||||||
|
connect(sm, &SessionManager::projectAdded, this, &FlatModel::handleProjectAdded);
|
||||||
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
|
void FlatModel::setView(QTreeView *view)
|
||||||
{
|
{
|
||||||
QModelIndex result;
|
QTC_CHECK(!m_view);
|
||||||
if (!parent.isValid() && row == 0 && column == 0) { // session
|
m_view = view;
|
||||||
result = createIndex(0, 0, m_rootNode);
|
connect(m_view, &QTreeView::expanded, this, &FlatModel::onExpanded);
|
||||||
} else if (parent.isValid() && column == 0) {
|
connect(m_view, &QTreeView::collapsed, this, &FlatModel::onCollapsed);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex FlatModel::parent(const QModelIndex &idx) const
|
void FlatModel::startupProjectChanged(Project *project)
|
||||||
{
|
{
|
||||||
QModelIndex parentIndex;
|
ProjectNode *projectNode = project ? project->rootProjectNode() : nullptr;
|
||||||
if (Node *node = nodeForIndex(idx)) {
|
if (m_startupProject == projectNode)
|
||||||
FolderNode *parentNode = visibleFolderNode(node->parentFolderNode());
|
return;
|
||||||
if (parentNode)
|
m_startupProject = projectNode;
|
||||||
return indexForNode(parentNode);
|
layoutChanged();
|
||||||
}
|
|
||||||
return parentIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant FlatModel::data(const QModelIndex &index, int role) const
|
QVariant FlatModel::data(const QModelIndex &index, int role) const
|
||||||
@@ -149,7 +115,6 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
|
|||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole: {
|
case Qt::DisplayRole: {
|
||||||
QString name = node->displayName();
|
QString name = node->displayName();
|
||||||
|
|
||||||
if (node->nodeType() == NodeType::Project
|
if (node->nodeType() == NodeType::Project
|
||||||
&& node->parentFolderNode()
|
&& node->parentFolderNode()
|
||||||
&& node->parentFolderNode()->nodeType() == NodeType::Session) {
|
&& 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
|
// We control the only view, and that one does the checks
|
||||||
Qt::ItemFlags f = Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsDragEnabled;
|
Qt::ItemFlags f = Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsDragEnabled;
|
||||||
if (Node *node = nodeForIndex(index)) {
|
if (Node *node = nodeForIndex(index)) {
|
||||||
if (node == m_rootNode)
|
if (node->asSessionNode())
|
||||||
return 0; // no flags for session node...
|
return 0; // no flags for session node...
|
||||||
if (!node->asProjectNode()) {
|
if (!node->asProjectNode()) {
|
||||||
// either folder or file node
|
// either folder or file node
|
||||||
@@ -235,142 +200,116 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FlatModel::rowCount(const QModelIndex &parent) const
|
void FlatModel::update()
|
||||||
{
|
{
|
||||||
int rows = 0;
|
m_timer.start(300);
|
||||||
if (!parent.isValid()) {
|
}
|
||||||
rows = 1;
|
|
||||||
} else {
|
void FlatModel::doUpdate()
|
||||||
FolderNode *folderNode = nodeForIndex(parent)->asFolderNode();
|
{
|
||||||
if (folderNode && m_childNodes.contains(folderNode))
|
m_timer.stop();
|
||||||
rows = m_childNodes.value(folderNode).size();
|
rebuildModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlatModel::rebuildModel()
|
||||||
|
{
|
||||||
|
QSet<Node *> seen;
|
||||||
|
|
||||||
|
rootItem()->removeChildren();
|
||||||
|
const QList<ProjectNode *> projectNodes = SessionManager::sessionNode()->projectNodes();
|
||||||
|
for (ProjectNode *projectNode : projectNodes) {
|
||||||
|
if (!seen.contains(projectNode))
|
||||||
|
addProjectNode(rootItem(), projectNode, &seen);
|
||||||
}
|
}
|
||||||
return rows;
|
|
||||||
|
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());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int FlatModel::columnCount(const QModelIndex &/*parent*/) const
|
void FlatModel::onCollapsed(const QModelIndex &idx)
|
||||||
{
|
{
|
||||||
return 1;
|
m_toExpand.remove(expandDataForNode(nodeForIndex(idx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlatModel::hasChildren(const QModelIndex &parent) const
|
void FlatModel::onExpanded(const QModelIndex &idx)
|
||||||
{
|
{
|
||||||
if (!parent.isValid())
|
m_toExpand.insert(expandDataForNode(nodeForIndex(idx)));
|
||||||
return true;
|
}
|
||||||
|
|
||||||
FolderNode *folderNode = nodeForIndex(parent)->asFolderNode();
|
ExpandData FlatModel::expandDataForNode(const Node *node) const
|
||||||
if (!folderNode)
|
{
|
||||||
return false;
|
QTC_ASSERT(node, return ExpandData());
|
||||||
|
const QString path = node->filePath().toString();
|
||||||
|
const QString displayName = node->displayName();
|
||||||
|
return ExpandData(path, displayName);
|
||||||
|
}
|
||||||
|
|
||||||
QHash<FolderNode*, QList<Node*> >::const_iterator it = m_childNodes.constFind(folderNode);
|
void FlatModel::handleProjectAdded(Project *project)
|
||||||
if (it == m_childNodes.constEnd()) {
|
{
|
||||||
fetchMore(folderNode);
|
Node *node = project->rootProjectNode();
|
||||||
it = m_childNodes.constFind(folderNode);
|
m_toExpand.insert(expandDataForNode(node));
|
||||||
|
if (WrapperNode *wrapper = wrapperForNode(node)) {
|
||||||
|
wrapper->forFirstLevelChildren([this](WrapperNode *child) {
|
||||||
|
m_toExpand.insert(expandDataForNode(child->m_node));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return !it.value().isEmpty();
|
doUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlatModel::canFetchMore(const QModelIndex & parent) const
|
void FlatModel::loadExpandData()
|
||||||
{
|
{
|
||||||
if (!parent.isValid()) {
|
const QList<QVariant> data = SessionManager::value("ProjectTree.ExpandData").value<QList<QVariant>>();
|
||||||
return false;
|
m_toExpand = Utils::transform<QSet>(data, [](const QVariant &v) { return ExpandData::fromSettings(v); });
|
||||||
} else {
|
m_toExpand.remove(ExpandData());
|
||||||
if (FolderNode *folderNode = nodeForIndex(parent)->asFolderNode())
|
}
|
||||||
return !m_childNodes.contains(folderNode);
|
|
||||||
else
|
void FlatModel::saveExpandData()
|
||||||
return false;
|
{
|
||||||
|
// 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::addProjectNode(WrapperNode *parent, ProjectNode *projectNode, QSet<Node *> *seen)
|
||||||
|
{
|
||||||
|
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::recursiveAddFolderNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
|
void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet<Node *> *seen)
|
||||||
{
|
{
|
||||||
foreach (FolderNode *folderNode, startNode->folderNodes()) {
|
const QList<FolderNode *> subFolderNodes = folderNode->folderNodes();
|
||||||
if (folderNode && !blackList.contains(folderNode))
|
for (FolderNode *subFolderNode : subFolderNodes) {
|
||||||
recursiveAddFolderNodesImpl(folderNode, list, blackList);
|
if (!filter(subFolderNode) && !seen->contains(subFolderNode)) {
|
||||||
}
|
seen->insert(subFolderNode);
|
||||||
}
|
auto node = new WrapperNode(subFolderNode);
|
||||||
|
parent->appendChild(node);
|
||||||
void FlatModel::recursiveAddFolderNodesImpl(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
|
addFolderNode(node, subFolderNode, seen);
|
||||||
{
|
node->sortChildren(&sortWrapperNodes);
|
||||||
if (!filter(startNode)) {
|
} else {
|
||||||
if (!blackList.contains(startNode))
|
addFolderNode(parent, subFolderNode, seen);
|
||||||
list->append(startNode);
|
|
||||||
} else {
|
|
||||||
foreach (FolderNode *folderNode, startNode->folderNodes()) {
|
|
||||||
if (folderNode && !blackList.contains(folderNode))
|
|
||||||
recursiveAddFolderNodesImpl(folderNode, list, blackList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
const QList<FileNode *> fileNodes = folderNode->fileNodes();
|
||||||
|
for (FileNode *fileNode : fileNodes) {
|
||||||
void FlatModel::recursiveAddFileNodes(FolderNode *startNode, QList<Node *> *list, const QSet<Node *> &blackList) const
|
if (!filter(fileNode) && !seen->contains(fileNode)) {
|
||||||
{
|
seen->insert(fileNode);
|
||||||
foreach (FolderNode *subFolderNode, startNode->folderNodes()) {
|
parent->appendChild(new WrapperNode(fileNode));
|
||||||
if (!blackList.contains(subFolderNode))
|
|
||||||
recursiveAddFileNodes(subFolderNode, list, blackList);
|
|
||||||
}
|
|
||||||
foreach (Node *node, startNode->fileNodes()) {
|
|
||||||
if (!blackList.contains(node) && !filter(node))
|
|
||||||
list->append(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Node*> FlatModel::childNodes(FolderNode *parentNode, const QSet<Node*> &blackList) const
|
|
||||||
{
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
Utils::sort(nodeList, sortNodes);
|
|
||||||
qCDebug(logger()) << " found" << nodeList.size() << "nodes";
|
|
||||||
return nodeList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlatModel::fetchMore(FolderNode *folderNode) const
|
|
||||||
{
|
|
||||||
Q_ASSERT(folderNode);
|
|
||||||
Q_ASSERT(!m_childNodes.contains(folderNode));
|
|
||||||
|
|
||||||
QList<Node*> nodeList = childNodes(folderNode);
|
|
||||||
m_childNodes.insert(folderNode, nodeList);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlatModel::fetchMore(const QModelIndex &parent)
|
|
||||||
{
|
|
||||||
FolderNode *folderNode = nodeForIndex(parent)->asFolderNode();
|
|
||||||
Q_ASSERT(folderNode);
|
|
||||||
|
|
||||||
fetchMore(folderNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlatModel::setStartupProject(ProjectNode *projectNode)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlatModel::reset()
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
m_childNodes.clear();
|
|
||||||
endResetModel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::DropActions FlatModel::supportedDragActions() const
|
Qt::DropActions FlatModel::supportedDragActions() const
|
||||||
@@ -395,32 +334,17 @@ QMimeData *FlatModel::mimeData(const QModelIndexList &indexes) const
|
|||||||
return data;
|
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
|
return findNonRooItem([this, node](WrapperNode *item) {
|
||||||
|
return item->m_node == node;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// we use non-const pointers internally
|
QModelIndex FlatModel::indexForNode(const Node *node) const
|
||||||
auto node = const_cast<Node*>(node_);
|
{
|
||||||
if (!node)
|
WrapperNode *wrapper = wrapperForNode(node);
|
||||||
return QModelIndex();
|
return wrapper ? indexForItem(wrapper) : QModelIndex();
|
||||||
|
|
||||||
if (node == m_rootNode)
|
|
||||||
return createIndex(0, 0, m_rootNode);
|
|
||||||
|
|
||||||
FolderNode *parentNode = visibleFolderNode(node->parentFolderNode());
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlatModel::setProjectFilterEnabled(bool filter)
|
void FlatModel::setProjectFilterEnabled(bool filter)
|
||||||
@@ -428,13 +352,13 @@ void FlatModel::setProjectFilterEnabled(bool filter)
|
|||||||
if (filter == m_filterProjects)
|
if (filter == m_filterProjects)
|
||||||
return;
|
return;
|
||||||
m_filterProjects = filter;
|
m_filterProjects = filter;
|
||||||
reset();
|
rebuildModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlatModel::setGeneratedFilesFilterEnabled(bool filter)
|
void FlatModel::setGeneratedFilesFilterEnabled(bool filter)
|
||||||
{
|
{
|
||||||
m_filterGeneratedFiles = filter;
|
m_filterGeneratedFiles = filter;
|
||||||
reset();
|
rebuildModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlatModel::projectFilterEnabled()
|
bool FlatModel::projectFilterEnabled()
|
||||||
@@ -449,28 +373,8 @@ bool FlatModel::generatedFilesFilterEnabled()
|
|||||||
|
|
||||||
Node *FlatModel::nodeForIndex(const QModelIndex &index) const
|
Node *FlatModel::nodeForIndex(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if (index.isValid())
|
WrapperNode *flatNode = itemForIndex(index);
|
||||||
return (Node*)index.internalPointer();
|
return flatNode ? flatNode->m_node : nullptr;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlatModel::filter(Node *node) const
|
bool FlatModel::filter(Node *node) const
|
||||||
@@ -502,343 +406,9 @@ bool isSorted(const QList<Node *> &nodes)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// slots and all the fun
|
void FlatModel::nodeUpdated(Node *)
|
||||||
void FlatModel::added(FolderNode* parentNode, const QList<Node*> &newNodeList)
|
|
||||||
{
|
{
|
||||||
qCDebug(logger()) << "FlatModel::added" << parentNode->filePath() << newNodeList.size() << "nodes";
|
update();
|
||||||
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)
|
|
||||||
{
|
|
||||||
QModelIndex idx = indexForNode(node);
|
|
||||||
emit dataChanged(idx, idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|||||||
@@ -25,51 +25,53 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include "expanddata.h"
|
||||||
|
#include "projectnodes.h"
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QTreeView>
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
|
|
||||||
class Node;
|
class Node;
|
||||||
class FileNode;
|
|
||||||
class FolderNode;
|
class FolderNode;
|
||||||
|
class Project;
|
||||||
class ProjectNode;
|
class ProjectNode;
|
||||||
class SessionNode;
|
|
||||||
|
|
||||||
namespace Internal {
|
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
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FlatModel(SessionNode *rootNode, QObject *parent);
|
FlatModel(QObject *parent);
|
||||||
|
|
||||||
|
void setView(QTreeView *view);
|
||||||
|
|
||||||
// QAbstractItemModel
|
// 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;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||||
bool setData(const QModelIndex &index, const QVariant &value, int role) 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;
|
Qt::DropActions supportedDragActions() const override;
|
||||||
QStringList mimeTypes() const override;
|
QStringList mimeTypes() const override;
|
||||||
QMimeData *mimeData(const QModelIndexList &indexes) const override;
|
QMimeData *mimeData(const QModelIndexList &indexes) const override;
|
||||||
|
|
||||||
void setStartupProject(ProjectNode *projectNode);
|
|
||||||
|
|
||||||
Node *nodeForIndex(const QModelIndex &index) const;
|
Node *nodeForIndex(const QModelIndex &index) const;
|
||||||
|
WrapperNode *wrapperForNode(const Node *node) const;
|
||||||
QModelIndex indexForNode(const Node *node) const;
|
QModelIndex indexForNode(const Node *node) const;
|
||||||
|
|
||||||
bool projectFilterEnabled();
|
bool projectFilterEnabled();
|
||||||
@@ -81,53 +83,34 @@ signals:
|
|||||||
void renamed(const Utils::FileName &oldName, const Utils::FileName &newName);
|
void renamed(const Utils::FileName &oldName, const Utils::FileName &newName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void aboutToShowInSimpleTreeChanged(ProjectExplorer::FolderNode *node);
|
void startupProjectChanged(Project *project);
|
||||||
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 nodeUpdated(ProjectExplorer::Node *node);
|
void nodeUpdated(ProjectExplorer::Node *node);
|
||||||
|
|
||||||
void added(FolderNode* folderNode, const QList<Node*> &newNodeList);
|
bool filter(Node *node) const; // Returns true if node is hidden.
|
||||||
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 m_filterProjects = false;
|
bool m_filterProjects = false;
|
||||||
bool m_filterGeneratedFiles = true;
|
bool m_filterGeneratedFiles = true;
|
||||||
|
|
||||||
SessionNode *m_rootNode;
|
|
||||||
mutable QHash<FolderNode*, QList<Node*> > m_childNodes;
|
|
||||||
ProjectNode *m_startupProject = nullptr;
|
ProjectNode *m_startupProject = nullptr;
|
||||||
|
|
||||||
FolderNode *m_parentFolderForChange = nullptr;
|
|
||||||
Node *m_nodeForSortKeyChange = nullptr;
|
|
||||||
|
|
||||||
static const QLoggingCategory &logger();
|
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);
|
int caseFriendlyCompare(const QString &a, const QString &b);
|
||||||
|
|||||||
@@ -68,30 +68,21 @@ void Node::setPriority(int p)
|
|||||||
m_priority = 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)
|
void Node::setAbsoluteFilePathAndLine(const Utils::FileName &path, int line)
|
||||||
{
|
{
|
||||||
if (m_filePath == path && m_line == line)
|
if (m_filePath == path && m_line == line)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
emitNodeSortKeyAboutToChange();
|
|
||||||
m_filePath = path;
|
m_filePath = path;
|
||||||
m_line = line;
|
m_line = line;
|
||||||
emitNodeSortKeyChanged();
|
|
||||||
emitNodeUpdated();
|
emitNodeUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node::~Node()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
NodeType Node::nodeType() const
|
NodeType Node::nodeType() const
|
||||||
{
|
{
|
||||||
return m_nodeType;
|
return m_nodeType;
|
||||||
@@ -186,7 +177,12 @@ void Node::setEnabled(bool enabled)
|
|||||||
void Node::emitNodeUpdated()
|
void Node::emitNodeUpdated()
|
||||||
{
|
{
|
||||||
if (parentFolderNode())
|
if (parentFolderNode())
|
||||||
ProjectTree::instance()->emitNodeUpdated(this);
|
ProjectTree::emitNodeUpdated(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::emitTreeChanged()
|
||||||
|
{
|
||||||
|
ProjectTree::emitDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *Node::trim(const QSet<Node *> &keepers)
|
Node *Node::trim(const QSet<Node *> &keepers)
|
||||||
@@ -511,9 +507,7 @@ void FolderNode::setDisplayName(const QString &name)
|
|||||||
{
|
{
|
||||||
if (m_displayName == name)
|
if (m_displayName == name)
|
||||||
return;
|
return;
|
||||||
emitNodeSortKeyAboutToChange();
|
|
||||||
m_displayName = name;
|
m_displayName = name;
|
||||||
emitNodeSortKeyChanged();
|
|
||||||
emitNodeUpdated();
|
emitNodeUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,8 +582,6 @@ void FolderNode::addFileNodes(const QList<FileNode *> &files)
|
|||||||
if (files.isEmpty())
|
if (files.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ProjectTree::instance()->emitFilesAboutToBeAdded(this, files);
|
|
||||||
|
|
||||||
foreach (FileNode *file, files) {
|
foreach (FileNode *file, files) {
|
||||||
QTC_ASSERT(!file->parentFolderNode(),
|
QTC_ASSERT(!file->parentFolderNode(),
|
||||||
qDebug("File node has already a parent folder"));
|
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;
|
QList<FileNode*> toRemove = files;
|
||||||
Utils::sort(toRemove);
|
Utils::sort(toRemove);
|
||||||
|
|
||||||
ProjectTree::instance()->emitFilesAboutToBeRemoved(this, toRemove);
|
|
||||||
|
|
||||||
auto toRemoveIter = toRemove.constBegin();
|
auto toRemoveIter = toRemove.constBegin();
|
||||||
auto filesIter = m_fileNodes.begin();
|
auto filesIter = m_fileNodes.begin();
|
||||||
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
|
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
|
||||||
@@ -641,7 +631,7 @@ void FolderNode::removeFileNodes(const QList<FileNode *> &files)
|
|||||||
filesIter = m_fileNodes.erase(filesIter);
|
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())
|
if (subFolders.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersAboutToBeAdded(this, subFolders);
|
|
||||||
foreach (FolderNode *folder, subFolders) {
|
foreach (FolderNode *folder, subFolders) {
|
||||||
QTC_ASSERT(!folder->parentFolderNode(),
|
QTC_ASSERT(!folder->parentFolderNode(),
|
||||||
qDebug("Project node has already a parent folder"));
|
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"));
|
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;
|
QList<FolderNode*> toRemove = subFolders;
|
||||||
Utils::sort(toRemove);
|
Utils::sort(toRemove);
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
|
|
||||||
|
|
||||||
auto toRemoveIter = toRemove.constBegin();
|
auto toRemoveIter = toRemove.constBegin();
|
||||||
auto folderIter = m_folderNodes.begin();
|
auto folderIter = m_folderNodes.begin();
|
||||||
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
|
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
|
||||||
@@ -712,7 +699,7 @@ void FolderNode::removeFolderNodes(const QList<FolderNode*> &subFolders)
|
|||||||
folderIter = m_folderNodes.erase(folderIter);
|
folderIter = m_folderNodes.erase(folderIter);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersRemoved(this);
|
ProjectTree::emitDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FolderNode::showInSimpleTree() const
|
bool FolderNode::showInSimpleTree() const
|
||||||
@@ -867,8 +854,6 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
|
|||||||
foreach (ProjectNode *projectNode, subProjects)
|
foreach (ProjectNode *projectNode, subProjects)
|
||||||
folderNodes << projectNode;
|
folderNodes << projectNode;
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersAboutToBeAdded(this, folderNodes);
|
|
||||||
|
|
||||||
foreach (ProjectNode *project, subProjects) {
|
foreach (ProjectNode *project, subProjects) {
|
||||||
QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this,
|
QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this,
|
||||||
qDebug("Project node has already a parent"));
|
qDebug("Project node has already a parent"));
|
||||||
@@ -876,10 +861,9 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
|
|||||||
m_folderNodes.append(project);
|
m_folderNodes.append(project);
|
||||||
m_projectNodes.append(project);
|
m_projectNodes.append(project);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::sort(m_folderNodes);
|
Utils::sort(m_folderNodes);
|
||||||
Utils::sort(m_projectNodes);
|
Utils::sort(m_projectNodes);
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersAdded(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,8 +882,6 @@ void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects)
|
|||||||
toRemove << projectNode;
|
toRemove << projectNode;
|
||||||
Utils::sort(toRemove);
|
Utils::sort(toRemove);
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
|
|
||||||
|
|
||||||
auto toRemoveIter = toRemove.constBegin();
|
auto toRemoveIter = toRemove.constBegin();
|
||||||
auto folderIter = m_folderNodes.begin();
|
auto folderIter = m_folderNodes.begin();
|
||||||
auto projectIter = m_projectNodes.begin();
|
auto projectIter = m_projectNodes.begin();
|
||||||
@@ -918,8 +900,6 @@ void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects)
|
|||||||
projectIter = m_projectNodes.erase(projectIter);
|
projectIter = m_projectNodes.erase(projectIter);
|
||||||
folderIter = m_folderNodes.erase(folderIter);
|
folderIter = m_folderNodes.erase(folderIter);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersRemoved(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -967,12 +947,6 @@ bool SessionNode::showInSimpleTree() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionNode::projectDisplayNameChanged(Node *node)
|
|
||||||
{
|
|
||||||
ProjectTree::instance()->emitNodeSortKeyAboutToChange(node);
|
|
||||||
ProjectTree::instance()->emitNodeSortKeyChanged(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<ProjectNode*> SessionNode::projectNodes() const
|
QList<ProjectNode*> SessionNode::projectNodes() const
|
||||||
{
|
{
|
||||||
return m_projectNodes;
|
return m_projectNodes;
|
||||||
@@ -990,8 +964,6 @@ void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes)
|
|||||||
foreach (ProjectNode *projectNode, projectNodes)
|
foreach (ProjectNode *projectNode, projectNodes)
|
||||||
folderNodes << projectNode;
|
folderNodes << projectNode;
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersAboutToBeAdded(this, folderNodes);
|
|
||||||
|
|
||||||
foreach (ProjectNode *project, projectNodes) {
|
foreach (ProjectNode *project, projectNodes) {
|
||||||
QTC_ASSERT(!project->parentFolderNode(),
|
QTC_ASSERT(!project->parentFolderNode(),
|
||||||
qDebug("Project node has already a parent folder"));
|
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_folderNodes);
|
||||||
Utils::sort(m_projectNodes);
|
Utils::sort(m_projectNodes);
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersAdded(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1015,9 +985,6 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
|
|||||||
toRemove << projectNode;
|
toRemove << projectNode;
|
||||||
|
|
||||||
Utils::sort(toRemove);
|
Utils::sort(toRemove);
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
|
|
||||||
|
|
||||||
auto toRemoveIter = toRemove.constBegin();
|
auto toRemoveIter = toRemove.constBegin();
|
||||||
auto folderIter = m_folderNodes.begin();
|
auto folderIter = m_folderNodes.begin();
|
||||||
auto projectIter = m_projectNodes.begin();
|
auto projectIter = m_projectNodes.begin();
|
||||||
@@ -1035,8 +1002,6 @@ void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
|
|||||||
projectIter = m_projectNodes.erase(projectIter);
|
projectIter = m_projectNodes.erase(projectIter);
|
||||||
folderIter = m_folderNodes.erase(folderIter);
|
folderIter = m_folderNodes.erase(folderIter);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectTree::instance()->emitFoldersRemoved(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,8 +104,9 @@ class NodesVisitor;
|
|||||||
class SessionManager;
|
class SessionManager;
|
||||||
|
|
||||||
// Documentation inside.
|
// Documentation inside.
|
||||||
class PROJECTEXPLORER_EXPORT Node
|
class PROJECTEXPLORER_EXPORT Node : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum PriorityLevel {
|
enum PriorityLevel {
|
||||||
DefaultPriority = 0,
|
DefaultPriority = 0,
|
||||||
@@ -116,7 +117,7 @@ public:
|
|||||||
DefaultProjectFilePriority = 500000
|
DefaultProjectFilePriority = 500000
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Node() = default;
|
virtual ~Node();
|
||||||
NodeType nodeType() const;
|
NodeType nodeType() const;
|
||||||
int priority() const;
|
int priority() const;
|
||||||
|
|
||||||
@@ -141,6 +142,7 @@ public:
|
|||||||
void setAbsoluteFilePathAndLine(const Utils::FileName &filePath, int line);
|
void setAbsoluteFilePathAndLine(const Utils::FileName &filePath, int line);
|
||||||
|
|
||||||
void emitNodeUpdated();
|
void emitNodeUpdated();
|
||||||
|
void emitTreeChanged();
|
||||||
|
|
||||||
virtual Node *trim(const QSet<Node *> &keepers);
|
virtual Node *trim(const QSet<Node *> &keepers);
|
||||||
|
|
||||||
@@ -161,9 +163,6 @@ protected:
|
|||||||
void setPriority(int priority);
|
void setPriority(int priority);
|
||||||
void setParentFolderNode(FolderNode *parentFolder);
|
void setParentFolderNode(FolderNode *parentFolder);
|
||||||
|
|
||||||
void emitNodeSortKeyAboutToChange();
|
|
||||||
void emitNodeSortKeyChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FolderNode *m_parentFolderNode = nullptr;
|
FolderNode *m_parentFolderNode = nullptr;
|
||||||
Utils::FileName m_filePath;
|
Utils::FileName m_filePath;
|
||||||
@@ -177,6 +176,7 @@ class PROJECTEXPLORER_EXPORT FileNode : public Node
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FileNode(const Utils::FileName &filePath, const FileType fileType, bool generated, int line = -1);
|
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;
|
FileType fileType() const;
|
||||||
bool isGenerated() const;
|
bool isGenerated() const;
|
||||||
@@ -255,8 +255,8 @@ public:
|
|||||||
void addFolderNodes(const QList<FolderNode*> &subFolders);
|
void addFolderNodes(const QList<FolderNode*> &subFolders);
|
||||||
void removeFolderNodes(const QList<FolderNode*> &subFolders);
|
void removeFolderNodes(const QList<FolderNode*> &subFolders);
|
||||||
|
|
||||||
FolderNode *asFolderNode() final { return this; }
|
FolderNode *asFolderNode() override { return this; }
|
||||||
const FolderNode *asFolderNode() const final { return this; }
|
const FolderNode *asFolderNode() const override { return this; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QList<FolderNode*> m_folderNodes;
|
QList<FolderNode*> m_folderNodes;
|
||||||
@@ -330,11 +330,8 @@ public:
|
|||||||
SessionNode();
|
SessionNode();
|
||||||
|
|
||||||
QList<ProjectAction> supportedActions(Node *node) const override;
|
QList<ProjectAction> supportedActions(Node *node) const override;
|
||||||
|
|
||||||
QList<ProjectNode*> projectNodes() const;
|
QList<ProjectNode*> projectNodes() const;
|
||||||
|
|
||||||
QString addFileFilter() const override;
|
QString addFileFilter() const override;
|
||||||
|
|
||||||
void accept(NodesVisitor *visitor) override;
|
void accept(NodesVisitor *visitor) override;
|
||||||
|
|
||||||
bool showInSimpleTree() const override;
|
bool showInSimpleTree() const override;
|
||||||
|
|||||||
@@ -258,167 +258,14 @@ void ProjectTree::updateContext()
|
|||||||
|
|
||||||
void ProjectTree::emitNodeUpdated(Node *node)
|
void ProjectTree::emitNodeUpdated(Node *node)
|
||||||
{
|
{
|
||||||
if (!isInNodeHierarchy(node))
|
if (!s_instance->isInNodeHierarchy(node))
|
||||||
return;
|
return;
|
||||||
emit nodeUpdated(node);
|
emit s_instance->nodeUpdated(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectTree::emitAboutToChangeShowInSimpleTree(FolderNode *node)
|
void ProjectTree::emitDataChanged()
|
||||||
{
|
{
|
||||||
if (!isInNodeHierarchy(node))
|
instance()->dataChanged();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectTree::collapseAll()
|
void ProjectTree::collapseAll()
|
||||||
|
|||||||
@@ -68,61 +68,14 @@ signals:
|
|||||||
|
|
||||||
// Emitted whenever the model needs to send a update signal.
|
// Emitted whenever the model needs to send a update signal.
|
||||||
void nodeUpdated(ProjectExplorer::Node *node);
|
void nodeUpdated(ProjectExplorer::Node *node);
|
||||||
|
void dataChanged();
|
||||||
// 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 aboutToShowContextMenu(ProjectExplorer::Project *project,
|
void aboutToShowContextMenu(ProjectExplorer::Project *project,
|
||||||
ProjectExplorer::Node *node);
|
ProjectExplorer::Node *node);
|
||||||
|
|
||||||
public: // for nodes to emit signals, do not call unless you are a node
|
public: // for nodes to emit signals, do not call unless you are a node
|
||||||
void emitNodeUpdated(ProjectExplorer::Node *node);
|
static void emitNodeUpdated(ProjectExplorer::Node *node);
|
||||||
|
static void emitDataChanged();
|
||||||
// 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);
|
|
||||||
|
|
||||||
void collapseAll();
|
void collapseAll();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -144,14 +97,9 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static ProjectTree *s_instance;
|
static ProjectTree *s_instance;
|
||||||
QList<Internal::ProjectTreeWidget *> m_projectTreeWidgets;
|
QList<QPointer<Internal::ProjectTreeWidget>> m_projectTreeWidgets;
|
||||||
Node *m_currentNode = nullptr;
|
QPointer<Node> m_currentNode;
|
||||||
Project *m_currentProject = nullptr;
|
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;
|
Internal::ProjectTreeWidget *m_focusForContextMenu = nullptr;
|
||||||
Core::Context m_lastProjectContext;
|
Core::Context m_lastProjectContext;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -167,17 +167,15 @@ private:
|
|||||||
*/
|
*/
|
||||||
ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
|
ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
m_model = new FlatModel(SessionManager::sessionNode(), this);
|
// We keep one instance per tree as this also manages the
|
||||||
Project *pro = SessionManager::startupProject();
|
// simple/non-simple etc state which is per tree.
|
||||||
if (pro)
|
m_model = new FlatModel(this);
|
||||||
m_model->setStartupProject(pro->rootProjectNode());
|
|
||||||
|
|
||||||
m_view = new ProjectTreeView;
|
m_view = new ProjectTreeView;
|
||||||
m_view->setModel(m_model);
|
m_view->setModel(m_model);
|
||||||
m_view->setItemDelegate(new ProjectTreeItemDelegate(this));
|
m_view->setItemDelegate(new ProjectTreeItemDelegate(this));
|
||||||
setFocusProxy(m_view);
|
setFocusProxy(m_view);
|
||||||
m_view->installEventFilter(this);
|
m_view->installEventFilter(this);
|
||||||
initView();
|
m_model->setView(m_view);
|
||||||
|
|
||||||
auto layout = new QVBoxLayout();
|
auto layout = new QVBoxLayout();
|
||||||
layout->addWidget(ItemViewFind::createSearchableWrapper(
|
layout->addWidget(ItemViewFind::createSearchableWrapper(
|
||||||
@@ -198,8 +196,6 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
|
|||||||
this, &ProjectTreeWidget::setGeneratedFilesFilter);
|
this, &ProjectTreeWidget::setGeneratedFilesFilter);
|
||||||
|
|
||||||
// connections
|
// connections
|
||||||
connect(m_model, &QAbstractItemModel::modelReset,
|
|
||||||
this, &ProjectTreeWidget::initView);
|
|
||||||
connect(m_model, &FlatModel::renamed,
|
connect(m_model, &FlatModel::renamed,
|
||||||
this, &ProjectTreeWidget::renamed);
|
this, &ProjectTreeWidget::renamed);
|
||||||
connect(m_view, &QAbstractItemView::activated,
|
connect(m_view, &QAbstractItemView::activated,
|
||||||
@@ -209,19 +205,6 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
|
|||||||
connect(m_view, &QWidget::customContextMenuRequested,
|
connect(m_view, &QWidget::customContextMenuRequested,
|
||||||
this, &ProjectTreeWidget::showContextMenu);
|
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 = new QToolButton;
|
||||||
m_toggleSync->setIcon(Utils::Icons::LINK.icon());
|
m_toggleSync->setIcon(Utils::Icons::LINK.icon());
|
||||||
m_toggleSync->setCheckable(true);
|
m_toggleSync->setCheckable(true);
|
||||||
@@ -230,6 +213,7 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
|
|||||||
connect(m_toggleSync, &QAbstractButton::clicked,
|
connect(m_toggleSync, &QAbstractButton::clicked,
|
||||||
this, &ProjectTreeWidget::toggleAutoSynchronization);
|
this, &ProjectTreeWidget::toggleAutoSynchronization);
|
||||||
|
|
||||||
|
setCurrentItem(ProjectTree::currentNode());
|
||||||
setAutoSynchronization(true);
|
setAutoSynchronization(true);
|
||||||
|
|
||||||
m_projectTreeWidgets << this;
|
m_projectTreeWidgets << this;
|
||||||
@@ -268,14 +252,6 @@ void ProjectTreeWidget::rowsInserted(const QModelIndex &parent, int start, int e
|
|||||||
{
|
{
|
||||||
Node *node = m_model->nodeForIndex(parent);
|
Node *node = m_model->nodeForIndex(parent);
|
||||||
QTC_ASSERT(node, return);
|
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;
|
int i = start;
|
||||||
while (i <= end) {
|
while (i <= end) {
|
||||||
QModelIndex idx = m_model->index(i, 0, parent);
|
QModelIndex idx = m_model->index(i, 0, parent);
|
||||||
@@ -317,68 +293,6 @@ Node *ProjectTreeWidget::mostExpandedNode(const QList<Node *> &nodes)
|
|||||||
return bestNode;
|
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()
|
QToolButton *ProjectTreeWidget::toggleSync()
|
||||||
{
|
{
|
||||||
return m_toggleSync;
|
return m_toggleSync;
|
||||||
@@ -427,9 +341,9 @@ void ProjectTreeWidget::editCurrentItem()
|
|||||||
m_view->edit(m_view->selectionModel()->currentIndex());
|
m_view->edit(m_view->selectionModel()->currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ProjectTreeWidget::renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath)
|
void ProjectTreeWidget::renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath)
|
||||||
{
|
{
|
||||||
|
update();
|
||||||
Q_UNUSED(oldPath);
|
Q_UNUSED(oldPath);
|
||||||
if (!currentNode() || currentNode()->filePath() != newPath) {
|
if (!currentNode() || currentNode()->filePath() != newPath) {
|
||||||
// try to find the node
|
// try to find the node
|
||||||
@@ -453,7 +367,6 @@ void ProjectTreeWidget::setCurrentItem(Node *node)
|
|||||||
} else {
|
} else {
|
||||||
m_view->clearSelection();
|
m_view->clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectTreeWidget::handleCurrentItemChange(const QModelIndex ¤t)
|
void ProjectTreeWidget::handleCurrentItemChange(const QModelIndex ¤t)
|
||||||
@@ -491,45 +404,6 @@ void ProjectTreeWidget::showContextMenu(const QPoint &pos)
|
|||||||
ProjectTree::showContextMenu(this, m_view->mapToGlobal(pos), node);
|
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)
|
void ProjectTreeWidget::openItem(const QModelIndex &mainIndex)
|
||||||
{
|
{
|
||||||
Node *node = m_model->nodeForIndex(mainIndex);
|
Node *node = m_model->nodeForIndex(mainIndex);
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ class FileNode;
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class FlatModel;
|
class FlatModel;
|
||||||
|
class WrapperNode;
|
||||||
|
|
||||||
class ProjectTreeWidget : public QWidget
|
class ProjectTreeWidget : public QWidget
|
||||||
{
|
{
|
||||||
@@ -78,32 +79,20 @@ private:
|
|||||||
void handleCurrentItemChange(const QModelIndex ¤t);
|
void handleCurrentItemChange(const QModelIndex ¤t);
|
||||||
void showContextMenu(const QPoint &pos);
|
void showContextMenu(const QPoint &pos);
|
||||||
void openItem(const QModelIndex &mainIndex);
|
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 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);
|
static int expandedCount(Node *node);
|
||||||
void rowsInserted(const QModelIndex &parent, int start, int end);
|
void rowsInserted(const QModelIndex &parent, int start, int end);
|
||||||
void renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath);
|
void renamed(const Utils::FileName &oldPath, const Utils::FileName &newPath);
|
||||||
|
|
||||||
QSet<ExpandData> m_toExpand;
|
|
||||||
QTreeView *m_view = nullptr;
|
QTreeView *m_view = nullptr;
|
||||||
FlatModel *m_model = nullptr;
|
FlatModel *m_model = nullptr;
|
||||||
QAction *m_filterProjectsAction = nullptr;
|
QAction *m_filterProjectsAction = nullptr;
|
||||||
QAction *m_filterGeneratedFilesAction;
|
QAction *m_filterGeneratedFilesAction;
|
||||||
QToolButton *m_toggleSync;
|
QToolButton *m_toggleSync;
|
||||||
|
|
||||||
QModelIndex m_subIndex;
|
|
||||||
QString m_modelId;
|
QString m_modelId;
|
||||||
bool m_autoSync = false;
|
bool m_autoSync = false;
|
||||||
bool m_autoExpand = true;
|
|
||||||
Utils::FileName m_delayedRename;
|
Utils::FileName m_delayedRename;
|
||||||
|
|
||||||
static QList<ProjectTreeWidget *> m_projectTreeWidgets;
|
static QList<ProjectTreeWidget *> m_projectTreeWidgets;
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public:
|
|||||||
static QString windowTitleAddition(const QString &filePath);
|
static QString windowTitleAddition(const QString &filePath);
|
||||||
static QString sessionTitle(const QString &filePath);
|
static QString sessionTitle(const QString &filePath);
|
||||||
|
|
||||||
std::unique_ptr<SessionNode> m_sessionNode;
|
SessionNode m_sessionNode;
|
||||||
QString m_sessionName = QLatin1String("default");
|
QString m_sessionName = QLatin1String("default");
|
||||||
bool m_virginSession = true;
|
bool m_virginSession = true;
|
||||||
bool m_loadingSession = false;
|
bool m_loadingSession = false;
|
||||||
@@ -124,8 +124,6 @@ SessionManager::SessionManager(QObject *parent) : QObject(parent)
|
|||||||
m_instance = this;
|
m_instance = this;
|
||||||
d = new SessionManagerPrivate;
|
d = new SessionManagerPrivate;
|
||||||
|
|
||||||
d->m_sessionNode.reset(new SessionNode);
|
|
||||||
|
|
||||||
connect(ModeManager::instance(), &ModeManager::currentModeChanged,
|
connect(ModeManager::instance(), &ModeManager::currentModeChanged,
|
||||||
this, &SessionManager::saveActiveMode);
|
this, &SessionManager::saveActiveMode);
|
||||||
|
|
||||||
@@ -383,13 +381,13 @@ void SessionManager::addProject(Project *pro)
|
|||||||
QTC_ASSERT(!d->m_projects.contains(pro), return);
|
QTC_ASSERT(!d->m_projects.contains(pro), return);
|
||||||
|
|
||||||
d->m_projects.append(pro);
|
d->m_projects.append(pro);
|
||||||
d->m_sessionNode->addProjectNodes(QList<ProjectNode *>() << pro->rootProjectNode());
|
d->m_sessionNode.addProjectNodes({ pro->rootProjectNode() });
|
||||||
|
|
||||||
connect(pro, &Project::fileListChanged,
|
connect(pro, &Project::fileListChanged,
|
||||||
m_instance, &SessionManager::clearProjectFileCache);
|
m_instance, &SessionManager::clearProjectFileCache);
|
||||||
|
|
||||||
connect(pro, &Project::displayNameChanged, m_instance, [pro] {
|
connect(pro, &Project::displayNameChanged, m_instance, [pro] {
|
||||||
d->m_sessionNode->projectDisplayNameChanged(pro->rootProjectNode());
|
d->m_sessionNode.emitNodeUpdated();
|
||||||
emit m_instance->projectDisplayNameChanged(pro);
|
emit m_instance->projectDisplayNameChanged(pro);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -650,11 +648,9 @@ Project *SessionManager::projectForNode(Node *node)
|
|||||||
if (!rootProjectNode)
|
if (!rootProjectNode)
|
||||||
rootProjectNode = node->parentFolderNode();
|
rootProjectNode = node->parentFolderNode();
|
||||||
|
|
||||||
while (rootProjectNode && rootProjectNode->parentFolderNode() != d->m_sessionNode.get())
|
while (rootProjectNode && rootProjectNode->parentFolderNode() != &d->m_sessionNode)
|
||||||
rootProjectNode = rootProjectNode->parentFolderNode();
|
rootProjectNode = rootProjectNode->parentFolderNode();
|
||||||
|
|
||||||
Q_ASSERT(rootProjectNode);
|
|
||||||
|
|
||||||
return Utils::findOrDefault(d->m_projects, Utils::equal(&Project::rootProjectNode, 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);
|
m_instance, &SessionManager::clearProjectFileCache);
|
||||||
d->m_projectFileCache.remove(pro);
|
d->m_projectFileCache.remove(pro);
|
||||||
|
|
||||||
d->m_sessionNode->removeProjectNodes(QList<ProjectNode *>() << pro->rootProjectNode());
|
d->m_sessionNode.removeProjectNodes({ pro->rootProjectNode() });
|
||||||
emit m_instance->projectRemoved(pro);
|
emit m_instance->projectRemoved(pro);
|
||||||
delete pro;
|
delete pro;
|
||||||
}
|
}
|
||||||
@@ -1095,7 +1091,7 @@ QString SessionManager::lastSession()
|
|||||||
|
|
||||||
SessionNode *SessionManager::sessionNode()
|
SessionNode *SessionManager::sessionNode()
|
||||||
{
|
{
|
||||||
return d->m_sessionNode.get();
|
return &d->m_sessionNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionManager::reportProjectLoadingProgress()
|
void SessionManager::reportProjectLoadingProgress()
|
||||||
|
|||||||
@@ -2083,15 +2083,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
|
|||||||
removeProjectNodes(projectNodes());
|
removeProjectNodes(projectNodes());
|
||||||
removeFolderNodes(folderNodes());
|
removeFolderNodes(folderNodes());
|
||||||
|
|
||||||
bool changesShowInSimpleTree = showInSimpleTree() ^ showInSimpleTree(result->projectType);
|
|
||||||
|
|
||||||
if (changesShowInSimpleTree)
|
|
||||||
ProjectTree::instance()->emitAboutToChangeShowInSimpleTree(this);
|
|
||||||
|
|
||||||
m_projectType = result->projectType;
|
m_projectType = result->projectType;
|
||||||
|
|
||||||
if (changesShowInSimpleTree)
|
|
||||||
ProjectTree::instance()->emitShowInSimpleTreeChanged(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -2232,6 +2224,7 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult)
|
|||||||
updateGeneratedFiles(buildDirectory);
|
updateGeneratedFiles(buildDirectory);
|
||||||
|
|
||||||
cleanupProFileReaders();
|
cleanupProFileReaders();
|
||||||
|
ProjectNode::emitTreeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmakeProFileNode::cleanupProFileReaders()
|
void QmakeProFileNode::cleanupProFileReaders()
|
||||||
|
|||||||
Reference in New Issue
Block a user