diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index 3a753fe9630..7114e136c6d 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -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); diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h index 7d234b5bbbd..b67183ba884 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.h +++ b/src/plugins/cmakeprojectmanager/builddirmanager.h @@ -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 buildTargets() const; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp index 06696847b60..d85ef176ef4 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp @@ -24,24 +24,46 @@ ****************************************************************************/ #include "cmakebuildsettingswidget.h" + +#include "configmodel.h" #include "cmakeproject.h" #include "cmakebuildconfiguration.h" #include +#include #include #include #include +#include #include +#include -#include +#include +#include +#include +#include +#include +#include +#include +#include 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(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(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 diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h index cca63741077..341781b9784 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h @@ -27,7 +27,21 @@ #include +#include + +#include + +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 diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index bcf7db72c76..424452bd99f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -339,6 +339,75 @@ bool CMakeProject::isParsing() const return m_buildDirManager && m_buildDirManager->isBusy(); } +QList CMakeProject::currentCMakeConfiguration() const +{ + if (!m_buildDirManager || m_buildDirManager->isBusy()) + return QList(); + const QList 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 &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) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 24c75319e69..f71ec0c9f2e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -27,6 +27,7 @@ #include "cmake_global.h" #include "cmakeprojectnodes.h" +#include "configmodel.h" #include #include @@ -112,6 +113,9 @@ public: void runCMake(); bool isParsing() const; + QList currentCMakeConfiguration() const; + void setCurrentCMakeConfiguration(const QList &items); + signals: /// emitted when parsing starts: void parsingStarted(); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro index 577fb88e15b..3e0dadcc24e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro @@ -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 diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs index 3dabc68db52..9d2b32d5a72 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs @@ -66,6 +66,8 @@ QtcPlugin { "cmakeindenter.h", "cmakeindenter.cpp", "cmakeautocompleter.h", - "cmakeautocompleter.cpp" + "cmakeautocompleter.cpp", + "configmodel.cpp", + "configmodel.h" ] } diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp new file mode 100644 index 00000000000..a5eccff5051 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -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 +#include + +#include + +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("") : 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 &config) +{ + QList 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 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 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::configurationChanges() const +{ + QList result; + const QList 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 + diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h new file mode 100644 index 00000000000..d3a335dbe20 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -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 + +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 &config); + void flush(); + void resetAllChanges(); + + bool hasChanges() const; + bool hasCMakeChanges() const; + + QList 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 m_configuration; +}; + +} // namespace CMakeProjectManager +