ProjectExplorer: Fix memory leaks in tree models

Fix widgets being leaked by the ToolChainOptionsPage.
This page created widgets and stored them in the tree node
and never deleted them.

The fix is to put all the widgets into one QStackedWidget, so
that this will clean up once the page is destroyed.

Change-Id: Ic02824a4c52771d8962dc594176077c2e139fb84
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-07-11 08:25:07 +02:00
parent 263cf4c608
commit 2c0554c187
15 changed files with 38 additions and 33 deletions

View File

@@ -181,9 +181,9 @@ bool AndroidToolChain::operator ==(const ToolChain &tc) const
return m_ndkToolChainVersion == static_cast<const AndroidToolChain &>(tc).m_ndkToolChainVersion;
}
ToolChainConfigWidget *AndroidToolChain::configurationWidget()
std::unique_ptr<ToolChainConfigWidget> AndroidToolChain::createConfigurationWidget()
{
return new AndroidToolChainConfigWidget(this);
return std::make_unique<AndroidToolChainConfigWidget>(this);
}
FileName AndroidToolChain::suggestedDebugger() const

View File

@@ -44,7 +44,7 @@ public:
bool operator ==(const ProjectExplorer::ToolChain &) const override;
ProjectExplorer::ToolChainConfigWidget *configurationWidget() override;
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() override;
Utils::FileName suggestedDebugger() const override;
Utils::FileName suggestedGdbServer() const;

View File

@@ -136,9 +136,9 @@ IOutputParser *NimToolChain::outputParser() const
return nullptr;
}
ToolChainConfigWidget *NimToolChain::configurationWidget()
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> NimToolChain::createConfigurationWidget()
{
return new NimToolChainConfigWidget(this);
return std::make_unique<NimToolChainConfigWidget>(this);
}
ToolChain *NimToolChain::clone() const

View File

@@ -54,7 +54,7 @@ public:
QString compilerVersion() const;
void setCompilerCommand(const Utils::FileName &compilerCommand);
ProjectExplorer::IOutputParser *outputParser() const final;
ProjectExplorer::ToolChainConfigWidget *configurationWidget() final;
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() final;
ProjectExplorer::ToolChain *clone() const final;
QVariantMap toMap() const final;

View File

@@ -412,9 +412,9 @@ QList<CustomToolChain::Parser> CustomToolChain::parsers()
return result;
}
ToolChainConfigWidget *CustomToolChain::configurationWidget()
std::unique_ptr<ToolChainConfigWidget> CustomToolChain::createConfigurationWidget()
{
return new Internal::CustomToolChainConfigWidget(this);
return std::make_unique<Internal::CustomToolChainConfigWidget>(this);
}
namespace Internal {

View File

@@ -90,7 +90,7 @@ public:
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override;
ToolChainConfigWidget *configurationWidget() override;
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
bool operator ==(const ToolChain &) const override;

View File

@@ -861,9 +861,9 @@ bool GccToolChain::operator ==(const ToolChain &other) const
&& m_platformLinkerFlags == gccTc->m_platformLinkerFlags;
}
ToolChainConfigWidget *GccToolChain::configurationWidget()
std::unique_ptr<ToolChainConfigWidget> GccToolChain::createConfigurationWidget()
{
return new GccToolChainConfigWidget(this);
return std::make_unique<GccToolChainConfigWidget>(this);
}
void GccToolChain::updateSupportedAbis() const

View File

@@ -158,7 +158,7 @@ public:
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override;
ToolChainConfigWidget *configurationWidget() override;
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
bool operator ==(const ToolChain &) const override;

View File

@@ -764,9 +764,9 @@ bool MsvcToolChain::fromMap(const QVariantMap &data)
}
ToolChainConfigWidget *MsvcToolChain::configurationWidget()
std::unique_ptr<ToolChainConfigWidget> MsvcToolChain::createConfigurationWidget()
{
return new MsvcToolChainConfigWidget(this);
return std::make_unique<MsvcToolChainConfigWidget>(this);
}
ToolChain *MsvcToolChain::clone() const
@@ -1048,9 +1048,9 @@ bool ClangClToolChain::fromMap(const QVariantMap &data)
return true;
}
ToolChainConfigWidget *ClangClToolChain::configurationWidget()
std::unique_ptr<ToolChainConfigWidget> ClangClToolChain::createConfigurationWidget()
{
return new ClangClToolChainConfigWidget(this);
return std::make_unique<ClangClToolChainConfigWidget>(this);
}
void ClangClToolChain::resetMsvcToolChain(const MsvcToolChain *base)

View File

@@ -73,7 +73,7 @@ public:
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override;
ToolChainConfigWidget *configurationWidget() override;
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
ToolChain *clone() const override;
@@ -127,7 +127,7 @@ public:
ToolChain *clone() const override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override;
ToolChainConfigWidget *configurationWidget() override;
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
const QList<MsvcToolChain *> &msvcToolchains() const;
QString clangPath() const { return m_clangPath; }

View File

@@ -146,7 +146,7 @@ public:
virtual bool operator ==(const ToolChain &) const;
virtual ToolChainConfigWidget *configurationWidget() = 0;
virtual std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() = 0;
virtual bool canClone() const;
virtual ToolChain *clone() const = 0;

View File

@@ -48,6 +48,7 @@
#include <QMessageBox>
#include <QPushButton>
#include <QSpacerItem>
#include <QStackedWidget>
#include <QTextStream>
#include <QTreeView>
#include <QVBoxLayout>
@@ -60,11 +61,12 @@ namespace Internal {
class ToolChainTreeItem : public TreeItem
{
public:
ToolChainTreeItem(ToolChain *tc, bool c) :
ToolChainTreeItem(QStackedWidget *parentWidget, ToolChain *tc, bool c) :
toolChain(tc), changed(c)
{
widget = tc->configurationWidget();
widget = tc->createConfigurationWidget().release();
if (widget) {
parentWidget->addWidget(widget);
if (tc->isAutoDetected())
widget->makeReadOnly();
QObject::connect(widget, &ToolChainConfigWidget::dirty,
@@ -132,9 +134,6 @@ public:
m_model.rootItem()->appendChild(autoRoot);
m_model.rootItem()->appendChild(manualRoot);
foreach (ToolChain *tc, ToolChainManager::toolChains())
insertToolChain(tc);
m_toolChainView = new QTreeView(this);
m_toolChainView->setUniformRowHeights(true);
m_toolChainView->setSelectionMode(QAbstractItemView::SingleSelection);
@@ -174,6 +173,12 @@ public:
m_container->setState(DetailsWidget::NoSummary);
m_container->setVisible(false);
m_widgetStack = new QStackedWidget;
m_container->setWidget(m_widgetStack);
foreach (ToolChain *tc, ToolChainManager::toolChains())
insertToolChain(tc);
auto buttonLayout = new QVBoxLayout;
buttonLayout->setSpacing(6);
buttonLayout->setContentsMargins(0, 0, 0, 0);
@@ -234,6 +239,7 @@ public:
QList<ToolChainFactory *> m_factories;
QTreeView *m_toolChainView;
DetailsWidget *m_container;
QStackedWidget *m_widgetStack;
QPushButton *m_addButton;
QPushButton *m_cloneButton;
QPushButton *m_delButton;
@@ -260,8 +266,9 @@ void ToolChainOptionsWidget::markForRemoval(ToolChainTreeItem *item)
ToolChainTreeItem *ToolChainOptionsWidget::insertToolChain(ToolChain *tc, bool changed)
{
StaticTreeItem *parent = parentForToolChain(tc);
auto item = new ToolChainTreeItem(tc, changed);
auto item = new ToolChainTreeItem(m_widgetStack, tc, changed);
parent->appendChild(item);
return item;
}
@@ -308,13 +315,10 @@ StaticTreeItem *ToolChainOptionsWidget::parentForToolChain(ToolChain *tc)
void ToolChainOptionsWidget::toolChainSelectionChanged()
{
ToolChainTreeItem *item = currentTreeItem();
QWidget *oldWidget = m_container->takeWidget(); // Prevent deletion.
if (oldWidget)
oldWidget->setVisible(false);
QWidget *currentTcWidget = item ? item->widget : nullptr;
m_container->setWidget(currentTcWidget);
m_widgetStack->setCurrentWidget(currentTcWidget);
m_container->setVisible(currentTcWidget);
updateState();
}

View File

@@ -281,6 +281,7 @@ QList<ToolChain *> ToolChainSettingsAccessor::toolChains(const QVariantMap &data
#include "headerpath.h"
#include "abi.h"
#include "toolchainconfigwidget.h"
#include <QSet>
#include <QTest>
@@ -318,7 +319,7 @@ public:
QString makeCommand(const Environment &env) const override { Q_UNUSED(env); return QString("make"); }
FileName compilerCommand() const override { return Utils::FileName::fromString("/tmp/test/gcc"); }
IOutputParser *outputParser() const override { return nullptr; }
ToolChainConfigWidget *configurationWidget() override { return nullptr; }
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override { return nullptr; }
TTC *clone() const override { return new TTC(*this); }
bool operator ==(const ToolChain &other) const override {
if (!ToolChain::operator==(other))

View File

@@ -118,9 +118,9 @@ QString QnxToolChain::typeDisplayName() const
return QnxToolChainFactory::tr("QCC");
}
ToolChainConfigWidget *QnxToolChain::configurationWidget()
std::unique_ptr<ToolChainConfigWidget> QnxToolChain::createConfigurationWidget()
{
return new QnxToolChainConfigWidget(this);
return std::make_unique<QnxToolChainConfigWidget>(this);
}
void QnxToolChain::addToEnvironment(Environment &env) const

View File

@@ -39,7 +39,7 @@ public:
QString typeDisplayName() const override;
ProjectExplorer::ToolChainConfigWidget *configurationWidget() override;
std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() override;
void addToEnvironment(Utils::Environment &env) const override;
Utils::FileNameList suggestedMkspecList() const override;