forked from qt-creator/qt-creator
CMake: Add UI to display and edit cmake configuration
Change-Id: I95944dcd58dc86023c2757068979f92b8989011b Reviewed-by: Tim Jenssen <tim.jenssen@theqtcompany.com>
This commit is contained in:
@@ -138,6 +138,12 @@ void BuildDirManager::forceReparse()
|
||||
startCMake(tool, generator, m_inputConfig);
|
||||
}
|
||||
|
||||
void BuildDirManager::setInputConfiguration(const CMakeConfig &config)
|
||||
{
|
||||
m_inputConfig = config;
|
||||
forceReparse();
|
||||
}
|
||||
|
||||
void BuildDirManager::parse()
|
||||
{
|
||||
CMakeTool *tool = CMakeKitInformation::cmakeTool(m_kit);
|
||||
|
||||
@@ -74,6 +74,8 @@ public:
|
||||
void parse();
|
||||
void forceReparse();
|
||||
|
||||
void setInputConfiguration(const CMakeConfig &config);
|
||||
|
||||
bool isProjectFile(const Utils::FileName &fileName) const;
|
||||
QString projectName() const;
|
||||
QList<CMakeBuildTarget> buildTargets() const;
|
||||
|
||||
@@ -24,24 +24,46 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "cmakebuildsettingswidget.h"
|
||||
|
||||
#include "configmodel.h"
|
||||
#include "cmakeproject.h"
|
||||
#include "cmakebuildconfiguration.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/find/itemviewfind.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <utils/detailswidget.h>
|
||||
#include <utils/headerviewstretcher.h>
|
||||
#include <utils/pathchooser.h>
|
||||
#include <utils/itemviews.h>
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QBoxLayout>
|
||||
#include <QCheckBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSpacerItem>
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// CMakeBuildSettingsWidget:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) :
|
||||
m_buildConfiguration(bc)
|
||||
m_buildConfiguration(bc),
|
||||
m_configModel(new ConfigModel(this)),
|
||||
m_configFilterModel(new QSortFilterProxyModel)
|
||||
{
|
||||
QTC_CHECK(bc);
|
||||
|
||||
setDisplayName(tr("CMake"));
|
||||
|
||||
auto vbox = new QVBoxLayout(this);
|
||||
vbox->setMargin(0);
|
||||
auto container = new Utils::DetailsWidget;
|
||||
@@ -51,22 +73,128 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
|
||||
auto details = new QWidget(container);
|
||||
container->setWidget(details);
|
||||
|
||||
auto fl = new QFormLayout(details);
|
||||
fl->setMargin(0);
|
||||
fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
||||
auto mainLayout = new QGridLayout(details);
|
||||
mainLayout->setMargin(0);
|
||||
mainLayout->setColumnStretch(1, 10);
|
||||
|
||||
auto project = static_cast<CMakeProject *>(bc->target()->project());
|
||||
|
||||
auto buildDirChooser = new Utils::PathChooser;
|
||||
buildDirChooser->setBaseFileName(project->projectDirectory());
|
||||
buildDirChooser->setFileName(bc->buildDirectory());
|
||||
connect(buildDirChooser, &Utils::PathChooser::rawPathChanged, this,
|
||||
[this, project](const QString &path) {
|
||||
m_configModel->flush(); // clear out config cache...
|
||||
project->changeBuildDirectory(m_buildConfiguration, path);
|
||||
});
|
||||
|
||||
fl->addRow(tr("Build directory:"), buildDirChooser);
|
||||
int row = 0;
|
||||
mainLayout->addWidget(new QLabel(tr("Build directory:")), row, 0);
|
||||
mainLayout->addWidget(buildDirChooser->lineEdit(), row, 1);
|
||||
mainLayout->addWidget(buildDirChooser->buttonAtIndex(0), row, 2);
|
||||
|
||||
setDisplayName(tr("CMake"));
|
||||
++row;
|
||||
mainLayout->addItem(new QSpacerItem(20, 20), row, 0);
|
||||
|
||||
++row;
|
||||
auto tree = new Utils::TreeView;
|
||||
connect(tree, &Utils::TreeView::activated,
|
||||
tree, [tree](const QModelIndex &idx) { tree->edit(idx); });
|
||||
m_configView = tree;
|
||||
m_configFilterModel->setSourceModel(m_configModel);
|
||||
m_configFilterModel->setFilterKeyColumn(2);
|
||||
m_configFilterModel->setFilterFixedString(QLatin1String("0"));
|
||||
m_configView->setModel(m_configFilterModel);
|
||||
m_configView->setMinimumHeight(300);
|
||||
m_configView->setRootIsDecorated(false);
|
||||
m_configView->setUniformRowHeights(true);
|
||||
new Utils::HeaderViewStretcher(m_configView->header(), 1);
|
||||
m_configView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_configView->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
m_configView->setFrameShape(QFrame::NoFrame);
|
||||
m_configView->hideColumn(2); // Hide isAdvanced column
|
||||
QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_configView, Core::ItemViewFind::LightColored);
|
||||
findWrapper->setFrameStyle(QFrame::StyledPanel);
|
||||
|
||||
m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Large, findWrapper);
|
||||
m_progressIndicator->attachToWidget(findWrapper);
|
||||
m_progressIndicator->raise();
|
||||
m_progressIndicator->hide();
|
||||
m_showProgressTimer.setSingleShot(true);
|
||||
m_showProgressTimer.setInterval(50); // don't show progress for < 50ms tasks
|
||||
connect(&m_showProgressTimer, &QTimer::timeout, [this]() { m_progressIndicator->show(); });
|
||||
|
||||
mainLayout->addWidget(findWrapper, row, 0, 1, 2);
|
||||
|
||||
auto buttonLayout = new QVBoxLayout;
|
||||
m_editButton = new QPushButton(tr("&Edit"));
|
||||
buttonLayout->addWidget(m_editButton);
|
||||
m_resetButton = new QPushButton(tr("&Reset"));
|
||||
m_resetButton->setEnabled(false);
|
||||
buttonLayout->addWidget(m_resetButton);
|
||||
buttonLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||
m_showAdvancedCheckBox = new QCheckBox(tr("Advanced"));
|
||||
buttonLayout->addWidget(m_showAdvancedCheckBox);
|
||||
buttonLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
|
||||
mainLayout->addLayout(buttonLayout, row, 2);
|
||||
|
||||
++row;
|
||||
m_reconfigureButton = new QPushButton(tr("Apply Configuration Changes"));
|
||||
m_reconfigureButton->setEnabled(false);
|
||||
mainLayout->addWidget(m_reconfigureButton, row, 0, 1, 3);
|
||||
|
||||
updateAdvancedCheckBox();
|
||||
|
||||
connect(project, &CMakeProject::parsingStarted, this, [this]() {
|
||||
updateButtonState();
|
||||
m_showProgressTimer.start();
|
||||
});
|
||||
connect(project, &CMakeProject::buildDirectoryDataAvailable,
|
||||
this, [this, project, buildDirChooser](ProjectExplorer::BuildConfiguration *bc) {
|
||||
updateButtonState();
|
||||
if (m_buildConfiguration == bc) {
|
||||
m_configModel->setConfiguration(project->currentCMakeConfiguration());
|
||||
buildDirChooser->triggerChanged(); // refresh valid state...
|
||||
}
|
||||
m_showProgressTimer.stop();
|
||||
m_progressIndicator->hide();
|
||||
});
|
||||
|
||||
connect(m_configModel, &QAbstractItemModel::dataChanged,
|
||||
this, &CMakeBuildSettingsWidget::updateButtonState);
|
||||
connect(m_configModel, &QAbstractItemModel::modelReset,
|
||||
this, &CMakeBuildSettingsWidget::updateButtonState);
|
||||
|
||||
connect(m_showAdvancedCheckBox, &QCheckBox::stateChanged,
|
||||
this, &CMakeBuildSettingsWidget::updateAdvancedCheckBox);
|
||||
|
||||
connect(m_resetButton, &QPushButton::clicked, m_configModel, &ConfigModel::resetAllChanges);
|
||||
connect(m_reconfigureButton, &QPushButton::clicked, this, [this, project]() {
|
||||
project->setCurrentCMakeConfiguration(m_configModel->configurationChanges());
|
||||
});
|
||||
connect(m_editButton, &QPushButton::clicked, this, [this]() {
|
||||
QModelIndex idx = m_configView->currentIndex();
|
||||
if (idx.column() != 1)
|
||||
idx = idx.sibling(idx.row(), 1);
|
||||
m_configView->setCurrentIndex(idx);
|
||||
m_configView->edit(idx);
|
||||
});
|
||||
}
|
||||
|
||||
void CMakeBuildSettingsWidget::updateButtonState()
|
||||
{
|
||||
auto project = static_cast<CMakeProject *>(m_buildConfiguration->target()->project());
|
||||
const bool isParsing = project->isParsing();
|
||||
const bool hasChanges = m_configModel->hasChanges();
|
||||
m_resetButton->setEnabled(hasChanges && !isParsing);
|
||||
m_reconfigureButton->setEnabled((hasChanges || m_configModel->hasCMakeChanges()) && !isParsing);
|
||||
}
|
||||
|
||||
void CMakeBuildSettingsWidget::updateAdvancedCheckBox()
|
||||
{
|
||||
// Switch between Qt::DisplayRole (everything is "0") and Qt::EditRole (advanced is "1").
|
||||
m_configFilterModel->setFilterRole(m_showAdvancedCheckBox->isChecked() ? Qt::EditRole : Qt::DisplayRole);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -27,7 +27,21 @@
|
||||
|
||||
#include <projectexplorer/namedwidget.h>
|
||||
|
||||
#include <utils/progressindicator.h>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCheckBox;
|
||||
class QPushButton;
|
||||
class QTreeView;
|
||||
class QSortFilterProxyModel;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
class ConfigModel;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class CMakeBuildConfiguration;
|
||||
@@ -39,7 +53,19 @@ public:
|
||||
CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc);
|
||||
|
||||
private:
|
||||
CMakeBuildConfiguration *m_buildConfiguration = 0;
|
||||
void updateButtonState();
|
||||
void updateAdvancedCheckBox();
|
||||
|
||||
CMakeBuildConfiguration *m_buildConfiguration;
|
||||
QTreeView *m_configView;
|
||||
ConfigModel *m_configModel;
|
||||
QSortFilterProxyModel *m_configFilterModel;
|
||||
Utils::ProgressIndicator *m_progressIndicator;
|
||||
QPushButton *m_editButton;
|
||||
QPushButton *m_resetButton;
|
||||
QCheckBox *m_showAdvancedCheckBox;
|
||||
QPushButton *m_reconfigureButton;
|
||||
QTimer m_showProgressTimer;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -339,6 +339,75 @@ bool CMakeProject::isParsing() const
|
||||
return m_buildDirManager && m_buildDirManager->isBusy();
|
||||
}
|
||||
|
||||
QList<ConfigModel::DataItem> CMakeProject::currentCMakeConfiguration() const
|
||||
{
|
||||
if (!m_buildDirManager || m_buildDirManager->isBusy())
|
||||
return QList<ConfigModel::DataItem>();
|
||||
const QList<CMakeConfigItem> cmakeItems = m_buildDirManager->configuration();
|
||||
return Utils::transform(cmakeItems, [](const CMakeConfigItem &i) {
|
||||
ConfigModel::DataItem j;
|
||||
j.key = QString::fromUtf8(i.key);
|
||||
j.value = QString::fromUtf8(i.value);
|
||||
j.description = QString::fromUtf8(i.documentation);
|
||||
|
||||
j.isAdvanced = i.isAdvanced;
|
||||
switch (i.type) {
|
||||
case CMakeConfigItem::FILEPATH:
|
||||
j.type = ConfigModel::DataItem::FILE;
|
||||
break;
|
||||
case CMakeConfigItem::PATH:
|
||||
j.type = ConfigModel::DataItem::DIRECTORY;
|
||||
break;
|
||||
case CMakeConfigItem::BOOL:
|
||||
j.type = ConfigModel::DataItem::BOOLEAN;
|
||||
break;
|
||||
case CMakeConfigItem::STRING:
|
||||
j.type = ConfigModel::DataItem::STRING;
|
||||
break;
|
||||
default:
|
||||
j.type = ConfigModel::DataItem::UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return j;
|
||||
});
|
||||
}
|
||||
|
||||
void CMakeProject::setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items)
|
||||
{
|
||||
if (!m_buildDirManager || m_buildDirManager->isBusy())
|
||||
return;
|
||||
|
||||
const CMakeConfig config = Utils::transform(items, [](const ConfigModel::DataItem &i) {
|
||||
CMakeConfigItem ni;
|
||||
ni.key = i.key.toUtf8();
|
||||
ni.value = i.value.toUtf8();
|
||||
ni.documentation = i.description.toUtf8();
|
||||
ni.isAdvanced = i.isAdvanced;
|
||||
switch (i.type) {
|
||||
case CMakeProjectManager::ConfigModel::DataItem::BOOLEAN:
|
||||
ni.type = CMakeConfigItem::BOOL;
|
||||
break;
|
||||
case CMakeProjectManager::ConfigModel::DataItem::FILE:
|
||||
ni.type = CMakeConfigItem::FILEPATH;
|
||||
break;
|
||||
case CMakeProjectManager::ConfigModel::DataItem::DIRECTORY:
|
||||
ni.type = CMakeConfigItem::PATH;
|
||||
break;
|
||||
case CMakeProjectManager::ConfigModel::DataItem::STRING:
|
||||
ni.type = CMakeConfigItem::STRING;
|
||||
break;
|
||||
case CMakeProjectManager::ConfigModel::DataItem::UNKNOWN:
|
||||
default:
|
||||
ni.type = CMakeConfigItem::INTERNAL;
|
||||
break;
|
||||
}
|
||||
return ni;
|
||||
});
|
||||
|
||||
m_buildDirManager->setInputConfiguration(config);
|
||||
}
|
||||
|
||||
bool CMakeProject::isProjectFile(const FileName &fileName)
|
||||
{
|
||||
if (!m_buildDirManager)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "cmake_global.h"
|
||||
#include "cmakeprojectnodes.h"
|
||||
#include "configmodel.h"
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
@@ -112,6 +113,9 @@ public:
|
||||
void runCMake();
|
||||
bool isParsing() const;
|
||||
|
||||
QList<ConfigModel::DataItem> currentCMakeConfiguration() const;
|
||||
void setCurrentCMakeConfiguration(const QList<ConfigModel::DataItem> &items);
|
||||
|
||||
signals:
|
||||
/// emitted when parsing starts:
|
||||
void parsingStarted();
|
||||
|
||||
@@ -26,7 +26,8 @@ HEADERS = builddirmanager.h \
|
||||
cmakefile.h \
|
||||
cmakebuildsettingswidget.h \
|
||||
cmakeindenter.h \
|
||||
cmakeautocompleter.h
|
||||
cmakeautocompleter.h \
|
||||
configmodel.h
|
||||
|
||||
SOURCES = builddirmanager.cpp \
|
||||
cmakebuildstep.cpp \
|
||||
@@ -50,6 +51,7 @@ SOURCES = builddirmanager.cpp \
|
||||
cmakefile.cpp \
|
||||
cmakebuildsettingswidget.cpp \
|
||||
cmakeindenter.cpp \
|
||||
cmakeautocompleter.cpp
|
||||
cmakeautocompleter.cpp \
|
||||
configmodel.cpp
|
||||
|
||||
RESOURCES += cmakeproject.qrc
|
||||
|
||||
@@ -66,6 +66,8 @@ QtcPlugin {
|
||||
"cmakeindenter.h",
|
||||
"cmakeindenter.cpp",
|
||||
"cmakeautocompleter.h",
|
||||
"cmakeautocompleter.cpp"
|
||||
"cmakeautocompleter.cpp",
|
||||
"configmodel.cpp",
|
||||
"configmodel.h"
|
||||
]
|
||||
}
|
||||
|
||||
309
src/plugins/cmakeprojectmanager/configmodel.cpp
Normal file
309
src/plugins/cmakeprojectmanager/configmodel.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "configmodel.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QFont>
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
static bool isTrue(const QString &value)
|
||||
{
|
||||
const QString lower = value.toLower();
|
||||
return lower == QStringLiteral("true") || lower == QStringLiteral("on") || lower == QStringLiteral("1");
|
||||
}
|
||||
|
||||
ConfigModel::ConfigModel(QObject *parent) : QAbstractTableModel(parent)
|
||||
{ }
|
||||
|
||||
int ConfigModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
QTC_ASSERT(parent.model() == nullptr || parent.model() == this, return 0);
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
return m_configuration.count();
|
||||
}
|
||||
|
||||
int ConfigModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
QTC_ASSERT(!parent.isValid(), return 0);
|
||||
QTC_ASSERT(parent.model() == nullptr, return 0);
|
||||
return 3;
|
||||
}
|
||||
|
||||
Qt::ItemFlags ConfigModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
QTC_ASSERT(index.model() == this, return Qt::NoItemFlags);
|
||||
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 {
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
}
|
||||
|
||||
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()];
|
||||
|
||||
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.description;
|
||||
case Qt::UserRole:
|
||||
return item.type;
|
||||
case Qt::FontRole: {
|
||||
QFont font;
|
||||
font.setItalic(item.isCMakeChanged);
|
||||
font.setBold(item.isUserNew);
|
||||
return font;
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
case 1: {
|
||||
const QString value = item.isUserChanged ? item.newValue : item.value;
|
||||
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::ToolTipRole:
|
||||
return item.description;
|
||||
case Qt::UserRole:
|
||||
return item.type;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
switch (role) {
|
||||
case Qt::EditRole:
|
||||
return QString::fromLatin1("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;
|
||||
}
|
||||
|
||||
InternalDataItem &item = itemAtRow(index.row());
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
if (!item.key.isEmpty())
|
||||
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::setConfiguration(const QList<ConfigModel::DataItem> &config)
|
||||
{
|
||||
QList<DataItem> tmp = config;
|
||||
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->key < oldIt->key) {
|
||||
// Add new entry:
|
||||
result << InternalDataItem(*newIt);
|
||||
++newIt;
|
||||
} else if (newIt->key > oldIt->key) {
|
||||
// skip old entry:
|
||||
++oldIt;
|
||||
} else {
|
||||
// merge old/new entry:
|
||||
InternalDataItem item(*newIt);
|
||||
item.isCMakeChanged = (oldIt->value != newIt->value);
|
||||
result << item;
|
||||
++newIt;
|
||||
++oldIt;
|
||||
}
|
||||
}
|
||||
|
||||
// Add remaining new entries:
|
||||
for (; newIt != newEndIt; ++newIt)
|
||||
result << InternalDataItem(*newIt);
|
||||
|
||||
beginResetModel();
|
||||
m_configuration = result;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ConfigModel::flush()
|
||||
{
|
||||
beginResetModel();
|
||||
m_configuration.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ConfigModel::resetAllChanges()
|
||||
{
|
||||
const QList<InternalDataItem> tmp
|
||||
= Utils::filtered(m_configuration,
|
||||
[](const InternalDataItem &i) { return !i.isUserNew; });
|
||||
|
||||
beginResetModel();
|
||||
m_configuration = Utils::transform(tmp, [](const InternalDataItem &i) -> InternalDataItem {
|
||||
InternalDataItem ni(i);
|
||||
ni.newValue.clear();
|
||||
ni.isUserChanged = false;
|
||||
return ni;
|
||||
});
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
bool ConfigModel::hasChanges() const
|
||||
{
|
||||
return Utils::contains(m_configuration, [](const InternalDataItem &i) { return i.isUserChanged || i.isUserNew; });
|
||||
}
|
||||
|
||||
bool ConfigModel::hasCMakeChanges() const
|
||||
{
|
||||
return Utils::contains(m_configuration, [](const InternalDataItem &i) { return i.isCMakeChanged; });
|
||||
}
|
||||
|
||||
QList<ConfigModel::DataItem> ConfigModel::configurationChanges() const
|
||||
{
|
||||
QList<DataItem> result;
|
||||
const QList<InternalDataItem> tmp
|
||||
= Utils::filtered(m_configuration, [](const InternalDataItem &i) { return i.isUserChanged || i.isUserNew; });
|
||||
foreach (const InternalDataItem &item, tmp) {
|
||||
DataItem newItem(item);
|
||||
if (item.isUserChanged)
|
||||
newItem.value = item.newValue;
|
||||
result << newItem;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ConfigModel::InternalDataItem &ConfigModel::itemAtRow(int row)
|
||||
{
|
||||
QTC_CHECK(row >= 0);
|
||||
return m_configuration[row];
|
||||
}
|
||||
|
||||
const ConfigModel::InternalDataItem &ConfigModel::itemAtRow(int row) const
|
||||
{
|
||||
QTC_CHECK(row >= 0);
|
||||
return m_configuration[row];
|
||||
}
|
||||
|
||||
ConfigModel::InternalDataItem::InternalDataItem(const ConfigModel::DataItem &item) : DataItem(item),
|
||||
isUserChanged(false), isUserNew(false), isCMakeChanged(false)
|
||||
{ }
|
||||
|
||||
} // namespace CMakeProjectManager
|
||||
|
||||
86
src/plugins/cmakeprojectmanager/configmodel.h
Normal file
86
src/plugins/cmakeprojectmanager/configmodel.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
class ConfigModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
class DataItem {
|
||||
public:
|
||||
enum Type { BOOLEAN, FILE, DIRECTORY, STRING, UNKNOWN};
|
||||
|
||||
QString key;
|
||||
Type type = STRING;
|
||||
bool isAdvanced = false;
|
||||
QString value;
|
||||
QString description;
|
||||
};
|
||||
|
||||
explicit ConfigModel(QObject *parent = nullptr);
|
||||
|
||||
// QAbstractItemModel interface
|
||||
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 setConfiguration(const QList<DataItem> &config);
|
||||
void flush();
|
||||
void resetAllChanges();
|
||||
|
||||
bool hasChanges() const;
|
||||
bool hasCMakeChanges() const;
|
||||
|
||||
QList<DataItem> configurationChanges() const;
|
||||
|
||||
private:
|
||||
class InternalDataItem : public DataItem
|
||||
{
|
||||
public:
|
||||
InternalDataItem(const DataItem &item);
|
||||
InternalDataItem(const InternalDataItem &item) = default;
|
||||
|
||||
bool isUserChanged;
|
||||
bool isUserNew;
|
||||
bool isCMakeChanged;
|
||||
QString newValue;
|
||||
};
|
||||
|
||||
InternalDataItem &itemAtRow(int row);
|
||||
const InternalDataItem &itemAtRow(int row) const;
|
||||
QList<InternalDataItem> m_configuration;
|
||||
};
|
||||
|
||||
} // namespace CMakeProjectManager
|
||||
|
||||
Reference in New Issue
Block a user