summaryrefslogtreecommitdiffstats
path: root/Source/QtDialog
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2020-09-29 14:17:47 (GMT)
committerKyle Edwards <kyle.edwards@kitware.com>2020-10-05 13:49:59 (GMT)
commita4382f72d7fb924f9649ae352d70a36df2d662a8 (patch)
tree15855284a47a3f3ab4a14f945559266ebabbb0a5 /Source/QtDialog
parent8617479061039e2b357b7efc922f1b88648dce42 (diff)
downloadCMake-a4382f72d7fb924f9649ae352d70a36df2d662a8.zip
CMake-a4382f72d7fb924f9649ae352d70a36df2d662a8.tar.gz
CMake-a4382f72d7fb924f9649ae352d70a36df2d662a8.tar.bz2
CMake GUI: Add presets functionality
Diffstat (limited to 'Source/QtDialog')
-rw-r--r--Source/QtDialog/CMakeLists.txt8
-rw-r--r--Source/QtDialog/CMakeSetup.cxx25
-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx86
-rw-r--r--Source/QtDialog/CMakeSetupDialog.h12
-rw-r--r--Source/QtDialog/CMakeSetupDialog.ui23
-rw-r--r--Source/QtDialog/FirstConfigure.cxx54
-rw-r--r--Source/QtDialog/FirstConfigure.h15
-rw-r--r--Source/QtDialog/QCMake.cxx160
-rw-r--r--Source/QtDialog/QCMake.h23
-rw-r--r--Source/QtDialog/QCMakePreset.cxx50
-rw-r--r--Source/QtDialog/QCMakePreset.h30
-rw-r--r--Source/QtDialog/QCMakePresetComboBox.cxx64
-rw-r--r--Source/QtDialog/QCMakePresetComboBox.h35
-rw-r--r--Source/QtDialog/QCMakePresetItemModel.cxx143
-rw-r--r--Source/QtDialog/QCMakePresetItemModel.h45
15 files changed, 762 insertions, 11 deletions
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index 5fd0e89..394762a 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -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
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index 37c1f15..a5b2f34 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -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 =
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index df22028..acd32ec 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -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());
diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h
index d752ef2..f0cc929 100644
--- a/Source/QtDialog/CMakeSetupDialog.h
+++ b/Source/QtDialog/CMakeSetupDialog.h
@@ -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;
diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui
index 5feee91..afb25eb 100644
--- a/Source/QtDialog/CMakeSetupDialog.ui
+++ b/Source/QtDialog/CMakeSetupDialog.ui
@@ -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>Where to build the binaries:</string>
+ <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="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"/>
diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx
index 918f137..10360bb 100644
--- a/Source/QtDialog/FirstConfigure.cxx
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -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);
}
}
diff --git a/Source/QtDialog/FirstConfigure.h b/Source/QtDialog/FirstConfigure.h
index ca5f52e..5844f3a 100644
--- a/Source/QtDialog/FirstConfigure.h
+++ b/Source/QtDialog/FirstConfigure.h
@@ -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;
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index 974c545..9017a63 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -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;
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
index f569951..a6751b0 100644
--- a/Source/QtDialog/QCMake.h
+++ b/Source/QtDialog/QCMake.h
@@ -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;
};
diff --git a/Source/QtDialog/QCMakePreset.cxx b/Source/QtDialog/QCMakePreset.cxx
new file mode 100644
index 0000000..b10cf07
--- /dev/null
+++ b/Source/QtDialog/QCMakePreset.cxx
@@ -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);
+}
diff --git a/Source/QtDialog/QCMakePreset.h b/Source/QtDialog/QCMakePreset.h
new file mode 100644
index 0000000..93d70d8
--- /dev/null
+++ b/Source/QtDialog/QCMakePreset.h
@@ -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)
diff --git a/Source/QtDialog/QCMakePresetComboBox.cxx b/Source/QtDialog/QCMakePresetComboBox.cxx
new file mode 100644
index 0000000..efadb73
--- /dev/null
+++ b/Source/QtDialog/QCMakePresetComboBox.cxx
@@ -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();
+ }
+}
diff --git a/Source/QtDialog/QCMakePresetComboBox.h b/Source/QtDialog/QCMakePresetComboBox.h
new file mode 100644
index 0000000..d1eeffe
--- /dev/null
+++ b/Source/QtDialog/QCMakePresetComboBox.h
@@ -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();
+};
diff --git a/Source/QtDialog/QCMakePresetItemModel.cxx b/Source/QtDialog/QCMakePresetItemModel.cxx
new file mode 100644
index 0000000..00a4e18
--- /dev/null
+++ b/Source/QtDialog/QCMakePresetItemModel.cxx
@@ -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;
+}
diff --git a/Source/QtDialog/QCMakePresetItemModel.h b/Source/QtDialog/QCMakePresetItemModel.h
new file mode 100644
index 0000000..79fba29
--- /dev/null
+++ b/Source/QtDialog/QCMakePresetItemModel.h
@@ -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);
+};