forked from qt-creator/qt-creator
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:
@@ -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();
|
||||||
|
|
||||||
|
@@ -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,
|
||||||
|
@@ -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();
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user