/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */

/*
    Rosegarden
    A MIDI and audio sequencer and musical notation editor.
    Copyright 2000-2026 the Rosegarden development team.

    Other copyrights also apply to some parts of this work.  Please
    see the AUTHORS file and individual file headers for details.

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/


#include "NotationConfigurationPage.h"

#include "misc/Strings.h"
#include "misc/ConfigGroups.h"
#include "base/Exception.h"
#include "base/NotationTypes.h"
#include "commands/edit/PasteEventsCommand.h"
#include "document/RosegardenDocument.h"
#include "gui/editors/notation/HeadersGroup.h"
#include "gui/editors/notation/NotationHLayout.h"
#include "gui/editors/notation/NoteFontFactory.h"
#include "gui/editors/notation/NoteFont.h"
#include "gui/editors/notation/NoteFontMap.h"
#include "gui/editors/notation/NotePixmapFactory.h"
#include "gui/editors/notation/NoteStyleFactory.h"
#include "gui/widgets/FontRequester.h"
#include "TabbedConfigurationPage.h"

#include <QComboBox>
#include <QSettings>
#include <QMessageBox>
#include <QCheckBox>
#include <QComboBox>
#include <QFont>
#include <QFrame>
#include <QLabel>
#include <QObject>
#include <QPushButton>
#include <QString>
#include <QStringList>
#include <QTabWidget>
#include <QWidget>
#include <QHBoxLayout>
#include <QToolTip>
#include <QGridLayout>
#include <QLayout>

#include <algorithm>

namespace Rosegarden
{

NotationConfigurationPage::NotationConfigurationPage(QWidget *parent) :
        TabbedConfigurationPage(parent)
{
    QSettings settings;
    settings.beginGroup(NotationViewConfigGroup);

    QFrame *frame;
    QGridLayout *layout;

    frame = new QFrame(m_tabWidget);
    frame->setContentsMargins(10, 10, 10, 10);
    layout = new QGridLayout(frame);
    layout->setSpacing(5);

    int row = 0;

    layout->setRowMinimumHeight(row, 15);
    ++row;

    layout->addWidget(new QLabel(tr("Default layout mode"), frame), row, 0);

    m_layoutMode = new QComboBox(frame);
    connect(m_layoutMode,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);
    m_layoutMode->setEditable(false);
    m_layoutMode->addItem(tr("Linear layout"));
    m_layoutMode->addItem(tr("Continuous page layout"));
    m_layoutMode->addItem(tr("Multiple page layout"));
    int defaultLayoutMode = settings.value("layoutmode", 0).toInt() ;
    if (defaultLayoutMode >= 0 && defaultLayoutMode <= 2) {
        m_layoutMode->setCurrentIndex(defaultLayoutMode);
    }
    layout->addWidget(m_layoutMode, row, 1, 1, 2);
    ++row;

    layout->addWidget(new QLabel(tr("Show track headers (linear layout only)"),
                                      frame), row, 0);

    m_showTrackHeaders = new QComboBox(frame);
    connect(m_showTrackHeaders,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);
    m_showTrackHeaders->setEditable(false);

    m_showTrackHeaders->addItem(tr("Never"), HeadersGroup::ShowNever);
    m_showTrackHeaders->addItem(tr("When needed"), HeadersGroup::ShowWhenNeeded);
    m_showTrackHeaders->addItem(tr("Always"), HeadersGroup::ShowAlways);
    int defaultShowTrackHeaders = settings.value("shownotationheader",
                                                 HeadersGroup::DefaultShowMode).toInt() ;
    if (HeadersGroup::isValidShowMode(defaultShowTrackHeaders)) {
        m_showTrackHeaders->setCurrentIndex(defaultShowTrackHeaders);
    }

    //$$$ After Thorn, reword this string into better English:
    m_showTrackHeaders->setToolTip(QString(tr(
        "\"Always\" and \"Never\" mean what they usually mean\n"
        "\"When needed\" means \"when staves are too many to all fit"
        " in the current window\"")));

    layout->addWidget(m_showTrackHeaders, row, 1, 1, 2);
    ++row;

    layout->setRowMinimumHeight(row, 20);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("Show non-notation events as question marks"), frame),
         row, 0, 1, 2);
    m_showUnknowns = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_showUnknowns, &QCheckBox::checkStateChanged,
#else
    connect(m_showUnknowns, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    bool defaultShowUnknowns = qStrToBool(settings.value("showunknowns", "false")) ;
    m_showUnknowns->setChecked(defaultShowUnknowns);
    layout->addWidget(m_showUnknowns, row, 2);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("Show notation-quantized notes in a different color"), frame),
         row, 0, 1, 2);
    m_colourQuantize = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_colourQuantize, &QCheckBox::checkStateChanged,
#else
    connect(m_colourQuantize, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    bool defaultColourQuantize = qStrToBool(settings.value("colourquantize", "false")) ;
    m_colourQuantize->setChecked(defaultColourQuantize);
    layout->addWidget(m_colourQuantize, row, 2);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("Show \"invisible\" events in grey"), frame),
         row, 0, 1, 2);
    m_showInvisibles = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_showInvisibles, &QCheckBox::checkStateChanged,
#else
    connect(m_showInvisibles, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    bool defaultShowInvisibles = qStrToBool(settings.value("showinvisibles", "true")) ;
    m_showInvisibles->setChecked(defaultShowInvisibles);
    layout->addWidget(m_showInvisibles, row, 2);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("Show notes outside suggested playable range in red"), frame),
         row, 0, 1, 2);
    m_showRanges = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_showRanges, &QCheckBox::checkStateChanged,
#else
    connect(m_showRanges, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    bool defaultShowRanges = qStrToBool(settings.value("showranges", "true")) ;
    m_showRanges->setChecked(defaultShowRanges);
    layout->addWidget(m_showRanges, row, 2);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("Highlight superimposed notes with a halo effect"), frame),
         row, 0, 1, 2);
    m_showCollisions = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_showCollisions, &QCheckBox::checkStateChanged,
#else
    connect(m_showCollisions, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    bool defaultShowCollisions = qStrToBool(settings.value("showcollisions", "true")) ;
    m_showCollisions->setChecked(defaultShowCollisions);
    layout->addWidget(m_showCollisions, row, 2);
    ++row;

    layout->setRowMinimumHeight(row, 20);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("When recording MIDI, split-and-tie long notes at barlines"), frame),
         row, 0, 1, 2);
    m_splitAndTie = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_splitAndTie, &QCheckBox::checkStateChanged,
#else
    connect(m_splitAndTie, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    //NB. The split-and-tie feature is turned on by default once more, now that
    // the matrix and notation editors both handle strings of adjacent tied
    // notes as though they were a single unit.  This makes more sense when
    // inserting, say, a whole note that won't fit inside a measure.
    bool defaultSplitAndTie = qStrToBool(settings.value("quantizemakeviable", "true")) ;
    m_splitAndTie->setChecked(defaultSplitAndTie);
    layout->addWidget(m_splitAndTie, row, 2);
    ++row;

    layout->setRowStretch(row, 10);
    frame->setLayout(layout);

    addTab(frame, tr("Layout"));

    frame = new QFrame(m_tabWidget);
    frame->setContentsMargins(10, 10, 10, 10);
    layout = new QGridLayout(frame);
    layout->setSpacing(5);

    row = 0;

    layout->setRowMinimumHeight(row, 15);
    ++row;

    layout->addWidget
        (new QLabel(tr("Default note style for new notes"), frame),
         row, 0, 1, 2);

    layout->setColumnStretch(2, 10);

    m_noteStyle = new QComboBox(frame);
    connect(m_noteStyle,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);
    m_noteStyle->setEditable(false);
    m_untranslatedNoteStyle.clear();

    QString defaultStyle = settings.value("style", NoteStyleFactory::DefaultStyle).toString();
    std::vector<NoteStyleName> styles
    (NoteStyleFactory::getAvailableStyleNames());

    for (std::vector<NoteStyleName>::iterator i = styles.begin();
            i != styles.end(); ++i) {

        QString styleQName(*i);
        m_untranslatedNoteStyle.append(styleQName);
        m_noteStyle->addItem(QObject::tr(styleQName.toUtf8()));
        if (styleQName == defaultStyle) {
            m_noteStyle->setCurrentIndex(m_noteStyle->count() - 1);
        }
    }

    layout->addWidget(m_noteStyle, row, 2);
    ++row;

    layout->setRowMinimumHeight(row, 20);
    ++row;

    layout->addWidget
    (new QLabel(tr("When inserting notes..."), frame), row, 0);

    int defaultInsertType = settings.value("inserttype", 0).toInt() ;

    m_insertType = new QComboBox(frame);
    connect(m_insertType,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);
    m_insertType->setEditable(false);
    m_insertType->addItem
    (tr("Split notes into ties to make durations match"));
    m_insertType->addItem(tr("Ignore existing durations"));
    m_insertType->setCurrentIndex(defaultInsertType);

    layout->addWidget(m_insertType, row, 1, 1, 2);
    ++row;

    bool autoBeam = qStrToBool(settings.value("autobeam", "true")) ;

    layout->addWidget
        (new QLabel
         (tr("Auto-beam on insert when appropriate"), frame),
         row, 0, 1, 2);
    m_autoBeam = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_autoBeam, &QCheckBox::checkStateChanged,
#else
    connect(m_autoBeam, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    m_autoBeam->setChecked(autoBeam);
    layout->addWidget(m_autoBeam, row, 2, 1, 1);

    ++row;

     bool autoCorrect = qStrToBool(settings.value("autotieatbarlines","true"));

     layout->addWidget(
             new QLabel
             (tr("Tie notes at barlines automatically"), frame),
             row, 0, 1, 2);
     m_autoTieBarlines = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_autoTieBarlines, &QCheckBox::checkStateChanged,
#else
    connect(m_autoTieBarlines, &QCheckBox::stateChanged,
#endif
             this, &NotationConfigurationPage::slotModified);
     m_autoTieBarlines->setChecked(autoCorrect);
     layout->addWidget(m_autoTieBarlines, row, 2, 1, 1);

     ++row;


    bool collapse = qStrToBool(settings.value("collapse", "false")) ;

    layout->addWidget
        (new QLabel
         (tr("Collapse rests after erase"), frame),
         row, 0, 1, 2);
    m_collapseRests = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_collapseRests, &QCheckBox::checkStateChanged,
#else
    connect(m_collapseRests, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    m_collapseRests->setChecked(collapse);
    layout->addWidget(m_collapseRests, row, 2, 1, 1);
    ++row;

    layout->setRowMinimumHeight(row, 20);
    ++row;

    layout->addWidget
    (new QLabel(tr("Default paste type"), frame), row, 0);

    m_pasteType = new QComboBox(frame);
    connect(m_pasteType,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);
    m_pasteType->setEditable(false);

    unsigned int defaultPasteType = settings.value("pastetype",
            PasteEventsCommand::Restricted).toUInt();

    PasteEventsCommand::PasteTypeMap pasteTypes =
        PasteEventsCommand::getPasteTypes();

    for (PasteEventsCommand::PasteTypeMap::iterator i = pasteTypes.begin();
            i != pasteTypes.end(); ++i) {
        m_pasteType->addItem(i->second);
    }

    m_pasteType->setCurrentIndex(defaultPasteType);
    layout->addWidget(m_pasteType, row, 1, 1, 2);
    ++row;

    layout->setRowMinimumHeight(row, 20);
    ++row;

    bool preview = qStrToBool(settings.value("alwayspreview", "true")) ;

    QLabel * previewLabel = new QLabel
         (tr("Always show note preview"), frame);
    layout->addWidget(previewLabel, row, 0, 1, 2);
    m_preview = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_preview, &QCheckBox::checkStateChanged,
#else
    connect(m_preview, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    m_preview->setChecked(preview);
    QString previewTip(tr(
        "<p>If checked, a preview of the note or rest is always displayed"
        " when inserting notes or rests with the mouse</p>"));
    previewLabel->setToolTip(previewTip);
    m_preview->setToolTip(previewTip);
   layout->addWidget(m_preview, row, 2, 1, 1);
    ++row;

    bool quickEdit = qStrToBool(settings.value("quickedit", "true"));

    QLabel * quickEditLabel = new QLabel(
         tr("Quick mouse entry mode"),
         frame);
    layout->addWidget(quickEditLabel, row, 0, 1, 2);
    m_quickEdit = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_quickEdit, &QCheckBox::checkStateChanged,
#else
    connect(m_quickEdit, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    m_quickEdit->setChecked(quickEdit);
    QString quickEditTip(tr(
        "<p>If checked, the following features are usable while inserting notes"
        " with the mouse:<ul>"
        "<li>The mouse wheel selects the note duration</li>"
        "<li>Shift adds a sharp</li>"
        "<li>Ctrl adds a flat</li>"
        "<li>Shift + Ctrl adds a natural</li>"
        "<li>A mouse mid button click switches between notes and rests</li>"
        "</ul></p>"));
    quickEditLabel->setToolTip(quickEditTip);
    m_quickEdit->setToolTip(quickEditTip);
    layout->addWidget(m_quickEdit, row, 2, 1, 1);
    ++row;

    layout->setRowStretch(row, 10);
    frame->setLayout(layout);

    addTab(frame, tr("Editing"));

    frame = new QFrame(m_tabWidget);
    frame->setContentsMargins(10, 10, 10, 10);
    layout = new QGridLayout(frame);
    layout->setSpacing(5);

    row = 0;

    layout->setRowMinimumHeight(row, 15);
    ++row;

    layout->addWidget(new QLabel(tr("Accidentals in one octave..."), frame), row, 0);
    m_accOctavePolicy = new QComboBox(frame);
    connect(m_accOctavePolicy,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);
    m_accOctavePolicy->addItem(tr("Affect only that octave"));
    m_accOctavePolicy->addItem(tr("Require cautionaries in other octaves"));
    m_accOctavePolicy->addItem(tr("Affect all subsequent octaves"));
    int accOctaveMode = settings.value("accidentaloctavemode", 1).toInt() ;
    if (accOctaveMode >= 0 && accOctaveMode < 3) {
        m_accOctavePolicy->setCurrentIndex(accOctaveMode);
    }
    layout->addWidget(m_accOctavePolicy, row, 1);
    ++row;

    layout->addWidget(new QLabel(tr("Accidentals in one bar..."), frame), row, 0);
    m_accBarPolicy = new QComboBox(frame);
    connect(m_accBarPolicy,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);

    m_accBarPolicy->addItem(tr("Affect only that bar"));
    m_accBarPolicy->addItem(tr("Require cautionary resets in following bar"));
    m_accBarPolicy->addItem(tr("Require explicit resets in following bar"));
    int accBarMode = settings.value("accidentalbarmode", 0).toInt() ;
    if (accBarMode >= 0 && accBarMode < 3) {
        m_accBarPolicy->setCurrentIndex(accBarMode);
    }
    layout->addWidget(m_accBarPolicy, row, 1);
    ++row;

    layout->addWidget(new QLabel(tr("Key signature cancellation style"), frame), row, 0);
    m_keySigCancelMode = new QComboBox(frame);
    connect(m_keySigCancelMode,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);
    m_keySigCancelMode->addItem(tr("Cancel only when entering C major or A minor"));
    m_keySigCancelMode->addItem(tr("Cancel whenever removing sharps or flats"));
    m_keySigCancelMode->addItem(tr("Cancel always"));
    int cancelMode = settings.value("keysigcancelmode", 1).toInt() ;
    if (cancelMode >= 0 && cancelMode < 3) {
        m_keySigCancelMode->setCurrentIndex(cancelMode);
    }
    layout->addWidget(m_keySigCancelMode, row, 1);
    ++row;

    layout->setRowStretch(row, 10);
    frame->setLayout(layout);

    addTab(frame, tr("Accidentals"));

    row = 0;

    frame = new QFrame(m_tabWidget);
    frame->setContentsMargins(10, 10, 10, 10);
    layout = new QGridLayout(frame);
    layout->setSpacing(5);

    layout->addWidget(new QLabel(tr("Notation font"), frame), 0, 0);

    m_font = new QComboBox(frame);
    connect(m_font,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);

    layout->addWidget(m_font, row, 1, 1, 3);
    m_font->setEditable(false);
    connect(m_font,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotFontComboChanged);

    ++row;

    QFrame *subFrame = new QFrame(frame);
    subFrame->setContentsMargins(12, 12, 12, 12);
    QGridLayout *subLayout = new QGridLayout(subFrame);
    subLayout->setSpacing(2);

    QFont font = m_font->font();
    font.setPointSize((font.pointSize() * 9) / 10);

    QLabel *originLabel = new QLabel(tr("Origin:"), subFrame);
    originLabel->setFont(font);
    subLayout->addWidget(originLabel, 0, 0);

    QLabel *copyrightLabel = new QLabel(tr("Copyright:"), subFrame);
    copyrightLabel->setFont(font);
    subLayout->addWidget(copyrightLabel, 1, 0);

    QLabel *mappedLabel = new QLabel(tr("Mapped by:"), subFrame);
    mappedLabel->setFont(font);
    subLayout->addWidget(mappedLabel, 2, 0);

    QLabel *typeLabel = new QLabel(tr("Type:"), subFrame);
    typeLabel->setFont(font);
    subLayout->addWidget(typeLabel, 3, 0);

    m_fontOriginLabel = new QLabel(subFrame);
    m_fontOriginLabel->setWordWrap(true);
    m_fontOriginLabel->setFont(font);
    m_fontCopyrightLabel = new QLabel(subFrame);
    m_fontCopyrightLabel->setWordWrap(true);
    m_fontCopyrightLabel->setFont(font);
    m_fontMappedByLabel = new QLabel(subFrame);
    m_fontMappedByLabel->setFont(font);
    m_fontTypeLabel = new QLabel(subFrame);
    m_fontTypeLabel->setFont(font);
    subLayout->addWidget(m_fontOriginLabel, 0, 1);
    subLayout->addWidget(m_fontCopyrightLabel, 1, 1);
    subLayout->addWidget(m_fontMappedByLabel, 2, 1);
    subLayout->addWidget(m_fontTypeLabel, 3, 1);

    subLayout->setColumnStretch(1, 10);
    subFrame->setLayout(subLayout);

    layout->addWidget(subFrame, row, 0, 1, 4);
    ++row;

    layout->addWidget
        (new QLabel(tr("Font size for single-staff views"), frame),
         row, 0, 1, 2);
    m_singleStaffSize = new QComboBox(frame);
    connect(m_singleStaffSize,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);
    m_singleStaffSize->setEditable(false);
    layout->addWidget(m_singleStaffSize, row, 2, 1, 1);
    ++row;

    layout->addWidget
        (new QLabel(tr("Font size for multi-staff views"), frame),
         row, 0, 1, 2);
    m_multiStaffSize = new QComboBox(frame);
    connect(m_multiStaffSize,
                static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
            this, &NotationConfigurationPage::slotModified);
    m_multiStaffSize->setEditable(false);
    layout->addWidget(m_multiStaffSize, row, 2, 1, 1);
    ++row;

    slotPopulateFontCombo(false);

    layout->setRowMinimumHeight(row, 15);
    ++row;

    QFont defaultTextFont(NotePixmapFactory::defaultSerifFontFamily);

    layout->addWidget
        (new QLabel(tr("Text font"), frame), row, 0);
    m_textFont = new FontRequester(frame);
    connect(m_textFont, &FontRequester::fontChanged, this, &NotationConfigurationPage::slotModified);
    QFont textFont = defaultTextFont;
    QVariant fv = settings.value("textfont", textFont);
    if (fv.canConvert<QFont>()) textFont = fv.value<QFont>();
    m_textFont->setFont(textFont);
    layout->addWidget(m_textFont, row, 1, 1, 3);
    ++row;

    layout->addWidget
        (new QLabel(tr("Sans-serif font"), frame), row, 0);
    m_sansFont = new FontRequester(frame);
    connect(m_sansFont, &FontRequester::fontChanged, this, &NotationConfigurationPage::slotModified);
    QFont sansFont = defaultTextFont;
    fv = settings.value("sansfont", sansFont);
    if (fv.canConvert<QFont>()) sansFont = fv.value<QFont>();
    m_sansFont->setFont(sansFont);
    layout->addWidget(m_sansFont, row, 1, 1, 3);

    frame->setLayout(layout);

    addTab(frame, tr("Font"));


    // Beginning of "Segments" tab

    frame = new QFrame(m_tabWidget);
    frame->setContentsMargins(10, 10, 10, 10);
    layout = new QGridLayout(frame);
    layout->setSpacing(5);

    row = 0;

    layout->setRowMinimumHeight(row, 15);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("Show repeated segments"), frame),
         row, 0, 1, 2);
    m_showRepeated = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_showRepeated, &QCheckBox::checkStateChanged,
#else
    connect(m_showRepeated, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    bool defaultShowRepeated = qStrToBool(settings.value("showrepeated",
                                                         "true")) ;
    m_showRepeated->setChecked(defaultShowRepeated);
    layout->addWidget(m_showRepeated, row, 2);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("Allow direct edition of repeated segments"), frame),
         row, 0, 1, 2);
    m_editRepeated = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_editRepeated, &QCheckBox::checkStateChanged,
#else
    connect(m_editRepeated, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    bool defaultEditRepeated = qStrToBool(settings.value("editrepeated",
                                                         "false")) ;
    m_editRepeated->setChecked(defaultEditRepeated);
    layout->addWidget(m_editRepeated, row, 2);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("Hide redundant clefs and keys"), frame),
         row, 0, 1, 2);
    m_hideRedundantClefKey = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_hideRedundantClefKey, &QCheckBox::checkStateChanged,
#else
    connect(m_hideRedundantClefKey, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    bool defaultHideRedundantClefKey =
        qStrToBool(settings.value("hideredundantclefkey", "true")) ;
    m_hideRedundantClefKey->setChecked(defaultHideRedundantClefKey);
    layout->addWidget(m_hideRedundantClefKey, row, 2);
    ++row;

    layout->addWidget
        (new QLabel
         (tr("Distribute verses among repeated segments"), frame),
         row, 0, 1, 2);
    m_distributeVerses = new QCheckBox(frame);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
    connect(m_distributeVerses, &QCheckBox::checkStateChanged,
#else
    connect(m_distributeVerses, &QCheckBox::stateChanged,
#endif
            this, &NotationConfigurationPage::slotModified);
    bool defaultDistributeVerses =
        qStrToBool(settings.value("distributeverses", "true")) ;
    m_distributeVerses->setChecked(defaultDistributeVerses);
    layout->addWidget(m_distributeVerses, row, 2);
    ++row;


    layout->setRowStretch(row, 10);
    frame->setLayout(layout);

    addTab(frame, tr("Segments"));

    // End of "Segments" tab

    settings.endGroup();
}

void
NotationConfigurationPage::slotPopulateFontCombo(bool rescan)
{
    QSettings settings;
    settings.beginGroup(NotationViewConfigGroup);

    QString defaultFont = settings.value
        ("notefont", NoteFontFactory::getDefaultFontName()).toString();
    settings.endGroup();

    try {
        (void)NoteFontFactory::getFont
            (defaultFont, NoteFontFactory::getDefaultSize(defaultFont));
    } catch (const Exception &e) {
        defaultFont = NoteFontFactory::getDefaultFontName();
    }

    std::set<QString> fs(NoteFontFactory::getFontNames(rescan));
    std::vector<QString> f;
    for (std::set<QString>::const_iterator i = fs.begin(); i != fs.end(); ++i) {
        f.push_back(*i);
    }
    std::sort(f.begin(), f.end());

    m_untranslatedFont.clear();
    m_font->clear();

    for (std::vector<QString>::const_iterator i = f.begin(); i != f.end(); ++i) {
        QString s(*i);
        m_untranslatedFont.append(s);
        m_font->addItem(s);
        if (s == defaultFont) m_font->setCurrentIndex(m_font->count() - 1);
    }

    slotFontComboChanged(m_font->currentIndex());
}

void
NotationConfigurationPage::slotFontComboChanged(int index)
{
    QString fontStr = m_untranslatedFont[index];

    QSettings settings;
    settings.beginGroup(NotationViewConfigGroup);

    populateSizeCombo
        (m_singleStaffSize, fontStr,
         settings.value("singlestaffnotesize",
                        NoteFontFactory::getDefaultSize(fontStr)).toInt());
    // I remember Chris talking recently about how the default for multiple
    // staffs was supposed to be 6 instead of 8 or something like that.
    // getDefaultMultiSize didn't exist until just now, and this was true in
    // Classic.  That never would have worked.
    populateSizeCombo
        (m_multiStaffSize, fontStr,
         settings.value("multistaffnotesize",
                        NoteFontFactory::getDefaultMultiSize(fontStr)).toInt());
    settings.endGroup();

    try {
        const NoteFont *noteFont = NoteFontFactory::getFont
            (fontStr, NoteFontFactory::getDefaultSize(fontStr));
        const NoteFontMap &map(noteFont->getNoteFontMap());
        m_fontOriginLabel->setText(tr(map.getOrigin().toStdString().c_str()));
        m_fontCopyrightLabel->setText(tr(map.getCopyright().toStdString().c_str()));
        m_fontMappedByLabel->setText(tr(map.getMappedBy().toStdString().c_str()));
        if (map.isSmooth()) {
            m_fontTypeLabel->setText(tr("%1 (smooth)").arg(tr(map.getType().toStdString().c_str())));
        } else {
            m_fontTypeLabel->setText(tr("%1 (jaggy)").arg(tr(map.getType().toStdString().c_str())));
        }
    } catch (const Exception &f) {
        QMessageBox::critical(nullptr, tr("Rosegarden"), strtoqstr(f.getMessage()));
    }
}

void
NotationConfigurationPage::populateSizeCombo(QComboBox *combo,
                                             QString font,
                                             int defaultSize)
{
    std::vector<int> sizes = NoteFontFactory::getScreenSizes(font);
    combo->clear();

    for (std::vector<int>::iterator i = sizes.begin(); i != sizes.end(); ++i) {
        combo->addItem(QString("%1").arg(*i));
        if (*i == defaultSize)
            combo->setCurrentIndex(combo->count() - 1);
    }
}

void
NotationConfigurationPage::apply()
{
    QSettings settings;
    settings.beginGroup(NotationViewConfigGroup);

    settings.setValue("notefont", m_untranslatedFont[m_font->currentIndex()]);
    settings.setValue("singlestaffnotesize",
                      m_singleStaffSize->currentText().toUInt());
    settings.setValue("multistaffnotesize",
                      m_multiStaffSize->currentText().toUInt());
    settings.setValue("textfont", m_textFont->getFont());
    settings.setValue("sansfont", m_sansFont->getFont());

    settings.setValue("layoutmode", m_layoutMode->currentIndex());
    settings.setValue("colourquantize", m_colourQuantize->isChecked());
    settings.setValue("showunknowns", m_showUnknowns->isChecked());
    settings.setValue("showinvisibles", m_showInvisibles->isChecked());
    settings.setValue("showranges", m_showRanges->isChecked());
    settings.setValue("showcollisions", m_showCollisions->isChecked());
    settings.setValue("shownotationheader",
                       m_showTrackHeaders->currentIndex());
    settings.setValue("style", m_untranslatedNoteStyle[m_noteStyle->currentIndex()]);
    settings.setValue("inserttype", m_insertType->currentIndex());
    settings.setValue("autobeam", m_autoBeam->isChecked());
    settings.setValue("autotieatbarlines", m_autoTieBarlines->isChecked());
    settings.setValue("collapse", m_collapseRests->isChecked());
    settings.setValue("pastetype", m_pasteType->currentIndex());
    settings.setValue("alwayspreview", m_preview->isChecked());
    settings.setValue("quickedit", m_quickEdit->isChecked());

    settings.setValue("accidentaloctavemode", m_accOctavePolicy->currentIndex());
    settings.setValue("accidentalbarmode", m_accBarPolicy->currentIndex());
    settings.setValue("keysigcancelmode", m_keySigCancelMode->currentIndex());

    settings.setValue("quantizemakeviable", m_splitAndTie->isChecked());

    settings.setValue("showrepeated", m_showRepeated->isChecked());
    settings.setValue("editrepeated", m_editRepeated->isChecked());
    settings.setValue("hideredundantclefkey",
                       m_hideRedundantClefKey->isChecked());
    settings.setValue("distributeverses",
                       m_distributeVerses->isChecked());

    settings.endGroup();
}

}
