2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2022 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2022-07-28 16:13:35 +02:00
|
|
|
|
|
|
|
|
#include "clangformatglobalconfigwidget.h"
|
|
|
|
|
|
|
|
|
|
#include "clangformatconstants.h"
|
|
|
|
|
#include "clangformatsettings.h"
|
2023-02-04 01:46:50 +01:00
|
|
|
#include "clangformattr.h"
|
2022-08-19 15:20:22 +02:00
|
|
|
#include "clangformatutils.h"
|
2022-07-28 16:13:35 +02:00
|
|
|
|
|
|
|
|
#include <projectexplorer/project.h>
|
2023-04-04 14:28:27 +02:00
|
|
|
#include <texteditor/icodestylepreferences.h>
|
2022-07-28 16:13:35 +02:00
|
|
|
|
2022-07-22 09:44:47 +02:00
|
|
|
#include <utils/layoutbuilder.h>
|
|
|
|
|
|
|
|
|
|
#include <QCheckBox>
|
|
|
|
|
#include <QComboBox>
|
|
|
|
|
#include <QLabel>
|
2023-05-11 11:34:08 +02:00
|
|
|
#include <QSpinBox>
|
2022-07-22 09:44:47 +02:00
|
|
|
#include <QWidget>
|
|
|
|
|
|
2022-07-28 16:13:35 +02:00
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
using namespace ProjectExplorer;
|
2022-07-22 09:44:47 +02:00
|
|
|
using namespace Utils;
|
2022-07-28 16:13:35 +02:00
|
|
|
|
|
|
|
|
namespace ClangFormat {
|
|
|
|
|
|
2023-04-04 14:28:27 +02:00
|
|
|
ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget(
|
|
|
|
|
TextEditor::ICodeStylePreferences *codeStyle, ProjectExplorer::Project *project, QWidget *parent)
|
2022-07-28 16:13:35 +02:00
|
|
|
: CppCodeStyleWidget(parent)
|
2022-08-19 15:20:22 +02:00
|
|
|
, m_project(project)
|
2023-04-04 14:28:27 +02:00
|
|
|
, m_codeStyle(codeStyle)
|
2022-07-28 16:13:35 +02:00
|
|
|
{
|
2023-05-11 11:34:08 +02:00
|
|
|
const QString sizeThresholdToolTip = Tr::tr(
|
|
|
|
|
"Files greater than this will not be indented by ClangFormat.\n"
|
|
|
|
|
"The built-in code indenter will handle indentation.");
|
|
|
|
|
|
2022-08-19 15:20:22 +02:00
|
|
|
m_projectHasClangFormat = new QLabel(this);
|
2023-02-04 01:46:50 +01:00
|
|
|
m_formattingModeLabel = new QLabel(Tr::tr("Formatting mode:"));
|
2023-05-11 11:34:08 +02:00
|
|
|
m_fileSizeThresholdLabel = new QLabel(Tr::tr("Ignore files greater than:"));
|
|
|
|
|
m_fileSizeThresholdSpinBox = new QSpinBox(this);
|
2022-07-22 09:44:47 +02:00
|
|
|
m_indentingOrFormatting = new QComboBox(this);
|
2023-02-04 01:46:50 +01:00
|
|
|
m_formatWhileTyping = new QCheckBox(Tr::tr("Format while typing"));
|
|
|
|
|
m_formatOnSave = new QCheckBox(Tr::tr("Format edited code on file save"));
|
2023-04-04 14:01:10 +02:00
|
|
|
m_overrideDefault = new QCheckBox(Tr::tr("Override .clang-format file"));
|
2023-02-04 01:46:50 +01:00
|
|
|
m_useGlobalSettings = new QCheckBox(Tr::tr("Use global settings"));
|
2023-01-10 14:29:49 +01:00
|
|
|
m_useGlobalSettings->hide();
|
2023-05-11 14:52:51 +02:00
|
|
|
m_overrideDefaultFile = ClangFormatSettings::instance().overrideDefaultFile();
|
2022-07-22 09:44:47 +02:00
|
|
|
|
|
|
|
|
using namespace Layouting;
|
|
|
|
|
|
2023-04-27 08:24:43 +02:00
|
|
|
QWidget *globalSettingsGroupBoxWidget = nullptr;
|
|
|
|
|
|
2022-07-22 09:44:47 +02:00
|
|
|
Group globalSettingsGroupBox {
|
2023-04-27 08:24:43 +02:00
|
|
|
bindTo(&globalSettingsGroupBoxWidget),
|
2023-02-04 01:46:50 +01:00
|
|
|
title(Tr::tr("ClangFormat settings:")),
|
2023-05-02 12:51:03 +02:00
|
|
|
Column {
|
|
|
|
|
m_useGlobalSettings,
|
2023-05-11 11:34:08 +02:00
|
|
|
Form {
|
|
|
|
|
m_formattingModeLabel, m_indentingOrFormatting, st, br,
|
|
|
|
|
m_fileSizeThresholdLabel, m_fileSizeThresholdSpinBox, st, br
|
|
|
|
|
},
|
2023-05-02 12:51:03 +02:00
|
|
|
m_formatWhileTyping,
|
|
|
|
|
m_formatOnSave,
|
|
|
|
|
m_projectHasClangFormat,
|
|
|
|
|
m_overrideDefault
|
2022-07-22 09:44:47 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Column {
|
2023-05-02 12:51:03 +02:00
|
|
|
globalSettingsGroupBox,
|
|
|
|
|
noMargin
|
|
|
|
|
}.attachTo(this);
|
2022-07-28 16:13:35 +02:00
|
|
|
|
|
|
|
|
initCheckBoxes();
|
|
|
|
|
initIndentationOrFormattingCombobox();
|
2022-08-19 15:20:22 +02:00
|
|
|
initOverrideCheckBox();
|
2023-01-10 14:29:49 +01:00
|
|
|
initUseGlobalSettingsCheckBox();
|
2023-05-11 11:34:08 +02:00
|
|
|
initFileSizeThresholdSpinBox();
|
2022-07-28 16:13:35 +02:00
|
|
|
|
|
|
|
|
if (project) {
|
2022-08-19 15:20:22 +02:00
|
|
|
m_formatOnSave->hide();
|
|
|
|
|
m_formatWhileTyping->hide();
|
2023-01-10 14:29:49 +01:00
|
|
|
|
|
|
|
|
m_useGlobalSettings->show();
|
2022-07-28 16:13:35 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2023-04-27 08:24:43 +02:00
|
|
|
|
|
|
|
|
globalSettingsGroupBoxWidget->show();
|
2022-07-28 16:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClangFormatGlobalConfigWidget::~ClangFormatGlobalConfigWidget() = default;
|
|
|
|
|
|
|
|
|
|
void ClangFormatGlobalConfigWidget::initCheckBoxes()
|
|
|
|
|
{
|
|
|
|
|
auto setEnableCheckBoxes = [this](int index) {
|
|
|
|
|
bool isFormatting = index == static_cast<int>(ClangFormatSettings::Mode::Formatting);
|
|
|
|
|
|
2022-07-22 09:44:47 +02:00
|
|
|
m_formatOnSave->setEnabled(isFormatting);
|
|
|
|
|
m_formatWhileTyping->setEnabled(isFormatting);
|
2022-07-28 16:13:35 +02:00
|
|
|
};
|
2022-07-22 09:44:47 +02:00
|
|
|
setEnableCheckBoxes(m_indentingOrFormatting->currentIndex());
|
|
|
|
|
connect(m_indentingOrFormatting, &QComboBox::currentIndexChanged,
|
2022-07-28 16:13:35 +02:00
|
|
|
this, setEnableCheckBoxes);
|
|
|
|
|
|
2022-07-22 09:44:47 +02:00
|
|
|
m_formatOnSave->setChecked(ClangFormatSettings::instance().formatOnSave());
|
|
|
|
|
m_formatWhileTyping->setChecked(ClangFormatSettings::instance().formatWhileTyping());
|
2022-07-28 16:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangFormatGlobalConfigWidget::initIndentationOrFormattingCombobox()
|
|
|
|
|
{
|
2022-07-22 09:44:47 +02:00
|
|
|
m_indentingOrFormatting->insertItem(static_cast<int>(ClangFormatSettings::Mode::Indenting),
|
2023-02-04 01:46:50 +01:00
|
|
|
Tr::tr("Indenting only"));
|
2022-07-22 09:44:47 +02:00
|
|
|
m_indentingOrFormatting->insertItem(static_cast<int>(ClangFormatSettings::Mode::Formatting),
|
2023-02-04 01:46:50 +01:00
|
|
|
Tr::tr("Full formatting"));
|
2022-07-22 09:44:47 +02:00
|
|
|
m_indentingOrFormatting->insertItem(static_cast<int>(ClangFormatSettings::Mode::Disable),
|
2023-02-04 01:46:50 +01:00
|
|
|
Tr::tr("Disable"));
|
2022-07-22 09:44:47 +02:00
|
|
|
|
2023-01-10 14:29:49 +01:00
|
|
|
m_indentingOrFormatting->setCurrentIndex(
|
|
|
|
|
static_cast<int>(getProjectIndentationOrFormattingSettings(m_project)));
|
2022-12-12 15:30:29 +01:00
|
|
|
|
|
|
|
|
connect(m_indentingOrFormatting, &QComboBox::currentIndexChanged, this, [this](int index) {
|
|
|
|
|
if (m_project)
|
|
|
|
|
m_project->setNamedSettings(Constants::MODE_ID, index);
|
|
|
|
|
});
|
2022-07-28 16:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-10 14:29:49 +01:00
|
|
|
void ClangFormatGlobalConfigWidget::initUseGlobalSettingsCheckBox()
|
|
|
|
|
{
|
|
|
|
|
if (!m_project)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const auto enableProjectSettings = [this] {
|
|
|
|
|
const bool isDisabled = m_project && m_useGlobalSettings->isChecked();
|
|
|
|
|
m_indentingOrFormatting->setDisabled(isDisabled);
|
2023-06-27 10:34:37 +02:00
|
|
|
m_formattingModeLabel->setDisabled(isDisabled);
|
|
|
|
|
m_projectHasClangFormat->setDisabled(
|
|
|
|
|
isDisabled
|
|
|
|
|
|| (m_indentingOrFormatting->currentIndex()
|
|
|
|
|
== static_cast<int>(ClangFormatSettings::Mode::Disable)));
|
2023-01-10 14:29:49 +01:00
|
|
|
m_overrideDefault->setDisabled(isDisabled
|
|
|
|
|
|| (m_indentingOrFormatting->currentIndex()
|
|
|
|
|
== static_cast<int>(ClangFormatSettings::Mode::Disable)));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
m_useGlobalSettings->setChecked(getProjectUseGlobalSettings(m_project));
|
|
|
|
|
enableProjectSettings();
|
|
|
|
|
|
|
|
|
|
connect(m_useGlobalSettings, &QCheckBox::toggled,
|
|
|
|
|
this, [this, enableProjectSettings] (bool checked) {
|
|
|
|
|
m_project->setNamedSettings(Constants::USE_GLOBAL_SETTINGS, checked);
|
|
|
|
|
enableProjectSettings();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-11 11:34:08 +02:00
|
|
|
void ClangFormatGlobalConfigWidget::initFileSizeThresholdSpinBox()
|
|
|
|
|
{
|
|
|
|
|
m_fileSizeThresholdSpinBox->setMinimum(1);
|
|
|
|
|
m_fileSizeThresholdSpinBox->setMaximum(std::numeric_limits<int>::max());
|
|
|
|
|
m_fileSizeThresholdSpinBox->setSuffix(" KB");
|
|
|
|
|
m_fileSizeThresholdSpinBox->setValue(ClangFormatSettings::instance().fileSizeThreshold());
|
2023-06-27 10:34:37 +02:00
|
|
|
if (m_project) {
|
2023-05-11 11:34:08 +02:00
|
|
|
m_fileSizeThresholdSpinBox->hide();
|
2023-06-27 10:34:37 +02:00
|
|
|
m_fileSizeThresholdLabel->hide();
|
|
|
|
|
}
|
2023-05-11 11:34:08 +02:00
|
|
|
|
|
|
|
|
connect(m_indentingOrFormatting, &QComboBox::currentIndexChanged, this, [this](int index) {
|
|
|
|
|
m_fileSizeThresholdLabel->setEnabled(
|
|
|
|
|
index != static_cast<int>(ClangFormatSettings::Mode::Disable));
|
|
|
|
|
m_fileSizeThresholdSpinBox->setEnabled(
|
|
|
|
|
index != static_cast<int>(ClangFormatSettings::Mode::Disable));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-19 15:20:22 +02:00
|
|
|
bool ClangFormatGlobalConfigWidget::projectClangFormatFileExists()
|
|
|
|
|
{
|
|
|
|
|
llvm::Expected<clang::format::FormatStyle> styleFromProjectFolder
|
|
|
|
|
= clang::format::getStyle("file", m_project->projectFilePath().path().toStdString(), "none");
|
|
|
|
|
|
|
|
|
|
return styleFromProjectFolder && !(*styleFromProjectFolder == clang::format::getNoStyle());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangFormatGlobalConfigWidget::initOverrideCheckBox()
|
|
|
|
|
{
|
|
|
|
|
if (!m_project || !projectClangFormatFileExists()) {
|
|
|
|
|
m_projectHasClangFormat->hide();
|
|
|
|
|
} else {
|
|
|
|
|
m_projectHasClangFormat->show();
|
2023-02-04 01:46:50 +01:00
|
|
|
m_projectHasClangFormat->setText(Tr::tr("The current project has its own .clang-format file which "
|
|
|
|
|
"can be overridden by the settings below."));
|
2022-08-19 15:20:22 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-08 11:00:04 +02:00
|
|
|
auto setTemporarilyReadOnly = [this]() {
|
|
|
|
|
if (m_ignoreChanges.isLocked())
|
|
|
|
|
return;
|
|
|
|
|
Utils::GuardLocker locker(m_ignoreChanges);
|
|
|
|
|
m_codeStyle->currentPreferences()->setTemporarilyReadOnly(!m_overrideDefault->isChecked());
|
|
|
|
|
m_codeStyle->currentPreferences()->setIsAdditionalTabDisabled(!m_overrideDefault->isEnabled());
|
|
|
|
|
ClangFormatSettings::instance().write();
|
|
|
|
|
emit m_codeStyle->currentPreferencesChanged(m_codeStyle->currentPreferences());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto setEnableOverrideCheckBox = [this, setTemporarilyReadOnly](int index) {
|
2022-08-19 15:20:22 +02:00
|
|
|
bool isDisable = index == static_cast<int>(ClangFormatSettings::Mode::Disable);
|
2023-01-10 14:29:49 +01:00
|
|
|
m_overrideDefault->setDisabled(isDisable);
|
2023-06-27 10:34:37 +02:00
|
|
|
m_projectHasClangFormat->setDisabled(isDisable);
|
2023-05-08 11:00:04 +02:00
|
|
|
setTemporarilyReadOnly();
|
2022-08-19 15:20:22 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setEnableOverrideCheckBox(m_indentingOrFormatting->currentIndex());
|
|
|
|
|
connect(m_indentingOrFormatting, &QComboBox::currentIndexChanged,
|
|
|
|
|
this, setEnableOverrideCheckBox);
|
|
|
|
|
|
2023-06-13 15:39:19 +02:00
|
|
|
m_overrideDefault->setToolTip("<html>"
|
|
|
|
|
+ Tr::tr("When this option is enabled, ClangFormat will use a "
|
|
|
|
|
"user-specified configuration from the widget below, "
|
|
|
|
|
"instead of the project .clang-format file. You can "
|
|
|
|
|
"customize the formatting options for your code by "
|
|
|
|
|
"adjusting the settings in the widget. Note that any "
|
|
|
|
|
"changes made there will only affect the current "
|
|
|
|
|
"configuration, and will not modify the project "
|
|
|
|
|
".clang-format file."));
|
2022-08-19 15:20:22 +02:00
|
|
|
|
2023-01-10 14:29:49 +01:00
|
|
|
m_overrideDefault->setChecked(getProjectOverriddenSettings(m_project));
|
2023-05-08 11:00:04 +02:00
|
|
|
setTemporarilyReadOnly();
|
2022-08-19 15:20:22 +02:00
|
|
|
|
2023-05-08 11:00:04 +02:00
|
|
|
connect(m_overrideDefault, &QCheckBox::toggled, this, [this, setTemporarilyReadOnly](bool checked) {
|
2023-05-11 14:52:51 +02:00
|
|
|
if (m_project) {
|
2022-08-19 15:20:22 +02:00
|
|
|
m_project->setNamedSettings(Constants::OVERRIDE_FILE_ID, checked);
|
2023-05-11 14:52:51 +02:00
|
|
|
} else {
|
|
|
|
|
ClangFormatSettings::instance().setOverrideDefaultFile(checked);
|
2023-05-08 11:00:04 +02:00
|
|
|
setTemporarilyReadOnly();
|
2023-05-11 14:52:51 +02:00
|
|
|
}
|
2023-04-04 14:28:27 +02:00
|
|
|
});
|
|
|
|
|
|
2023-05-08 11:00:04 +02:00
|
|
|
connect(m_codeStyle,
|
|
|
|
|
&TextEditor::ICodeStylePreferences::currentPreferencesChanged,
|
|
|
|
|
this,
|
|
|
|
|
setTemporarilyReadOnly);
|
2022-08-19 15:20:22 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-28 16:13:35 +02:00
|
|
|
|
|
|
|
|
void ClangFormatGlobalConfigWidget::apply()
|
|
|
|
|
{
|
|
|
|
|
ClangFormatSettings &settings = ClangFormatSettings::instance();
|
2022-07-22 09:44:47 +02:00
|
|
|
settings.setFormatOnSave(m_formatOnSave->isChecked());
|
|
|
|
|
settings.setFormatWhileTyping(m_formatWhileTyping->isChecked());
|
2022-12-12 15:30:29 +01:00
|
|
|
if (!m_project) {
|
|
|
|
|
settings.setMode(
|
|
|
|
|
static_cast<ClangFormatSettings::Mode>(m_indentingOrFormatting->currentIndex()));
|
|
|
|
|
settings.setOverrideDefaultFile(m_overrideDefault->isChecked());
|
2023-05-11 11:34:08 +02:00
|
|
|
settings.setFileSizeThreshold(m_fileSizeThresholdSpinBox->value());
|
2023-05-11 14:52:51 +02:00
|
|
|
m_overrideDefaultFile = m_overrideDefault->isChecked();
|
2022-12-12 15:30:29 +01:00
|
|
|
}
|
2022-07-28 16:13:35 +02:00
|
|
|
settings.write();
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-17 14:14:22 +02:00
|
|
|
void ClangFormatGlobalConfigWidget::finish()
|
|
|
|
|
{
|
2023-05-11 14:52:51 +02:00
|
|
|
ClangFormatSettings::instance().setOverrideDefaultFile(m_overrideDefaultFile);
|
2023-04-17 14:14:22 +02:00
|
|
|
m_codeStyle->currentPreferences()->setTemporarilyReadOnly(
|
|
|
|
|
!ClangFormatSettings::instance().overrideDefaultFile());
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-28 16:13:35 +02:00
|
|
|
} // namespace ClangFormat
|