forked from qt-creator/qt-creator
Toolchains: Make options page more stable.
Avoid double deletions by using shared pointers. Reset the model after discard as the structure may change. Use qtc_assert (to catch cases of add/delete again).
This commit is contained in:
@@ -44,6 +44,7 @@
|
|||||||
|
|
||||||
#include <QtCore/QSignalMapper>
|
#include <QtCore/QSignalMapper>
|
||||||
#include <QtCore/QTextStream>
|
#include <QtCore/QTextStream>
|
||||||
|
|
||||||
#include <QtGui/QAction>
|
#include <QtGui/QAction>
|
||||||
#include <QtGui/QItemSelectionModel>
|
#include <QtGui/QItemSelectionModel>
|
||||||
#include <QtGui/QLabel>
|
#include <QtGui/QLabel>
|
||||||
@@ -53,14 +54,14 @@
|
|||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
typedef QSharedPointer<ToolChainNode> ToolChainNodePtr;
|
||||||
|
|
||||||
class ToolChainNode
|
class ToolChainNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ToolChainNode(ToolChainNode *p, ToolChain *tc = 0, bool c = false) :
|
explicit ToolChainNode(ToolChain *tc = 0, bool c = false) :
|
||||||
parent(p), toolChain(tc), changed(c)
|
parent(0), toolChain(tc), changed(c)
|
||||||
{
|
{
|
||||||
if (p)
|
|
||||||
p->childNodes.append(this);
|
|
||||||
widget = tc ? tc->configurationWidget() : 0;
|
widget = tc ? tc->configurationWidget() : 0;
|
||||||
if (widget) {
|
if (widget) {
|
||||||
widget->setEnabled(tc ? !tc->isAutoDetected() : false);
|
widget->setEnabled(tc ? !tc->isAutoDetected() : false);
|
||||||
@@ -70,39 +71,60 @@ public:
|
|||||||
|
|
||||||
~ToolChainNode()
|
~ToolChainNode()
|
||||||
{
|
{
|
||||||
qDeleteAll(childNodes);
|
|
||||||
// Do not delete toolchain, we do not own it.
|
// Do not delete toolchain, we do not own it.
|
||||||
delete widget;
|
delete widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addChild(const ToolChainNodePtr &c)
|
||||||
|
{
|
||||||
|
c->parent = this;
|
||||||
|
childNodes.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
ToolChainNode *parent;
|
ToolChainNode *parent;
|
||||||
QString newName;
|
QString newName;
|
||||||
QList<ToolChainNode *> childNodes;
|
QList<ToolChainNodePtr> childNodes;
|
||||||
ToolChain *toolChain;
|
ToolChain *toolChain;
|
||||||
ToolChainConfigWidget *widget;
|
ToolChainConfigWidget *widget;
|
||||||
bool changed;
|
bool changed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int indexOfToolChain(const QList<ToolChainNodePtr> &l, const ToolChain *tc)
|
||||||
|
{
|
||||||
|
const int count = l.size();
|
||||||
|
for (int i = 0; i < count ; i++)
|
||||||
|
if (l.at(i)->toolChain == tc)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int indexOfToolChainNode(const QList<ToolChainNodePtr> &l, const ToolChainNode *node)
|
||||||
|
{
|
||||||
|
const int count = l.size();
|
||||||
|
for (int i = 0; i < count ; i++)
|
||||||
|
if (l.at(i).data() == node)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// ToolChainModel
|
// ToolChainModel
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
ToolChainModel::ToolChainModel(QObject *parent) :
|
ToolChainModel::ToolChainModel(QObject *parent) :
|
||||||
QAbstractItemModel(parent)
|
QAbstractItemModel(parent), m_autoRoot(new ToolChainNode), m_manualRoot(new ToolChainNode)
|
||||||
{
|
{
|
||||||
connect(ToolChainManager::instance(), SIGNAL(toolChainAdded(ProjectExplorer::ToolChain*)),
|
connect(ToolChainManager::instance(), SIGNAL(toolChainAdded(ProjectExplorer::ToolChain*)),
|
||||||
this, SLOT(addToolChain(ProjectExplorer::ToolChain*)));
|
this, SLOT(addToolChain(ProjectExplorer::ToolChain*)));
|
||||||
connect(ToolChainManager::instance(), SIGNAL(toolChainRemoved(ProjectExplorer::ToolChain*)),
|
connect(ToolChainManager::instance(), SIGNAL(toolChainRemoved(ProjectExplorer::ToolChain*)),
|
||||||
this, SLOT(removeToolChain(ProjectExplorer::ToolChain*)));
|
this, SLOT(removeToolChain(ProjectExplorer::ToolChain*)));
|
||||||
|
|
||||||
m_autoRoot = new ToolChainNode(0);
|
|
||||||
m_manualRoot = new ToolChainNode(0);
|
|
||||||
|
|
||||||
foreach (ToolChain *tc, ToolChainManager::instance()->toolChains()) {
|
foreach (ToolChain *tc, ToolChainManager::instance()->toolChains()) {
|
||||||
if (tc->isAutoDetected())
|
if (tc->isAutoDetected()) {
|
||||||
new ToolChainNode(m_autoRoot, tc);
|
m_autoRoot->addChild(ToolChainNodePtr(new ToolChainNode(tc)));
|
||||||
else {
|
} else {
|
||||||
ToolChainNode *node = new ToolChainNode(m_manualRoot, tc);
|
ToolChainNodePtr node(new ToolChainNode(tc));
|
||||||
|
m_manualRoot->addChild(node);
|
||||||
if (node->widget)
|
if (node->widget)
|
||||||
connect(node->widget, SIGNAL(dirty(ProjectExplorer::ToolChain*)),
|
connect(node->widget, SIGNAL(dirty(ProjectExplorer::ToolChain*)),
|
||||||
this, SLOT(setDirty(ProjectExplorer::ToolChain*)));
|
this, SLOT(setDirty(ProjectExplorer::ToolChain*)));
|
||||||
@@ -112,21 +134,19 @@ ToolChainModel::ToolChainModel(QObject *parent) :
|
|||||||
|
|
||||||
ToolChainModel::~ToolChainModel()
|
ToolChainModel::~ToolChainModel()
|
||||||
{
|
{
|
||||||
delete m_autoRoot;
|
|
||||||
delete m_manualRoot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex ToolChainModel::index(int row, int column, const QModelIndex &parent) const
|
QModelIndex ToolChainModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (!parent.isValid()) {
|
if (!parent.isValid()) {
|
||||||
if (row == 0)
|
if (row == 0)
|
||||||
return createIndex(0, 0, static_cast<void *>(m_autoRoot));
|
return createIndex(0, 0, static_cast<void *>(m_autoRoot.data()));
|
||||||
else
|
else
|
||||||
return createIndex(1, 0, static_cast<void *>(m_manualRoot));
|
return createIndex(1, 0, static_cast<void *>(m_manualRoot.data()));
|
||||||
}
|
}
|
||||||
ToolChainNode *node = static_cast<ToolChainNode *>(parent.internalPointer());
|
ToolChainNode *node = static_cast<ToolChainNode *>(parent.internalPointer());
|
||||||
if (row < node->childNodes.count() && column < 2)
|
if (row < node->childNodes.count() && column < 2)
|
||||||
return createIndex(row, column, static_cast<void *>(node->childNodes.at(row)));
|
return createIndex(row, column, static_cast<void *>(node->childNodes.at(row).data()));
|
||||||
else
|
else
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
@@ -252,7 +272,7 @@ ToolChainConfigWidget *ToolChainModel::widget(const QModelIndex &index)
|
|||||||
|
|
||||||
bool ToolChainModel::isDirty() const
|
bool ToolChainModel::isDirty() const
|
||||||
{
|
{
|
||||||
foreach (ToolChainNode *n, m_manualRoot->childNodes) {
|
foreach (const ToolChainNodePtr &n, m_manualRoot->childNodes) {
|
||||||
if (n->changed)
|
if (n->changed)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -261,7 +281,7 @@ bool ToolChainModel::isDirty() const
|
|||||||
|
|
||||||
bool ToolChainModel::isDirty(ToolChain *tc) const
|
bool ToolChainModel::isDirty(ToolChain *tc) const
|
||||||
{
|
{
|
||||||
foreach (ToolChainNode *n, m_manualRoot->childNodes) {
|
foreach (const ToolChainNodePtr &n, m_manualRoot->childNodes) {
|
||||||
if (n->toolChain == tc && n->changed)
|
if (n->toolChain == tc && n->changed)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -270,10 +290,10 @@ bool ToolChainModel::isDirty(ToolChain *tc) const
|
|||||||
|
|
||||||
void ToolChainModel::setDirty(ToolChain *tc)
|
void ToolChainModel::setDirty(ToolChain *tc)
|
||||||
{
|
{
|
||||||
foreach (ToolChainNode *n, m_manualRoot->childNodes) {
|
foreach (const ToolChainNodePtr &n, m_manualRoot->childNodes) {
|
||||||
if (n->toolChain == tc) {
|
if (n->toolChain == tc) {
|
||||||
n->changed = true;
|
n->changed = true;
|
||||||
emit dataChanged(index(n, 0), index(n, columnCount(QModelIndex())));
|
emit dataChanged(index(n.data(), 0), index(n.data(), columnCount(QModelIndex())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,15 +301,15 @@ void ToolChainModel::setDirty(ToolChain *tc)
|
|||||||
void ToolChainModel::apply()
|
void ToolChainModel::apply()
|
||||||
{
|
{
|
||||||
// Remove unused ToolChains:
|
// Remove unused ToolChains:
|
||||||
QList<ToolChainNode *> nodes = m_toRemoveList;
|
QList<ToolChainNodePtr> nodes = m_toRemoveList;
|
||||||
foreach (ToolChainNode *n, nodes) {
|
foreach (const ToolChainNodePtr &n, nodes) {
|
||||||
ToolChainManager::instance()->deregisterToolChain(n->toolChain);
|
ToolChainManager::instance()->deregisterToolChain(n->toolChain);
|
||||||
}
|
}
|
||||||
Q_ASSERT(m_toRemoveList.isEmpty());
|
QTC_ASSERT(m_toRemoveList.isEmpty(), /* */ );
|
||||||
|
|
||||||
// Update toolchains:
|
// Update toolchains:
|
||||||
foreach (ToolChainNode *n, m_manualRoot->childNodes) {
|
foreach (const ToolChainNodePtr &n, m_manualRoot->childNodes) {
|
||||||
Q_ASSERT(n);
|
Q_ASSERT(n.data());
|
||||||
if (n->changed) {
|
if (n->changed) {
|
||||||
Q_ASSERT(n->toolChain);
|
Q_ASSERT(n->toolChain);
|
||||||
if (!n->newName.isEmpty())
|
if (!n->newName.isEmpty())
|
||||||
@@ -298,72 +318,66 @@ void ToolChainModel::apply()
|
|||||||
n->widget->apply();
|
n->widget->apply();
|
||||||
n->changed = false;
|
n->changed = false;
|
||||||
|
|
||||||
emit dataChanged(index(n, 0), index(n, columnCount(QModelIndex())));
|
emit dataChanged(index(n.data(), 0), index(n.data(), columnCount(QModelIndex())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new (and already updated) toolchains
|
// Add new (and already updated) toolchains
|
||||||
nodes = m_toAddList;
|
nodes = m_toAddList;
|
||||||
foreach (ToolChainNode *n, nodes) {
|
foreach (const ToolChainNodePtr &n, nodes) {
|
||||||
ToolChainManager::instance()->registerToolChain(n->toolChain);
|
ToolChainManager::instance()->registerToolChain(n->toolChain);
|
||||||
}
|
}
|
||||||
Q_ASSERT(m_toAddList.isEmpty());
|
QTC_ASSERT(m_toAddList.isEmpty(), qDebug() << m_toAddList.front()->toolChain; );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolChainModel::discard()
|
void ToolChainModel::discard()
|
||||||
{
|
{
|
||||||
// Remove newly "added" toolchains:
|
// Remove newly "added" toolchains:
|
||||||
foreach (ToolChainNode *n, m_toAddList) {
|
foreach (const ToolChainNodePtr &n, m_toAddList) {
|
||||||
int pos = m_manualRoot->childNodes.indexOf(n);
|
const int pos = indexOfToolChainNode(m_manualRoot->childNodes, n.data());
|
||||||
Q_ASSERT(pos >= 0);
|
QTC_ASSERT(pos >= 0, continue ; );
|
||||||
m_manualRoot->childNodes.removeAt(pos);
|
m_manualRoot->childNodes.removeAt(pos);
|
||||||
|
|
||||||
// Clean up Node: We still own the toolchain!
|
// Clean up Node: We still own the toolchain!
|
||||||
delete n->toolChain;
|
delete n->toolChain;
|
||||||
n->toolChain = 0;
|
n->toolChain = 0;
|
||||||
}
|
}
|
||||||
qDeleteAll(m_toAddList);
|
|
||||||
m_toAddList.clear();
|
m_toAddList.clear();
|
||||||
|
|
||||||
// Add "removed" toolchains again:
|
// Add "removed" toolchains again:
|
||||||
foreach (ToolChainNode *n, m_toRemoveList) {
|
foreach (const ToolChainNodePtr &n, m_toRemoveList) {
|
||||||
m_manualRoot->childNodes.append(n);
|
m_manualRoot->addChild(n);
|
||||||
}
|
}
|
||||||
m_toRemoveList.clear();
|
m_toRemoveList.clear();
|
||||||
|
|
||||||
// Reset toolchains:
|
// Reset toolchains:
|
||||||
foreach (ToolChainNode *n, m_manualRoot->childNodes) {
|
foreach (const ToolChainNodePtr &n, m_manualRoot->childNodes) {
|
||||||
Q_ASSERT(n);
|
|
||||||
n->newName.clear();
|
n->newName.clear();
|
||||||
if (n->widget)
|
if (n->widget)
|
||||||
n->widget->discard();
|
n->widget->discard();
|
||||||
n->changed = false;
|
n->changed = false;
|
||||||
}
|
}
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolChainModel::markForRemoval(ToolChain *tc)
|
void ToolChainModel::markForRemoval(ToolChain *tc)
|
||||||
{
|
{
|
||||||
ToolChainNode *node = 0;
|
// Delete newly added item?
|
||||||
foreach (ToolChainNode *n, m_manualRoot->childNodes) {
|
const int tcIndex = indexOfToolChain(m_manualRoot->childNodes, tc);
|
||||||
if (n->toolChain == tc) {
|
if (tcIndex != -1) {
|
||||||
node = n;
|
m_toRemoveList.append(m_manualRoot->childNodes.at(tcIndex));
|
||||||
break;
|
emit beginRemoveRows(index(m_manualRoot.data()), tcIndex, tcIndex);
|
||||||
}
|
m_manualRoot->childNodes.removeAt(tcIndex);
|
||||||
}
|
|
||||||
if (node) {
|
|
||||||
m_toRemoveList.append(node);
|
|
||||||
emit beginRemoveRows(index(m_manualRoot), m_manualRoot->childNodes.indexOf(node), m_manualRoot->childNodes.indexOf(node));
|
|
||||||
m_manualRoot->childNodes.removeOne(node);
|
|
||||||
emit endRemoveRows();
|
emit endRemoveRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolChainModel::markForAddition(ToolChain *tc)
|
void ToolChainModel::markForAddition(ToolChain *tc)
|
||||||
{
|
{
|
||||||
int pos = m_manualRoot->childNodes.size();
|
const int pos = m_manualRoot->childNodes.size();
|
||||||
emit beginInsertRows(index(m_manualRoot), pos, pos);
|
emit beginInsertRows(index(m_manualRoot.data()), pos, pos);
|
||||||
|
|
||||||
ToolChainNode *node = new ToolChainNode(m_manualRoot, tc);
|
const ToolChainNodePtr node(new ToolChainNode(tc));
|
||||||
|
m_manualRoot->addChild(node);
|
||||||
node->changed = true;
|
node->changed = true;
|
||||||
m_toAddList.append(node);
|
m_toAddList.append(node);
|
||||||
|
|
||||||
@@ -373,29 +387,28 @@ void ToolChainModel::markForAddition(ToolChain *tc)
|
|||||||
QModelIndex ToolChainModel::index(ToolChainNode *node, int column) const
|
QModelIndex ToolChainModel::index(ToolChainNode *node, int column) const
|
||||||
{
|
{
|
||||||
if (!node->parent)
|
if (!node->parent)
|
||||||
return index(node == m_autoRoot ? 0 : 1, column, QModelIndex());
|
return index(node == m_autoRoot.data() ? 0 : 1, column, QModelIndex());
|
||||||
else
|
else {
|
||||||
return index(node->parent->childNodes.indexOf(node), column, index(node->parent));
|
const int tcIndex = indexOfToolChainNode(node->parent->childNodes, node);
|
||||||
|
QTC_ASSERT(tcIndex != -1, return QModelIndex());
|
||||||
|
return index(tcIndex, column, index(node->parent));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolChainModel::addToolChain(ToolChain *tc)
|
void ToolChainModel::addToolChain(ToolChain *tc)
|
||||||
{
|
{
|
||||||
QList<ToolChainNode *> nodes = m_toAddList;
|
const int tcIndex = indexOfToolChain(m_toAddList, tc);
|
||||||
foreach (ToolChainNode *n, nodes) {
|
if (tcIndex != -1) {
|
||||||
if (n->toolChain == tc) {
|
m_toAddList.removeAt(tcIndex);
|
||||||
m_toAddList.removeOne(n);
|
|
||||||
// do not delete n: Still used elsewhere!
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
const ToolChainNodePtr parent = tc->isAutoDetected() ? m_autoRoot : m_manualRoot;
|
||||||
|
QTC_ASSERT(indexOfToolChain(parent->childNodes, tc) == -1, return ; )
|
||||||
|
|
||||||
ToolChainNode *parent = m_manualRoot;
|
const int row = parent->childNodes.count();
|
||||||
if (tc->isAutoDetected())
|
beginInsertRows(index(parent.data()), row, row);
|
||||||
parent = m_autoRoot;
|
ToolChainNodePtr newNode(new ToolChainNode(tc, true));
|
||||||
int row = parent->childNodes.count();
|
parent->addChild(newNode);
|
||||||
|
|
||||||
beginInsertRows(index(parent), row, row);
|
|
||||||
new ToolChainNode(parent, tc, true);
|
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
|
||||||
emit toolChainStateChanged();
|
emit toolChainStateChanged();
|
||||||
@@ -403,32 +416,17 @@ void ToolChainModel::addToolChain(ToolChain *tc)
|
|||||||
|
|
||||||
void ToolChainModel::removeToolChain(ToolChain *tc)
|
void ToolChainModel::removeToolChain(ToolChain *tc)
|
||||||
{
|
{
|
||||||
QList<ToolChainNode *> nodes = m_toRemoveList;
|
const int tcIndex = indexOfToolChain(m_toRemoveList, tc);
|
||||||
foreach (ToolChainNode *n, nodes) {
|
if (tcIndex != -1)
|
||||||
if (n->toolChain == tc) {
|
m_toRemoveList.removeAt(tcIndex);
|
||||||
m_toRemoveList.removeOne(n);
|
|
||||||
delete n;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolChainNode *parent = m_manualRoot;
|
const ToolChainNodePtr parent = tc->isAutoDetected() ? m_autoRoot : m_manualRoot;
|
||||||
if (tc->isAutoDetected())
|
const int row = indexOfToolChain(parent->childNodes, tc);
|
||||||
parent = m_autoRoot;
|
if (row != -1) {
|
||||||
int row = 0;
|
beginRemoveRows(index(parent.data()), row, row);
|
||||||
ToolChainNode *node = 0;
|
|
||||||
foreach (ToolChainNode *current, parent->childNodes) {
|
|
||||||
if (current->toolChain == tc) {
|
|
||||||
node = current;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++row;
|
|
||||||
}
|
|
||||||
|
|
||||||
beginRemoveRows(index(parent), row, row);
|
|
||||||
parent->childNodes.removeAt(row);
|
parent->childNodes.removeAt(row);
|
||||||
delete node;
|
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
|
||||||
emit toolChainStateChanged();
|
emit toolChainStateChanged();
|
||||||
}
|
}
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
#include <coreplugin/dialogs/ioptionspage.h>
|
#include <coreplugin/dialogs/ioptionspage.h>
|
||||||
|
|
||||||
#include <QtCore/QAbstractItemModel>
|
#include <QtCore/QAbstractItemModel>
|
||||||
|
#include <QtCore/QSharedPointer>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QTreeWidgetItem;
|
class QTreeWidgetItem;
|
||||||
@@ -101,12 +102,11 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
QModelIndex index(ToolChainNode *, int column = 0) const;
|
QModelIndex index(ToolChainNode *, int column = 0) const;
|
||||||
|
|
||||||
ToolChainNode * m_root;
|
QSharedPointer<ToolChainNode> m_autoRoot;
|
||||||
ToolChainNode * m_autoRoot;
|
QSharedPointer<ToolChainNode> m_manualRoot;
|
||||||
ToolChainNode * m_manualRoot;
|
|
||||||
|
|
||||||
QList<ToolChainNode *> m_toAddList;
|
QList<QSharedPointer<ToolChainNode> > m_toAddList;
|
||||||
QList<ToolChainNode *> m_toRemoveList;
|
QList<QSharedPointer<ToolChainNode> > m_toRemoveList;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
Reference in New Issue
Block a user