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 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);
|
||||
|
||||
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;
|
||||
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);
|
||||
|
Reference in New Issue
Block a user