CMake GUI: Add environment editor

This commit is contained in:
Kyle Edwards
2020-09-24 17:20:10 -04:00
parent d6c051c126
commit 85f5009d27
17 changed files with 768 additions and 44 deletions

View File

@@ -0,0 +1,4 @@
cmake-gui-environment
---------------------
* The :manual:`CMake GUI <cmake-gui(1)>` now has an environment variable editor.

View File

@@ -84,6 +84,8 @@ set(SRCS
CMakeSetupDialog.cxx
CMakeSetupDialog.h
Compilers.h
EnvironmentDialog.cxx
EnvironmentDialog.h
FirstConfigure.cxx
FirstConfigure.h
QCMake.cxx
@@ -102,6 +104,7 @@ qt5_wrap_ui(UI_SRCS
Compilers.ui
CrossCompiler.ui
AddCacheEntry.ui
EnvironmentDialog.ui
RegexExplorer.ui
WarningMessagesDialog.ui
)
@@ -109,6 +112,7 @@ qt5_wrap_cpp(MOC_SRCS
AddCacheEntry.h
Compilers.h
CMakeSetupDialog.h
EnvironmentDialog.h
FirstConfigure.h
QCMake.h
QCMakeCacheView.h

View File

@@ -16,6 +16,7 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QMimeData>
#include <QProcessEnvironment>
#include <QProgressBar>
#include <QSettings>
#include <QShortcut>
@@ -35,6 +36,7 @@
#include "cmVersion.h"
#include "AddCacheEntry.h"
#include "EnvironmentDialog.h"
#include "FirstConfigure.h"
#include "RegexExplorer.h"
#include "WarningMessagesDialog.h"
@@ -292,6 +294,9 @@ void CMakeSetupDialog::initialize()
QObject::connect(this->AddEntry, &QToolButton::clicked, this,
&CMakeSetupDialog::addCacheEntry);
QObject::connect(this->Environment, &QToolButton::clicked, this,
&CMakeSetupDialog::editEnvironment);
QObject::connect(this->WarnUninitializedAction, &QAction::triggered,
this->CMakeThread->cmakeInstance(),
&QCMake::setWarnUninitializedMode);
@@ -742,6 +747,7 @@ void CMakeSetupDialog::setEnabledState(bool enabled)
this->ConfigureAction->setEnabled(enabled);
this->AddEntry->setEnabled(enabled);
this->RemoveEntry->setEnabled(false); // let selection re-enable it
this->Environment->setEnabled(enabled);
}
bool CMakeSetupDialog::setupFirstConfigure()
@@ -1075,6 +1081,17 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
}
}
void CMakeSetupDialog::editEnvironment()
{
EnvironmentDialog dialog(this->CMakeThread->cmakeInstance()->environment(),
this);
if (dialog.exec() == QDialog::Accepted) {
QMetaObject::invokeMethod(
this->CMakeThread->cmakeInstance(), "setEnvironment",
Q_ARG(QProcessEnvironment, dialog.environment()));
}
}
void CMakeSetupDialog::addCacheEntry()
{
QDialog dialog(this);

View File

@@ -65,6 +65,7 @@ protected slots:
void setCacheModified();
void removeSelectedCacheEntries();
void selectionChanged();
void editEnvironment();
void addCacheEntry();
void startSearch();
void setDebugOutput(bool);

View File

@@ -11,7 +11,16 @@
</rect>
</property>
<layout class="QGridLayout">
<property name="margin">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
@@ -19,7 +28,16 @@
</property>
<item row="0" column="0">
<layout class="QGridLayout">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
@@ -90,7 +108,16 @@
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -98,7 +125,16 @@
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -191,6 +227,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="Environment">
<property name="text">
<string>E&amp;nvironment...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -224,7 +267,16 @@
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -241,13 +293,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="OpenProjectButton">
<property name="text">
<string>Open &amp;Project</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="OpenProjectButton">
<property name="text">
<string>Open &amp;Project</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="Generator">
<property name="text">

View File

@@ -0,0 +1,194 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "EnvironmentDialog.h"
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QItemSelectionModel>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QStandardItem>
EnvironmentItemModel::EnvironmentItemModel(
const QProcessEnvironment& environment, QObject* parent)
: QStandardItemModel(parent)
{
this->clear();
for (auto const& key : environment.keys()) {
auto value = environment.value(key);
this->appendVariable(key, value);
}
}
QProcessEnvironment EnvironmentItemModel::environment() const
{
QProcessEnvironment env;
for (int i = 0; i < this->rowCount(); ++i) {
auto name = this->data(this->index(i, 0), Qt::DisplayRole).toString();
auto value = this->data(this->index(i, 1), Qt::DisplayRole).toString();
env.insert(name, value);
}
return env;
}
void EnvironmentItemModel::clear()
{
this->QStandardItemModel::clear();
QStringList labels;
labels << tr("Name") << tr("Value");
this->setHorizontalHeaderLabels(labels);
}
QModelIndex EnvironmentItemModel::buddy(const QModelIndex& index) const
{
if (index.column() == 0) {
return this->index(index.row(), index.column() + 1, index.parent());
}
return index;
}
void EnvironmentItemModel::appendVariable(const QString& key,
const QString& value)
{
this->insertVariable(this->rowCount(), key, value);
}
void EnvironmentItemModel::insertVariable(int row, const QString& key,
const QString& value)
{
for (int i = 0; i < this->rowCount(); ++i) {
if (this->data(this->index(i, 0), Qt::DisplayRole) == key) {
this->setData(this->index(i, 1), value, Qt::DisplayRole);
return;
}
}
auto* keyItem = new QStandardItem(key);
auto* valueItem = new QStandardItem(value);
this->insertRow(row, { keyItem, valueItem });
}
EnvironmentSearchFilter::EnvironmentSearchFilter(QObject* parent)
: QSortFilterProxyModel(parent)
{
}
bool EnvironmentSearchFilter::filterAcceptsRow(int row,
const QModelIndex& parent) const
{
auto* model = this->sourceModel();
auto key =
model->data(model->index(row, 0, parent), Qt::DisplayRole).toString();
return key.contains(this->filterRegExp());
}
EnvironmentDialog::EnvironmentDialog(const QProcessEnvironment& environment,
QWidget* parent)
: QDialog(parent)
{
this->setupUi(this);
this->RemoveEntry->setEnabled(false);
this->m_model = new EnvironmentItemModel(environment, this);
this->m_filter = new EnvironmentSearchFilter(this);
this->m_filter->setSourceModel(this->m_model);
this->Environment->setModel(this->m_filter);
this->Environment->setUniformRowHeights(true);
this->Environment->setRootIsDecorated(false);
this->Environment->setSelectionMode(QAbstractItemView::ExtendedSelection);
this->Environment->setSelectionBehavior(QAbstractItemView::SelectRows);
QObject::connect(this->AddEntry, &QToolButton::clicked, this,
&EnvironmentDialog::addEntry);
QObject::connect(this->RemoveEntry, &QToolButton::clicked, this,
&EnvironmentDialog::removeSelectedEntries);
QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter,
&EnvironmentSearchFilter::setFilterFixedString);
QObject::connect(this->Environment->selectionModel(),
&QItemSelectionModel::selectionChanged, this,
&EnvironmentDialog::selectionChanged);
}
QProcessEnvironment EnvironmentDialog::environment() const
{
return this->m_model->environment();
}
void EnvironmentDialog::addEntry()
{
// Build the dialog manually because it's simple enough
QDialog dialog(this);
dialog.setWindowTitle("Add Environment Variable");
auto* layout = new QGridLayout;
dialog.setLayout(layout);
auto* nameLabel = new QLabel;
nameLabel->setText("Name:");
layout->addWidget(nameLabel, 0, 0);
auto* nameEdit = new QLineEdit;
nameEdit->setObjectName("name");
layout->addWidget(nameEdit, 0, 1);
auto* valueLabel = new QLabel;
valueLabel->setText("Value:");
layout->addWidget(valueLabel, 1, 0);
auto* valueEdit = new QLineEdit;
valueEdit->setObjectName("value");
layout->addWidget(valueEdit, 1, 1);
auto* buttons = new QDialogButtonBox;
buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
QObject::connect(
buttons, &QDialogButtonBox::accepted, &dialog,
[this, &dialog, nameEdit]() {
auto text = nameEdit->text();
if (text.isEmpty()) {
QMessageBox::critical(&dialog, "Error", "Name must be non-empty.");
return;
}
auto* model = this->Environment->model();
for (int i = 0; i < model->rowCount(); ++i) {
if (model->data(model->index(i, 0), Qt::DisplayRole) == text) {
QMessageBox::critical(
&dialog, "Error",
tr("Environment variable \"%1\" already exists.").arg(text));
return;
}
}
dialog.accept();
});
QObject::connect(buttons, &QDialogButtonBox::rejected, &dialog,
&QDialog::reject);
layout->addWidget(buttons, 2, 0, 1, 2);
if (dialog.exec() == QDialog::Accepted) {
this->m_model->insertVariable(0, nameEdit->text(), valueEdit->text());
}
}
void EnvironmentDialog::removeSelectedEntries()
{
QModelIndexList idxs = this->Environment->selectionModel()->selectedRows();
QList<QPersistentModelIndex> pidxs;
foreach (QModelIndex const& i, idxs) {
pidxs.append(i);
}
foreach (QPersistentModelIndex const& pi, pidxs) {
this->Environment->model()->removeRow(pi.row(), pi.parent());
}
}
void EnvironmentDialog::selectionChanged()
{
auto selected = this->Environment->selectionModel()->selectedRows();
this->RemoveEntry->setEnabled(!selected.isEmpty());
}

View File

@@ -0,0 +1,59 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include <QDialog>
#include <QObject>
#include <QProcessEnvironment>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include "ui_EnvironmentDialog.h"
class EnvironmentItemModel : public QStandardItemModel
{
Q_OBJECT
public:
EnvironmentItemModel(const QProcessEnvironment& environment,
QObject* parent = nullptr);
QProcessEnvironment environment() const;
void clear();
QModelIndex buddy(const QModelIndex& index) const override;
public slots:
void appendVariable(const QString& key, const QString& value);
void insertVariable(int row, const QString& key, const QString& value);
};
class EnvironmentSearchFilter : public QSortFilterProxyModel
{
Q_OBJECT
public:
EnvironmentSearchFilter(QObject* parent = nullptr);
protected:
bool filterAcceptsRow(int row, const QModelIndex& parent) const override;
};
class EnvironmentDialog
: public QDialog
, public Ui::EnvironmentDialog
{
Q_OBJECT
public:
EnvironmentDialog(const QProcessEnvironment& environment,
QWidget* parent = nullptr);
QProcessEnvironment environment() const;
protected slots:
void addEntry();
void removeSelectedEntries();
void selectionChanged();
private:
EnvironmentItemModel* m_model;
EnvironmentSearchFilter* m_filter;
};

View File

@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EnvironmentDialog</class>
<widget class="QDialog" name="EnvironmentDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Environment Editor</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>S&amp;earch:</string>
</property>
<property name="buddy">
<cstring>Search</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="Search"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>12</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="AddEntry">
<property name="text">
<string>&amp;Add Entry</string>
</property>
<property name="icon">
<iconset resource="CMakeSetup.qrc">
<normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="RemoveEntry">
<property name="text">
<string>&amp;Remove Entry</string>
</property>
<property name="icon">
<iconset resource="CMakeSetup.qrc">
<normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="Environment"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="CMakeSetup.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>EnvironmentDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>EnvironmentDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -19,10 +19,12 @@
QCMake::QCMake(QObject* p)
: QObject(p)
, Environment(QProcessEnvironment::systemEnvironment())
{
this->WarnUninitializedMode = false;
qRegisterMetaType<QCMakeProperty>();
qRegisterMetaType<QCMakePropertyList>();
qRegisterMetaType<QProcessEnvironment>();
cmSystemTools::DisableRunCommandOutput();
cmSystemTools::SetRunCommandHideConsole(true);
@@ -151,54 +153,72 @@ void QCMake::setToolset(const QString& toolset)
}
}
void QCMake::setEnvironment(const QProcessEnvironment& environment)
{
this->Environment = environment;
}
void QCMake::configure()
{
#ifdef Q_OS_WIN
UINT lastErrorMode = SetErrorMode(0);
#endif
this->CMakeInstance->SetHomeDirectory(
this->SourceDirectory.toLocal8Bit().data());
this->CMakeInstance->SetHomeOutputDirectory(
this->BinaryDirectory.toLocal8Bit().data());
this->CMakeInstance->SetGlobalGenerator(
this->CMakeInstance->CreateGlobalGenerator(
this->Generator.toLocal8Bit().data()));
this->CMakeInstance->SetGeneratorPlatform(
this->Platform.toLocal8Bit().data());
this->CMakeInstance->SetGeneratorToolset(this->Toolset.toLocal8Bit().data());
this->CMakeInstance->LoadCache();
this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode);
this->CMakeInstance->PreLoadCMakeFiles();
InterruptFlag = 0;
cmSystemTools::ResetErrorOccuredFlag();
int err = this->CMakeInstance->Configure();
int err;
{
cmSystemTools::SaveRestoreEnvironment restoreEnv;
this->setUpEnvironment();
#ifdef Q_OS_WIN
SetErrorMode(lastErrorMode);
UINT lastErrorMode = SetErrorMode(0);
#endif
this->CMakeInstance->SetHomeDirectory(
this->SourceDirectory.toLocal8Bit().data());
this->CMakeInstance->SetHomeOutputDirectory(
this->BinaryDirectory.toLocal8Bit().data());
this->CMakeInstance->SetGlobalGenerator(
this->CMakeInstance->CreateGlobalGenerator(
this->Generator.toLocal8Bit().data()));
this->CMakeInstance->SetGeneratorPlatform(
this->Platform.toLocal8Bit().data());
this->CMakeInstance->SetGeneratorToolset(
this->Toolset.toLocal8Bit().data());
this->CMakeInstance->LoadCache();
this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode);
this->CMakeInstance->PreLoadCMakeFiles();
InterruptFlag = 0;
cmSystemTools::ResetErrorOccuredFlag();
err = this->CMakeInstance->Configure();
#ifdef Q_OS_WIN
SetErrorMode(lastErrorMode);
#endif
}
emit this->propertiesChanged(this->properties());
emit this->configureDone(err);
}
void QCMake::generate()
{
#ifdef Q_OS_WIN
UINT lastErrorMode = SetErrorMode(0);
#endif
InterruptFlag = 0;
cmSystemTools::ResetErrorOccuredFlag();
int err = this->CMakeInstance->Generate();
int err;
{
cmSystemTools::SaveRestoreEnvironment restoreEnv;
this->setUpEnvironment();
#ifdef Q_OS_WIN
SetErrorMode(lastErrorMode);
UINT lastErrorMode = SetErrorMode(0);
#endif
InterruptFlag = 0;
cmSystemTools::ResetErrorOccuredFlag();
err = this->CMakeInstance->Generate();
#ifdef Q_OS_WIN
SetErrorMode(lastErrorMode);
#endif
}
emit this->generateDone(err);
checkOpenPossible();
}
@@ -373,6 +393,18 @@ void QCMake::stderrCallback(std::string const& msg)
QCoreApplication::processEvents();
}
void QCMake::setUpEnvironment() const
{
auto env = QProcessEnvironment::systemEnvironment();
for (auto const& key : env.keys()) {
cmSystemTools::UnsetEnv(key.toLocal8Bit().data());
}
for (auto const& var : this->Environment.toStringList()) {
cmSystemTools::PutEnv(var.toLocal8Bit().data());
}
}
QString QCMake::binaryDirectory() const
{
return this->BinaryDirectory;
@@ -388,6 +420,11 @@ QString QCMake::generator() const
return this->Generator;
}
QProcessEnvironment QCMake::environment() const
{
return this->Environment;
}
std::vector<cmake::GeneratorInfo> const& QCMake::availableGenerators() const
{
return AvailableGenerators;

View File

@@ -18,6 +18,7 @@
#include <QList>
#include <QMetaType>
#include <QObject>
#include <QProcessEnvironment>
#include <QString>
#include <QStringList>
#include <QVariant>
@@ -55,6 +56,7 @@ using QCMakePropertyList = QList<QCMakeProperty>;
// allow QVariant to be a property or list of properties
Q_DECLARE_METATYPE(QCMakeProperty)
Q_DECLARE_METATYPE(QCMakePropertyList)
Q_DECLARE_METATYPE(QProcessEnvironment)
/// Qt API for CMake library.
/// Wrapper like class allows for easier integration with
@@ -78,6 +80,8 @@ public slots:
void setPlatform(const QString& platform);
/// set the desired generator to use
void setToolset(const QString& toolset);
/// set the configure and generate environment
void setEnvironment(const QProcessEnvironment& environment);
/// do the configure step
void configure();
/// generate the files
@@ -125,6 +129,8 @@ public:
QString sourceDirectory() const;
/// get the current generator
QString generator() const;
/// get the configure and generate environment
QProcessEnvironment environment() const;
/// get the available generators
std::vector<cmake::GeneratorInfo> const& availableGenerators() const;
/// get whether to do debug output
@@ -170,6 +176,7 @@ protected:
void messageCallback(std::string const& msg, const char* title);
void stdoutCallback(std::string const& msg);
void stderrCallback(std::string const& msg);
void setUpEnvironment() const;
bool WarnUninitializedMode;
QString SourceDirectory;
@@ -180,4 +187,5 @@ protected:
std::vector<cmake::GeneratorInfo> AvailableGenerators;
QString CMakeExecutable;
QAtomicInt InterruptFlag;
QProcessEnvironment Environment;
};

View File

@@ -112,3 +112,9 @@ run_cmake_gui_test(sourceBinaryArgs:noExistConfigExists
run_cmake_gui_test(simpleConfigure:success)
run_cmake_gui_test(simpleConfigure:fail)
unset(ENV{ADDED_VARIABLE})
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)

View File

@@ -143,6 +143,35 @@ void CMakeGUITest::simpleConfigure_data()
<< -1;
}
void CMakeGUITest::environment()
{
auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance();
this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR
"/environment/src");
this->m_window->BinaryDirectory->setCurrentText(CMakeGUITest_BINARY_DIR
"/environment/build");
// We are already testing EnvironmentDialog, so just trust that it's
// connected correctly and modify the environment directly.
auto env = cmake->environment();
env.insert("ADDED_VARIABLE", "Added variable");
env.insert("CHANGED_VARIABLE", "Changed variable");
env.remove("REMOVED_VARIABLE");
cmake->setEnvironment(env);
// Wait a bit for everything to update
loopSleep();
this->tryConfigure();
auto penv = QProcessEnvironment::systemEnvironment();
QVERIFY(!penv.contains("ADDED_VARIABLE"));
QCOMPARE(penv.value("KEPT_VARIABLE"), "Kept variable");
QCOMPARE(penv.value("CHANGED_VARIABLE"), "This variable will be changed");
QCOMPARE(penv.value("REMOVED_VARIABLE"), "Removed variable");
}
void SetupDefaultQSettings()
{
QSettings::setDefaultFormat(QSettings::IniFormat);

View File

@@ -22,4 +22,5 @@ private slots:
void sourceBinaryArgs_data();
void simpleConfigure();
void simpleConfigure_data();
void environment();
};

View File

@@ -58,6 +58,13 @@ add_cmake_gui_lib_test(CatchShow
MOC_SOURCES
CatchShowTest.h
)
add_cmake_gui_lib_test(EnvironmentDialog
SOURCES
EnvironmentDialogTest.cxx
EnvironmentDialogTest.h
MOC_SOURCES
EnvironmentDialogTest.h
)
add_cmake_gui_lib_test(QCMakeCacheModel
SOURCES
QCMakeCacheModelTest.cxx

View File

@@ -0,0 +1,142 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "EnvironmentDialogTest.h"
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QObject>
#include <QPushButton>
#include <QString>
#include <QtTest>
#include "CatchShow.h"
#include "EnvironmentDialog.h"
EnvironmentDialogTest::EnvironmentDialogTest(QObject* parent)
: QObject(parent)
{
}
void EnvironmentDialogTest::environmentDialog()
{
CatchShow catcher;
catcher.setCallback<QMessageBox>([](QMessageBox* box) { box->accept(); });
QProcessEnvironment env;
env.insert("DELETED_VARIABLE_1", "Deleted variable 1");
env.insert("DELETED_VARIABLE_2", "Deleted variable 2");
env.insert("KEPT_VARIABLE", "Kept variable");
env.insert("CHANGED_VARIABLE", "This will be changed");
EnvironmentDialog dialog(env);
{
QStringList expected{
"CHANGED_VARIABLE=This will be changed",
"DELETED_VARIABLE_1=Deleted variable 1",
"DELETED_VARIABLE_2=Deleted variable 2",
"KEPT_VARIABLE=Kept variable",
};
QCOMPARE(dialog.environment().toStringList(), expected);
QCOMPARE(catcher.count(), 0);
}
{
CatchShow catcher2;
bool done = false;
catcher2.setCallback<QDialog>([&catcher, &done](QDialog* box) {
if (done) {
return;
}
done = true;
auto name = box->findChild<QLineEdit*>("name");
auto value = box->findChild<QLineEdit*>("value");
auto acceptReject = box->findChild<QDialogButtonBox*>();
name->setText("");
value->setText("");
acceptReject->button(QDialogButtonBox::Ok)->click();
QCOMPARE(catcher.count(), 1);
name->setText("KEPT_VARIABLE");
value->setText("");
acceptReject->button(QDialogButtonBox::Ok)->click();
QCOMPARE(catcher.count(), 2);
name->setText("ADDED_VARIABLE");
value->setText("Added variable");
acceptReject->button(QDialogButtonBox::Ok)->click();
QCOMPARE(catcher.count(), 2);
});
dialog.AddEntry->click();
QStringList expected{
"ADDED_VARIABLE=Added variable",
"CHANGED_VARIABLE=This will be changed",
"DELETED_VARIABLE_1=Deleted variable 1",
"DELETED_VARIABLE_2=Deleted variable 2",
"KEPT_VARIABLE=Kept variable",
};
QCOMPARE(dialog.environment().toStringList(), expected);
QCOMPARE(catcher.count(), 2);
QVERIFY(done);
}
{
CatchShow catcher2;
bool done = false;
catcher2.setCallback<QDialog>([&done](QDialog* box) {
if (done) {
return;
}
done = true;
auto name = box->findChild<QLineEdit*>("name");
auto value = box->findChild<QLineEdit*>("value");
auto acceptReject = box->findChild<QDialogButtonBox*>();
name->setText("DISCARDED_VARIABLE");
value->setText("Discarded variable");
acceptReject->button(QDialogButtonBox::Cancel)->click();
});
dialog.AddEntry->click();
QStringList expected{
"ADDED_VARIABLE=Added variable",
"CHANGED_VARIABLE=This will be changed",
"DELETED_VARIABLE_1=Deleted variable 1",
"DELETED_VARIABLE_2=Deleted variable 2",
"KEPT_VARIABLE=Kept variable",
};
QCOMPARE(dialog.environment().toStringList(), expected);
QCOMPARE(catcher.count(), 2);
QVERIFY(done);
}
{
auto* model = dialog.Environment->model();
auto* selectionModel = dialog.Environment->selectionModel();
for (int i = 0; i < model->rowCount(); ++i) {
auto index1 = model->index(i, 0);
auto index2 = model->buddy(index1);
auto name = model->data(index1, Qt::DisplayRole).toString();
if (name == "DELETED_VARIABLE_1" || name == "DELETED_VARIABLE_2") {
selectionModel->select(index1, QItemSelectionModel::Select);
selectionModel->select(index2, QItemSelectionModel::Select);
} else if (name == "CHANGED_VARIABLE") {
model->setData(index2, "Changed variable", Qt::DisplayRole);
}
}
dialog.RemoveEntry->click();
QStringList expected{
"ADDED_VARIABLE=Added variable",
"CHANGED_VARIABLE=Changed variable",
"KEPT_VARIABLE=Kept variable",
};
QCOMPARE(dialog.environment().toStringList(), expected);
}
}
QTEST_MAIN(EnvironmentDialogTest)

View File

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

View File

@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.18)
project(environment NONE)
if(NOT "$ENV{KEPT_VARIABLE}" STREQUAL "Kept variable")
message(SEND_ERROR "KEPT_VARIABLE is \"$ENV{KEPT_VARIABLE}\", should be \"Kept variable\"")
endif()
if(NOT "$ENV{ADDED_VARIABLE}" STREQUAL "Added variable")
message(SEND_ERROR "ADDED_VARIABLE is \"$ENV{ADDED_VARIABLE}\", should be \"Added variable\"")
endif()
if(NOT "$ENV{CHANGED_VARIABLE}" STREQUAL "Changed variable")
message(SEND_ERROR "CHANGED_VARIABLE is \"$ENV{CHANGED_VARIABLE}\", should be \"Changed variable\"")
endif()
if(DEFINED ENV{REMOVED_VARIABLE})
message(SEND_ERROR "REMOVED_VARIABLE should not be defined")
endif()