CMake GUI: Add presets functionality

This commit is contained in:
Kyle Edwards
2020-09-29 10:17:47 -04:00
parent 8617479061
commit a4382f72d7
32 changed files with 1632 additions and 11 deletions

View File

@@ -92,6 +92,12 @@ set(SRCS
QCMake.h
QCMakeCacheView.cxx
QCMakeCacheView.h
QCMakePreset.cxx
QCMakePreset.h
QCMakePresetComboBox.cxx
QCMakePresetComboBox.h
QCMakePresetItemModel.cxx
QCMakePresetItemModel.h
QCMakeWidgets.cxx
QCMakeWidgets.h
RegexExplorer.cxx
@@ -116,6 +122,8 @@ qt5_wrap_cpp(MOC_SRCS
FirstConfigure.h
QCMake.h
QCMakeCacheView.h
QCMakePresetComboBox.h
QCMakePresetItemModel.h
QCMakeWidgets.h
RegexExplorer.h
WarningMessagesDialog.h

View File

@@ -32,7 +32,8 @@ static const char* cmDocumentationUsage[][2] = {
" cmake-gui [options]\n"
" cmake-gui [options] <path-to-source>\n"
" cmake-gui [options] <path-to-existing-build>\n"
" cmake-gui [options] -S <path-to-source> -B <path-to-build>\n" },
" cmake-gui [options] -S <path-to-source> -B <path-to-build>\n"
" cmake-gui [options] -S <path-to-source> --preset=<preset-name>\n" },
{ nullptr, nullptr }
};
@@ -147,6 +148,7 @@ int main(int argc, char** argv)
QStringList args = QApplication::arguments();
std::string binaryDirectory;
std::string sourceDirectory;
std::string presetName;
for (int i = 1; i < args.size(); ++i) {
const QString& arg = args[i];
if (arg.startsWith("-S")) {
@@ -185,11 +187,28 @@ int main(int argc, char** argv)
binaryDirectory =
cmSystemTools::CollapseFullPath(path.toLocal8Bit().data());
cmSystemTools::ConvertToUnixSlashes(binaryDirectory);
} else if (arg.startsWith("--preset=")) {
QString preset = arg.mid(cmStrLen("--preset="));
if (preset.isEmpty()) {
std::cerr << "No preset specified for --preset" << std::endl;
return 1;
}
presetName = preset.toLocal8Bit().data();
}
}
if (!sourceDirectory.empty() && !binaryDirectory.empty()) {
if (!sourceDirectory.empty() &&
(!binaryDirectory.empty() || !presetName.empty())) {
dialog.setSourceDirectory(QString::fromLocal8Bit(sourceDirectory.c_str()));
dialog.setBinaryDirectory(QString::fromLocal8Bit(binaryDirectory.c_str()));
if (!binaryDirectory.empty()) {
dialog.setBinaryDirectory(
QString::fromLocal8Bit(binaryDirectory.c_str()));
if (!presetName.empty()) {
dialog.setStartupBinaryDirectory(true);
}
}
if (!presetName.empty()) {
dialog.setDeferredPreset(QString::fromLocal8Bit(presetName.c_str()));
}
} else {
if (args.count() == 2) {
std::string filePath =

View File

@@ -21,8 +21,10 @@
#include <QSettings>
#include <QShortcut>
#include <QStatusBar>
#include <QString>
#include <QToolButton>
#include <QUrl>
#include <QVector>
#ifdef QT_WINEXTRAS
# include <QWinTaskbarButton>
@@ -263,6 +265,8 @@ void CMakeSetupDialog::initialize()
&CMakeSetupDialog::onBinaryDirectoryChanged);
QObject::connect(this->SourceDirectory, &QLineEdit::textChanged, this,
&CMakeSetupDialog::onSourceDirectoryChanged);
QObject::connect(this->Preset, &QCMakePresetComboBox::presetChanged, this,
&CMakeSetupDialog::onBuildPresetChanged);
QObject::connect(this->CMakeThread->cmakeInstance(),
&QCMake::sourceDirChanged, this,
@@ -270,6 +274,13 @@ void CMakeSetupDialog::initialize()
QObject::connect(this->CMakeThread->cmakeInstance(),
&QCMake::binaryDirChanged, this,
&CMakeSetupDialog::updateBinaryDirectory);
QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::presetsChanged,
this, &CMakeSetupDialog::updatePresets);
QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::presetChanged,
this, &CMakeSetupDialog::updatePreset);
QObject::connect(this->CMakeThread->cmakeInstance(),
&QCMake::presetLoadError, this,
&CMakeSetupDialog::showPresetLoadError);
QObject::connect(this->CMakeThread->cmakeInstance(),
&QCMake::progressChanged, this,
@@ -314,9 +325,15 @@ void CMakeSetupDialog::initialize()
QObject::connect(this->WarnUninitializedAction, &QAction::triggered,
this->CMakeThread->cmakeInstance(),
&QCMake::setWarnUninitializedMode);
QObject::connect(this->CMakeThread->cmakeInstance(),
&QCMake::warnUninitializedModeChanged,
this->WarnUninitializedAction, &QAction::setChecked);
if (!this->SourceDirectory->text().isEmpty() ||
!this->BinaryDirectory->lineEdit()->text().isEmpty()) {
if (!this->SourceDirectory->text().isEmpty() &&
!this->DeferredPreset.isNull()) {
this->onSourceDirectoryChanged(this->SourceDirectory->text());
} else if (!this->SourceDirectory->text().isEmpty() ||
!this->BinaryDirectory->lineEdit()->text().isEmpty()) {
this->onSourceDirectoryChanged(this->SourceDirectory->text());
this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
} else {
@@ -671,6 +688,41 @@ void CMakeSetupDialog::updateBinaryDirectory(const QString& dir)
}
}
void CMakeSetupDialog::updatePresets(const QVector<QCMakePreset>& presets)
{
if (this->Preset->presets() != presets) {
this->Preset->blockSignals(true);
this->Preset->setPresets(presets);
this->Preset->blockSignals(false);
}
this->Preset->setHidden(presets.isEmpty());
this->PresetLabel->setHidden(presets.isEmpty());
if (!this->DeferredPreset.isNull()) {
this->Preset->setPresetName(this->DeferredPreset);
this->DeferredPreset = QString{};
}
}
void CMakeSetupDialog::updatePreset(const QString& name)
{
if (this->Preset->presetName() != name) {
this->Preset->blockSignals(true);
this->Preset->setPresetName(name);
this->Preset->blockSignals(false);
}
}
void CMakeSetupDialog::showPresetLoadError(
const QString& dir, cmCMakePresetsFile::ReadFileResult result)
{
QMessageBox::warning(
this, "Error Reading CMake Presets",
QString::fromLocal8Bit("Could not read presets from %1: %2")
.arg(dir, cmCMakePresetsFile::ResultToString(result)));
}
void CMakeSetupDialog::doBinaryBrowse()
{
QString dir = QFileDialog::getExistingDirectory(
@@ -686,6 +738,11 @@ void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
this->BinaryDirectory->setEditText(dir);
}
void CMakeSetupDialog::setStartupBinaryDirectory(bool startup)
{
this->StartupBinaryDirectory = startup;
}
void CMakeSetupDialog::onSourceDirectoryChanged(const QString& dir)
{
this->Output->clear();
@@ -711,11 +768,24 @@ void CMakeSetupDialog::onBinaryDirectoryChanged(const QString& dir)
Q_ARG(QString, dir));
}
void CMakeSetupDialog::onBuildPresetChanged(const QString& name)
{
QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "setPreset",
Qt::QueuedConnection, Q_ARG(QString, name),
Q_ARG(bool, !this->StartupBinaryDirectory));
this->StartupBinaryDirectory = false;
}
void CMakeSetupDialog::setSourceDirectory(const QString& dir)
{
this->SourceDirectory->setText(dir);
}
void CMakeSetupDialog::setDeferredPreset(const QString& preset)
{
this->DeferredPreset = preset;
}
void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent)
{
percent = (percent * ProgressFactor) + ProgressOffset;
@@ -753,6 +823,7 @@ void CMakeSetupDialog::setEnabledState(bool enabled)
this->CacheValues->cacheModel()->setEditEnabled(enabled);
this->SourceDirectory->setEnabled(enabled);
this->BrowseSourceDirectoryButton->setEnabled(enabled);
this->Preset->setEnabled(enabled);
this->BinaryDirectory->setEnabled(enabled);
this->BrowseBinaryDirectoryButton->setEnabled(enabled);
this->ReloadCacheAction->setEnabled(enabled);
@@ -777,6 +848,17 @@ bool CMakeSetupDialog::setupFirstConfigure()
// restore from settings
dialog.loadFromSettings();
auto presetData = this->Preset->currentData();
if (presetData.isValid()) {
auto preset = presetData.value<QCMakePreset>();
dialog.setCurrentGenerator(preset.generator);
if (preset.setGenConfig) {
dialog.setPlatform(preset.architecture);
dialog.setToolset(preset.toolset);
}
dialog.setCompilerOption(CompilerOption::DefaultNative);
}
if (dialog.exec() == QDialog::Accepted) {
dialog.saveToSettings();
this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());

View File

@@ -5,12 +5,15 @@
#include <memory>
#include "QCMake.h"
#include "QCMakePreset.h"
#include <QEventLoop>
#include <QMainWindow>
#include <QThread>
#include <QVector>
#include "ui_CMakeSetupDialog.h"
class QCMakePresetItemModel;
class QCMakeThread;
class CMakeCacheModel;
class QProgressBar;
@@ -33,6 +36,8 @@ public:
public slots:
void setBinaryDirectory(const QString& dir);
void setSourceDirectory(const QString& dir);
void setDeferredPreset(const QString& preset);
void setStartupBinaryDirectory(bool startup);
protected slots:
void initialize();
@@ -52,6 +57,10 @@ protected slots:
void doDeleteCache();
void updateSourceDirectory(const QString& dir);
void updateBinaryDirectory(const QString& dir);
void updatePresets(const QVector<QCMakePreset>& presets);
void updatePreset(const QString& name);
void showPresetLoadError(const QString& dir,
cmCMakePresetsFile::ReadFileResult result);
void showProgress(const QString& msg, float percent);
void setEnabledState(bool);
bool setupFirstConfigure();
@@ -62,6 +71,7 @@ protected slots:
void saveBuildPaths(const QStringList&);
void onBinaryDirectoryChanged(const QString& dir);
void onSourceDirectoryChanged(const QString& dir);
void onBuildPresetChanged(const QString& name);
void setCacheModified();
void removeSelectedCacheEntries();
void selectionChanged();
@@ -113,6 +123,8 @@ protected:
QAction* WarnUninitializedAction;
QAction* InstallForCommandLineAction;
State CurrentState;
QString DeferredPreset;
bool StartupBinaryDirectory = false;
QTextCharFormat ErrorFormat;
QTextCharFormat MessageFormat;

View File

@@ -44,7 +44,7 @@
<number>6</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<widget class="QLabel" name="SourceLabel">
<property name="text">
<string>Where is the source code:</string>
</property>
@@ -61,13 +61,23 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="PresetLabel">
<property name="text">
<string>Preset:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCMakePresetComboBox" name="Preset"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="BinaryLabel">
<property name="text">
<string>Where to build the binaries:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QComboBox" name="BinaryDirectory">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
@@ -83,7 +93,7 @@
</property>
</widget>
</item>
<item row="1" column="2">
<item row="2" column="2">
<widget class="QPushButton" name="BrowseBinaryDirectoryButton">
<property name="text">
<string>Browse &amp;Build...</string>
@@ -367,6 +377,11 @@
<extends>QTreeView</extends>
<header>QCMakeCacheView.h</header>
</customwidget>
<customwidget>
<class>QCMakePresetComboBox</class>
<extends>QComboBox</extends>
<header>QCMakePresetComboBox.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="CMakeSetup.qrc"/>

View File

@@ -145,6 +145,36 @@ void StartCompilerSetup::setCurrentGenerator(const QString& gen)
}
}
void StartCompilerSetup::setPlatform(const QString& platform)
{
this->PlatformOptions->setCurrentText(platform);
}
void StartCompilerSetup::setToolset(const QString& toolset)
{
this->Toolset->setText(toolset);
}
void StartCompilerSetup::setCompilerOption(CompilerOption option)
{
std::size_t index = 0;
switch (option) {
case CompilerOption::DefaultNative:
index = 0;
break;
case CompilerOption::SpecifyNative:
index = 1;
break;
case CompilerOption::ToolchainFile:
index = 2;
break;
case CompilerOption::Options:
index = 3;
break;
}
this->CompilerSetupOptions[index]->setChecked(true);
}
QString StartCompilerSetup::getGenerator() const
{
return this->GeneratorOptions->currentText();
@@ -482,6 +512,26 @@ void FirstConfigure::setGenerators(
this->mStartCompilerSetupPage->setGenerators(gens);
}
void FirstConfigure::setCurrentGenerator(const QString& gen)
{
this->mStartCompilerSetupPage->setCurrentGenerator(gen);
}
void FirstConfigure::setPlatform(const QString& platform)
{
this->mStartCompilerSetupPage->setPlatform(platform);
}
void FirstConfigure::setToolset(const QString& toolset)
{
this->mStartCompilerSetupPage->setToolset(toolset);
}
void FirstConfigure::setCompilerOption(CompilerOption option)
{
this->mStartCompilerSetupPage->setCompilerOption(option);
}
QString FirstConfigure::getGenerator() const
{
return this->mStartCompilerSetupPage->getGenerator();
@@ -503,7 +553,7 @@ void FirstConfigure::loadFromSettings()
// restore generator
settings.beginGroup("Settings/StartPath");
QString lastGen = settings.value("LastGenerator").toString();
this->mStartCompilerSetupPage->setCurrentGenerator(lastGen);
this->setCurrentGenerator(lastGen);
settings.endGroup();
// restore compiler setup
@@ -550,7 +600,7 @@ void FirstConfigure::loadFromSettings()
// this prevents them from being taken from environment, while the
// generator is taken from application settings
if (!mDefaultGenerator.isEmpty()) {
this->mStartCompilerSetupPage->setCurrentGenerator(mDefaultGenerator);
this->setCurrentGenerator(mDefaultGenerator);
}
}

View File

@@ -22,6 +22,14 @@ enum FirstConfigurePages
Done
};
enum class CompilerOption
{
DefaultNative,
SpecifyNative,
ToolchainFile,
Options,
};
//! the first page that gives basic options for what compilers setup to choose
//! from
class StartCompilerSetup : public QWizardPage
@@ -33,6 +41,9 @@ public:
~StartCompilerSetup();
void setGenerators(std::vector<cmake::GeneratorInfo> const& gens);
void setCurrentGenerator(const QString& gen);
void setToolset(const QString& toolset);
void setPlatform(const QString& platform);
void setCompilerOption(CompilerOption option);
QString getGenerator() const;
QString getToolset() const;
QString getPlatform() const;
@@ -167,6 +178,10 @@ public:
~FirstConfigure();
void setGenerators(std::vector<cmake::GeneratorInfo> const& gens);
void setCurrentGenerator(const QString& gen);
void setToolset(const QString& toolset);
void setPlatform(const QString& platform);
void setCompilerOption(CompilerOption option);
QString getGenerator() const;
QString getPlatform() const;
QString getToolset() const;

View File

@@ -2,10 +2,14 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "QCMake.h"
#include <algorithm>
#include <cm/memory>
#include <QCoreApplication>
#include <QDir>
#include <QString>
#include <QVector>
#include "cmExternalMakefileProjectGenerator.h"
#include "cmGlobalGenerator.h"
@@ -19,12 +23,15 @@
QCMake::QCMake(QObject* p)
: QObject(p)
, StartEnvironment(QProcessEnvironment::systemEnvironment())
, Environment(QProcessEnvironment::systemEnvironment())
{
this->WarnUninitializedMode = false;
qRegisterMetaType<QCMakeProperty>();
qRegisterMetaType<QCMakePropertyList>();
qRegisterMetaType<QProcessEnvironment>();
qRegisterMetaType<QVector<QCMakePreset>>();
qRegisterMetaType<cmCMakePresetsFile::ReadFileResult>();
cmSystemTools::DisableRunCommandOutput();
cmSystemTools::SetRunCommandHideConsole(true);
@@ -57,6 +64,17 @@ QCMake::QCMake(QObject* p)
for (cmake::GeneratorInfo const& gen : generators) {
this->AvailableGenerators.push_back(gen);
}
connect(&this->LoadPresetsTimer, &QTimer::timeout, this, [this]() {
this->loadPresets();
if (!this->PresetName.isEmpty() &&
this->CMakePresetsFile.Presets.find(
std::string(this->PresetName.toLocal8Bit())) ==
this->CMakePresetsFile.Presets.end()) {
this->setPreset(QString{});
}
});
this->LoadPresetsTimer.start(1000);
}
QCMake::~QCMake() = default;
@@ -73,6 +91,8 @@ void QCMake::setSourceDirectory(const QString& _dir)
if (this->SourceDirectory != dir) {
this->SourceDirectory = QDir::fromNativeSeparators(dir);
emit this->sourceDirChanged(this->SourceDirectory);
this->loadPresets();
this->setPreset(QString{});
}
}
@@ -129,6 +149,56 @@ void QCMake::setBinaryDirectory(const QString& _dir)
}
}
void QCMake::setPreset(const QString& name, bool setBinary)
{
if (this->PresetName != name) {
this->PresetName = name;
emit this->presetChanged(this->PresetName);
if (!name.isNull()) {
std::string presetName(name.toLocal8Bit());
auto const& preset = this->CMakePresetsFile.Presets[presetName];
auto expandedPreset = this->CMakePresetsFile.ExpandMacros(preset);
if (expandedPreset) {
if (setBinary) {
QString binaryDir =
QString::fromLocal8Bit(expandedPreset->BinaryDir.data());
this->setBinaryDirectory(binaryDir);
}
if (expandedPreset->WarnDev) {
this->CMakeInstance->SetSuppressDevWarnings(
!*expandedPreset->WarnDev);
}
if (expandedPreset->ErrorDev) {
this->CMakeInstance->SetDevWarningsAsErrors(
*expandedPreset->ErrorDev);
}
if (expandedPreset->WarnDeprecated) {
this->CMakeInstance->SetSuppressDeprecatedWarnings(
!*expandedPreset->WarnDeprecated);
}
if (expandedPreset->ErrorDeprecated) {
this->CMakeInstance->SetDeprecatedWarningsAsErrors(
*expandedPreset->ErrorDeprecated);
}
if (expandedPreset->WarnUninitialized) {
this->WarnUninitializedMode = *expandedPreset->WarnUninitialized;
emit this->warnUninitializedModeChanged(
*expandedPreset->WarnUninitialized);
}
this->Environment = this->StartEnvironment;
for (auto const& v : expandedPreset->Environment) {
if (v.second) {
this->Environment.insert(QString::fromLocal8Bit(v.first.data()),
QString::fromLocal8Bit(v.second->data()));
}
}
}
}
emit this->propertiesChanged(this->properties());
}
}
void QCMake::setGenerator(const QString& gen)
{
if (this->Generator != gen) {
@@ -348,6 +418,56 @@ QCMakePropertyList QCMake::properties() const
ret.append(prop);
}
if (!this->PresetName.isNull()) {
std::string presetName(this->PresetName.toLocal8Bit());
auto p = this->CMakePresetsFile.ExpandMacros(
this->CMakePresetsFile.Presets.at(presetName));
if (p) {
for (auto const& v : p->CacheVariables) {
if (!v.second) {
continue;
}
QCMakeProperty prop;
prop.Key = QString::fromLocal8Bit(v.first.data());
prop.Value = QString::fromLocal8Bit(v.second->Value.data());
prop.Type = QCMakeProperty::STRING;
if (!v.second->Type.empty()) {
auto type = cmState::StringToCacheEntryType(v.second->Type);
switch (type) {
case cmStateEnums::BOOL:
prop.Type = QCMakeProperty::BOOL;
prop.Value = cmIsOn(v.second->Value);
break;
case cmStateEnums::PATH:
prop.Type = QCMakeProperty::PATH;
break;
case cmStateEnums::FILEPATH:
prop.Type = QCMakeProperty::FILEPATH;
break;
default:
prop.Type = QCMakeProperty::STRING;
break;
}
}
// QCMakeCacheModel prefers variables earlier in the list rather than
// later, so overwrite them if they already exist rather than simply
// appending
bool found = false;
for (auto& orig : ret) {
if (orig.Key == prop.Key) {
orig = prop;
found = true;
break;
}
}
if (!found) {
ret.append(prop);
}
}
}
}
return ret;
}
@@ -405,6 +525,46 @@ void QCMake::setUpEnvironment() const
}
}
void QCMake::loadPresets()
{
auto result = this->CMakePresetsFile.ReadProjectPresets(
this->SourceDirectory.toLocal8Bit().data(), true);
if (result != this->LastLoadPresetsResult &&
result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
emit this->presetLoadError(this->SourceDirectory, result);
}
this->LastLoadPresetsResult = result;
QVector<QCMakePreset> presets;
for (auto const& name : this->CMakePresetsFile.PresetOrder) {
auto const& p = this->CMakePresetsFile.Presets[name];
if (p.Hidden) {
continue;
}
QCMakePreset preset;
preset.name = std::move(QString::fromLocal8Bit(p.Name.data()));
preset.displayName =
std::move(QString::fromLocal8Bit(p.DisplayName.data()));
preset.description =
std::move(QString::fromLocal8Bit(p.Description.data()));
preset.generator = std::move(QString::fromLocal8Bit(p.Generator.data()));
preset.architecture =
std::move(QString::fromLocal8Bit(p.Architecture.data()));
preset.toolset = std::move(QString::fromLocal8Bit(p.Toolset.data()));
preset.setGenConfig = !p.GeneratorConfig ||
p.GeneratorConfig == cmCMakePresetsFile::CMakeGeneratorConfig::Default;
preset.enabled = std::find_if(this->AvailableGenerators.begin(),
this->AvailableGenerators.end(),
[&p](const cmake::GeneratorInfo& g) {
return g.name == p.Generator;
}) != this->AvailableGenerators.end() &&
this->CMakePresetsFile.ExpandMacros(p);
presets.push_back(preset);
}
emit this->presetsChanged(presets);
}
QString QCMake::binaryDirectory() const
{
return this->BinaryDirectory;

View File

@@ -4,6 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include "cmCMakePresetsFile.h"
#include "cmake.h"
#ifdef _MSC_VER
@@ -14,6 +15,7 @@
#include <memory>
#include <vector>
#include "QCMakePreset.h"
#include <QAtomicInt>
#include <QList>
#include <QMetaType>
@@ -21,6 +23,7 @@
#include <QProcessEnvironment>
#include <QString>
#include <QStringList>
#include <QTimer>
#include <QVariant>
/// struct to represent cmake properties in Qt
@@ -57,6 +60,7 @@ using QCMakePropertyList = QList<QCMakeProperty>;
Q_DECLARE_METATYPE(QCMakeProperty)
Q_DECLARE_METATYPE(QCMakePropertyList)
Q_DECLARE_METATYPE(QProcessEnvironment)
Q_DECLARE_METATYPE(cmCMakePresetsFile::ReadFileResult)
/// Qt API for CMake library.
/// Wrapper like class allows for easier integration with
@@ -74,6 +78,8 @@ public slots:
void setSourceDirectory(const QString& dir);
/// set the binary directory to build in
void setBinaryDirectory(const QString& dir);
/// set the preset name to use
void setPreset(const QString& name, bool setBinary = true);
/// set the desired generator to use
void setGenerator(const QString& generator);
/// set the desired generator to use
@@ -147,6 +153,15 @@ signals:
void sourceDirChanged(const QString& dir);
/// signal when the binary directory changes
void binaryDirChanged(const QString& dir);
/// signal when the preset list changes
void presetsChanged(const QVector<QCMakePreset>& presets);
/// signal when the selected preset changes
void presetChanged(const QString& name);
/// signal when there's an error reading the presets files
void presetLoadError(const QString& dir,
cmCMakePresetsFile::ReadFileResult error);
/// signal when uninitialized warning changes
void warnUninitializedModeChanged(bool value);
/// signal for progress events
void progressChanged(const QString& msg, float percent);
/// signal when configure is done
@@ -178,6 +193,8 @@ protected:
void stderrCallback(std::string const& msg);
void setUpEnvironment() const;
void loadPresets();
bool WarnUninitializedMode;
QString SourceDirectory;
QString BinaryDirectory;
@@ -185,7 +202,13 @@ protected:
QString Platform;
QString Toolset;
std::vector<cmake::GeneratorInfo> AvailableGenerators;
cmCMakePresetsFile CMakePresetsFile;
cmCMakePresetsFile::ReadFileResult LastLoadPresetsResult =
cmCMakePresetsFile::ReadFileResult::READ_OK;
QString PresetName;
QString CMakeExecutable;
QAtomicInt InterruptFlag;
QProcessEnvironment StartEnvironment;
QProcessEnvironment Environment;
QTimer LoadPresetsTimer;
};

View File

@@ -0,0 +1,50 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "QCMakePreset.h"
bool operator==(const QCMakePreset& lhs, const QCMakePreset& rhs)
{
return lhs.name == rhs.name && lhs.displayName == rhs.displayName &&
lhs.description == rhs.description && lhs.generator == rhs.generator &&
lhs.architecture == rhs.architecture && lhs.toolset == rhs.toolset &&
lhs.setGenConfig == rhs.setGenConfig && lhs.enabled == rhs.enabled;
}
bool operator!=(const QCMakePreset& lhs, const QCMakePreset& rhs)
{
return !(lhs == rhs);
}
bool operator<(const QCMakePreset& lhs, const QCMakePreset& rhs)
{
return lhs.name < rhs.name ||
(lhs.name == rhs.name &&
(lhs.displayName < rhs.displayName ||
(lhs.displayName == rhs.displayName &&
(lhs.description < rhs.description ||
(lhs.description == rhs.description &&
(lhs.generator < rhs.generator ||
(lhs.generator == rhs.generator &&
(lhs.architecture < rhs.architecture ||
(lhs.architecture == rhs.architecture &&
(lhs.toolset < rhs.toolset ||
(lhs.toolset == rhs.toolset &&
(lhs.setGenConfig < rhs.setGenConfig ||
(lhs.setGenConfig == rhs.setGenConfig &&
(lhs.enabled < rhs.enabled))))))))))))));
}
bool operator<=(const QCMakePreset& lhs, const QCMakePreset& rhs)
{
return rhs >= lhs;
}
bool operator>(const QCMakePreset& lhs, const QCMakePreset& rhs)
{
return rhs < lhs;
}
bool operator>=(const QCMakePreset& lhs, const QCMakePreset& rhs)
{
return !(lhs < rhs);
}

View File

@@ -0,0 +1,30 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include <QString>
#include <QVariant>
#include "cmCMakePresetsFile.h"
class QCMakePreset
{
public:
QString name;
QString displayName;
QString description;
QString generator;
QString architecture;
QString toolset;
bool setGenConfig;
bool enabled;
};
bool operator==(const QCMakePreset& lhs, const QCMakePreset& rhs);
bool operator!=(const QCMakePreset& lhs, const QCMakePreset& rhs);
bool operator<(const QCMakePreset& lhs, const QCMakePreset& rhs);
bool operator<=(const QCMakePreset& lhs, const QCMakePreset& rhs);
bool operator>(const QCMakePreset& lhs, const QCMakePreset& rhs);
bool operator>=(const QCMakePreset& lhs, const QCMakePreset& rhs);
Q_DECLARE_METATYPE(QCMakePreset)

View File

@@ -0,0 +1,64 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "QCMakePresetComboBox.h"
#include "QCMakePresetItemModel.h"
QCMakePresetComboBox::QCMakePresetComboBox(QWidget* parent)
: QComboBox(parent)
{
this->m_model = new QCMakePresetItemModel(this);
this->setModel(this->m_model);
QObject::connect(this->m_model, &QCMakePresetItemModel::modelAboutToBeReset,
this, [this]() { this->m_resetting = true; });
QObject::connect(this->m_model, &QCMakePresetItemModel::modelReset, this,
[this]() {
this->setPresetName(this->m_lastPreset);
this->m_resetting = false;
this->emitPresetChanged();
});
QObject::connect(
this,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, [this](int /*row*/) {
if (!this->m_resetting) {
this->emitPresetChanged();
}
});
}
const QVector<QCMakePreset>& QCMakePresetComboBox::presets() const
{
return this->m_model->presets();
}
QString QCMakePresetComboBox::presetName() const
{
auto preset = this->currentData();
if (preset.canConvert<QCMakePreset>()) {
return preset.value<QCMakePreset>().name;
}
return QString{};
}
void QCMakePresetComboBox::setPresets(const QVector<QCMakePreset>& presets)
{
this->m_model->setPresets(presets);
}
void QCMakePresetComboBox::setPresetName(const QString& name)
{
this->setCurrentIndex(this->m_model->presetNameToRow(name));
if (this->signalsBlocked()) {
this->m_lastPreset = this->presetName();
}
}
void QCMakePresetComboBox::emitPresetChanged()
{
if (this->presetName() != this->m_lastPreset) {
emit this->presetChanged(this->presetName());
this->m_lastPreset = this->presetName();
}
}

View File

@@ -0,0 +1,35 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "QCMakePreset.h"
#include <QComboBox>
#include <QObject>
#include <QString>
#include <QVector>
class QCMakePresetItemModel;
class QCMakePresetComboBox : public QComboBox
{
Q_OBJECT
public:
QCMakePresetComboBox(QWidget* parent = nullptr);
const QVector<QCMakePreset>& presets() const;
QString presetName() const;
public slots:
void setPresets(const QVector<QCMakePreset>& presets);
void setPresetName(const QString& name);
signals:
void presetChanged(const QString& name);
private:
QCMakePresetItemModel* m_model;
bool m_resetting = false;
QString m_lastPreset;
void emitPresetChanged();
};

View File

@@ -0,0 +1,143 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "QCMakePresetItemModel.h"
#include <QFont>
QCMakePresetItemModel::QCMakePresetItemModel(QObject* parent)
: QAbstractItemModel(parent)
{
}
QVariant QCMakePresetItemModel::data(const QModelIndex& index, int role) const
{
switch (role) {
case Qt::AccessibleDescriptionRole:
// Separators have to return "separator" for the
// AccessibleDescriptionRole. This was determined by looking at
// QComboBoxDelegate::isSeparator() (located in qcombobox_p.h.)
if (index.internalId() == SEPARATOR_INDEX) {
return QString::fromLocal8Bit("separator");
}
return QString{};
case Qt::DisplayRole: {
if (index.internalId() == CUSTOM_INDEX) {
return QString::fromLocal8Bit("<custom>");
}
if (index.internalId() == SEPARATOR_INDEX) {
return QVariant{};
}
auto const& preset = this->m_presets[index.internalId()];
return preset.displayName.isEmpty() ? preset.name : preset.displayName;
}
case Qt::ToolTipRole:
if (index.internalId() == CUSTOM_INDEX) {
return QString::fromLocal8Bit("Specify all settings manually");
}
if (index.internalId() == SEPARATOR_INDEX) {
return QVariant{};
}
return this->m_presets[index.internalId()].description;
case Qt::UserRole:
if (index.internalId() == CUSTOM_INDEX) {
return QVariant{};
}
if (index.internalId() == SEPARATOR_INDEX) {
return QVariant{};
}
return QVariant::fromValue(this->m_presets[index.internalId()]);
case Qt::FontRole:
if (index.internalId() == CUSTOM_INDEX) {
QFont font;
font.setItalic(true);
return font;
}
return QFont{};
default:
return QVariant{};
}
}
Qt::ItemFlags QCMakePresetItemModel::flags(const QModelIndex& index) const
{
Qt::ItemFlags flags =
Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
if (index.internalId() != SEPARATOR_INDEX &&
(index.internalId() == CUSTOM_INDEX ||
this->m_presets[index.internalId()].enabled)) {
flags |= Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
return flags;
}
int QCMakePresetItemModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid()) {
return 0;
}
if (this->m_presets.empty()) {
return 1;
}
return this->m_presets.size() + 2;
}
int QCMakePresetItemModel::columnCount(const QModelIndex& parent) const
{
if (parent.isValid()) {
return 0;
}
return 1;
}
QModelIndex QCMakePresetItemModel::index(int row, int column,
const QModelIndex& parent) const
{
if (parent.isValid() || column != 0 || row < 0 ||
row >= this->rowCount(QModelIndex{})) {
return QModelIndex{};
}
if (this->m_presets.empty() || row == this->m_presets.size() + 1) {
return this->createIndex(row, column, CUSTOM_INDEX);
}
if (row == this->m_presets.size()) {
return this->createIndex(row, column, SEPARATOR_INDEX);
}
return this->createIndex(row, column, static_cast<quintptr>(row));
}
QModelIndex QCMakePresetItemModel::parent(const QModelIndex& /*index*/) const
{
return QModelIndex{};
}
QVector<QCMakePreset> const& QCMakePresetItemModel::presets() const
{
return this->m_presets;
}
void QCMakePresetItemModel::setPresets(QVector<QCMakePreset> const& presets)
{
this->beginResetModel();
this->m_presets = presets;
this->endResetModel();
}
int QCMakePresetItemModel::presetNameToRow(const QString& name) const
{
if (this->m_presets.empty()) {
return 0;
}
int index = 0;
for (auto const& preset : this->m_presets) {
if (preset.name == name) {
return index;
}
index++;
}
return this->m_presets.size() + 1;
}

View File

@@ -0,0 +1,45 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include <cm/optional>
#include "QCMakePreset.h"
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QString>
#include <QVariant>
#include <QVector>
#include <QtGlobal>
class QObject;
class QCMakePresetItemModel : public QAbstractItemModel
{
Q_OBJECT
public:
QCMakePresetItemModel(QObject* parent = nullptr);
QVariant data(const QModelIndex& index, int role) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
int rowCount(const QModelIndex& parent = QModelIndex{}) const override;
int columnCount(const QModelIndex& parent = QModelIndex{}) const override;
QModelIndex index(int row, int column,
const QModelIndex& parent = QModelIndex{}) const override;
QModelIndex parent(const QModelIndex& index) const override;
QVector<QCMakePreset> const& presets() const;
int presetNameToRow(const QString& name) const;
public slots:
void setPresets(QVector<QCMakePreset> const& presets);
private:
QVector<QCMakePreset> m_presets;
static constexpr quintptr SEPARATOR_INDEX = static_cast<quintptr>(-2);
static constexpr quintptr CUSTOM_INDEX = static_cast<quintptr>(-1);
};

View File

@@ -27,6 +27,10 @@ function(run_cmake_gui_test name)
if(EXISTS "${_cmakelists_in}")
configure_file("${_cmakelists_in}" "${_workdir}/src/CMakeLists.txt" @ONLY)
endif()
set(_cmakepresets_in "${_srcdir}/CMakePresets.json.in")
if(EXISTS "${_cmakepresets_in}")
configure_file("${_cmakepresets_in}" "${_workdir}/src/CMakePresets.json" @ONLY)
endif()
if(_rcgt_DO_CONFIGURE)
if(NOT _rcgt_GENERATOR)
set(_rcgt_GENERATOR "${CMakeGUITest_GENERATOR}")
@@ -118,3 +122,37 @@ set(ENV{KEPT_VARIABLE} "Kept variable")
set(ENV{CHANGED_VARIABLE} "This variable will be changed")
set(ENV{REMOVED_VARIABLE} "Removed variable")
run_cmake_gui_test(environment)
run_cmake_gui_test(presetArg:preset
ARGS
-S "${CMakeGUITest_BINARY_DIR}/presetArg-preset/src"
"--preset=ninja"
)
run_cmake_gui_test(presetArg:presetBinary
ARGS
-S "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinary/src"
-B "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinary/build"
"--preset=ninja"
)
run_cmake_gui_test(presetArg:presetBinaryChange
ARGS
-S "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinaryChange/src"
-B "${CMakeGUITest_BINARY_DIR}/presetArg-presetBinaryChange/build"
"--preset=ninja"
)
run_cmake_gui_test(presetArg:noPresetBinaryChange
ARGS
-S "${CMakeGUITest_BINARY_DIR}/presetArg-noPresetBinaryChange/src"
-B "${CMakeGUITest_BINARY_DIR}/presetArg-noPresetBinaryChange/build"
)
run_cmake_gui_test(presetArg:presetConfigExists
ARGS
-S "${CMakeGUITest_BINARY_DIR}/presetArg-presetConfigExists/src"
"--preset=ninja"
)
run_cmake_gui_test(presetArg:noExist
ARGS
-S "${CMakeGUITest_BINARY_DIR}/presetArg-noExist/src"
"--preset=noExist"
)
run_cmake_gui_test(changingPresets)

View File

@@ -5,6 +5,10 @@
#include "QCMake.h"
#include <QApplication>
#include <QEventLoop>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QSettings>
#include <QString>
@@ -18,6 +22,9 @@
#include "CatchShow.h"
#include "FirstConfigure.h"
using WindowSetupHelper = std::function<void(CMakeSetupDialog*)>;
Q_DECLARE_METATYPE(WindowSetupHelper)
namespace {
void loopSleep(int msecs = 500)
{
@@ -172,6 +179,264 @@ void CMakeGUITest::environment()
QCOMPARE(penv.value("REMOVED_VARIABLE"), "Removed variable");
}
void CMakeGUITest::presetArg()
{
QFETCH(WindowSetupHelper, setupFunction);
QFETCH(QString, presetName);
QFETCH(QString, sourceDir);
QFETCH(QString, binaryDir);
QFETCH(QCMakePropertyList, properties);
if (setupFunction) {
setupFunction(this->m_window);
}
// Wait a bit for everything to update
loopSleep();
QCOMPARE(this->m_window->Preset->presetName(), presetName);
QCOMPARE(this->m_window->SourceDirectory->text(), sourceDir);
QCOMPARE(this->m_window->BinaryDirectory->currentText(), binaryDir);
auto actualProperties =
this->m_window->CacheValues->cacheModel()->properties();
QCOMPARE(actualProperties.size(), properties.size());
for (int i = 0; i < actualProperties.size(); ++i) {
// operator==() only compares Key, we need to compare Value and Type too
QCOMPARE(actualProperties[i].Key, properties[i].Key);
QCOMPARE(actualProperties[i].Value, properties[i].Value);
QCOMPARE(actualProperties[i].Type, properties[i].Type);
}
}
namespace {
QCMakePropertyList makePresetProperties(const QString& name)
{
return QCMakePropertyList{
QCMakeProperty{
/*Key=*/"FALSE_VARIABLE",
/*Value=*/false,
/*Strings=*/{},
/*Help=*/"",
/*Type=*/QCMakeProperty::BOOL,
/*Advanced=*/false,
},
QCMakeProperty{
/*Key=*/"FILEPATH_VARIABLE",
/*Value=*/
QString::fromLocal8Bit(CMakeGUITest_BINARY_DIR "/%1/src/CMakeLists.txt")
.arg(name),
/*Strings=*/{},
/*Help=*/"",
/*Type=*/QCMakeProperty::FILEPATH,
/*Advanced=*/false,
},
QCMakeProperty{
/*Key=*/"ON_VARIABLE",
/*Value=*/true,
/*Strings=*/{},
/*Help=*/"",
/*Type=*/QCMakeProperty::BOOL,
/*Advanced=*/false,
},
QCMakeProperty{
/*Key=*/"PATH_VARIABLE",
/*Value=*/
QString::fromLocal8Bit(CMakeGUITest_BINARY_DIR "/%1/src").arg(name),
/*Strings=*/{},
/*Help=*/"",
/*Type=*/QCMakeProperty::PATH,
/*Advanced=*/false,
},
QCMakeProperty{
/*Key=*/"STRING_VARIABLE",
/*Value=*/"String value",
/*Strings=*/{},
/*Help=*/"",
/*Type=*/QCMakeProperty::STRING,
/*Advanced=*/false,
},
QCMakeProperty{
/*Key=*/"UNINITIALIZED_VARIABLE",
/*Value=*/"Uninitialized value",
/*Strings=*/{},
/*Help=*/"",
/*Type=*/QCMakeProperty::STRING,
/*Advanced=*/false,
},
};
}
}
void CMakeGUITest::presetArg_data()
{
QTest::addColumn<WindowSetupHelper>("setupFunction");
QTest::addColumn<QString>("presetName");
QTest::addColumn<QString>("sourceDir");
QTest::addColumn<QString>("binaryDir");
QTest::addColumn<QCMakePropertyList>("properties");
QTest::newRow("preset") << WindowSetupHelper{} << "ninja"
<< CMakeGUITest_BINARY_DIR "/presetArg-preset/src"
<< CMakeGUITest_BINARY_DIR
"/presetArg-preset/src/build"
<< makePresetProperties("presetArg-preset");
QTest::newRow("presetBinary")
<< WindowSetupHelper{} << "ninja"
<< CMakeGUITest_BINARY_DIR "/presetArg-presetBinary/src"
<< CMakeGUITest_BINARY_DIR "/presetArg-presetBinary/build"
<< makePresetProperties("presetArg-presetBinary");
QTest::newRow("presetBinaryChange")
<< WindowSetupHelper{ [](CMakeSetupDialog* window) {
loopSleep();
window->Preset->setPresetName("ninja2");
} }
<< "ninja2" << CMakeGUITest_BINARY_DIR "/presetArg-presetBinaryChange/src"
<< CMakeGUITest_BINARY_DIR "/presetArg-presetBinaryChange/src/build"
<< makePresetProperties("presetArg-presetBinaryChange");
QTest::newRow("noPresetBinaryChange")
<< WindowSetupHelper{ [](CMakeSetupDialog* window) {
loopSleep();
window->Preset->setPresetName("ninja");
} }
<< "ninja" << CMakeGUITest_BINARY_DIR "/presetArg-noPresetBinaryChange/src"
<< CMakeGUITest_BINARY_DIR "/presetArg-noPresetBinaryChange/src/build"
<< makePresetProperties("presetArg-noPresetBinaryChange");
QTest::newRow("presetConfigExists")
<< WindowSetupHelper{} << "ninja"
<< CMakeGUITest_BINARY_DIR "/presetArg-presetConfigExists/src"
<< CMakeGUITest_BINARY_DIR "/presetArg-presetConfigExists/src/build"
<< makePresetProperties("presetArg-presetConfigExists");
QTest::newRow("noExist") << WindowSetupHelper{} << QString{}
<< CMakeGUITest_BINARY_DIR "/presetArg-noExist/src"
<< "" << QCMakePropertyList{};
}
namespace {
void writePresets(const QString& buildDir, const QStringList& names)
{
QJsonArray presets{
QJsonObject{
{ "name", "base" },
{ "generator", "Ninja" },
{ "binaryDir",
QString::fromLocal8Bit("${sourceDir}/%1/${presetName}")
.arg(buildDir) },
{ "hidden", true },
},
};
for (auto const& name : names) {
presets.append(QJsonObject{
{ "name", name },
{ "inherits", QJsonArray{ "base" } },
});
}
QJsonDocument doc{ QJsonObject{
{ "version", 1 },
{ "configurePresets", presets },
} };
QFile presetsFile(CMakeGUITest_BINARY_DIR
"/changingPresets/src/CMakePresets.json");
bool open = presetsFile.open(QIODevice::WriteOnly);
Q_ASSERT(open);
presetsFile.write(doc.toJson());
}
}
void CMakeGUITest::changingPresets()
{
QDir::root().mkpath(CMakeGUITest_BINARY_DIR "/changingPresets/src");
this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR
"/changingPresets/src");
loopSleep();
QCOMPARE(this->m_window->Preset->presetName(), QString{});
QCOMPARE(this->m_window->Preset->presets().size(), 0);
QCOMPARE(this->m_window->BinaryDirectory->currentText(), "");
QCOMPARE(this->m_window->Preset->isHidden(), true);
QCOMPARE(this->m_window->PresetLabel->isHidden(), true);
writePresets("build1", { "preset" });
loopSleep(1500);
QCOMPARE(this->m_window->Preset->presetName(), QString{});
QCOMPARE(this->m_window->Preset->presets().size(), 1);
QCOMPARE(this->m_window->BinaryDirectory->currentText(), "");
QCOMPARE(this->m_window->Preset->isHidden(), false);
QCOMPARE(this->m_window->PresetLabel->isHidden(), false);
this->m_window->Preset->setPresetName("preset");
loopSleep();
QCOMPARE(this->m_window->Preset->presetName(), "preset");
QCOMPARE(this->m_window->Preset->presets().size(), 1);
QCOMPARE(this->m_window->BinaryDirectory->currentText(),
CMakeGUITest_BINARY_DIR "/changingPresets/src/build1/preset");
QCOMPARE(this->m_window->Preset->isHidden(), false);
QCOMPARE(this->m_window->PresetLabel->isHidden(), false);
writePresets("build2", { "preset2", "preset" });
loopSleep(1500);
QCOMPARE(this->m_window->Preset->presetName(), "preset");
QCOMPARE(this->m_window->Preset->presets().size(), 2);
QCOMPARE(this->m_window->BinaryDirectory->currentText(),
CMakeGUITest_BINARY_DIR "/changingPresets/src/build1/preset");
QCOMPARE(this->m_window->Preset->isHidden(), false);
QCOMPARE(this->m_window->PresetLabel->isHidden(), false);
writePresets("build3", { "preset2" });
loopSleep(1500);
QCOMPARE(this->m_window->Preset->presetName(), QString{});
QCOMPARE(this->m_window->Preset->presets().size(), 1);
QCOMPARE(this->m_window->BinaryDirectory->currentText(),
CMakeGUITest_BINARY_DIR "/changingPresets/src/build1/preset");
QCOMPARE(this->m_window->Preset->isHidden(), false);
QCOMPARE(this->m_window->PresetLabel->isHidden(), false);
this->m_window->Preset->setPresetName("preset2");
loopSleep();
QCOMPARE(this->m_window->Preset->presetName(), "preset2");
QCOMPARE(this->m_window->Preset->presets().size(), 1);
QCOMPARE(this->m_window->BinaryDirectory->currentText(),
CMakeGUITest_BINARY_DIR "/changingPresets/src/build3/preset2");
QCOMPARE(this->m_window->Preset->isHidden(), false);
QCOMPARE(this->m_window->PresetLabel->isHidden(), false);
QDir::root().mkpath(CMakeGUITest_BINARY_DIR "/changingPresets/src2");
QFile::copy(CMakeGUITest_BINARY_DIR "/changingPresets/src/CMakePresets.json",
CMakeGUITest_BINARY_DIR
"/changingPresets/src2/CMakePresets.json");
this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR
"/changingPresets/src2");
loopSleep();
QCOMPARE(this->m_window->Preset->presetName(), QString{});
QCOMPARE(this->m_window->Preset->presets().size(), 1);
QCOMPARE(this->m_window->BinaryDirectory->currentText(),
CMakeGUITest_BINARY_DIR "/changingPresets/src/build3/preset2");
QCOMPARE(this->m_window->Preset->isHidden(), false);
QCOMPARE(this->m_window->PresetLabel->isHidden(), false);
this->m_window->Preset->setPresetName("preset2");
loopSleep();
QCOMPARE(this->m_window->Preset->presetName(), "preset2");
QCOMPARE(this->m_window->Preset->presets().size(), 1);
QCOMPARE(this->m_window->BinaryDirectory->currentText(),
CMakeGUITest_BINARY_DIR "/changingPresets/src2/build3/preset2");
QCOMPARE(this->m_window->Preset->isHidden(), false);
QCOMPARE(this->m_window->PresetLabel->isHidden(), false);
QFile(CMakeGUITest_BINARY_DIR "/changingPresets/src2/CMakePresets.json")
.remove();
loopSleep(1500);
QCOMPARE(this->m_window->Preset->presetName(), QString{});
QCOMPARE(this->m_window->Preset->presets().size(), 0);
QCOMPARE(this->m_window->BinaryDirectory->currentText(),
CMakeGUITest_BINARY_DIR "/changingPresets/src2/build3/preset2");
QCOMPARE(this->m_window->Preset->isHidden(), true);
QCOMPARE(this->m_window->PresetLabel->isHidden(), true);
}
void SetupDefaultQSettings()
{
QSettings::setDefaultFormat(QSettings::IniFormat);

View File

@@ -23,4 +23,7 @@ private slots:
void simpleConfigure();
void simpleConfigure_data();
void environment();
void presetArg();
void presetArg_data();
void changingPresets();
};

View File

@@ -72,3 +72,24 @@ add_cmake_gui_lib_test(QCMakeCacheModel
MOC_SOURCES
QCMakeCacheModelTest.h
)
add_cmake_gui_lib_test(QCMakePreset
SOURCES
QCMakePresetTest.cxx
QCMakePresetTest.h
MOC_SOURCES
QCMakePresetTest.h
)
add_cmake_gui_lib_test(QCMakePresetItemModel
SOURCES
QCMakePresetItemModelTest.cxx
QCMakePresetItemModelTest.h
MOC_SOURCES
QCMakePresetItemModelTest.h
)
add_cmake_gui_lib_test(QCMakePresetComboBox
SOURCES
QCMakePresetComboBoxTest.cxx
QCMakePresetComboBoxTest.h
MOC_SOURCES
QCMakePresetComboBoxTest.h
)

View File

@@ -0,0 +1,80 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "QCMakePresetComboBoxTest.h"
#include <QtTest>
void QCMakePresetComboBoxTest::changePresets()
{
QCMakePresetComboBox box;
QSignalSpy presetChanged(&box, &QCMakePresetComboBox::presetChanged);
QCOMPARE(presetChanged.size(), 0);
box.setPresets({});
QCOMPARE(presetChanged.size(), 0);
box.setPresetName(QString{});
QCOMPARE(presetChanged.size(), 0);
box.setPresets({
{
/*name=*/"preset",
/*description=*/"",
/*description=*/"",
/*generator=*/"Ninja",
/*architecture=*/"",
/*toolset=*/"",
/*setGenConfig=*/true,
/*enabled=*/true,
},
});
QCOMPARE(presetChanged.size(), 0);
box.setPresetName(QString{});
QCOMPARE(presetChanged.size(), 0);
box.setPresetName("noexist");
QCOMPARE(presetChanged.size(), 0);
box.setPresetName("preset");
QCOMPARE(presetChanged.size(), 1);
QCOMPARE(presetChanged.last(), QList<QVariant>{ "preset" });
box.setPresets({
{
/*name=*/"preset",
/*description=*/"",
/*description=*/"",
/*generator=*/"Ninja Multi-Config",
/*architecture=*/"",
/*toolset=*/"",
/*setGenConfig=*/true,
/*enabled=*/true,
},
});
QCOMPARE(presetChanged.size(), 1);
box.setPresetName("noexist");
QCOMPARE(presetChanged.size(), 2);
QCOMPARE(presetChanged.last(), QList<QVariant>{ QString{} });
box.setPresetName("preset");
QCOMPARE(presetChanged.size(), 3);
QCOMPARE(presetChanged.last(), QList<QVariant>{ "preset" });
box.blockSignals(true);
box.setPresetName(QString{});
box.blockSignals(false);
QCOMPARE(presetChanged.size(), 3);
box.setPresetName("preset");
QCOMPARE(presetChanged.size(), 4);
QCOMPARE(presetChanged.last(), QList<QVariant>{ "preset" });
box.setPresets({});
QCOMPARE(presetChanged.size(), 5);
QCOMPARE(presetChanged.last(), QList<QVariant>{ QString{} });
}
QTEST_MAIN(QCMakePresetComboBoxTest)

View File

@@ -0,0 +1,13 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "QCMakePresetComboBox.h"
#include <QObject>
class QCMakePresetComboBoxTest : public QObject
{
Q_OBJECT
private slots:
void changePresets();
};

View File

@@ -0,0 +1,162 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "QCMakePresetItemModelTest.h"
#include <utility>
#include "QCMakePreset.h"
#include "QCMakePresetItemModel.h"
#include <QHash>
#include <QMetaType>
#include <QSignalSpy>
#include <QVariant>
#include <QVector>
#include <QtTest>
using QItemDataHash = QHash<Qt::ItemDataRole, QVariant>;
void QCMakePresetItemModelTest::initTestCase()
{
QMetaType::registerComparators<QCMakePreset>();
}
void QCMakePresetItemModelTest::initTestCase_data()
{
QTest::addColumn<QVector<QCMakePreset>>("presets");
QTest::addColumn<QVector<QItemDataHash>>("data");
QVector<QCMakePreset> presets{
QCMakePreset{
/*name=*/"no-description",
/*description=*/"",
/*description=*/"",
/*generator=*/"",
/*architecture=*/"",
/*toolset=*/"",
/*setGenConfig=*/true,
/*enabled=*/true,
},
QCMakePreset{
/*name=*/"short-description",
/*description=*/"Short Description",
/*description=*/"",
/*generator=*/"",
/*architecture=*/"",
/*toolset=*/"",
/*setGenConfig=*/true,
/*enabled=*/true,
},
QCMakePreset{
/*name=*/"long-description",
/*description=*/"",
/*description=*/"Long Description",
/*generator=*/"",
/*architecture=*/"",
/*toolset=*/"",
/*setGenConfig=*/true,
/*enabled=*/true,
},
QCMakePreset{
/*name=*/"disabled",
/*description=*/"",
/*description=*/"",
/*generator=*/"",
/*architecture=*/"",
/*toolset=*/"",
/*setGenConfig=*/true,
/*enabled=*/false,
},
};
QVector<QItemDataHash> data{
QItemDataHash{
{ Qt::AccessibleDescriptionRole, "" },
{ Qt::DisplayRole, "no-description" },
{ Qt::ToolTipRole, "" },
{ Qt::UserRole, QVariant::fromValue(presets[0]) },
{ Qt::FontRole, QFont{} },
},
QItemDataHash{
{ Qt::AccessibleDescriptionRole, "" },
{ Qt::DisplayRole, "Short Description" },
{ Qt::ToolTipRole, "" },
{ Qt::UserRole, QVariant::fromValue(presets[1]) },
{ Qt::FontRole, QFont{} },
},
QItemDataHash{
{ Qt::AccessibleDescriptionRole, "" },
{ Qt::DisplayRole, "long-description" },
{ Qt::ToolTipRole, "Long Description" },
{ Qt::UserRole, QVariant::fromValue(presets[2]) },
{ Qt::FontRole, QFont{} },
},
QItemDataHash{
{ Qt::AccessibleDescriptionRole, "" },
{ Qt::DisplayRole, "disabled" },
{ Qt::ToolTipRole, "" },
{ Qt::UserRole, QVariant::fromValue(presets[3]) },
{ Qt::FontRole, QFont{} },
},
QItemDataHash{
{ Qt::AccessibleDescriptionRole, "separator" },
{ Qt::DisplayRole, QVariant{} },
{ Qt::ToolTipRole, QVariant{} },
{ Qt::UserRole, QVariant{} },
{ Qt::FontRole, QFont{} },
},
QItemDataHash{
{ Qt::AccessibleDescriptionRole, "" },
{ Qt::DisplayRole, "<custom>" },
{ Qt::ToolTipRole, "Specify all settings manually" },
{ Qt::UserRole, QVariant{} },
{ Qt::FontRole,
[]() {
QFont f;
f.setItalic(true);
return f;
}() },
},
};
QTest::newRow("many") << presets << data;
QTest::newRow("none") << QVector<QCMakePreset>{}
<< QVector<QItemDataHash>{ data.last() };
}
void QCMakePresetItemModelTest::data()
{
QFETCH_GLOBAL(QVector<QCMakePreset>, presets);
QFETCH_GLOBAL(QVector<QItemDataHash>, data);
QFETCH(Qt::ItemDataRole, role);
QCMakePresetItemModel model;
QSignalSpy spy1(&model, &QCMakePresetItemModel::modelAboutToBeReset);
QSignalSpy spy2(&model, &QCMakePresetItemModel::modelReset);
model.setPresets(presets);
QCOMPARE(spy1.size(), 1);
QCOMPARE(spy2.size(), 1);
QVector<QVariant> expectedData(data.size());
for (int i = 0; i < data.size(); ++i) {
expectedData[i] = data[i][role];
}
auto rows = model.rowCount();
QVector<QVariant> actualData(rows);
for (int i = 0; i < rows; ++i) {
actualData[i] = model.data(model.index(i, 0), role);
}
QCOMPARE(actualData, expectedData);
}
void QCMakePresetItemModelTest::data_data()
{
QTest::addColumn<Qt::ItemDataRole>("role");
QTest::newRow("accessible") << Qt::AccessibleDescriptionRole;
QTest::newRow("display") << Qt::DisplayRole;
QTest::newRow("tooltip") << Qt::ToolTipRole;
QTest::newRow("user") << Qt::UserRole;
QTest::newRow("font") << Qt::FontRole;
}
QTEST_MAIN(QCMakePresetItemModelTest)

View File

@@ -0,0 +1,17 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "QCMakePresetItemModel.h"
#include <QObject>
class QCMakePresetItemModelTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void initTestCase_data();
void data();
void data_data();
};

View File

@@ -0,0 +1,82 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "QCMakePresetTest.h"
#include <utility>
#include "QCMakePreset.h"
#include <QtTest>
namespace {
QCMakePreset makePreset()
{
return QCMakePreset{
/*name=*/"name",
/*displayName=*/"displayName",
/*description=*/"description",
/*generator=*/"generator",
/*architecture=*/"architecture",
/*toolset=*/"toolset",
/*setGenConfig=*/true,
/*enabled=*/true,
};
}
template <typename T, typename U>
QCMakePreset makePreset(T QCMakePreset::*field, U&& value)
{
auto preset = makePreset();
preset.*field = std::forward<U>(value);
return preset;
}
}
void QCMakePresetTest::equality()
{
QFETCH(QCMakePreset, rhs);
QFETCH(bool, equal);
QFETCH(bool, lt);
QFETCH(bool, gt);
auto lhs = makePreset();
QVERIFY((lhs == rhs) == equal);
QVERIFY((lhs != rhs) == !equal);
QVERIFY((lhs < rhs) == lt);
QVERIFY((lhs >= rhs) == !lt);
QVERIFY((lhs > rhs) == gt);
QVERIFY((lhs <= rhs) == !gt);
}
void QCMakePresetTest::equality_data()
{
QTest::addColumn<QCMakePreset>("rhs");
QTest::addColumn<bool>("equal");
QTest::addColumn<bool>("lt");
QTest::addColumn<bool>("gt");
QTest::newRow("equal") << makePreset() << true << false << false;
QTest::newRow("name") << makePreset(&QCMakePreset::name, "other-name")
<< false << true << false;
QTest::newRow("displayName")
<< makePreset(&QCMakePreset::displayName, "other-displayName") << false
<< true << false;
QTest::newRow("description")
<< makePreset(&QCMakePreset::description, "other-description") << false
<< true << false;
QTest::newRow("generator")
<< makePreset(&QCMakePreset::generator, "other-generator") << false << true
<< false;
QTest::newRow("architecture")
<< makePreset(&QCMakePreset::architecture, "other-architecture") << false
<< true << false;
QTest::newRow("toolset") << makePreset(&QCMakePreset::toolset,
"other-toolset")
<< false << false << true;
QTest::newRow("setGenConfig")
<< makePreset(&QCMakePreset::setGenConfig, false) << false << false
<< true;
QTest::newRow("enabled") << makePreset(&QCMakePreset::enabled, false)
<< false << false << true;
}
QTEST_MAIN(QCMakePresetTest)

View File

@@ -0,0 +1,14 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "QCMakePreset.h"
#include <QObject>
class QCMakePresetTest : public QObject
{
Q_OBJECT
private slots:
void equality();
void equality_data();
};

View File

@@ -0,0 +1,33 @@
{
"version": 1,
"configurePresets": [
{
"name": "ninja",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"STRING_VARIABLE": {
"type": "STRING",
"value": "String value"
},
"PATH_VARIABLE": {
"type": "PATH",
"value": "${sourceDir}"
},
"FILEPATH_VARIABLE": {
"type": "FILEPATH",
"value": "${sourceDir}/CMakeLists.txt"
},
"ON_VARIABLE": {
"type": "BOOL",
"value": "ON"
},
"FALSE_VARIABLE": {
"type": "BOOL",
"value": "FALSE"
},
"UNINITIALIZED_VARIABLE": "Uninitialized value"
}
}
]
}

View File

@@ -0,0 +1,33 @@
{
"version": 1,
"configurePresets": [
{
"name": "ninja",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"STRING_VARIABLE": {
"type": "STRING",
"value": "String value"
},
"PATH_VARIABLE": {
"type": "PATH",
"value": "${sourceDir}"
},
"FILEPATH_VARIABLE": {
"type": "FILEPATH",
"value": "${sourceDir}/CMakeLists.txt"
},
"ON_VARIABLE": {
"type": "BOOL",
"value": "ON"
},
"FALSE_VARIABLE": {
"type": "BOOL",
"value": "FALSE"
},
"UNINITIALIZED_VARIABLE": "Uninitialized value"
}
}
]
}

View File

@@ -0,0 +1,33 @@
{
"version": 1,
"configurePresets": [
{
"name": "ninja",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"STRING_VARIABLE": {
"type": "STRING",
"value": "String value"
},
"PATH_VARIABLE": {
"type": "PATH",
"value": "${sourceDir}"
},
"FILEPATH_VARIABLE": {
"type": "FILEPATH",
"value": "${sourceDir}/CMakeLists.txt"
},
"ON_VARIABLE": {
"type": "BOOL",
"value": "ON"
},
"FALSE_VARIABLE": {
"type": "BOOL",
"value": "FALSE"
},
"UNINITIALIZED_VARIABLE": "Uninitialized value"
}
}
]
}

View File

@@ -0,0 +1,39 @@
{
"version": 1,
"configurePresets": [
{
"name": "ninja",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"STRING_VARIABLE": {
"type": "STRING",
"value": "String value"
},
"PATH_VARIABLE": {
"type": "PATH",
"value": "${sourceDir}"
},
"FILEPATH_VARIABLE": {
"type": "FILEPATH",
"value": "${sourceDir}/CMakeLists.txt"
},
"ON_VARIABLE": {
"type": "BOOL",
"value": "ON"
},
"FALSE_VARIABLE": {
"type": "BOOL",
"value": "FALSE"
},
"UNINITIALIZED_VARIABLE": "Uninitialized value"
}
},
{
"name": "ninja2",
"inherits": [
"ninja"
]
}
]
}

View File

@@ -0,0 +1,2 @@
cmake_minimum_required(VERSION 3.18)
project(sourceBinaryArgs-sourceDir NONE)

View File

@@ -0,0 +1,33 @@
{
"version": 1,
"configurePresets": [
{
"name": "ninja",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"STRING_VARIABLE": {
"type": "STRING",
"value": "String value"
},
"PATH_VARIABLE": {
"type": "PATH",
"value": "${sourceDir}"
},
"FILEPATH_VARIABLE": {
"type": "FILEPATH",
"value": "${sourceDir}/CMakeLists.txt"
},
"ON_VARIABLE": {
"type": "BOOL",
"value": "ON"
},
"FALSE_VARIABLE": {
"type": "BOOL",
"value": "FALSE"
},
"UNINITIALIZED_VARIABLE": "Uninitialized value"
}
}
]
}

View File

@@ -0,0 +1,2 @@
[Settings]
StartPath\WhereBuild0=@CMake_BINARY_DIR@