ProjectExplorer: Fix undefined behavior regarding ShowMoreItem

Introduce ITargetItem interface for TargetItem and ShowMoreItem.

Fixes: QTCREATORBUG-31074
Change-Id: I8aa15b985ac3a18b44169f93520057837e1718ea
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Artem Sokolovskii
2024-09-24 15:52:28 +02:00
parent 59cd009850
commit f470846866
2 changed files with 55 additions and 33 deletions

View File

@@ -194,11 +194,38 @@ public:
TargetSetupPageWrapper *m_targetSetupPageWrapper = nullptr; TargetSetupPageWrapper *m_targetSetupPageWrapper = nullptr;
}; };
class ShowMoreItem : public TreeItem class ITargetItem : public TypedTreeItem<TreeItem, TargetGroupItem>
{
public:
enum { DefaultPage = 0 }; // Build page.
ITargetItem(Project *project, Id kitId, const Tasks &issues)
: m_project(project)
, m_kitId(kitId)
, m_kitIssues(issues)
{}
virtual Target *target() const = 0;
virtual void updateSubItems() = 0;
virtual void addToContextMenu(QMenu *menu, bool isSelectable) = 0;
bool isEnabled() const { return target() != nullptr; }
public:
QPointer<Project> m_project; // Not owned.
Id m_kitId;
int m_currentChild = DefaultPage;
bool m_kitErrorsForProject = false;
bool m_kitWarningForProject = false;
Tasks m_kitIssues;
};
class ShowMoreItem : public ITargetItem
{ {
public: public:
ShowMoreItem(TargetGroupItemPrivate *p) ShowMoreItem(TargetGroupItemPrivate *p)
: m_p(p) : ITargetItem(nullptr, Id(), Tasks())
, m_p(p)
{} {}
QVariant data(int column, int role) const override QVariant data(int column, int role) const override
@@ -230,6 +257,13 @@ public:
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable; return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
} }
// ITargetItem
Target *target() const override {
return nullptr;
}
void updateSubItems() override {}
void addToContextMenu(QMenu *, bool) override {}
private: private:
TargetGroupItemPrivate *m_p; TargetGroupItemPrivate *m_p;
}; };
@@ -274,13 +308,11 @@ void TargetGroupItemPrivate::ensureWidget()
// //
// Third level: The per-kit entries (inactive or with a 'Build' and a 'Run' subitem) // Third level: The per-kit entries (inactive or with a 'Build' and a 'Run' subitem)
// //
class TargetItem : public TypedTreeItem<TreeItem, TargetGroupItem> class TargetItem : public ITargetItem
{ {
public: public:
enum { DefaultPage = 0 }; // Build page.
TargetItem(Project *project, Id kitId, const Tasks &issues) TargetItem(Project *project, Id kitId, const Tasks &issues)
: m_project(project), m_kitId(kitId), m_kitIssues(issues) : ITargetItem(project, kitId, issues)
{ {
m_kitWarningForProject = containsType(m_kitIssues, Task::TaskType::Warning); m_kitWarningForProject = containsType(m_kitIssues, Task::TaskType::Warning);
m_kitErrorsForProject = containsType(m_kitIssues, Task::TaskType::Error); m_kitErrorsForProject = containsType(m_kitIssues, Task::TaskType::Error);
@@ -288,12 +320,12 @@ public:
updateSubItems(); updateSubItems();
} }
Target *target() const Target *target() const override
{ {
return m_project->target(m_kitId); return m_project->target(m_kitId);
} }
void updateSubItems(); void updateSubItems() override;
Qt::ItemFlags flags(int column) const override Qt::ItemFlags flags(int column) const override
{ {
@@ -332,7 +364,7 @@ public:
case Qt::FontRole: { case Qt::FontRole: {
QFont font = parent()->data(column, role).value<QFont>(); QFont font = parent()->data(column, role).value<QFont>();
if (TargetItem *targetItem = parent()->currentTargetItem()) { if (ITargetItem *targetItem = parent()->currentTargetItem()) {
Target *t = targetItem->target(); Target *t = targetItem->target();
if (t && t->id() == m_kitId && m_project == ProjectManager::startupProject()) if (t && t->id() == m_kitId && m_project == ProjectManager::startupProject())
font.setBold(true); font.setBold(true);
@@ -384,7 +416,7 @@ public:
m_project->addTargetForKit(KitManager::kit(m_kitId)); m_project->addTargetForKit(KitManager::kit(m_kitId));
} else { } else {
// Go to Run page, when on Run previously etc. // Go to Run page, when on Run previously etc.
TargetItem *previousItem = parent()->currentTargetItem(); ITargetItem *previousItem = parent()->currentTargetItem();
m_currentChild = previousItem ? previousItem->m_currentChild : DefaultPage; m_currentChild = previousItem ? previousItem->m_currentChild : DefaultPage;
m_project->setActiveTarget(target(), SetActive::Cascade); m_project->setActiveTarget(target(), SetActive::Cascade);
parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)), parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)),
@@ -413,7 +445,7 @@ public:
return false; return false;
} }
void addToContextMenu(QMenu *menu, bool isSelectable) void addToContextMenu(QMenu *menu, bool isSelectable) override
{ {
Kit *kit = KitManager::kit(m_kitId); Kit *kit = KitManager::kit(m_kitId);
QTC_ASSERT(kit, return); QTC_ASSERT(kit, return);
@@ -493,16 +525,6 @@ public:
} }
} }
bool isEnabled() const { return target() != nullptr; }
public:
QPointer<Project> m_project; // Not owned.
Id m_kitId;
int m_currentChild = DefaultPage;
bool m_kitErrorsForProject = false;
bool m_kitWarningForProject = false;
Tasks m_kitIssues;
private: private:
enum class IconOverlay { enum class IconOverlay {
Add, Add,
@@ -744,13 +766,13 @@ QVariant TargetGroupItem::data(int column, int role) const
return d->m_displayName; return d->m_displayName;
if (role == ActiveItemRole) { if (role == ActiveItemRole) {
if (TargetItem *item = currentTargetItem()) if (ITargetItem *item = currentTargetItem())
return item->data(column, role); return item->data(column, role);
return QVariant::fromValue<TreeItem *>(const_cast<TargetGroupItem *>(this)); return QVariant::fromValue<TreeItem *>(const_cast<TargetGroupItem *>(this));
} }
if (role == PanelWidgetRole) { if (role == PanelWidgetRole) {
if (TargetItem *item = currentTargetItem()) if (ITargetItem *item = currentTargetItem())
return item->data(column, role); return item->data(column, role);
d->ensureWidget(); d->ensureWidget();
@@ -776,16 +798,16 @@ Qt::ItemFlags TargetGroupItem::flags(int) const
return Qt::NoItemFlags; return Qt::NoItemFlags;
} }
TargetItem *TargetGroupItem::currentTargetItem() const ITargetItem *TargetGroupItem::currentTargetItem() const
{ {
return targetItem(d->m_project->activeTarget()); return targetItem(d->m_project->activeTarget());
} }
TargetItem *TargetGroupItem::targetItem(Target *target) const ITargetItem *TargetGroupItem::targetItem(Target *target) const
{ {
if (target) { if (target) {
Id needle = target->id(); // Unconfigured project have no active target. Id needle = target->id(); // Unconfigured project have no active target.
return findFirstLevelChild([needle](TargetItem *item) { return item->m_kitId == needle; }); return findFirstLevelChild([needle](ITargetItem *item) { return item->m_kitId == needle; });
} }
return nullptr; return nullptr;
} }
@@ -854,7 +876,7 @@ void TargetGroupItemPrivate::rebuildContents()
void TargetGroupItemPrivate::handleTargetAdded(Target *target) void TargetGroupItemPrivate::handleTargetAdded(Target *target)
{ {
if (TargetItem *item = q->targetItem(target)) if (ITargetItem *item = q->targetItem(target))
item->updateSubItems(); item->updateSubItems();
ensureShowMoreItem(); ensureShowMoreItem();
q->update(); q->update();
@@ -862,7 +884,7 @@ void TargetGroupItemPrivate::handleTargetAdded(Target *target)
void TargetGroupItemPrivate::handleTargetRemoved(Target *target) void TargetGroupItemPrivate::handleTargetRemoved(Target *target)
{ {
if (TargetItem *item = q->targetItem(target)) if (ITargetItem *item = q->targetItem(target))
item->updateSubItems(); item->updateSubItems();
ensureShowMoreItem(); ensureShowMoreItem();
q->parent()->setData(0, QVariant::fromValue(static_cast<TreeItem *>(q)), q->parent()->setData(0, QVariant::fromValue(static_cast<TreeItem *>(q)),
@@ -871,7 +893,7 @@ void TargetGroupItemPrivate::handleTargetRemoved(Target *target)
void TargetGroupItemPrivate::handleTargetChanged(Target *target) void TargetGroupItemPrivate::handleTargetChanged(Target *target)
{ {
if (TargetItem *item = q->targetItem(target)) if (ITargetItem *item = q->targetItem(target))
item->updateSubItems(); item->updateSubItems();
ensureShowMoreItem(); ensureShowMoreItem();
q->setData(0, QVariant(), ItemActivatedFromBelowRole); q->setData(0, QVariant(), ItemActivatedFromBelowRole);

View File

@@ -15,11 +15,11 @@ class Target;
namespace Internal { namespace Internal {
class TargetItem; class ITargetItem;
class TargetGroupItemPrivate; class TargetGroupItemPrivate;
// Second level: Special case for the Build & Run item (with per-kit subItems) // Second level: Special case for the Build & Run item (with per-kit subItems)
class TargetGroupItem : public Utils::TypedTreeItem<TargetItem /*, ProjectItem */> class TargetGroupItem : public Utils::TypedTreeItem<ITargetItem /*, ProjectItem */>
{ {
public: public:
TargetGroupItem(const QString &displayName, Project *project); TargetGroupItem(const QString &displayName, Project *project);
@@ -29,8 +29,8 @@ public:
bool setData(int column, const QVariant &data, int role) override; bool setData(int column, const QVariant &data, int role) override;
Qt::ItemFlags flags(int) const override; Qt::ItemFlags flags(int) const override;
TargetItem *currentTargetItem() const; ITargetItem *currentTargetItem() const;
TargetItem *targetItem(Target *target) const; ITargetItem *targetItem(Target *target) const;
private: private:
const std::unique_ptr<TargetGroupItemPrivate> d; const std::unique_ptr<TargetGroupItemPrivate> d;