void ClangDiagnosticConfigsWidget::syncClangTidyWidgets(const ClangDiagnosticConfig &config)
{
    disconnectClangTidyItemChanged();

    ClangDiagnosticConfig::TidyMode tidyMode = config.clangTidyMode();

    m_tidyChecks->tidyMode->setCurrentIndex(static_cast<int>(tidyMode));
    switch (tidyMode) {
    case ClangDiagnosticConfig::TidyMode::Disabled:
    case ClangDiagnosticConfig::TidyMode::File:
        m_tidyChecks->checksString->setVisible(false);
        m_tidyChecks->checksListWrapper->setCurrentIndex(1);
        break;
    case ClangDiagnosticConfig::TidyMode::ChecksString:
        m_tidyChecks->checksString->setVisible(true);
        m_tidyChecks->checksListWrapper->setCurrentIndex(1);
        m_tidyChecks->checksString->setText(config.clangTidyChecksString());
        break;
    case ClangDiagnosticConfig::TidyMode::ChecksPrefixList:
        m_tidyChecks->checksString->setVisible(false);
        m_tidyChecks->checksListWrapper->setCurrentIndex(0);
        syncTidyChecksList(config);
        break;
    }

    m_tidyChecksWidget->setEnabled(!config.isReadOnly());
    connectClangTidyItemChanged();
}
void ClangDiagnosticConfigsWidget::onClangTidyModeChanged(int index)
{
    ClangDiagnosticConfig config = currentConfig();
    config.setClangTidyMode(static_cast<ClangDiagnosticConfig::TidyMode>(index));
    updateConfig(config);
    syncClangTidyWidgets(config);
}
static QString displayNameWithBuiltinIndication(const ClangDiagnosticConfig &config,
                                                const Core::Id &exceptionalConfig)
{
    if (exceptionalConfig == config.id())
        return config.displayName();

    return ClangDiagnosticConfigsModel::displayNameWithBuiltinIndication(config);
}
QString
ClangDiagnosticConfigsModel::displayNameWithBuiltinIndication(const ClangDiagnosticConfig &config)
{
    return config.isReadOnly()
            ? QCoreApplication::translate("ClangDiagnosticConfigsModel", "%1 [built-in]")
                .arg(config.displayName())
            : config.displayName();
}
static ClangDiagnosticConfig createCustomConfig(const ClangDiagnosticConfig &config,
                                                const QString &displayName)
{
    ClangDiagnosticConfig copied = config;
    copied.setId(Core::Id::fromString(QUuid::createUuid().toString()));
    copied.setDisplayName(displayName);
    copied.setIsReadOnly(false);

    return copied;
}
static void addConfigForPedanticWarnings(ClangDiagnosticConfigsModel &model)
{
    ClangDiagnosticConfig config;
    config.setId("Builtin.Pedantic");
    config.setDisplayName(QCoreApplication::translate("ClangDiagnosticConfigsModel",
                                                      "Pedantic Warnings"));
    config.setIsReadOnly(true);
    config.setCommandLineOptions({QStringLiteral("-Wpedantic")});

    model.appendOrUpdate(config);
}
void ClangDiagnosticConfigsWidget::onClangTidyItemChanged(QListWidgetItem *item)
{
    const QString prefix = item->text();
    ClangDiagnosticConfig config = currentConfig();
    QString checks = config.clangTidyChecksPrefixes();
    item->checkState() == Qt::Checked
            ? checks.append(',' + prefix)
            : checks.remove(',' + prefix);
    config.setClangTidyChecksPrefixes(checks);
    updateConfig(config);
}
void ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited()
{
    const QString diagnosticOptions
            = m_ui->diagnosticOptionsTextEdit->document()->toPlainText().trimmed();
    const QStringList updatedCommandLine
            = diagnosticOptions.trimmed().split(QLatin1Char(' '), QString::SkipEmptyParts);

    ClangDiagnosticConfig updatedConfig = currentConfig();
    updatedConfig.setCommandLineOptions(updatedCommandLine);

    m_diagnosticConfigsModel.appendOrUpdate(updatedConfig);
    emit customConfigsChanged(customConfigs());
}
void ClangDiagnosticConfigsModel::appendOrUpdate(const ClangDiagnosticConfig &config)
{
    const int index = indexOfConfig(config.id());

    if (index >= 0 && index < m_diagnosticConfigs.size())
        m_diagnosticConfigs.replace(index, config);
    else
        m_diagnosticConfigs.append(config);
}
void ClangDiagnosticConfigsWidget::syncClazyWidgets(const ClangDiagnosticConfig &config)
{
    const QString clazyChecks = config.clazyChecks();

    QRadioButton *button = m_clazyChecks->clazyRadioDisabled;
    if (clazyChecks.isEmpty())
        button = m_clazyChecks->clazyRadioDisabled;
    else if (clazyChecks == "level0")
        button = m_clazyChecks->clazyRadioLevel0;
    else if (clazyChecks == "level1")
        button = m_clazyChecks->clazyRadioLevel1;
    else if (clazyChecks == "level2")
        button = m_clazyChecks->clazyRadioLevel2;
    else if (clazyChecks == "level3")
        button = m_clazyChecks->clazyRadioLevel3;

    button->setChecked(true);
    m_clazyChecksWidget->setEnabled(!config.isReadOnly());
}
void ClangDiagnosticConfigsWidget::onCopyButtonClicked()
{
    const ClangDiagnosticConfig &config = currentConfig();

    bool diaglogAccepted = false;
    const QString newName = QInputDialog::getText(this,
                                                  tr("Copy Diagnostic Configuration"),
                                                  tr("Diagnostic configuration name:"),
                                                  QLineEdit::Normal,
                                                  tr("%1 (Copy)").arg(config.displayName()),
                                                  &diaglogAccepted);
    if (diaglogAccepted) {
        const ClangDiagnosticConfig customConfig = createCustomConfig(config, newName);
        m_diagnosticConfigsModel.appendOrUpdate(customConfig);
        emit customConfigsChanged(customConfigs());

        syncConfigChooserToModel(customConfig.id());
        m_ui->diagnosticOptionsTextEdit->setFocus();
    }
}
void ClangDiagnosticConfigsWidget::syncTidyChecksList(const ClangDiagnosticConfig &config)
{
    const QString tidyChecks = config.clangTidyChecksPrefixes();
    for (int row = 0; row < m_tidyChecks->checksPrefixesList->count(); ++row) {
        QListWidgetItem *item = m_tidyChecks->checksPrefixesList->item(row);

        Qt::ItemFlags flags = item->flags();
        flags |= Qt::ItemIsUserCheckable;
        if (config.isReadOnly())
            flags &= ~Qt::ItemIsEnabled;
        else
            flags |= Qt::ItemIsEnabled;
        item->setFlags(flags);

        if (tidyChecks.indexOf(item->text()) != -1)
            item->setCheckState(Qt::Checked);
        else
            item->setCheckState(Qt::Unchecked);
    }
}
void ClangDiagnosticConfigsWidget::onClazyRadioButtonChanged(bool checked)
{
    if (!checked)
        return;

    QString checks;
    if (m_clazyChecks->clazyRadioDisabled->isChecked())
        checks = QString();
    else if (m_clazyChecks->clazyRadioLevel0->isChecked())
        checks = "level0";
    else if (m_clazyChecks->clazyRadioLevel1->isChecked())
        checks = "level1";
    else if (m_clazyChecks->clazyRadioLevel2->isChecked())
        checks = "level2";
    else if (m_clazyChecks->clazyRadioLevel3->isChecked())
        checks = "level3";

    ClangDiagnosticConfig config = currentConfig();
    config.setClazyChecks(checks);
    updateConfig(config);
}
void ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited()
{
    // Clean up input
    const QString diagnosticOptions = m_clangBaseChecks->diagnosticOptionsTextEdit->document()
                                          ->toPlainText();
    const QStringList normalizedOptions = normalizeDiagnosticInputOptions(diagnosticOptions);

    // Validate
    const QString errorMessage = validateDiagnosticOptions(normalizedOptions);
    updateValidityWidgets(errorMessage);
    if (!errorMessage.isEmpty()) {
        // Remember the entered options in case the user will switch back.
        m_notAcceptedOptions.insert(currentConfigId(), diagnosticOptions);
        return;
    }
    m_notAcceptedOptions.remove(currentConfigId());

    // Commit valid changes
    ClangDiagnosticConfig updatedConfig = currentConfig();
    updatedConfig.setClangOptions(normalizedOptions);
    updateConfig(updatedConfig);
}
static void addConfigForAlmostEveryWarning(ClangDiagnosticConfigsModel &model)
{
    ClangDiagnosticConfig config;
    config.setId(Constants::CPP_CLANG_BUILTIN_CONFIG_ID_EVERYTHING_WITH_EXCEPTIONS);
    config.setDisplayName(QCoreApplication::translate("ClangDiagnosticConfigsModel",
                                                      "Warnings for almost everything"));
    config.setIsReadOnly(true);
    config.setCommandLineOptions({
        QStringLiteral("-Weverything"),
        QStringLiteral("-Wno-c++98-compat"),
        QStringLiteral("-Wno-c++98-compat-pedantic"),
        QStringLiteral("-Wno-unused-macros"),
        QStringLiteral("-Wno-newline-eof"),
        QStringLiteral("-Wno-exit-time-destructors"),
        QStringLiteral("-Wno-global-constructors"),
        QStringLiteral("-Wno-gnu-zero-variadic-macro-arguments"),
        QStringLiteral("-Wno-documentation"),
        QStringLiteral("-Wno-shadow"),
        QStringLiteral("-Wno-missing-prototypes"), // Not optimal for C projects.
    });

    model.appendOrUpdate(config);
}
void ClangDiagnosticConfigsWidget::onClangTidyLineEdited(const QString &text)
{
    ClangDiagnosticConfig config = currentConfig();
    config.setClangTidyChecksString(text);
    updateConfig(config);
}