ProjectTree: Show parsing state of projects

Show which projects are currently parsing in the project tree.

Change-Id: Ie69907a73ec7c3cf2ef40c37db620a0144178f95
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Tobias Hunger
2017-07-21 11:47:27 +02:00
parent 905b9298ed
commit f5beeb4c7e
5 changed files with 124 additions and 24 deletions

View File

@@ -116,7 +116,7 @@ private:
void handleActiveBuildConfigurationChanged(); void handleActiveBuildConfigurationChanged();
void handleParsingStarted(const Internal::CMakeBuildConfiguration *bc); void handleParsingStarted(const Internal::CMakeBuildConfiguration *bc);
void handleTreeScanningFinished(); void handleTreeScanningFinished();
void updateProjectData(Internal::CMakeBuildConfiguration *cmakeBc); void updateProjectData(Internal::CMakeBuildConfiguration *bc);
void handleParsingError(Internal::CMakeBuildConfiguration *bc); void handleParsingError(Internal::CMakeBuildConfiguration *bc);
void updateQmlJSCodeModel(); void updateQmlJSCodeModel();

View File

@@ -85,7 +85,8 @@ public:
enum ModelRoles { enum ModelRoles {
// Absolute file path // Absolute file path
FilePathRole = QFileSystemModel::FilePathRole, FilePathRole = QFileSystemModel::FilePathRole,
EnabledRole EnabledRole,
isParsingRole
}; };
Project(const QString &mimeType, const Utils::FileName &fileName, Project(const QString &mimeType, const Utils::FileName &fileName,

View File

@@ -32,15 +32,18 @@
#include "session.h" #include "session.h"
#include <coreplugin/fileiconprovider.h> #include <coreplugin/fileiconprovider.h>
#include <utils/utilsicons.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/dropsupport.h> #include <utils/dropsupport.h>
#include <utils/theme/theme.h>
#include <QDebug>
#include <QFileInfo> #include <QFileInfo>
#include <QFont> #include <QFont>
#include <QMimeData> #include <QMimeData>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <functional>
using namespace Utils; using namespace Utils;
namespace ProjectExplorer { namespace ProjectExplorer {
@@ -106,10 +109,19 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
} }
case Qt::DecorationRole: { case Qt::DecorationRole: {
if (folderNode) { if (folderNode) {
result = folderNode->icon(); static QIcon emptyIcon = Utils::Icons::EMPTY16.icon();
if (ContainerNode *containerNode = folderNode->asContainerNode()) { if (ContainerNode *containerNode = folderNode->asContainerNode()) {
if (ProjectNode *projectNode = containerNode->rootProjectNode()) WrapperNode *wn = wrapperForNode(node);
result = projectNode->icon(); Project *project = Utils::findOrDefault(SessionManager::projects(), [this, wn](const Project *p) {
return nodeForProject(p) == wn;
});
if (project->isParsing())
result = emptyIcon;
else
result = containerNode->rootProjectNode() ? containerNode->rootProjectNode()->icon() :
folderNode->icon();
} else {
result = folderNode->icon();
} }
} else { } else {
result = Core::FileIconProvider::icon(node->filePath().toString()); result = Core::FileIconProvider::icon(node->filePath().toString());
@@ -133,6 +145,17 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
result = node->isEnabled(); result = node->isEnabled();
break; break;
} }
case Project::isParsingRole: {
const Project *project = nullptr;
if (node->asContainerNode()) {
WrapperNode *wn = wrapperForNode(node);
project = Utils::findOrDefault(SessionManager::projects(), [this, wn](const Project *p) {
return nodeForProject(p) == wn;
});
}
result = project ? project->isParsing() : false;
break;
}
} }
} }
@@ -216,6 +239,13 @@ void FlatModel::addOrRebuildProjectModel(Project *project)
emit requestExpansion(container->index()); emit requestExpansion(container->index());
} }
void FlatModel::parsingStateChanged(Project *project)
{
const WrapperNode *const node = nodeForProject(project);
const QModelIndex nodeIdx = indexForNode(node->m_node);
emit dataChanged(nodeIdx, nodeIdx);
}
void FlatModel::updateSubtree(FolderNode *node) void FlatModel::updateSubtree(FolderNode *node)
{ {
// FIXME: This is still excessive, should be limited to the affected subtree. // FIXME: This is still excessive, should be limited to the affected subtree.
@@ -261,6 +291,12 @@ ExpandData FlatModel::expandDataForNode(const Node *node) const
void FlatModel::handleProjectAdded(Project *project) void FlatModel::handleProjectAdded(Project *project)
{ {
QTC_ASSERT(project, return);
connect(project, &Project::parsingStarted,
this, [this, project]() { parsingStateChanged(project); });
connect(project, &Project::parsingFinished,
this, [this, project]() { parsingStateChanged(project); });
addOrRebuildProjectModel(project); addOrRebuildProjectModel(project);
} }
@@ -269,7 +305,7 @@ void FlatModel::handleProjectRemoved(Project *project)
destroyItem(nodeForProject(project)); destroyItem(nodeForProject(project));
} }
WrapperNode *FlatModel::nodeForProject(Project *project) WrapperNode *FlatModel::nodeForProject(const Project *project) const
{ {
QTC_ASSERT(project, return nullptr); QTC_ASSERT(project, return nullptr);
ContainerNode *containerNode = project->containerNode(); ContainerNode *containerNode = project->containerNode();

View File

@@ -99,9 +99,11 @@ private:
void saveExpandData(); void saveExpandData();
void handleProjectAdded(Project *project); void handleProjectAdded(Project *project);
void handleProjectRemoved(Project *project); void handleProjectRemoved(Project *project);
WrapperNode *nodeForProject(Project *project); WrapperNode *nodeForProject(const Project *project) const;
void addOrRebuildProjectModel(Project *project); void addOrRebuildProjectModel(Project *project);
void parsingStateChanged(Project *project);
QTimer m_timer; QTimer m_timer;
QSet<ExpandData> m_toExpand; QSet<ExpandData> m_toExpand;
}; };

View File

@@ -40,23 +40,28 @@
#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/find/itemviewfind.h> #include <coreplugin/find/itemviewfind.h>
#include <utils/navigationtreeview.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/navigationtreeview.h>
#include <utils/progressindicator.h>
#include <utils/tooltip/tooltip.h> #include <utils/tooltip/tooltip.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <QDebug> #include <QApplication>
#include <QSettings> #include <QSettings>
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QToolButton> #include <QToolButton>
#include <QPainter>
#include <QAction> #include <QAction>
#include <QMenu> #include <QMenu>
#include <memory>
using namespace Core; using namespace Core;
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal; using namespace ProjectExplorer::Internal;
using namespace Utils;
QList<ProjectTreeWidget *> ProjectTreeWidget::m_projectTreeWidgets; QList<ProjectTreeWidget *> ProjectTreeWidget::m_projectTreeWidgets;
@@ -65,22 +70,78 @@ namespace {
class ProjectTreeItemDelegate : public QStyledItemDelegate class ProjectTreeItemDelegate : public QStyledItemDelegate
{ {
public: public:
ProjectTreeItemDelegate(QObject *parent) : QStyledItemDelegate(parent) ProjectTreeItemDelegate(QTreeView *view) : QStyledItemDelegate(view),
{ } m_view(view)
{
connect(m_view->model(), &QAbstractItemModel::modelReset,
this, &ProjectTreeItemDelegate::deleteAllIndicators);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const // Actually this only needs to delete the indicators in the effected rows and *after* it,
// but just be lazy and nuke all the indicators.
connect(m_view->model(), &QAbstractItemModel::rowsAboutToBeRemoved,
this, &ProjectTreeItemDelegate::deleteAllIndicators);
connect(m_view->model(), &QAbstractItemModel::rowsAboutToBeInserted,
this, &ProjectTreeItemDelegate::deleteAllIndicators);
}
~ProjectTreeItemDelegate() override
{
deleteAllIndicators();
}
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
{ {
QStyleOptionViewItem opt = option; QStyleOptionViewItem opt = option;
if (!index.data(Project::EnabledRole).toBool()) if (!index.data(Project::EnabledRole).toBool())
opt.state &= ~QStyle::State_Enabled; opt.state &= ~QStyle::State_Enabled;
QStyledItemDelegate::paint(painter, opt, index); QStyledItemDelegate::paint(painter, opt, index);
if (index.data(Project::isParsingRole).toBool()) {
initStyleOption(&opt, index);
ProgressIndicatorPainter *indicator = findOrCreateIndicatorPainter(index);
QStyle *style = option.widget ? option.widget->style() : QApplication::style();
const QRect rect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, opt.widget);
indicator->paint(*painter, rect);
} else {
delete m_indicators.value(index);
m_indicators.remove(index);
}
} }
private:
ProgressIndicatorPainter *findOrCreateIndicatorPainter(const QModelIndex &index) const
{
ProgressIndicatorPainter *indicator = m_indicators.value(index);
if (!indicator)
indicator = createIndicatorPainter(index);
return indicator;
}
ProgressIndicatorPainter *createIndicatorPainter(const QModelIndex &index) const
{
auto indicator = new ProgressIndicatorPainter(ProgressIndicatorSize::Small);
indicator->setUpdateCallback([index, this]() { m_view->update(index); });
indicator->startAnimation();
m_indicators.insert(index, indicator);
return indicator;
}
void deleteAllIndicators()
{
qDeleteAll(m_indicators);
m_indicators.clear();
}
mutable QHash<QModelIndex, ProgressIndicatorPainter *> m_indicators;
QTreeView *m_view;
}; };
bool debug = false; bool debug = false;
} }
class ProjectTreeView : public Utils::NavigationTreeView class ProjectTreeView : public NavigationTreeView
{ {
public: public:
ProjectTreeView() ProjectTreeView()
@@ -138,7 +199,7 @@ public:
connect(newModel, &QAbstractItemModel::rowsRemoved, connect(newModel, &QAbstractItemModel::rowsRemoved,
this, &ProjectTreeView::invalidateSize); this, &ProjectTreeView::invalidateSize);
} }
Utils::NavigationTreeView::setModel(newModel); NavigationTreeView::setModel(newModel);
} }
~ProjectTreeView() ~ProjectTreeView()
@@ -150,7 +211,7 @@ public:
int sizeHintForColumn(int column) const override int sizeHintForColumn(int column) const override
{ {
if (m_cachedSize < 0) if (m_cachedSize < 0)
m_cachedSize = Utils::NavigationTreeView::sizeHintForColumn(column); m_cachedSize = NavigationTreeView::sizeHintForColumn(column);
return m_cachedSize; return m_cachedSize;
} }
@@ -172,7 +233,7 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
m_model = new FlatModel(this); m_model = new FlatModel(this);
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(m_view));
setFocusProxy(m_view); setFocusProxy(m_view);
m_view->installEventFilter(this); m_view->installEventFilter(this);
@@ -211,7 +272,7 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
m_model, &FlatModel::onCollapsed); m_model, &FlatModel::onCollapsed);
m_toggleSync = new QToolButton; m_toggleSync = new QToolButton;
m_toggleSync->setIcon(Utils::Icons::LINK.icon()); m_toggleSync->setIcon(Icons::LINK.icon());
m_toggleSync->setCheckable(true); m_toggleSync->setCheckable(true);
m_toggleSync->setChecked(autoSynchronization()); m_toggleSync->setChecked(autoSynchronization());
m_toggleSync->setToolTip(tr("Synchronize with Editor")); m_toggleSync->setToolTip(tr("Synchronize with Editor"));
@@ -270,7 +331,7 @@ void ProjectTreeWidget::rowsInserted(const QModelIndex &parent, int start, int e
} }
} }
Node *ProjectTreeWidget::nodeForFile(const Utils::FileName &fileName) Node *ProjectTreeWidget::nodeForFile(const FileName &fileName)
{ {
Node *bestNode = nullptr; Node *bestNode = nullptr;
int bestNodeExpandCount = INT_MAX; int bestNodeExpandCount = INT_MAX;
@@ -328,7 +389,7 @@ void ProjectTreeWidget::setAutoSynchronization(bool sync)
if (m_autoSync) { if (m_autoSync) {
// sync from document manager // sync from document manager
Utils::FileName fileName; FileName fileName;
if (IDocument *doc = EditorManager::currentDocument()) if (IDocument *doc = EditorManager::currentDocument())
fileName = doc->filePath(); fileName = doc->filePath();
if (!currentNode() || currentNode()->filePath() != fileName) if (!currentNode() || currentNode()->filePath() != fileName)
@@ -348,7 +409,7 @@ 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 FileName &oldPath, const FileName &newPath)
{ {
update(); update();
Q_UNUSED(oldPath); Q_UNUSED(oldPath);
@@ -400,8 +461,8 @@ void ProjectTreeWidget::showMessage(Node *node, const QString &message)
m_view->scrollTo(idx); m_view->scrollTo(idx);
QPoint pos = m_view->mapToGlobal(m_view->visualRect(idx).bottomLeft()); QPoint pos = m_view->mapToGlobal(m_view->visualRect(idx).bottomLeft());
pos -= Utils::ToolTip::offsetFromPosition(); pos -= ToolTip::offsetFromPosition();
Utils::ToolTip::show(pos, message); ToolTip::show(pos, message);
} }
void ProjectTreeWidget::showContextMenu(const QPoint &pos) void ProjectTreeWidget::showContextMenu(const QPoint &pos)
@@ -459,7 +520,7 @@ NavigationView ProjectTreeWidgetFactory::createWidget()
n.widget = ptw; n.widget = ptw;
auto filter = new QToolButton; auto filter = new QToolButton;
filter->setIcon(Utils::Icons::FILTER.icon()); filter->setIcon(Icons::FILTER.icon());
filter->setToolTip(tr("Filter Tree")); filter->setToolTip(tr("Filter Tree"));
filter->setPopupMode(QToolButton::InstantPopup); filter->setPopupMode(QToolButton::InstantPopup);
filter->setProperty("noArrow", true); filter->setProperty("noArrow", true);