From 145be455eedf8d61cef7cfbe8b495834fd7ebfc0 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 24 Feb 2021 14:33:38 +0100 Subject: [PATCH 1/2] CMakeProjectManager: Add Batch Edit support for CMake configuration For the initial CMake parameters one can have an edit dialog. Now it's possible to batch edit variables also after the project has been configured. Change-Id: I406b8e7db16147032a75c82fddf9b7acec85c4bf Reviewed-by: Eike Ziller --- .../cmakebuildconfiguration.cpp | 54 +++++++++++++++++++ .../cmakeprojectmanager/configmodel.cpp | 53 +++++++++--------- src/plugins/cmakeprojectmanager/configmodel.h | 42 ++++++++++++++- 3 files changed, 118 insertions(+), 31 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index c6e9dd0a759..e29d54dba97 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -66,14 +66,18 @@ #include #include #include +#include #include #include +#include +#include #include #include #include #include #include +#include #include #include @@ -112,6 +116,8 @@ private: bool eventFilter(QObject *target, QEvent *event) override; + void batchEditConfiguration(); + CMakeBuildConfiguration *m_buildConfiguration; QTreeView *m_configView; ConfigModel *m_configModel; @@ -130,6 +136,8 @@ private: QTimer m_showProgressTimer; FancyLineEdit *m_filterEdit; InfoLabel *m_warningMessageLabel; + + QPushButton *m_batchEditButton = nullptr; }; static QModelIndex mapToSource(const QAbstractItemView *view, const QModelIndex &idx) @@ -288,6 +296,9 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) m_clearSelectionButton->setEnabled(false); buttonLayout->addWidget(m_clearSelectionButton); buttonLayout->addWidget(m_resetButton); + m_batchEditButton = new QPushButton(tr("Batch Edit...")); + m_batchEditButton->setToolTip(tr("Set or reset multiple values in the CMake Configuration.")); + buttonLayout->addWidget(m_batchEditButton); buttonLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed)); m_showAdvancedCheckBox = new QCheckBox(tr("Advanced")); buttonLayout->addWidget(m_showAdvancedCheckBox); @@ -403,6 +414,8 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) m_configView->setCurrentIndex(idx); m_configView->edit(idx); }); + connect(m_batchEditButton, &QAbstractButton::clicked, + this, &CMakeBuildSettingsWidget::batchEditConfiguration); connect(bc, &CMakeBuildConfiguration::errorOccurred, this, &CMakeBuildSettingsWidget::setError); connect(bc, &CMakeBuildConfiguration::warningOccurred, this, &CMakeBuildSettingsWidget::setWarning); @@ -418,6 +431,47 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) updateSelection(); } + +void CMakeBuildSettingsWidget::batchEditConfiguration() +{ + auto dialog = new QDialog(this); + dialog->setWindowTitle(tr("Edit CMake Configuration")); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setModal(true); + auto layout = new QVBoxLayout(dialog); + auto editor = new QPlainTextEdit(dialog); + + auto label = new QLabel(dialog); + label->setText(tr("Enter one CMake variable per line.\n" + "To set or change a variable, use -D:=.\n" + " can have one of the following values: FILEPATH, PATH, BOOL, INTERNAL, or STRING.\n" + "To unset a variable, use -U.\n")); + editor->setMinimumSize(800, 200); + + auto chooser = new Utils::VariableChooser(dialog); + chooser->addSupportedWidget(editor); + chooser->addMacroExpanderProvider([this]() { return m_buildConfiguration->macroExpander(); }); + + auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); + + layout->addWidget(editor); + layout->addWidget(label); + layout->addWidget(buttons); + + connect(buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject); + connect(dialog, &QDialog::accepted, this, [=]{ + const CMakeConfig config = CMakeConfigItem::itemsFromArguments( + editor->toPlainText().split('\n', Qt::SkipEmptyParts)); + + m_configModel->setBatchEditConfiguration(config); + }); + + editor->setPlainText(m_buildConfiguration->configurationChangesArguments().join('\n')); + + dialog->show(); +} + void CMakeBuildSettingsWidget::setError(const QString &message) { m_buildConfiguration->buildDirectoryAspect()->setProblem(message); diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 8dea7e57efc..f30adb22394 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -209,38 +209,33 @@ QList ConfigModel::configurationForCMake() const void ConfigModel::setConfiguration(const CMakeConfig &config) { setConfiguration(Utils::transform(config, [](const CMakeConfigItem &i) { - ConfigModel::DataItem j; - j.key = QString::fromUtf8(i.key); - j.value = QString::fromUtf8(i.value); - j.description = QString::fromUtf8(i.documentation); - j.values = i.values; - j.inCMakeCache = i.inCMakeCache; - - j.isAdvanced = i.isAdvanced; - j.isHidden = i.type == CMakeConfigItem::INTERNAL || i.type == CMakeConfigItem::STATIC; - - switch (i.type) { - case CMakeConfigItem::FILEPATH: - j.type = ConfigModel::DataItem::FILE; - break; - case CMakeConfigItem::PATH: - j.type = ConfigModel::DataItem::DIRECTORY; - break; - case CMakeConfigItem::BOOL: - j.type = ConfigModel::DataItem::BOOLEAN; - break; - case CMakeConfigItem::STRING: - j.type = ConfigModel::DataItem::STRING; - break; - default: - j.type = ConfigModel::DataItem::UNKNOWN; - break; - } - - return j; + return DataItem(i); })); } +void ConfigModel::setBatchEditConfiguration(const CMakeConfig &config) +{ + for (const auto &c: config) { + DataItem di(c); + auto existing = std::find(m_configuration.begin(), m_configuration.end(), di); + if (existing != m_configuration.end()) { + existing->isUnset = c.isUnset; + if (!c.isUnset) { + existing->isUserChanged = true; + existing->setType(c.type); + existing->value = QString::fromUtf8(c.value); + existing->newValue = existing->value; + } + } else if (!c.isUnset) { + InternalDataItem i(di); + i.isUserNew = true; + i.newValue = di.value; + m_configuration.append(i); + } + } + + generateTree(); +} void ConfigModel::setConfiguration(const QList &config) { diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 7c5cfa205b1..74b12c7d742 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -44,8 +44,45 @@ public: ItemIsAdvancedRole = Qt::UserRole, }; - class DataItem { - public: + struct DataItem { + bool operator == (const DataItem& other) const { + return key == other.key; + } + + DataItem() {} + DataItem(const CMakeConfigItem &cmi) { + key = QString::fromUtf8(cmi.key); + value = QString::fromUtf8(cmi.value); + description = QString::fromUtf8(cmi.documentation); + values = cmi.values; + inCMakeCache = cmi.inCMakeCache; + + isAdvanced = cmi.isAdvanced; + isHidden = cmi.type == CMakeConfigItem::INTERNAL || cmi.type == CMakeConfigItem::STATIC; + + setType(cmi.type); + } + + void setType(CMakeConfigItem::Type cmt) { + switch (cmt) { + case CMakeConfigItem::FILEPATH: + type = FILE; + break; + case CMakeConfigItem::PATH: + type = DIRECTORY; + break; + case CMakeConfigItem::BOOL: + type = BOOLEAN; + break; + case CMakeConfigItem::STRING: + type = STRING; + break; + default: + type = UNKNOWN; + break; + } + } + enum Type { BOOLEAN, FILE, DIRECTORY, STRING, UNKNOWN}; QString key; @@ -70,6 +107,7 @@ public: const QString &description = QString(), const QStringList &values = QStringList()); void setConfiguration(const CMakeConfig &config); + void setBatchEditConfiguration(const CMakeConfig &config); void setConfiguration(const QList &config); void setConfigurationFromKit(const QHash &kitConfig); From c5d4515ec1411defd7041b00d7b12e4a6ca81f3b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 24 Feb 2021 15:57:24 +0100 Subject: [PATCH 2/2] build.py: Make it possible to skip building Qt Creator And only build the windows tools qtcreatorcdbext and wininterrupt. For minimal 32bit Windows build. Change-Id: I126c0963a8917c95300c0b2e9f00da274a62887d Reviewed-by: Cristian Adam --- scripts/build.py | 53 ++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/scripts/build.py b/scripts/build.py index 2ccb1a98f44..2f26b674574 100755 --- a/scripts/build.py +++ b/scripts/build.py @@ -52,7 +52,7 @@ def get_arguments(): parser = argparse.ArgumentParser(description='Build Qt Creator for packaging') parser.add_argument('--src', help='path to sources', required=True) parser.add_argument('--build', help='path that should be used for building', required=True) - parser.add_argument('--qt-path', help='Path to Qt', required=True) + parser.add_argument('--qt-path', help='Path to Qt') parser.add_argument('--build-type', help='Build type to pass to CMake (defaults to RelWithDebInfo)', default='RelWithDebInfo') @@ -79,6 +79,9 @@ def get_arguments(): parser.add_argument('--python3', help='File path to python3 executable for generating translations', default=default_python3()) + parser.add_argument('--no-qtcreator', + help='Skip Qt Creator build (only build separate tools)', + action='store_true', default=False) parser.add_argument('--no-cdb', help='Skip cdbextension and the python dependency packaging step (Windows)', action='store_true', default=(not common.is_windows_platform())) @@ -105,6 +108,9 @@ def get_arguments(): default='') args = parser.parse_args() args.with_debug_info = args.build_type == 'RelWithDebInfo' + + if not args.qt_path and not args.no_qtcreator: + parser.error("argument --qt-path is required if --no-qtcreator is not given") return args def common_cmake_arguments(args): @@ -136,6 +142,8 @@ def common_cmake_arguments(args): return cmake_args def build_qtcreator(args, paths): + if args.no_qtcreator: + return if not os.path.exists(paths.build): os.makedirs(paths.build) prefix_paths = [os.path.abspath(fp) for fp in args.prefix_paths] + [paths.qt] @@ -235,19 +243,20 @@ def build_qtcreatorcdbext(args, paths): def package_qtcreator(args, paths): if not args.no_zip: - common.check_print_call(['7z', 'a', '-mmt2', - os.path.join(paths.result, 'qtcreator' + args.zip_infix + '.7z'), - '*'], - paths.install) - common.check_print_call(['7z', 'a', '-mmt2', - os.path.join(paths.result, 'qtcreator' + args.zip_infix + '_dev.7z'), - '*'], - paths.dev_install) - if args.with_debug_info: + if not args.no_qtcreator: common.check_print_call(['7z', 'a', '-mmt2', - os.path.join(paths.result, 'qtcreator' + args.zip_infix + '-debug.7z'), + os.path.join(paths.result, 'qtcreator' + args.zip_infix + '.7z'), '*'], - paths.debug_install) + paths.install) + common.check_print_call(['7z', 'a', '-mmt2', + os.path.join(paths.result, 'qtcreator' + args.zip_infix + '_dev.7z'), + '*'], + paths.dev_install) + if args.with_debug_info: + common.check_print_call(['7z', 'a', '-mmt2', + os.path.join(paths.result, 'qtcreator' + args.zip_infix + '-debug.7z'), + '*'], + paths.debug_install) if common.is_windows_platform(): common.check_print_call(['7z', 'a', '-mmt2', os.path.join(paths.result, 'wininterrupt' + args.zip_infix + '.7z'), @@ -259,17 +268,16 @@ def package_qtcreator(args, paths): '*'], paths.qtcreatorcdbext_install) - if common.is_mac_platform(): + if common.is_mac_platform() and not args.no_dmg and not args.no_qtcreator: if args.keychain_unlock_script: common.check_print_call([args.keychain_unlock_script], paths.install) - if not args.no_dmg: - common.check_print_call(['python', '-u', - os.path.join(paths.src, 'scripts', 'makedmg.py'), - 'qt-creator' + args.zip_infix + '.dmg', - 'Qt Creator', - paths.src, - paths.install], - paths.result) + common.check_print_call(['python', '-u', + os.path.join(paths.src, 'scripts', 'makedmg.py'), + 'qt-creator' + args.zip_infix + '.dmg', + 'Qt Creator', + paths.src, + paths.install], + paths.result) def get_paths(args): Paths = collections.namedtuple('Paths', @@ -279,7 +287,8 @@ def get_paths(args): 'elfutils', 'llvm']) build_path = os.path.abspath(args.build) install_path = os.path.join(build_path, 'install') - return Paths(qt=os.path.abspath(args.qt_path), + qt_path = os.path.abspath(args.qt_path) if args.qt_path else None + return Paths(qt=qt_path, src=os.path.abspath(args.src), build=os.path.join(build_path, 'build'), wininterrupt_build=os.path.join(build_path, 'build-wininterrupt'),