Commit f5beeb4c authored by Tobias Hunger's avatar Tobias Hunger

ProjectTree: Show parsing state of projects

Show which projects are currently parsing in the project tree.

Change-Id: Ie69907a73ec7c3cf2ef40c37db620a0144178f95
Reviewed-by: Tim Jenssen's avatarTim Jenssen <tim.jenssen@qt.io>
parent 905b9298
......@@ -116,7 +116,7 @@ private:
void handleActiveBuildConfigurationChanged();
void handleParsingStarted(const Internal::CMakeBuildConfiguration *bc);
void handleTreeScanningFinished();
void updateProjectData(Internal::CMakeBuildConfiguration *cmakeBc);
void updateProjectData(Internal::CMakeBuildConfiguration *bc);
void handleParsingError(Internal::CMakeBuildConfiguration *bc);
void updateQmlJSCodeModel();
......
......@@ -85,7 +85,8 @@ public:
enum ModelRoles {
// Absolute file path
FilePathRole = QFileSystemModel::FilePathRole,
EnabledRole
EnabledRole,
isParsingRole
};
Project(const QString &mimeType, const Utils::FileName &fileName,
......
......@@ -32,15 +32,18 @@
#include "session.h"
#include <coreplugin/fileiconprovider.h>
#include <utils/utilsicons.h>
#include <utils/algorithm.h>
#include <utils/dropsupport.h>
#include <utils/theme/theme.h>
#include <QDebug>
#include <QFileInfo>
#include <QFont>
#include <QMimeData>
#include <QLoggingCategory>
#include <functional>
using namespace Utils;
namespace ProjectExplorer {
......@@ -106,10 +109,19 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
}
case Qt::DecorationRole: {
if (folderNode) {
result = folderNode->icon();
static QIcon emptyIcon = Utils::Icons::EMPTY16.icon();
if (ContainerNode *containerNode = folderNode->asContainerNode()) {
if (ProjectNode *projectNode = containerNode->rootProjectNode())
result = projectNode->icon();
WrapperNode *wn = wrapperForNode(node);
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 {
result = Core::FileIconProvider::icon(node->filePath().toString());
......@@ -133,6 +145,17 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
result = node->isEnabled();
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());
}
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)
{
// 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)
{
QTC_ASSERT(project, return);
connect(project, &Project::parsingStarted,
this, [this, project]() { parsingStateChanged(project); });
connect(project, &Project::parsingFinished,
this, [this, project]() { parsingStateChanged(project); });
addOrRebuildProjectModel(project);
}
......@@ -269,7 +305,7 @@ void FlatModel::handleProjectRemoved(Project *project)
destroyItem(nodeForProject(project));
}
WrapperNode *FlatModel::nodeForProject(Project *project)
WrapperNode *FlatModel::nodeForProject(const Project *project) const
{
QTC_ASSERT(project, return nullptr);
ContainerNode *containerNode = project->containerNode();
......
......@@ -99,9 +99,11 @@ private:
void saveExpandData();
void handleProjectAdded(Project *project);
void handleProjectRemoved(Project *project);
WrapperNode *nodeForProject(Project *project);
WrapperNode *nodeForProject(const Project *project) const;
void addOrRebuildProjectModel(Project *project);
void parsingStateChanged(Project *project);
QTimer m_timer;
QSet<ExpandData> m_toExpand;
};
......
......@@ -40,23 +40,28 @@
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/find/itemviewfind.h>
#include <utils/navigationtreeview.h>
#include <utils/algorithm.h>
#include <utils/navigationtreeview.h>
#include <utils/progressindicator.h>
#include <utils/tooltip/tooltip.h>
#include <utils/utilsicons.h>
#include <QDebug>
#include <QApplication>
#include <QSettings>
#include <QStyledItemDelegate>
#include <QVBoxLayout>
#include <QToolButton>
#include <QPainter>
#include <QAction>
#include <QMenu>
#include <memory>
using namespace Core;
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
using namespace Utils;
QList<ProjectTreeWidget *> ProjectTreeWidget::m_projectTreeWidgets;
......@@ -65,22 +70,78 @@ namespace {
class ProjectTreeItemDelegate : public QStyledItemDelegate
{
public:
ProjectTreeItemDelegate(QObject *parent) : QStyledItemDelegate(parent)
{ }
ProjectTreeItemDelegate(QTreeView *view) : QStyledItemDelegate(view),
m_view(view)
{
connect(m_view->model(), &QAbstractItemModel::modelReset,
this, &ProjectTreeItemDelegate::deleteAllIndicators);
// 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
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
QStyleOptionViewItem opt = option;
if (!index.data(Project::EnabledRole).toBool())
opt.state &= ~QStyle::State_Enabled;
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;
}
class ProjectTreeView : public Utils::NavigationTreeView
class ProjectTreeView : public NavigationTreeView
{
public:
ProjectTreeView()
......@@ -138,7 +199,7 @@ public:
connect(newModel, &QAbstractItemModel::rowsRemoved,
this, &ProjectTreeView::invalidateSize);
}
Utils::NavigationTreeView::setModel(newModel);
NavigationTreeView::setModel(newModel);
}
~ProjectTreeView()
......@@ -150,7 +211,7 @@ public:
int sizeHintForColumn(int column) const override
{
if (m_cachedSize < 0)
m_cachedSize = Utils::NavigationTreeView::sizeHintForColumn(column);
m_cachedSize = NavigationTreeView::sizeHintForColumn(column);
return m_cachedSize;
}
......@@ -172,7 +233,7 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
m_model = new FlatModel(this);
m_view = new ProjectTreeView;
m_view->setModel(m_model);
m_view->setItemDelegate(new ProjectTreeItemDelegate(this));
m_view->setItemDelegate(new ProjectTreeItemDelegate(m_view));
setFocusProxy(m_view);
m_view->installEventFilter(this);
......@@ -211,7 +272,7 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent)
m_model, &FlatModel::onCollapsed);
m_toggleSync = new QToolButton;
m_toggleSync->setIcon(Utils::Icons::LINK.icon());
m_toggleSync->setIcon(Icons::LINK.icon());
m_toggleSync->setCheckable(true);
m_toggleSync->setChecked(autoSynchronization());
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;
int bestNodeExpandCount = INT_MAX;
......@@ -328,7 +389,7 @@ void ProjectTreeWidget::setAutoSynchronization(bool sync)
if (m_autoSync) {
// sync from document manager
Utils::FileName fileName;
FileName fileName;
if (IDocument *doc = EditorManager::currentDocument())
fileName = doc->filePath();
if (!currentNode() || currentNode()->filePath() != fileName)
......@@ -348,7 +409,7 @@ void ProjectTreeWidget::editCurrentItem()
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();
Q_UNUSED(oldPath);
......@@ -400,8 +461,8 @@ void ProjectTreeWidget::showMessage(Node *node, const QString &message)
m_view->scrollTo(idx);
QPoint pos = m_view->mapToGlobal(m_view->visualRect(idx).bottomLeft());
pos -= Utils::ToolTip::offsetFromPosition();
Utils::ToolTip::show(pos, message);
pos -= ToolTip::offsetFromPosition();
ToolTip::show(pos, message);
}
void ProjectTreeWidget::showContextMenu(const QPoint &pos)
......@@ -459,7 +520,7 @@ NavigationView ProjectTreeWidgetFactory::createWidget()
n.widget = ptw;
auto filter = new QToolButton;
filter->setIcon(Utils::Icons::FILTER.icon());
filter->setIcon(Icons::FILTER.icon());
filter->setToolTip(tr("Filter Tree"));
filter->setPopupMode(QToolButton::InstantPopup);
filter->setProperty("noArrow", true);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment