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'), 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);