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