diff --git a/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp b/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp index db3a38f7469..d75908fe221 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp @@ -43,7 +43,9 @@ #include #include #include +#include #include +#include #include using namespace ProjectExplorer; @@ -208,22 +210,21 @@ void CMakeKitConfigWidget::manageCMakeTools() CMakeGeneratorKitConfigWidget::CMakeGeneratorKitConfigWidget(Kit *kit, const KitInformation *ki) : KitConfigWidget(kit, ki), - m_comboBox(new QComboBox) + m_label(new QLabel), + m_changeButton(new QPushButton) { - m_comboBox->setToolTip(toolTip()); + m_label->setToolTip(toolTip()); + m_changeButton->setText(tr("Change...")); refresh(); - connect(m_comboBox, static_cast(&QComboBox::currentIndexChanged), - this, [this](int idx) { - m_ignoreChange = true; - CMakeGeneratorKitInformation::setGenerator(m_kit, m_comboBox->itemData(idx).toString()); - m_ignoreChange = false; - }); + connect(m_changeButton, &QPushButton::clicked, + this, &CMakeGeneratorKitConfigWidget::changeGenerator); } CMakeGeneratorKitConfigWidget::~CMakeGeneratorKitConfigWidget() { - delete m_comboBox; + delete m_label; + delete m_changeButton; } QString CMakeGeneratorKitConfigWidget::displayName() const @@ -233,7 +234,7 @@ QString CMakeGeneratorKitConfigWidget::displayName() const void CMakeGeneratorKitConfigWidget::makeReadOnly() { - m_comboBox->setEnabled(false); + m_changeButton->setEnabled(false); } void CMakeGeneratorKitConfigWidget::refresh() @@ -242,33 +243,31 @@ void CMakeGeneratorKitConfigWidget::refresh() return; CMakeTool *const tool = CMakeKitInformation::cmakeTool(m_kit); - if (tool != m_currentTool) { + if (tool != m_currentTool) m_currentTool = tool; - m_comboBox->clear(); - m_comboBox->addItem(tr(""), QString()); - if (tool && tool->isValid()) { - foreach (const QString &g, tool->supportedGenerators()) - m_comboBox->addItem(g, g); - } - } - const QString generator = CMakeGeneratorKitInformation::generator(m_kit); - const QString extraGenerator = CMakeGeneratorKitInformation::extraGenerator(m_kit); - QString fullName = extraGenerator; - if (!fullName.isEmpty()) - fullName += " - "; - fullName += generator; - m_comboBox->setCurrentIndex(m_comboBox->findData(fullName)); + m_changeButton->setEnabled(m_currentTool); + const QString generator = CMakeGeneratorKitInformation::generator(kit()); + const QString extraGenerator = CMakeGeneratorKitInformation::extraGenerator(kit()); + const QString platform = CMakeGeneratorKitInformation::platform(kit()); + const QString toolset = CMakeGeneratorKitInformation::toolset(kit()); + + const QString message = tr("%1 - %2, Platform: %3, Toolset: %4") + .arg(extraGenerator.isEmpty() ? tr("") : extraGenerator) + .arg(generator.isEmpty() ? tr("") : generator) + .arg(platform.isEmpty() ? tr("") : platform) + .arg(toolset.isEmpty() ? tr("") : toolset); + m_label->setText(message); } QWidget *CMakeGeneratorKitConfigWidget::mainWidget() const { - return m_comboBox; + return m_label; } QWidget *CMakeGeneratorKitConfigWidget::buttonWidget() const { - return nullptr; + return m_changeButton; } QString CMakeGeneratorKitConfigWidget::toolTip() const @@ -277,6 +276,91 @@ QString CMakeGeneratorKitConfigWidget::toolTip() const "This setting is ignored when using other build systems."); } +void CMakeGeneratorKitConfigWidget::changeGenerator() +{ + QPointer changeDialog = new QDialog(m_changeButton); + changeDialog->setWindowTitle(tr("CMake Generator")); + + auto *layout = new QGridLayout(changeDialog); + + auto *cmakeLabel = new QLabel; + + auto *generatorCombo = new QComboBox; + auto *extraGeneratorCombo = new QComboBox; + auto *platformEdit = new QLineEdit; + auto *toolsetEdit = new QLineEdit; + + int row = 0; + layout->addWidget(new QLabel(QLatin1String("Executable:"))); + layout->addWidget(cmakeLabel, row, 1); + + ++row; + layout->addWidget(new QLabel(tr("Generator:")), row, 0); + layout->addWidget(generatorCombo, row, 1); + + ++row; + layout->addWidget(new QLabel(tr("Extra Generator:")), row, 0); + layout->addWidget(extraGeneratorCombo, row, 1); + + ++row; + layout->addWidget(new QLabel(tr("Platform:")), row, 0); + layout->addWidget(platformEdit, row, 1); + + ++row; + layout->addWidget(new QLabel(tr("Toolset:")), row, 0); + layout->addWidget(toolsetEdit, row, 1); + + ++row; + auto *bb = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); + layout->addWidget(bb, row, 0, 1, 2); + + connect(bb, &QDialogButtonBox::accepted, changeDialog, &QDialog::accept); + connect(bb, &QDialogButtonBox::rejected, changeDialog, &QDialog::reject); + + cmakeLabel->setText(m_currentTool->cmakeExecutable().toUserOutput()); + + const QList generatorList = m_currentTool->supportedGenerators(); + + for (auto it = generatorList.constBegin(); it != generatorList.constEnd(); ++it) + generatorCombo->addItem(it->name); + + auto updateDialog = [this, &generatorList, generatorCombo, extraGeneratorCombo, + platformEdit, toolsetEdit](const QString &name) { + auto it = std::find_if(generatorList.constBegin(), generatorList.constEnd(), + [name](const CMakeTool::Generator &g) { return g.name == name; }); + QTC_ASSERT(it != generatorList.constEnd(), return); + generatorCombo->setCurrentText(name); + + extraGeneratorCombo->clear(); + extraGeneratorCombo->addItem(tr(""), QString()); + foreach (const QString &eg, it->extraGenerators) + extraGeneratorCombo->addItem(eg, eg); + extraGeneratorCombo->setEnabled(extraGeneratorCombo->count() > 1); + + platformEdit->setEnabled(it->supportsPlatform); + toolsetEdit->setEnabled(it->supportsToolset); + }; + + updateDialog(CMakeGeneratorKitInformation::generator(kit())); + + generatorCombo->setCurrentText(CMakeGeneratorKitInformation::generator(kit())); + extraGeneratorCombo->setCurrentText(CMakeGeneratorKitInformation::extraGenerator(kit())); + platformEdit->setText(platformEdit->isEnabled() ? CMakeGeneratorKitInformation::platform(kit()) : QLatin1String("")); + toolsetEdit->setText(toolsetEdit->isEnabled() ? CMakeGeneratorKitInformation::toolset(kit()) : QLatin1String("")); + + connect(generatorCombo, &QComboBox::currentTextChanged, updateDialog); + + if (changeDialog->exec() == QDialog::Accepted) { + if (!changeDialog) + return; + + CMakeGeneratorKitInformation::set(kit(), generatorCombo->currentText(), + extraGeneratorCombo->currentData().toString(), + platformEdit->isEnabled() ? platformEdit->text() : QString(), + toolsetEdit->isEnabled() ? toolsetEdit->text() : QString()); + } +} + // -------------------------------------------------------------------- // CMakeConfigurationKitConfigWidget: // -------------------------------------------------------------------- diff --git a/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.h b/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.h index 782b43fe056..48ccf1673a8 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.h +++ b/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.h @@ -98,8 +98,11 @@ public: QString toolTip() const override; private: + void changeGenerator(); + bool m_ignoreChange = false; - QComboBox *m_comboBox; + QLabel *m_label; + QPushButton *m_changeButton; CMakeTool *m_currentTool = nullptr; }; diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index bb0cf52c7c2..5fb1f7193ec 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -166,10 +166,6 @@ struct GeneratorInfo { toolset = value.value(TOOLSET_KEY).toString(); } - QString fullName() const { - return extraGenerator.isEmpty() ? generator : extraGenerator + " - " + generator; - } - QString generator; QString extraGenerator; QString platform; @@ -250,6 +246,14 @@ void CMakeGeneratorKitInformation::setToolset(Kit *k, const QString &toolset) setGeneratorInfo(k, info); } +void CMakeGeneratorKitInformation::set(Kit *k, + const QString &generator, const QString &extraGenerator, + const QString &platform, const QString &toolset) +{ + GeneratorInfo info = { generator, extraGenerator, platform, toolset }; + setGeneratorInfo(k, info); +} + QStringList CMakeGeneratorKitInformation::generatorArguments(const Kit *k) { QStringList result; @@ -277,50 +281,49 @@ QVariant CMakeGeneratorKitInformation::defaultValue(const Kit *k) const CMakeTool *tool = CMakeKitInformation::cmakeTool(k); if (!tool) return QVariant(); - QString generator; + const QString extraGenerator = "CodeBlocks"; - QStringList known = tool->supportedGenerators(); + QList known = tool->supportedGenerators(); auto it = std::find_if(known.constBegin(), known.constEnd(), - [](const QString &s) { return s == QLatin1String("CodeBlocks - Ninja"); }); + [extraGenerator](const CMakeTool::Generator &g) { + return g.matches("Ninja", extraGenerator); + }); if (it != known.constEnd()) { - generator = "Ninja"; Utils::Environment env = Utils::Environment::systemEnvironment(); k->addToEnvironment(env); const Utils::FileName ninjaExec = env.searchInPath(QLatin1String("ninja")); - if (ninjaExec.isEmpty()) - it = known.constEnd(); // Ignore ninja generator without ninja exectuable + if (!ninjaExec.isEmpty()) + return GeneratorInfo({ "Ninja", extraGenerator, QString(), QString() }).toVariant(); } + if (Utils::HostOsInfo::isWindowsHost()) { // *sigh* Windows with its zoo of incompatible stuff again... ToolChain *tc = ToolChainKitInformation::toolChain(k, ToolChain::Language::Cxx); if (tc && tc->typeId() == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID) { - if (it == known.constEnd()) - it = std::find_if(known.constBegin(), known.constEnd(), - [](const QString &s) { return s == QLatin1String("CodeBlocks - MinGW Makefiles"); }); + it = std::find_if(known.constBegin(), known.constEnd(), + [extraGenerator](const CMakeTool::Generator &g) { + return g.matches("MinGW Makefiles", extraGenerator); + }); } else { - if (it == known.constEnd()) - it = std::find_if(known.constBegin(), known.constEnd(), - [](const QString &s) { return s == QLatin1String("CodeBlocks - NMake Makefiles"); }); + it = std::find_if(known.constBegin(), known.constEnd(), + [extraGenerator](const CMakeTool::Generator &g) { + return g.matches("NMake Makefiles", extraGenerator); + }); } - } else { // Unix-oid OSes: - if (it == known.constEnd()) - it = std::find_if(known.constBegin(), known.constEnd(), - [](const QString &s) { return s == QLatin1String("CodeBlocks - Unix Makefiles"); }); + it = std::find_if(known.constBegin(), known.constEnd(), + [extraGenerator](const CMakeTool::Generator &g) { + return g.matches("Unix Makefiles", extraGenerator); + }); } if (it == known.constEnd()) it = known.constBegin(); // Fallback to the first generator... if (it == known.constEnd()) return QVariant(); - GeneratorInfo info; - info.extraGenerator = "CodeBlocks"; - const int pos = it->indexOf(" - "); - info.generator = (pos < 0) ? *it : it->mid(pos + 3); - - return info.toVariant(); + return GeneratorInfo({ it->name, extraGenerator, QString(), QString() }).toVariant(); } QList CMakeGeneratorKitInformation::validate(const Kit *k) const @@ -334,10 +337,22 @@ QList CMakeGeneratorKitInformation::validate(const Kit *k) const result << Task(Task::Warning, tr("CMake Tool is unconfigured, CMake generator will be ignored."), Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)); } else { - QStringList known = tool->supportedGenerators(); - if (!known.contains(info.fullName())) { + QList known = tool->supportedGenerators(); + auto it = std::find_if(known.constBegin(), known.constEnd(), [info](const CMakeTool::Generator &g) { + return g.matches(info.generator, info.extraGenerator); + }); + if (it == known.constEnd()) { result << Task(Task::Warning, tr("CMake Tool does not support the configured generator."), Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)); + } else { + if (!it->supportsPlatform && !info.platform.isEmpty()) { + result << Task(Task::Warning, tr("Platform is not supported by the selected CMake generator."), + Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)); + } + if (!it->supportsToolset && !info.toolset.isEmpty()) { + result << Task(Task::Warning, tr("Toolset is not supported by the selected CMake generator."), + Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)); + } } if (info.extraGenerator != "CodeBlocks") { result << Task(Task::Warning, tr("CMake generator does not generate a CodeBlocks file. " @@ -363,11 +378,20 @@ void CMakeGeneratorKitInformation::fix(Kit *k) if (!tool) return; - QStringList known = tool->supportedGenerators(); - if (info.generator.isEmpty() || !known.contains(info.fullName())) { + QList known = tool->supportedGenerators(); + auto it = std::find_if(known.constBegin(), known.constEnd(), + [info](const CMakeTool::Generator &g) { + return g.matches(info.generator, info.extraGenerator); + }); + if (it == known.constEnd()) { GeneratorInfo dv; dv.fromVariant(defaultValue(k)); setGeneratorInfo(k, dv); + } else { + const GeneratorInfo dv = { info.generator, info.extraGenerator, + it->supportsPlatform ? info.platform : QString(), + it->supportsToolset ? info.toolset : QString() }; + setGeneratorInfo(k, dv); } } diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.h b/src/plugins/cmakeprojectmanager/cmakekitinformation.h index 6e06ace65dc..05d1d036b46 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.h +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.h @@ -69,6 +69,8 @@ public: static void setExtraGenerator(ProjectExplorer::Kit *k, const QString &extraGenerator); static void setPlatform(ProjectExplorer::Kit *k, const QString &platform); static void setToolset(ProjectExplorer::Kit *k, const QString &toolset); + static void set(ProjectExplorer::Kit *k, const QString &generator, + const QString &extraGenerator, const QString &platform, const QString &toolset); static QStringList generatorArguments(const ProjectExplorer::Kit *k); // KitInformation interface diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index 306f96c02a2..642a368cfb4 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -45,6 +45,12 @@ const char CMAKE_INFORMATION_DISPLAYNAME[] = "DisplayName"; const char CMAKE_INFORMATION_AUTORUN[] = "AutoRun"; const char CMAKE_INFORMATION_AUTODETECTED[] = "AutoDetected"; + +bool CMakeTool::Generator::matches(const QString &n, const QString &ex) const +{ + return n == name && (ex.isEmpty() || extraGenerators.contains(ex)); +} + /////////////////////////// // CMakeTool /////////////////////////// @@ -153,37 +159,10 @@ bool CMakeTool::isAutoRun() const return m_isAutoRun; } -QStringList CMakeTool::supportedGenerators() const +QList CMakeTool::supportedGenerators() const { if (m_generators.isEmpty()) { - Utils::SynchronousProcessResponse response = run("--help"); - if (response.result == Utils::SynchronousProcessResponse::Finished) { - bool inGeneratorSection = false; - const QStringList lines = response.stdOut().split('\n'); - foreach (const QString &line, lines) { - if (line.isEmpty()) - continue; - if (line == "Generators") { - inGeneratorSection = true; - continue; - } - if (!inGeneratorSection) - continue; - - if (line.startsWith(" ") && line.at(3) != ' ') { - int pos = line.indexOf('='); - if (pos < 0) - pos = line.length(); - if (pos >= 0) { - --pos; - while (pos > 2 && line.at(pos).isSpace()) - --pos; - } - if (pos > 2) - m_generators.append(line.mid(2, pos - 1)); - } - } - } + fetchGeneratorsFromHelp(); } return m_generators; } @@ -334,4 +313,60 @@ QStringList CMakeTool::parseVariableOutput(const QString &output) return result; } +void CMakeTool::fetchGeneratorsFromHelp() const +{ + Utils::SynchronousProcessResponse response = run("--help"); + if (response.result != Utils::SynchronousProcessResponse::Finished) + return; + + bool inGeneratorSection = false; + QHash generatorInfo; + const QStringList lines = response.stdOut().split('\n'); + foreach (const QString &line, lines) { + if (line.isEmpty()) + continue; + if (line == "Generators") { + inGeneratorSection = true; + continue; + } + if (!inGeneratorSection) + continue; + + if (line.startsWith(" ") && line.at(3) != ' ') { + int pos = line.indexOf('='); + if (pos < 0) + pos = line.length(); + if (pos >= 0) { + --pos; + while (pos > 2 && line.at(pos).isSpace()) + --pos; + } + if (pos > 2) { + const QString fullName = line.mid(2, pos - 1); + const int dashPos = fullName.indexOf(" - "); + QString generator; + QString extra; + if (dashPos < 0) { + generator = fullName; + } else { + extra = fullName.mid(0, dashPos); + generator = fullName.mid(dashPos + 3); + } + QStringList value = generatorInfo.value(generator); + if (!extra.isEmpty()) + value.append(extra); + generatorInfo.insert(generator, value); + } + } + } + + // Populate genertor list: + for (auto it = generatorInfo.constBegin(); it != generatorInfo.constEnd(); ++it) { + Generator info; + info.name = it.key(); + info.extraGenerators = it.value(); + m_generators.append(info); + } +} + } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h index 891e2addeb6..8ddc8eafa2e 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.h +++ b/src/plugins/cmakeprojectmanager/cmaketool.h @@ -52,6 +52,17 @@ public: AutoDetection }; + class Generator + { + public: + QString name; + QStringList extraGenerators; + bool supportsPlatform = true; + bool supportsToolset = true; + + bool matches(const QString &n, const QString &ex) const; + }; + typedef std::function PathMapper; explicit CMakeTool(Detection d, const Core::Id &id); @@ -70,7 +81,7 @@ public: Utils::FileName cmakeExecutable() const; bool isAutoRun() const; - QStringList supportedGenerators() const; + QList supportedGenerators() const; TextEditor::Keywords keywords(); bool isAutoDetected() const; @@ -85,6 +96,8 @@ private: void parseFunctionDetailsOutput(const QString &output); QStringList parseVariableOutput(const QString &output); + void fetchGeneratorsFromHelp() const; + Core::Id m_id; QString m_displayName; Utils::FileName m_executable; @@ -95,7 +108,7 @@ private: mutable bool m_didAttemptToRun = false; mutable bool m_didRun = false; - mutable QStringList m_generators; + mutable QList m_generators; mutable QMap m_functionArgs; mutable QStringList m_variables; mutable QStringList m_functions;