forked from qt-creator/qt-creator
CMake: Group entries in project configuration
Change-Id: I6aa797f5ff49a5cc33dfbdf0b25dcd78abbff66e Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -139,21 +139,23 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
|
|||||||
connect(tree, &Utils::TreeView::activated,
|
connect(tree, &Utils::TreeView::activated,
|
||||||
tree, [tree](const QModelIndex &idx) { tree->edit(idx); });
|
tree, [tree](const QModelIndex &idx) { tree->edit(idx); });
|
||||||
m_configView = tree;
|
m_configView = tree;
|
||||||
|
|
||||||
m_configFilterModel->setSourceModel(m_configModel);
|
m_configFilterModel->setSourceModel(m_configModel);
|
||||||
m_configFilterModel->setFilterKeyColumn(2);
|
m_configFilterModel->setFilterKeyColumn(0);
|
||||||
m_configFilterModel->setFilterFixedString(QLatin1String("0"));
|
m_configFilterModel->setFilterRole(ConfigModel::ItemIsAdvancedRole);
|
||||||
|
m_configFilterModel->setFilterFixedString("0");
|
||||||
|
|
||||||
m_configTextFilterModel->setSourceModel(m_configFilterModel);
|
m_configTextFilterModel->setSourceModel(m_configFilterModel);
|
||||||
m_configTextFilterModel->setFilterKeyColumn(-1);
|
m_configTextFilterModel->setFilterKeyColumn(-1);
|
||||||
m_configTextFilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
m_configTextFilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
|
||||||
m_configView->setModel(m_configTextFilterModel);
|
m_configView->setModel(m_configTextFilterModel);
|
||||||
m_configView->setMinimumHeight(300);
|
m_configView->setMinimumHeight(300);
|
||||||
m_configView->setRootIsDecorated(false);
|
|
||||||
m_configView->setUniformRowHeights(true);
|
m_configView->setUniformRowHeights(true);
|
||||||
auto stretcher = new Utils::HeaderViewStretcher(m_configView->header(), 1);
|
auto stretcher = new Utils::HeaderViewStretcher(m_configView->header(), 1);
|
||||||
m_configView->setSelectionMode(QAbstractItemView::SingleSelection);
|
m_configView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
|
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||||
m_configView->setFrameShape(QFrame::NoFrame);
|
m_configView->setFrameShape(QFrame::NoFrame);
|
||||||
m_configView->hideColumn(2); // Hide isAdvanced column
|
|
||||||
m_configView->setItemDelegate(new ConfigModelItemDelegate(m_configView));
|
m_configView->setItemDelegate(new ConfigModelItemDelegate(m_configView));
|
||||||
QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_configView, Core::ItemViewFind::LightColored);
|
QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_configView, Core::ItemViewFind::LightColored);
|
||||||
findWrapper->setFrameStyle(QFrame::StyledPanel);
|
findWrapper->setFrameStyle(QFrame::StyledPanel);
|
||||||
@@ -311,8 +313,10 @@ void CMakeBuildSettingsWidget::updateButtonState()
|
|||||||
|
|
||||||
void CMakeBuildSettingsWidget::updateAdvancedCheckBox()
|
void CMakeBuildSettingsWidget::updateAdvancedCheckBox()
|
||||||
{
|
{
|
||||||
// Switch between Qt::DisplayRole (everything is "0") and Qt::EditRole (advanced is "1").
|
if (m_showAdvancedCheckBox->isChecked())
|
||||||
m_configFilterModel->setFilterRole(m_showAdvancedCheckBox->isChecked() ? Qt::EditRole : Qt::DisplayRole);
|
m_configTextFilterModel->setSourceModel(m_configModel);
|
||||||
|
else
|
||||||
|
m_configTextFilterModel->setSourceModel(m_configFilterModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMakeBuildSettingsWidget::updateFromKit()
|
void CMakeBuildSettingsWidget::updateFromKit()
|
||||||
|
@@ -25,12 +25,14 @@
|
|||||||
|
|
||||||
#include "configmodel.h"
|
#include "configmodel.h"
|
||||||
|
|
||||||
|
#include <utils/asconst.h>
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/theme/theme.h>
|
#include <utils/theme/theme.h>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
|
|
||||||
@@ -41,186 +43,27 @@ static bool isTrue(const QString &value)
|
|||||||
|| lower == QStringLiteral("1") || lower == QStringLiteral("yes");
|
|| lower == QStringLiteral("1") || lower == QStringLiteral("yes");
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigModel::ConfigModel(QObject *parent) : QAbstractTableModel(parent)
|
ConfigModel::ConfigModel(QObject *parent) : Utils::TreeModel<>(parent)
|
||||||
{ }
|
|
||||||
|
|
||||||
int ConfigModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : m_configuration.count();
|
setHeader({tr("Key"), tr("Value")});
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConfigModel::columnCount(const QModelIndex &parent) const
|
QVariant ConfigModel::data(const QModelIndex &idx, int role) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : 3;
|
// Hide/show groups according to "isAdvanced" setting:
|
||||||
}
|
Utils::TreeItem *item = static_cast<Utils::TreeItem *>(idx.internalPointer());
|
||||||
|
if (role == ItemIsAdvancedRole && item->childCount() > 0) {
|
||||||
Qt::ItemFlags ConfigModel::flags(const QModelIndex &index) const
|
const bool hasNormalChildren = item->findAnyChild([](const Utils::TreeItem *ti) {
|
||||||
{
|
if (auto cmti = dynamic_cast<const Internal::ConfigModelTreeItem*>(ti))
|
||||||
QTC_ASSERT(index.model() == this, return Qt::NoItemFlags);
|
return !cmti->dataItem->isAdvanced;
|
||||||
QTC_ASSERT(index.isValid(), return Qt::NoItemFlags);
|
|
||||||
QTC_ASSERT(index.column() >= 0 && index.column() < columnCount(QModelIndex()), return Qt::NoItemFlags);
|
|
||||||
QTC_ASSERT(index.row() >= 0 && index.row() < rowCount(QModelIndex()), return Qt::NoItemFlags);
|
|
||||||
|
|
||||||
const InternalDataItem &item = itemAtRow(index.row());
|
|
||||||
|
|
||||||
if (index.column() == 1) {
|
|
||||||
if (item.type == DataItem::BOOLEAN)
|
|
||||||
return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
|
|
||||||
else
|
|
||||||
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
|
|
||||||
} else {
|
|
||||||
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
|
||||||
if (item.isUserNew)
|
|
||||||
return flags |= Qt::ItemIsEditable;
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ConfigModel::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(index.model() == this, return QVariant());
|
|
||||||
QTC_ASSERT(index.isValid(), return QVariant());
|
|
||||||
QTC_ASSERT(index.row() >= 0 && index.row() < rowCount(QModelIndex()), return QVariant());
|
|
||||||
QTC_ASSERT(index.column() >= 0 && index.column() < columnCount(QModelIndex()), return QVariant());
|
|
||||||
|
|
||||||
const InternalDataItem &item = m_configuration[index.row()];
|
|
||||||
|
|
||||||
if (index.column() < 2) {
|
|
||||||
switch (role) {
|
|
||||||
case ItemTypeRole:
|
|
||||||
return item.type;
|
|
||||||
case ItemValuesRole:
|
|
||||||
return item.values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (index.column()) {
|
|
||||||
case 0:
|
|
||||||
switch (role) {
|
|
||||||
case Qt::DisplayRole:
|
|
||||||
return item.key.isEmpty() ? tr("<UNSET>") : item.key;
|
|
||||||
case Qt::EditRole:
|
|
||||||
return item.key;
|
|
||||||
case Qt::ToolTipRole:
|
|
||||||
return item.toolTip();
|
|
||||||
case Qt::FontRole: {
|
|
||||||
QFont font;
|
|
||||||
font.setItalic(item.isCMakeChanged);
|
|
||||||
font.setBold(item.isUserNew);
|
|
||||||
font.setStrikeOut(!item.inCMakeCache && !item.isUserNew);
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
const QString value = item.currentValue();
|
|
||||||
const QString kitValue = m_kitConfiguartion.value(item.key);
|
|
||||||
|
|
||||||
switch (role) {
|
|
||||||
case Qt::CheckStateRole:
|
|
||||||
return (item.type == DataItem::BOOLEAN)
|
|
||||||
? QVariant(isTrue(value) ? Qt::Checked : Qt::Unchecked) : QVariant();
|
|
||||||
case Qt::DisplayRole:
|
|
||||||
return value;
|
|
||||||
case Qt::EditRole:
|
|
||||||
return (item.type == DataItem::BOOLEAN) ? QVariant(isTrue(value)) : QVariant(value);
|
|
||||||
case Qt::FontRole: {
|
|
||||||
QFont font;
|
|
||||||
font.setBold(item.isUserChanged || item.isUserNew);
|
|
||||||
font.setItalic(item.isCMakeChanged);
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
case Qt::ForegroundRole:
|
|
||||||
return Utils::creatorTheme()->color((!kitValue.isNull() && kitValue != value)
|
|
||||||
? Utils::Theme::TextColorHighlight : Utils::Theme::TextColorNormal);
|
|
||||||
case Qt::ToolTipRole: {
|
|
||||||
QString tooltip = item.toolTip();
|
|
||||||
const QString kitValue = m_kitConfiguartion.value(item.key);
|
|
||||||
if (!kitValue.isNull()) {
|
|
||||||
if (!tooltip.isEmpty())
|
|
||||||
tooltip.append("<br>");
|
|
||||||
tooltip.append(tr("Kit value: %1").arg(kitValue));
|
|
||||||
}
|
|
||||||
return tooltip;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
switch (role) {
|
|
||||||
case Qt::EditRole:
|
|
||||||
return "0";
|
|
||||||
case Qt::DisplayRole:
|
|
||||||
return QString::fromLatin1(item.isAdvanced ? "1" : "0");
|
|
||||||
case Qt::CheckStateRole:
|
|
||||||
return item.isAdvanced ? Qt::Checked : Qt::Unchecked;
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ConfigModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(index.model() == this, return false);
|
|
||||||
QTC_ASSERT(index.isValid(), return false);
|
|
||||||
QTC_ASSERT(index.row() >= 0 && index.row() < rowCount(QModelIndex()), return false);
|
|
||||||
QTC_ASSERT(index.column() >= 0 && index.column() < 2, return false);
|
|
||||||
|
|
||||||
QString newValue = value.toString();
|
|
||||||
if (role == Qt::CheckStateRole) {
|
|
||||||
if (index.column() != 1)
|
|
||||||
return false;
|
|
||||||
newValue = QString::fromLatin1(value.toInt() == 0 ? "OFF" : "ON");
|
|
||||||
} else if (role != Qt::EditRole) {
|
|
||||||
return false;
|
return false;
|
||||||
|
}) != nullptr;
|
||||||
|
return hasNormalChildren ? "0" : "1";
|
||||||
|
}
|
||||||
|
return Utils::TreeModel<>::data(idx, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalDataItem &item = itemAtRow(index.row());
|
ConfigModel::~ConfigModel() = default;
|
||||||
switch (index.column()) {
|
|
||||||
case 0:
|
|
||||||
if (!item.key.isEmpty() && !item.isUserNew)
|
|
||||||
return false;
|
|
||||||
item.key = newValue;
|
|
||||||
item.isUserNew = true;
|
|
||||||
item.isUserChanged = false;
|
|
||||||
emit dataChanged(index, index);
|
|
||||||
return true;
|
|
||||||
case 1:
|
|
||||||
if (item.value == newValue) {
|
|
||||||
item.newValue.clear();
|
|
||||||
item.isUserChanged = false;
|
|
||||||
} else {
|
|
||||||
item.newValue = newValue;
|
|
||||||
item.isUserChanged = true;
|
|
||||||
}
|
|
||||||
emit dataChanged(index, index);
|
|
||||||
return true;
|
|
||||||
case 2:
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ConfigModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
||||||
{
|
|
||||||
if (orientation == Qt::Vertical || role != Qt::DisplayRole)
|
|
||||||
return QVariant();
|
|
||||||
switch (section) {
|
|
||||||
case 0:
|
|
||||||
return tr("Setting");
|
|
||||||
case 1:
|
|
||||||
return tr("Value");
|
|
||||||
case 2:
|
|
||||||
return tr("Advanced");
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigModel::appendConfiguration(const QString &key,
|
void ConfigModel::appendConfiguration(const QString &key,
|
||||||
const QString &value,
|
const QString &value,
|
||||||
@@ -238,70 +81,33 @@ void ConfigModel::appendConfiguration(const QString &key,
|
|||||||
InternalDataItem internalItem(item);
|
InternalDataItem internalItem(item);
|
||||||
internalItem.isUserNew = true;
|
internalItem.isUserNew = true;
|
||||||
|
|
||||||
beginResetModel();
|
if (m_kitConfiguration.contains(key))
|
||||||
|
internalItem.kitValue = m_kitConfiguration.value(key);
|
||||||
|
|
||||||
m_configuration.append(internalItem);
|
m_configuration.append(internalItem);
|
||||||
endResetModel();
|
setConfiguration(m_configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigModel::setConfiguration(const QList<ConfigModel::DataItem> &config)
|
void ConfigModel::setConfiguration(const QList<DataItem> &config)
|
||||||
{
|
{
|
||||||
QList<DataItem> tmp = config;
|
setConfiguration(Utils::transform(config, [](const DataItem &di) { return InternalDataItem(di); }));
|
||||||
Utils::sort(tmp,
|
|
||||||
[](const ConfigModel::DataItem &i, const ConfigModel::DataItem &j) {
|
|
||||||
return i.key < j.key;
|
|
||||||
});
|
|
||||||
auto newIt = tmp.constBegin();
|
|
||||||
auto newEndIt = tmp.constEnd();
|
|
||||||
auto oldIt = m_configuration.constBegin();
|
|
||||||
auto oldEndIt = m_configuration.constEnd();
|
|
||||||
|
|
||||||
QList<InternalDataItem> result;
|
|
||||||
while (newIt != newEndIt && oldIt != oldEndIt) {
|
|
||||||
if (newIt->isHidden) {
|
|
||||||
++newIt;
|
|
||||||
} else if (newIt->key < oldIt->key) {
|
|
||||||
// Add new entry:
|
|
||||||
result << InternalDataItem(*newIt);
|
|
||||||
++newIt;
|
|
||||||
} else if (newIt->key > oldIt->key) {
|
|
||||||
// Keep old user settings, but skip other entries:
|
|
||||||
if (oldIt->isUserChanged || oldIt->isUserNew)
|
|
||||||
result << InternalDataItem(*oldIt);
|
|
||||||
++oldIt;
|
|
||||||
} else {
|
|
||||||
// merge old/new entry:
|
|
||||||
InternalDataItem item(*newIt);
|
|
||||||
item.newValue = (newIt->value != oldIt->newValue) ? oldIt->newValue : QString();
|
|
||||||
item.isCMakeChanged = (oldIt->value != newIt->value);
|
|
||||||
item.isUserChanged = !item.newValue.isEmpty() && (item.newValue != item.value);
|
|
||||||
result << item;
|
|
||||||
++newIt;
|
|
||||||
++oldIt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add remaining new entries:
|
|
||||||
for (; newIt != newEndIt; ++newIt) {
|
|
||||||
if (newIt->isHidden)
|
|
||||||
continue;
|
|
||||||
result << InternalDataItem(*newIt);
|
|
||||||
}
|
|
||||||
|
|
||||||
beginResetModel();
|
|
||||||
m_configuration = result;
|
|
||||||
endResetModel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigModel::setKitConfiguration(const QHash<QString, QString> &kitConfig)
|
void ConfigModel::setKitConfiguration(const QHash<QString, QString> &kitConfig)
|
||||||
{
|
{
|
||||||
m_kitConfiguartion = kitConfig;
|
m_kitConfiguration = kitConfig;
|
||||||
|
|
||||||
|
for (InternalDataItem &i : m_configuration) {
|
||||||
|
if (m_kitConfiguration.contains(i.key)) {
|
||||||
|
i.kitValue = m_kitConfiguration.value(i.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setConfiguration(m_configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigModel::flush()
|
void ConfigModel::flush()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
setConfiguration(QList<InternalDataItem>());
|
||||||
m_configuration.clear();
|
|
||||||
endResetModel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigModel::resetAllChanges()
|
void ConfigModel::resetAllChanges()
|
||||||
@@ -310,14 +116,12 @@ void ConfigModel::resetAllChanges()
|
|||||||
= Utils::filtered(m_configuration,
|
= Utils::filtered(m_configuration,
|
||||||
[](const InternalDataItem &i) { return !i.isUserNew; });
|
[](const InternalDataItem &i) { return !i.isUserNew; });
|
||||||
|
|
||||||
beginResetModel();
|
setConfiguration(Utils::transform(tmp, [](const InternalDataItem &i) {
|
||||||
m_configuration = Utils::transform(tmp, [](const InternalDataItem &i) -> InternalDataItem {
|
|
||||||
InternalDataItem ni(i);
|
InternalDataItem ni(i);
|
||||||
ni.newValue.clear();
|
ni.newValue.clear();
|
||||||
ni.isUserChanged = false;
|
ni.isUserChanged = false;
|
||||||
return ni;
|
return ni;
|
||||||
});
|
}));
|
||||||
endResetModel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConfigModel::hasChanges() const
|
bool ConfigModel::hasChanges() const
|
||||||
@@ -344,16 +148,101 @@ QList<ConfigModel::DataItem> ConfigModel::configurationChanges() const
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigModel::InternalDataItem &ConfigModel::itemAtRow(int row)
|
void ConfigModel::setConfiguration(const QList<ConfigModel::InternalDataItem> &config)
|
||||||
{
|
{
|
||||||
QTC_CHECK(row >= 0);
|
QList<InternalDataItem> tmp = config;
|
||||||
return m_configuration[row];
|
Utils::sort(tmp,
|
||||||
|
[](const ConfigModel::InternalDataItem &i, const ConfigModel::InternalDataItem &j) {
|
||||||
|
return i.key < j.key;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto newIt = tmp.constBegin();
|
||||||
|
auto newEndIt = tmp.constEnd();
|
||||||
|
auto oldIt = m_configuration.constBegin();
|
||||||
|
auto oldEndIt = m_configuration.constEnd();
|
||||||
|
|
||||||
|
QList<InternalDataItem> result;
|
||||||
|
while (newIt != newEndIt && oldIt != oldEndIt) {
|
||||||
|
if (newIt->isHidden) {
|
||||||
|
++newIt;
|
||||||
|
} else if (newIt->key < oldIt->key) {
|
||||||
|
// Add new entry:
|
||||||
|
result << *newIt;
|
||||||
|
++newIt;
|
||||||
|
} else if (newIt->key > oldIt->key) {
|
||||||
|
// Keep old user settings, but skip other entries:
|
||||||
|
if (oldIt->isUserChanged || oldIt->isUserNew)
|
||||||
|
result << InternalDataItem(*oldIt);
|
||||||
|
++oldIt;
|
||||||
|
} else {
|
||||||
|
// merge old/new entry:
|
||||||
|
InternalDataItem item(*newIt);
|
||||||
|
item.newValue = (newIt->value != oldIt->newValue) ? oldIt->newValue : QString();
|
||||||
|
item.isCMakeChanged = (oldIt->value != newIt->value);
|
||||||
|
item.isUserChanged = !item.newValue.isEmpty() && (item.newValue != item.value);
|
||||||
|
result << item;
|
||||||
|
++newIt;
|
||||||
|
++oldIt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConfigModel::InternalDataItem &ConfigModel::itemAtRow(int row) const
|
// Add remaining new entries:
|
||||||
|
for (; newIt != newEndIt; ++newIt) {
|
||||||
|
if (newIt->isHidden)
|
||||||
|
continue;
|
||||||
|
result << InternalDataItem(*newIt);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_configuration = result;
|
||||||
|
|
||||||
|
generateTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString prefix(const QString &key)
|
||||||
{
|
{
|
||||||
QTC_CHECK(row >= 0);
|
int pos = key.indexOf('_');
|
||||||
return m_configuration[row];
|
if (pos > 0)
|
||||||
|
return key.left(pos);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigModel::generateTree()
|
||||||
|
{
|
||||||
|
QList<QString> prefixList;
|
||||||
|
|
||||||
|
// Generate nodes for *all* prefixes
|
||||||
|
QHash<QString, QList<Utils::TreeItem *>> prefixes;
|
||||||
|
for (const InternalDataItem &di : m_configuration) {
|
||||||
|
const QString p = prefix(di.key);
|
||||||
|
if (!prefixes.contains(p)) {
|
||||||
|
prefixes.insert(p, {});
|
||||||
|
prefixList.append(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill prefix nodes:
|
||||||
|
for (InternalDataItem &di : m_configuration)
|
||||||
|
prefixes[prefix(di.key)].append(new Internal::ConfigModelTreeItem(&di));
|
||||||
|
|
||||||
|
Utils::TreeItem *root = new Utils::TreeItem;
|
||||||
|
|
||||||
|
for (const QString &p : Utils::asConst(prefixList)) {
|
||||||
|
const QList<Utils::TreeItem *> &prefixItemList = prefixes.value(p);
|
||||||
|
QTC_ASSERT(!prefixItemList.isEmpty(), continue);
|
||||||
|
|
||||||
|
if (prefixItemList.count() == 1) {
|
||||||
|
root->appendChild(prefixItemList.at(0));
|
||||||
|
} else {
|
||||||
|
Utils::TreeItem *sti = new Utils::StaticTreeItem(p);
|
||||||
|
for (Utils::TreeItem *const ti : prefixItemList)
|
||||||
|
sti->appendChild(ti);
|
||||||
|
root->appendChild(sti);
|
||||||
|
}
|
||||||
|
prefixes.remove(p);
|
||||||
|
}
|
||||||
|
QTC_CHECK(prefixes.isEmpty());
|
||||||
|
|
||||||
|
setRootItem(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigModel::InternalDataItem::InternalDataItem(const ConfigModel::DataItem &item) : DataItem(item)
|
ConfigModel::InternalDataItem::InternalDataItem(const ConfigModel::DataItem &item) : DataItem(item)
|
||||||
@@ -361,13 +250,18 @@ ConfigModel::InternalDataItem::InternalDataItem(const ConfigModel::DataItem &ite
|
|||||||
|
|
||||||
QString ConfigModel::InternalDataItem::toolTip() const
|
QString ConfigModel::InternalDataItem::toolTip() const
|
||||||
{
|
{
|
||||||
QStringList tooltip(description);
|
QString desc = description;
|
||||||
|
if (isAdvanced)
|
||||||
|
desc += QCoreApplication::translate("CMakeProjectManager::ConfigModel", " (ADVANCED)");
|
||||||
|
QStringList tooltip(desc);
|
||||||
if (inCMakeCache) {
|
if (inCMakeCache) {
|
||||||
if (value != newValue)
|
if (value != newValue)
|
||||||
tooltip << QCoreApplication::translate("CMakeProjectManager", "Current CMake: %1").arg(value);
|
tooltip << QCoreApplication::translate("CMakeProjectManager", "Current CMake: %1").arg(value);
|
||||||
} else {
|
} else {
|
||||||
tooltip << QCoreApplication::translate("CMakeProjectManager", "Not in CMakeCache.txt").arg(value);
|
tooltip << QCoreApplication::translate("CMakeProjectManager", "Not in CMakeCache.txt").arg(value);
|
||||||
}
|
}
|
||||||
|
if (!kitValue.isEmpty())
|
||||||
|
tooltip << QCoreApplication::translate("CMakeProjectManager::ConfigModel", "Current Kit: %1").arg(kitValue);
|
||||||
return tooltip.join("<br>");
|
return tooltip.join("<br>");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,4 +270,158 @@ QString ConfigModel::InternalDataItem::currentValue() const
|
|||||||
return isUserChanged ? newValue : value;
|
return isUserChanged ? newValue : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
ConfigModelTreeItem::~ConfigModelTreeItem() = default;
|
||||||
|
|
||||||
|
QVariant ConfigModelTreeItem::data(int column, int role) const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(column >= 0 && column < 2, return QVariant());
|
||||||
|
|
||||||
|
QTC_ASSERT(dataItem, return QVariant());
|
||||||
|
|
||||||
|
if (firstChild()) {
|
||||||
|
// Node with children: Only ever show name:
|
||||||
|
if (column == 0)
|
||||||
|
return dataItem->key;
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leaf node:
|
||||||
|
if (role == ConfigModel::ItemTypeRole)
|
||||||
|
return dataItem->type;
|
||||||
|
if (role == ConfigModel::ItemValuesRole)
|
||||||
|
return dataItem->values;
|
||||||
|
if (role == ConfigModel::ItemIsAdvancedRole)
|
||||||
|
return dataItem->isAdvanced ? "1" : "0";
|
||||||
|
|
||||||
|
switch (column) {
|
||||||
|
case 0:
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
return dataItem->key.isEmpty() ? QCoreApplication::translate("CMakeProjectManager::ConfigModel", "<UNSET>") : dataItem->key;
|
||||||
|
case Qt::EditRole:
|
||||||
|
return dataItem->key;
|
||||||
|
case Qt::ToolTipRole:
|
||||||
|
return toolTip();
|
||||||
|
case Qt::FontRole: {
|
||||||
|
QFont font;
|
||||||
|
font.setItalic(dataItem->isCMakeChanged);
|
||||||
|
font.setBold(dataItem->isUserNew);
|
||||||
|
font.setStrikeOut(!dataItem->inCMakeCache && !dataItem->isUserNew);
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
const QString value = currentValue();
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case Qt::CheckStateRole:
|
||||||
|
return (dataItem->type == ConfigModel::DataItem::BOOLEAN)
|
||||||
|
? QVariant(isTrue(value) ? Qt::Checked : Qt::Unchecked) : QVariant();
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
return value;
|
||||||
|
case Qt::EditRole:
|
||||||
|
return (dataItem->type == ConfigModel::DataItem::BOOLEAN) ? QVariant(isTrue(value)) : QVariant(value);
|
||||||
|
case Qt::FontRole: {
|
||||||
|
QFont font;
|
||||||
|
font.setBold(dataItem->isUserChanged || dataItem->isUserNew);
|
||||||
|
font.setItalic(dataItem->isCMakeChanged);
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
case Qt::ForegroundRole:
|
||||||
|
return Utils::creatorTheme()->color((!dataItem->kitValue.isNull() && dataItem->kitValue != value)
|
||||||
|
? Utils::Theme::TextColorHighlight : Utils::Theme::TextColorNormal);
|
||||||
|
case Qt::ToolTipRole: {
|
||||||
|
return toolTip();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigModelTreeItem::setData(int column, const QVariant &value, int role)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(column >= 0 && column < 2, return false);
|
||||||
|
QTC_ASSERT(dataItem, return false);
|
||||||
|
|
||||||
|
QString newValue = value.toString();
|
||||||
|
if (role == Qt::CheckStateRole) {
|
||||||
|
if (column != 1)
|
||||||
|
return false;
|
||||||
|
newValue = QString::fromLatin1(value.toInt() == 0 ? "OFF" : "ON");
|
||||||
|
} else if (role != Qt::EditRole) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (column) {
|
||||||
|
case 0:
|
||||||
|
if (!dataItem->key.isEmpty() && !dataItem->isUserNew)
|
||||||
|
return false;
|
||||||
|
dataItem->key = newValue;
|
||||||
|
dataItem->isUserNew = true;
|
||||||
|
dataItem->isUserChanged = false;
|
||||||
|
return true;
|
||||||
|
case 1:
|
||||||
|
if (dataItem->value == newValue) {
|
||||||
|
dataItem->newValue.clear();
|
||||||
|
dataItem->isUserChanged = false;
|
||||||
|
} else {
|
||||||
|
dataItem->newValue = newValue;
|
||||||
|
dataItem->isUserChanged = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags ConfigModelTreeItem::flags(int column) const
|
||||||
|
{
|
||||||
|
if (column < 0 || column >= 2)
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
|
||||||
|
QTC_ASSERT(dataItem, return Qt::NoItemFlags);
|
||||||
|
|
||||||
|
if (column == 1) {
|
||||||
|
if (dataItem->type == ConfigModel::DataItem::BOOLEAN)
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
|
||||||
|
else
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
|
||||||
|
} else {
|
||||||
|
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||||
|
if (dataItem->isUserNew)
|
||||||
|
return flags |= Qt::ItemIsEditable;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConfigModelTreeItem::toolTip() const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(dataItem, return QString());
|
||||||
|
QStringList tooltip(dataItem->description);
|
||||||
|
if (!dataItem->kitValue.isEmpty())
|
||||||
|
tooltip << QCoreApplication::translate("CMakeProjectManager", "Value requested by Kit: %1").arg(dataItem->kitValue);
|
||||||
|
if (dataItem->inCMakeCache) {
|
||||||
|
if (dataItem->value != dataItem->newValue)
|
||||||
|
tooltip << QCoreApplication::translate("CMakeProjectManager", "Current CMake: %1").arg(dataItem->value);
|
||||||
|
} else {
|
||||||
|
tooltip << QCoreApplication::translate("CMakeProjectManager", "Not in CMakeCache.txt");
|
||||||
|
}
|
||||||
|
return tooltip.join("<br>");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConfigModelTreeItem::currentValue() const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(dataItem, return QString());
|
||||||
|
return dataItem->isUserChanged ? dataItem->newValue : dataItem->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace CMakeProjectManager
|
} // namespace CMakeProjectManager
|
||||||
|
@@ -26,17 +26,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
|
|
||||||
class ConfigModel : public QAbstractTableModel
|
namespace Internal { class ConfigModelTreeItem; }
|
||||||
|
|
||||||
|
class ConfigModel : public Utils::TreeModel<>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Roles {
|
enum Roles {
|
||||||
ItemTypeRole = Qt::UserRole,
|
ItemTypeRole = Qt::UserRole,
|
||||||
ItemValuesRole
|
ItemValuesRole,
|
||||||
|
ItemIsAdvancedRole
|
||||||
};
|
};
|
||||||
|
|
||||||
class DataItem {
|
class DataItem {
|
||||||
@@ -54,14 +58,9 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
explicit ConfigModel(QObject *parent = nullptr);
|
explicit ConfigModel(QObject *parent = nullptr);
|
||||||
|
~ConfigModel() override;
|
||||||
|
|
||||||
// QAbstractItemModel interface
|
QVariant data(const QModelIndex &idx, int role) const final;
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
|
||||||
int columnCount(const QModelIndex &parent) const override;
|
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
|
||||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
|
||||||
|
|
||||||
void appendConfiguration(const QString &key,
|
void appendConfiguration(const QString &key,
|
||||||
const QString &value = QString(),
|
const QString &value = QString(),
|
||||||
@@ -92,12 +91,35 @@ private:
|
|||||||
bool isUserNew = false;
|
bool isUserNew = false;
|
||||||
bool isCMakeChanged = false;
|
bool isCMakeChanged = false;
|
||||||
QString newValue;
|
QString newValue;
|
||||||
|
QString kitValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
InternalDataItem &itemAtRow(int row);
|
void setConfiguration(const QList<InternalDataItem> &config);
|
||||||
const InternalDataItem &itemAtRow(int row) const;
|
void generateTree();
|
||||||
|
|
||||||
QList<InternalDataItem> m_configuration;
|
QList<InternalDataItem> m_configuration;
|
||||||
QHash<QString, QString> m_kitConfiguartion;
|
QHash<QString, QString> m_kitConfiguration;
|
||||||
|
|
||||||
|
friend class Internal::ConfigModelTreeItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ConfigModelTreeItem : public Utils::TreeItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConfigModelTreeItem(ConfigModel::InternalDataItem *di = nullptr) : dataItem(di) {}
|
||||||
|
virtual ~ConfigModelTreeItem() override;
|
||||||
|
|
||||||
|
QVariant data(int column, int role) const final;
|
||||||
|
bool setData(int column, const QVariant &data, int role) final;
|
||||||
|
Qt::ItemFlags flags(int column) const final;
|
||||||
|
|
||||||
|
QString toolTip() const;
|
||||||
|
QString currentValue() const;
|
||||||
|
|
||||||
|
ConfigModel::InternalDataItem *dataItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace CMakeProjectManager
|
} // namespace CMakeProjectManager
|
||||||
|
Reference in New Issue
Block a user