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:
hjk
2017-01-19 14:54:23 +01:00
parent 03a68a91bb
commit 3c743346b0
13 changed files with 236 additions and 1063 deletions

View File

@@ -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 &current)
@@ -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);