File indexing completed on 2025-02-23 04:34:16

0001 /**
0002  * \file configdialogpages.cpp
0003  * Pages for configuration dialog.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 17 Sep 2003
0008  *
0009  * Copyright (C) 2003-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #include "configdialogpages.h"
0028 #include <QLayout>
0029 #include <QPushButton>
0030 #include <QLabel>
0031 #include <QString>
0032 #include <QCheckBox>
0033 #include <QComboBox>
0034 #include <QLineEdit>
0035 #include <QTabWidget>
0036 #include <QListView>
0037 #include <QSpinBox>
0038 #include <QToolBox>
0039 #include <QVBoxLayout>
0040 #include <QHBoxLayout>
0041 #include <QFormLayout>
0042 #include <QGroupBox>
0043 #include <QStringListModel>
0044 #include <QStandardItemModel>
0045 #if defined HAVE_QTMULTIMEDIA && QT_VERSION >= 0x060200
0046 #include <QMediaDevices>
0047 #include <QAudioDevice>
0048 #endif
0049 #include "formatconfig.h"
0050 #include "filenameformatbox.h"
0051 #include "tagformatbox.h"
0052 #include "tablemodeledit.h"
0053 #include "tagconfig.h"
0054 #include "fileconfig.h"
0055 #include "useractionsconfig.h"
0056 #include "guiconfig.h"
0057 #include "networkconfig.h"
0058 #include "importconfig.h"
0059 #include "playlistconfig.h"
0060 #include "stringlistedit.h"
0061 #include "stringlisteditdialog.h"
0062 #include "configtable.h"
0063 #include "commandstablemodel.h"
0064 #include "checkablestringlistmodel.h"
0065 #include "starratingmappingsmodel.h"
0066 #include "fileproxymodel.h"
0067 #include "contexthelp.h"
0068 #include "frame.h"
0069 #include "iplatformtools.h"
0070 
0071 namespace {
0072 
0073 /**
0074  * @brief Get string representation of folder patterns.
0075  * @param folders folder patterns
0076  * @param asteriskIfEmpty if true "*" is returned if @a folders is empty
0077  * @return string representation of folder patterns.
0078  */
0079 QString folderPatternListToString(const QStringList& folders,
0080                                   bool asteriskIfEmpty = false)
0081 {
0082   QStringList patterns;
0083   QChar sep = QLatin1Char(' ');
0084   for (const QString& folder : folders) {
0085     if (QString pattern = folder.trimmed(); !pattern.isEmpty()) {
0086       if (pattern.contains(QLatin1Char(' '))) {
0087         sep = QLatin1Char(';');
0088       }
0089       patterns.append(pattern); // clazy:exclude=reserve-candidates
0090     }
0091   }
0092   patterns.removeDuplicates();
0093   if (patterns.isEmpty())
0094     return QLatin1String(asteriskIfEmpty ? "*" : "");
0095 
0096   // Keep semicolon to mark that space is not a separator.
0097   if (patterns.size() == 1 && sep == QLatin1Char(';'))
0098     return patterns.first() + sep;
0099 
0100   return patterns.join(sep);
0101 }
0102 
0103 /**
0104  * @brief Get folder patterns from string representation.
0105  * @param patterns string representation of folder patterns
0106  * @param asteriskIfEmpty if true an empty list is returned for "*"
0107  * @return folder pattern list.
0108  */
0109 QStringList folderPatternListFromString(const QString& patterns,
0110                                         bool asteriskIfEmpty = false)
0111 {
0112   if (asteriskIfEmpty && patterns == QLatin1String("*"))
0113     return QStringList();
0114 
0115   QStringList folders;
0116   const QChar sep = patterns.contains(QLatin1Char(';'))
0117       ? QLatin1Char(';') : QLatin1Char(' ');
0118   const auto patternList = patterns.split(sep);
0119   for (const QString& pattern : patternList) {
0120     if (QString folder = pattern.trimmed(); !folder.isEmpty()) {
0121       folders.append(folder); // clazy:exclude=reserve-candidates
0122     }
0123   }
0124 
0125   return folders;
0126 }
0127 
0128 }
0129 
0130 /**
0131  * Constructor.
0132  */
0133 ConfigDialogPages::ConfigDialogPages(IPlatformTools* platformTools,
0134                                      QObject* parent) : QObject(parent),
0135   m_platformTools(platformTools),
0136   m_loadLastOpenedFileCheckBox(nullptr), m_preserveTimeCheckBox(nullptr),
0137   m_markChangesCheckBox(nullptr), m_coverFileNameLineEdit(nullptr),
0138   m_nameFilterComboBox(nullptr), m_includeFoldersLineEdit(nullptr),
0139   m_excludeFoldersLineEdit(nullptr), m_showHiddenFilesCheckBox(nullptr),
0140   m_fileTextEncodingComboBox(nullptr),
0141   m_markTruncationsCheckBox(nullptr), m_textEncodingV1ComboBox(nullptr),
0142   m_totalNumTracksCheckBox(nullptr), m_commentNameComboBox(nullptr),
0143   m_pictureNameComboBox(nullptr), m_markOversizedPicturesCheckBox(nullptr),
0144   m_maximumPictureSizeSpinBox(nullptr), m_genreNotNumericCheckBox(nullptr),
0145   m_lowercaseId3ChunkCheckBox(nullptr),
0146   m_markStandardViolationsCheckBox(nullptr), m_textEncodingComboBox(nullptr),
0147   m_id3v2VersionComboBox(nullptr), m_trackNumberDigitsSpinBox(nullptr),
0148   m_fnFormatBox(nullptr), m_tagFormatBox(nullptr),
0149   m_onlyCustomGenresCheckBox(nullptr), m_genresEditModel(nullptr),
0150   m_customFramesEditModel(nullptr),
0151   m_quickAccessTagsModel(nullptr), m_starRatingMappingsModel(nullptr),
0152   m_trackNameComboBox(nullptr), m_playOnDoubleClickCheckBox(nullptr),
0153   m_selectFileOnPlayCheckBox(nullptr),
0154 #if defined HAVE_QTMULTIMEDIA && QT_VERSION >= 0x060200
0155   m_audioOutputComboBox(nullptr),
0156 #endif
0157   m_commandsTable(nullptr), m_commandsTableModel(nullptr),
0158   m_browserLineEdit(nullptr), m_proxyCheckBox(nullptr),
0159   m_proxyLineEdit(nullptr), m_proxyAuthenticationCheckBox(nullptr),
0160   m_proxyUserNameLineEdit(nullptr), m_proxyPasswordLineEdit(nullptr),
0161   m_enabledMetadataPluginsModel(nullptr), m_enabledPluginsModel(nullptr)
0162 {
0163 }
0164 
0165 /**
0166  * Create page with tags settings.
0167  * @return tags page.
0168  */
0169 QWidget* ConfigDialogPages::createTagsPage()
0170 {
0171   auto tagsPage = new QWidget;
0172   auto vlayout = new QVBoxLayout(tagsPage);
0173 
0174   auto tag1Page = new QWidget;
0175   auto tag1Layout = new QVBoxLayout(tag1Page);
0176   auto v1GroupBox = new QGroupBox(tr("ID3v1"), tag1Page);
0177   auto v1GroupBoxLayout = new QGridLayout(v1GroupBox);
0178   m_markTruncationsCheckBox = new QCheckBox(
0179         tr("&Mark truncated fields"), v1GroupBox);
0180   v1GroupBoxLayout->addWidget(m_markTruncationsCheckBox, 0, 0, 1, 2);
0181   auto textEncodingV1Label = new QLabel(tr("Text &encoding:"), v1GroupBox);
0182   m_textEncodingV1ComboBox = new QComboBox(v1GroupBox);
0183   m_textEncodingV1ComboBox->addItems(TagConfig::getTextCodecNames());
0184   m_textEncodingV1ComboBox->setSizePolicy(
0185         QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
0186   textEncodingV1Label->setBuddy(m_textEncodingV1ComboBox);
0187   v1GroupBoxLayout->addWidget(textEncodingV1Label, 1, 0);
0188   v1GroupBoxLayout->addWidget(m_textEncodingV1ComboBox, 1, 1);
0189   tag1Layout->addWidget(v1GroupBox);
0190   tag1Layout->addStretch();
0191 
0192   auto tag2Page = new QWidget;
0193   auto tag2Layout = new QHBoxLayout(tag2Page);
0194   auto tag2LeftLayout = new QVBoxLayout;
0195   auto v2GroupBox = new QGroupBox(tr("ID3v2"), tag2Page);
0196   auto v2GroupBoxLayout = new QGridLayout(v2GroupBox);
0197   m_totalNumTracksCheckBox = new QCheckBox(
0198         tr("Use &track/total number of tracks format"), v2GroupBox);
0199   v2GroupBoxLayout->addWidget(m_totalNumTracksCheckBox, 0, 0, 1, 2);
0200   auto trackNumberDigitsLabel = new QLabel(
0201         tr("Track number &digits:"), v2GroupBox);
0202   m_trackNumberDigitsSpinBox = new QSpinBox(v2GroupBox);
0203   m_trackNumberDigitsSpinBox->setMaximum(5);
0204   m_genreNotNumericCheckBox = new QCheckBox(
0205         tr("&Genre as text instead of numeric string"), v2GroupBox);
0206   m_lowercaseId3ChunkCheckBox = new QCheckBox(
0207         tr("&WAV files with lowercase id3 chunk"), v2GroupBox);
0208   m_markStandardViolationsCheckBox =
0209       new QCheckBox(tr("Mar&k standard violations"));
0210   auto textEncodingLabel = new QLabel(tr("Text &encoding:"), v2GroupBox);
0211   m_textEncodingComboBox = new QComboBox(v2GroupBox);
0212   m_textEncodingComboBox->addItems(TagConfig::getTextEncodingNames());
0213   m_textEncodingComboBox->setSizePolicy(
0214         QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
0215   textEncodingLabel->setBuddy(m_textEncodingComboBox);
0216   v2GroupBoxLayout->addWidget(m_genreNotNumericCheckBox, 1, 0, 1, 2);
0217   v2GroupBoxLayout->addWidget(m_lowercaseId3ChunkCheckBox, 2, 0, 1, 2);
0218   v2GroupBoxLayout->addWidget(m_markStandardViolationsCheckBox, 3, 0, 1, 2);
0219   v2GroupBoxLayout->addWidget(textEncodingLabel, 4, 0);
0220   v2GroupBoxLayout->addWidget(m_textEncodingComboBox, 4, 1);
0221   const TagConfig& tagCfg = TagConfig::instance();
0222   if (!(tagCfg.taggedFileFeatures() &
0223         (TaggedFile::TF_ID3v22 | TaggedFile::TF_ID3v23 | TaggedFile::TF_ID3v24))) {
0224     m_genreNotNumericCheckBox->hide();
0225     textEncodingLabel->hide();
0226     m_textEncodingComboBox->hide();
0227   }
0228   auto id3v2VersionLabel = new QLabel(tr("&Version used for new tags:"),
0229                                       v2GroupBox);
0230   m_id3v2VersionComboBox = new QComboBox(v2GroupBox);
0231   if (tagCfg.taggedFileFeatures() & TaggedFile::TF_ID3v23)
0232     m_id3v2VersionComboBox->addItem(tr("ID3v2.3.0"), TagConfig::ID3v2_3_0);
0233   if (tagCfg.taggedFileFeatures() & TaggedFile::TF_ID3v24)
0234     m_id3v2VersionComboBox->addItem(tr("ID3v2.4.0"), TagConfig::ID3v2_4_0);
0235   m_id3v2VersionComboBox->setSizePolicy(
0236         QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
0237   id3v2VersionLabel->setBuddy(m_id3v2VersionComboBox);
0238   v2GroupBoxLayout->addWidget(id3v2VersionLabel, 5, 0);
0239   v2GroupBoxLayout->addWidget(m_id3v2VersionComboBox, 5, 1);
0240   if (m_id3v2VersionComboBox->count() < 2) {
0241     id3v2VersionLabel->hide();
0242     m_id3v2VersionComboBox->hide();
0243   }
0244   trackNumberDigitsLabel->setBuddy(m_trackNumberDigitsSpinBox);
0245   v2GroupBoxLayout->addWidget(trackNumberDigitsLabel, 6, 0);
0246   v2GroupBoxLayout->addWidget(m_trackNumberDigitsSpinBox, 6, 1);
0247   tag2LeftLayout->addWidget(v2GroupBox);
0248   auto vorbisGroupBox = new QGroupBox(tr("Ogg/Vorbis"), tag2Page);
0249   auto commentNameLabel = new QLabel(tr("Co&mment field name:"),
0250                                      vorbisGroupBox);
0251   m_commentNameComboBox = new QComboBox(vorbisGroupBox);
0252   auto pictureNameLabel = new QLabel(tr("&Picture field name:"),
0253                                      vorbisGroupBox);
0254   m_pictureNameComboBox = new QComboBox(vorbisGroupBox);
0255   m_commentNameComboBox->setEditable(true);
0256   m_commentNameComboBox->addItems(TagConfig::getCommentNames());
0257   m_commentNameComboBox->setSizePolicy(
0258         QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
0259   commentNameLabel->setBuddy(m_commentNameComboBox);
0260   m_pictureNameComboBox->addItems(TagConfig::getPictureNames());
0261   m_pictureNameComboBox->setSizePolicy(
0262         QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
0263   pictureNameLabel->setBuddy(m_pictureNameComboBox);
0264   auto vorbisGroupBoxLayout = new QGridLayout(vorbisGroupBox);
0265   vorbisGroupBoxLayout->addWidget(commentNameLabel, 0, 0);
0266   vorbisGroupBoxLayout->addWidget(m_commentNameComboBox, 0, 1);
0267   vorbisGroupBoxLayout->addWidget(pictureNameLabel, 1, 0);
0268   vorbisGroupBoxLayout->addWidget(m_pictureNameComboBox, 1, 1);
0269   vorbisGroupBox->setLayout(vorbisGroupBoxLayout);
0270   tag2LeftLayout->addWidget(vorbisGroupBox);
0271   if (!(tagCfg.taggedFileFeatures() & TaggedFile::TF_OggPictures)) {
0272     vorbisGroupBox->hide();
0273   }
0274   auto pictureGroupBox = new QGroupBox(tr("Picture"), tag2Page);
0275   auto pictureGroupBoxLayout = new QHBoxLayout(pictureGroupBox);
0276   m_markOversizedPicturesCheckBox =
0277       new QCheckBox(tr("Mark if &larger than (bytes):"));
0278   m_maximumPictureSizeSpinBox = new QSpinBox;
0279   m_maximumPictureSizeSpinBox->setRange(0, INT_MAX);
0280   pictureGroupBoxLayout->addWidget(m_markOversizedPicturesCheckBox);
0281   pictureGroupBoxLayout->addWidget(m_maximumPictureSizeSpinBox);
0282   tag2LeftLayout->addWidget(pictureGroupBox);
0283   tag2LeftLayout->addStretch();
0284   tag2Layout->addLayout(tag2LeftLayout);
0285 
0286   auto tag2RightLayout = new QVBoxLayout;
0287   auto tag2RightToolBox = new QToolBox;
0288 
0289   auto genresWidget = new QWidget;
0290   m_onlyCustomGenresCheckBox = new QCheckBox(tr("&Show only custom genres"),
0291                                              genresWidget);
0292   m_genresEditModel = new QStringListModel(genresWidget);
0293   auto genresEdit = new StringListEdit(m_genresEditModel, genresWidget);
0294   auto vbox = new QVBoxLayout;
0295   vbox->addWidget(m_onlyCustomGenresCheckBox);
0296   vbox->addWidget(genresEdit);
0297   genresWidget->setLayout(vbox);
0298   tag2RightToolBox->addItem(genresWidget, tr("Cu&stom Genres"));
0299 
0300   auto customFramesWidget = new QWidget;
0301   m_customFramesEditModel = new QStringListModel(customFramesWidget);
0302   connect(m_customFramesEditModel, &QStringListModel::dataChanged,
0303           this, &ConfigDialogPages::onCustomFramesEditModelChanged);
0304   connect(m_customFramesEditModel, &QStringListModel::rowsRemoved,
0305           this, &ConfigDialogPages::onCustomFramesEditModelChanged);
0306   auto customFramesEdit = new StringListEdit(m_customFramesEditModel, customFramesWidget);
0307   auto customFramesVBox = new QVBoxLayout;
0308   customFramesVBox->addWidget(customFramesEdit);
0309   customFramesWidget->setLayout(customFramesVBox);
0310   tag2RightToolBox->addItem(customFramesWidget, tr("Custom F&rames"));
0311 
0312   auto quickAccessWidget = new QWidget;
0313   auto quickAccessTagsLayout = new QVBoxLayout(quickAccessWidget);
0314   auto quickAccessTagsListView = new QListView;
0315   m_quickAccessTagsModel = new QStandardItemModel(quickAccessWidget);
0316   quickAccessTagsListView->setModel(m_quickAccessTagsModel);
0317   quickAccessTagsListView->setAcceptDrops(true);
0318   quickAccessTagsListView->setDragEnabled(true);
0319   quickAccessTagsListView->setDragDropMode(QAbstractItemView::InternalMove);
0320   quickAccessTagsListView->setDragDropOverwriteMode(false);
0321   quickAccessTagsListView->setDefaultDropAction(Qt::MoveAction);
0322   quickAccessTagsListView->setDropIndicatorShown(true);
0323   quickAccessTagsLayout->addWidget(quickAccessTagsListView);
0324   auto reorderLabel =
0325       new QLabel(tr("Use drag and drop to reorder the items"));
0326   reorderLabel->setWordWrap(true);
0327   quickAccessTagsLayout->addWidget(reorderLabel);
0328   tag2RightToolBox->addItem(quickAccessWidget, tr("&Quick Access Frames"));
0329   tag2RightToolBox->setCurrentWidget(quickAccessWidget);
0330   tag2RightLayout->addWidget(tag2RightToolBox);
0331   tag2Layout->addLayout(tag2RightLayout);
0332 
0333   auto tag3Page = new QWidget;
0334   auto tag3Layout = new QVBoxLayout(tag3Page);
0335   auto riffGroupBox = new QGroupBox(tr("RIFF INFO"), tag3Page);
0336   auto trackNameLabel = new QLabel(tr("Track nu&mber field name:"),
0337                                    riffGroupBox);
0338   m_trackNameComboBox = new QComboBox(riffGroupBox);
0339   m_trackNameComboBox->setEditable(true);
0340   m_trackNameComboBox->addItems(TagConfig::getRiffTrackNames());
0341   m_trackNameComboBox->setSizePolicy(
0342         QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
0343   trackNameLabel->setBuddy(m_trackNameComboBox);
0344   auto riffGroupBoxLayout = new QGridLayout(riffGroupBox);
0345   riffGroupBoxLayout->addWidget(trackNameLabel, 0, 0);
0346   riffGroupBoxLayout->addWidget(m_trackNameComboBox, 0, 1);
0347   riffGroupBox->setLayout(riffGroupBoxLayout);
0348   tag3Layout->addWidget(riffGroupBox);
0349   tag3Layout->addStretch();
0350 
0351   auto tag1AndTag2Page = new QWidget;
0352   auto tag1AndTag2Layout = new QVBoxLayout(tag1AndTag2Page);
0353   QString tagFormatTitle(tr("&Tag Format"));
0354   m_tagFormatBox = new TagFormatBox(tagFormatTitle, tag1AndTag2Page);
0355   auto ratingGroupBox = new QGroupBox(tr("Rating"), tag1AndTag2Page);
0356   auto ratingLayout = new QVBoxLayout(ratingGroupBox);
0357   m_starRatingMappingsModel = new StarRatingMappingsModel(ratingGroupBox);
0358   auto ratingEdit = new TableModelEdit(m_starRatingMappingsModel);
0359   ratingLayout->addWidget(ratingEdit);
0360   tag1AndTag2Layout->addWidget(m_tagFormatBox);
0361   tag1AndTag2Layout->addWidget(ratingGroupBox);
0362 
0363   auto tagsTabWidget = new QTabWidget;
0364   if (tagCfg.taggedFileFeatures() & TaggedFile::TF_ID3v11) {
0365     tagsTabWidget->addTab(tag1Page, tr("Tag &1"));
0366   }
0367   tagsTabWidget->addTab(tag2Page, tr("Tag &2"));
0368   tagsTabWidget->addTab(tag3Page, tr("Tag &3"));
0369   tagsTabWidget->addTab(tag1AndTag2Page, tr("All Ta&gs"));
0370   tagsTabWidget->setCurrentIndex(1);
0371   vlayout->addWidget(tagsTabWidget);
0372   return tagsPage;
0373 }
0374 
0375 /**
0376  * Create page with files settings.
0377  * @return files page.
0378  */
0379 QWidget* ConfigDialogPages::createFilesPage()
0380 {
0381   auto filesPage = new QWidget;
0382   auto vlayout = new QVBoxLayout(filesPage);
0383   auto hlayout = new QHBoxLayout;
0384   auto leftLayout = new QVBoxLayout;
0385   auto rightLayout = new QVBoxLayout;
0386 
0387   auto startupGroupBox = new QGroupBox(tr("Startup"), filesPage);
0388   m_loadLastOpenedFileCheckBox = new QCheckBox(tr("&Load last-opened files"),
0389                                                startupGroupBox);
0390   auto startupLayout = new QVBoxLayout;
0391   startupLayout->addWidget(m_loadLastOpenedFileCheckBox);
0392   startupGroupBox->setLayout(startupLayout);
0393   leftLayout->addWidget(startupGroupBox);
0394   auto saveGroupBox = new QGroupBox(tr("Save"), filesPage);
0395   m_preserveTimeCheckBox = new QCheckBox(tr("&Preserve file timestamp"),
0396                                          saveGroupBox);
0397   m_markChangesCheckBox = new QCheckBox(tr("&Mark changes"), saveGroupBox);
0398   m_coverFileNameLineEdit = new QLineEdit(saveGroupBox);
0399   m_fileTextEncodingComboBox = new QComboBox(saveGroupBox);
0400   m_fileTextEncodingComboBox->addItems(FileConfig::getTextCodecNames());
0401   m_fileTextEncodingComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,
0402                                                         QSizePolicy::Minimum));
0403   auto formLayout = new QFormLayout;
0404   formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
0405   formLayout->addRow(m_preserveTimeCheckBox);
0406   formLayout->addRow(m_markChangesCheckBox);
0407   formLayout->addRow(tr("F&ilename for cover:"), m_coverFileNameLineEdit);
0408   formLayout->addRow(tr("Text &encoding (Export, Playlist):"),
0409                      m_fileTextEncodingComboBox);
0410   saveGroupBox->setLayout(formLayout);
0411   leftLayout->addWidget(saveGroupBox);
0412 
0413   auto fileListGroupBox = new QGroupBox(tr("File List"), filesPage);
0414   auto nameFilterLabel = new QLabel(tr("Filte&r:"), fileListGroupBox);
0415   m_nameFilterComboBox = new QComboBox(fileListGroupBox);
0416   m_nameFilterComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,
0417                                                   QSizePolicy::Minimum));
0418   QList<QPair<QString, QString> > filters = FileProxyModel::createNameFilters();
0419   for (auto it = filters.constBegin(); it != filters.constEnd(); ++it) {
0420     QString nameFilter = m_platformTools->fileDialogNameFilter({*it});
0421     m_nameFilterComboBox->addItem(it->first, nameFilter);
0422   }
0423   nameFilterLabel->setBuddy(m_nameFilterComboBox);
0424   auto includeFoldersLabel = new QLabel(tr("Inclu&de folders:"),
0425                                         fileListGroupBox);
0426   m_includeFoldersLineEdit = new QLineEdit(fileListGroupBox);
0427   includeFoldersLabel->setBuddy(m_includeFoldersLineEdit);
0428   auto excludeFoldersLabel = new QLabel(tr("E&xclude folders:"),
0429                                         fileListGroupBox);
0430   m_excludeFoldersLineEdit = new QLineEdit(fileListGroupBox);
0431   excludeFoldersLabel->setBuddy(m_excludeFoldersLineEdit);
0432   m_showHiddenFilesCheckBox = new QCheckBox(tr("&Show hidden files"),
0433                                             fileListGroupBox);
0434   auto fileListGroupBoxLayout = new QGridLayout(fileListGroupBox);
0435   fileListGroupBoxLayout->addWidget(nameFilterLabel, 0, 0);
0436   fileListGroupBoxLayout->addWidget(m_nameFilterComboBox, 0, 1);
0437   fileListGroupBoxLayout->addWidget(includeFoldersLabel, 1, 0);
0438   fileListGroupBoxLayout->addWidget(m_includeFoldersLineEdit, 1, 1);
0439   fileListGroupBoxLayout->addWidget(excludeFoldersLabel, 2, 0);
0440   fileListGroupBoxLayout->addWidget(m_excludeFoldersLineEdit, 2, 1);
0441   fileListGroupBoxLayout->addWidget(m_showHiddenFilesCheckBox, 3, 0, 1, 2);
0442   rightLayout->addWidget(fileListGroupBox);
0443 
0444   auto formatGroupBox = new QGroupBox(tr("Format"), filesPage);
0445   auto formatLayout = new QVBoxLayout(formatGroupBox);
0446   auto filenameTagFormatLayout = new QHBoxLayout;
0447   auto editFormatsFromTagButton =
0448           new QPushButton(tr("Filename from tag") + QLatin1String("..."));
0449   connect(editFormatsFromTagButton, &QPushButton::clicked,
0450           this, &ConfigDialogPages::editFormatsFromTag);
0451   filenameTagFormatLayout->addWidget(editFormatsFromTagButton);
0452   auto editFormatsToTagButton =
0453           new QPushButton(tr("Tag from filename") + QLatin1String("..."));
0454   connect(editFormatsToTagButton, &QPushButton::clicked,
0455           this, &ConfigDialogPages::editFormatsToTag);
0456   filenameTagFormatLayout->addWidget(editFormatsToTagButton);
0457   formatLayout->addLayout(filenameTagFormatLayout);
0458   auto editPlaylistFormatsButton =
0459           new QPushButton(tr("Playlist") + QLatin1String("..."));
0460   connect(editPlaylistFormatsButton, &QPushButton::clicked,
0461           this, &ConfigDialogPages::editPlaylistFormats);
0462   formatLayout->addWidget(editPlaylistFormatsButton);
0463   rightLayout->addWidget(formatGroupBox);
0464 
0465   rightLayout->addStretch();
0466 
0467   hlayout->addLayout(leftLayout);
0468   hlayout->addLayout(rightLayout);
0469   vlayout->addLayout(hlayout);
0470 
0471   QString fnFormatTitle(tr("&Filename Format"));
0472   m_fnFormatBox = new FilenameFormatBox(fnFormatTitle, filesPage);
0473   vlayout->addWidget(m_fnFormatBox, 1);
0474   return filesPage;
0475 }
0476 
0477 /**
0478  * Open dialog to edit "Filename from tag" formats.
0479  */
0480 void ConfigDialogPages::editFormatsFromTag()
0481 {
0482   QWidget* parentWindow = nullptr;
0483   if (auto button = qobject_cast<QPushButton*>(sender())) {
0484     parentWindow = button->window();
0485   }
0486   if (StringListEditDialog dialog(
0487       m_toFilenameFormats, tr("Filename from Tag"), parentWindow);
0488       dialog.exec() == QDialog::Accepted) {
0489     m_toFilenameFormats = dialog.stringList();
0490   }
0491 }
0492 
0493 /**
0494  * Open dialog to edit "Filename to tag" formats.
0495  */
0496 void ConfigDialogPages::editFormatsToTag()
0497 {
0498   QWidget* parentWindow = nullptr;
0499   if (auto button = qobject_cast<QPushButton*>(sender())) {
0500     parentWindow = button->window();
0501   }
0502   if (StringListEditDialog dialog(
0503       m_fromFilenameFormats, tr("Tag from Filename"), parentWindow);
0504       dialog.exec() == QDialog::Accepted) {
0505     m_fromFilenameFormats = dialog.stringList();
0506   }
0507 }
0508 
0509 /**
0510  * Open dialog to edit playlist file name formats.
0511  */
0512 void ConfigDialogPages::editPlaylistFormats()
0513 {
0514   QWidget* parentWindow = nullptr;
0515   if (auto button = qobject_cast<QPushButton*>(sender())) {
0516     parentWindow = button->window();
0517   }
0518   if (StringListEditDialog dialog(
0519       m_playlistFileNameFormats, tr("Playlist"), parentWindow);
0520       dialog.exec() == QDialog::Accepted) {
0521     m_playlistFileNameFormats = dialog.stringList();
0522   }
0523 }
0524 
0525 /**
0526  * Create page with actions settings.
0527  * @return actions page.
0528  */
0529 QWidget* ConfigDialogPages::createActionsPage()
0530 {
0531   auto actionsPage = new QWidget;
0532   auto vlayout = new QVBoxLayout(actionsPage);
0533   auto browserGroupBox = new QGroupBox(tr("Browser"), actionsPage);
0534   auto browserLabel = new QLabel(tr("Web &browser:"), browserGroupBox);
0535   m_browserLineEdit = new QLineEdit(browserGroupBox);
0536   browserLabel->setBuddy(m_browserLineEdit);
0537   auto hbox = new QHBoxLayout;
0538   hbox->addWidget(browserLabel);
0539   hbox->addWidget(m_browserLineEdit);
0540   browserGroupBox->setLayout(hbox);
0541   vlayout->addWidget(browserGroupBox);
0542 
0543   auto commandsGroupBox = new QGroupBox(tr("Context &Menu Commands"),
0544                                         actionsPage);
0545   m_playOnDoubleClickCheckBox =
0546       new QCheckBox(tr("&Play on double click"), commandsGroupBox);
0547   m_selectFileOnPlayCheckBox =
0548       new QCheckBox(tr("&Select file on play"), commandsGroupBox);
0549 #if defined HAVE_QTMULTIMEDIA && QT_VERSION >= 0x060200
0550   auto audioOutputLayout = new QHBoxLayout;
0551   QLabel* audioOutputLabel = new QLabel(tr("A&udio output:"), commandsGroupBox);
0552   m_audioOutputComboBox = new QComboBox(commandsGroupBox);
0553   m_audioOutputComboBox->addItem(tr("System"));
0554   const auto audioOutputs = QMediaDevices::audioOutputs();
0555   for (const auto& audioOutput : audioOutputs) {
0556     m_audioOutputComboBox->addItem(audioOutput.description(), audioOutput.id());
0557   }
0558   audioOutputLabel->setBuddy(m_audioOutputComboBox);
0559   audioOutputLayout->addWidget(audioOutputLabel);
0560   audioOutputLayout->addWidget(m_audioOutputComboBox, 1);
0561 #endif
0562   m_commandsTableModel = new CommandsTableModel(commandsGroupBox);
0563   m_commandsTable = new ConfigTable(m_commandsTableModel, commandsGroupBox);
0564   m_commandsTable->setHorizontalResizeModes(
0565     m_commandsTableModel->getHorizontalResizeModes());
0566   auto commandsLayout = new QVBoxLayout;
0567   commandsLayout->addWidget(m_playOnDoubleClickCheckBox);
0568   commandsLayout->addWidget(m_selectFileOnPlayCheckBox);
0569 #if defined HAVE_QTMULTIMEDIA && QT_VERSION >= 0x060200
0570   commandsLayout->addLayout(audioOutputLayout);
0571 #endif
0572   commandsLayout->addWidget(m_commandsTable);
0573   commandsGroupBox->setLayout(commandsLayout);
0574   vlayout->addWidget(commandsGroupBox);
0575   return actionsPage;
0576 }
0577 
0578 /**
0579  * Create page with network settings.
0580  * @return network page.
0581  */
0582 QWidget* ConfigDialogPages::createNetworkPage()
0583 {
0584   auto networkPage = new QWidget;
0585   auto vlayout = new QVBoxLayout(networkPage);
0586   auto proxyGroupBox = new QGroupBox(tr("Proxy"), networkPage);
0587   m_proxyCheckBox = new QCheckBox(tr("&Proxy:"), proxyGroupBox);
0588   m_proxyLineEdit = new QLineEdit(proxyGroupBox);
0589   m_proxyAuthenticationCheckBox = new QCheckBox(
0590         tr("&Use authentication with proxy"), proxyGroupBox);
0591   auto proxyUserNameLabel =
0592       new QLabel(tr("Proxy user &name:"), proxyGroupBox);
0593   m_proxyUserNameLineEdit = new QLineEdit(proxyGroupBox);
0594   proxyUserNameLabel->setBuddy(m_proxyUserNameLineEdit);
0595   auto proxyPasswordLabel =
0596       new QLabel(tr("Proxy pass&word:"), proxyGroupBox);
0597   m_proxyPasswordLineEdit = new QLineEdit(proxyGroupBox);
0598   proxyPasswordLabel->setBuddy(m_proxyPasswordLineEdit);
0599   m_proxyPasswordLineEdit->setEchoMode(QLineEdit::Password);
0600   auto vbox = new QVBoxLayout;
0601   auto proxyHbox = new QHBoxLayout;
0602   proxyHbox->addWidget(m_proxyCheckBox);
0603   proxyHbox->addWidget(m_proxyLineEdit);
0604   vbox->addLayout(proxyHbox);
0605   vbox->addWidget(m_proxyAuthenticationCheckBox);
0606   auto authLayout = new QGridLayout;
0607   authLayout->addWidget(proxyUserNameLabel, 0, 0);
0608   authLayout->addWidget(m_proxyUserNameLineEdit, 0, 1);
0609   authLayout->addWidget(proxyPasswordLabel, 1, 0);
0610   authLayout->addWidget(m_proxyPasswordLineEdit, 1, 1);
0611   vbox->addLayout(authLayout);
0612   proxyGroupBox->setLayout(vbox);
0613   vlayout->addWidget(proxyGroupBox);
0614 
0615   auto vspacer = new QSpacerItem(0, 0,
0616                                  QSizePolicy::Minimum, QSizePolicy::Expanding);
0617   vlayout->addItem(vspacer);
0618   return networkPage;
0619 }
0620 
0621 /**
0622  * Create page with plugins settings.
0623  * @return plugins page.
0624  */
0625 QWidget* ConfigDialogPages::createPluginsPage()
0626 {
0627   auto pluginsPage = new QWidget;
0628   auto vlayout = new QVBoxLayout(pluginsPage);
0629   auto metadataGroupBox = new QGroupBox(
0630         tr("&Metadata Plugins && Priority"), pluginsPage);
0631 
0632 
0633   auto metadataPluginsLayout = new QVBoxLayout(metadataGroupBox);
0634   m_enabledMetadataPluginsModel =
0635       new CheckableStringListModel(metadataGroupBox);
0636   auto metadataEdit =
0637       new StringListEdit(m_enabledMetadataPluginsModel, metadataGroupBox);
0638   metadataEdit->setEditingDisabled(true);
0639   metadataPluginsLayout->addWidget(metadataEdit);
0640   vlayout->addWidget(metadataGroupBox);
0641 
0642   auto pluginsGroupBox = new QGroupBox(tr("A&vailable Plugins"));
0643   auto pluginsLayout = new QVBoxLayout(pluginsGroupBox);
0644   auto pluginsListView = new QListView;
0645   pluginsListView->setSelectionMode(QAbstractItemView::NoSelection);
0646   m_enabledPluginsModel = new CheckableStringListModel(pluginsGroupBox);
0647   pluginsListView->setModel(m_enabledPluginsModel);
0648   pluginsLayout->addWidget(pluginsListView);
0649   vlayout->addWidget(pluginsGroupBox);
0650 
0651   vlayout->addStretch();
0652   vlayout->addWidget(
0653         new QLabel(tr("Changes take only effect after a restart!")));
0654   return pluginsPage;
0655 }
0656 
0657 /**
0658  * Set values in pages from default configuration.
0659  */
0660 void ConfigDialogPages::setDefaultConfig()
0661 {
0662   FilenameFormatConfig fnCfg;
0663   TagFormatConfig id3Cfg;
0664   TagConfig tagCfg;
0665   tagCfg.setAvailablePlugins(TagConfig::instance().availablePlugins());
0666   tagCfg.setTaggedFileFeatures(TagConfig::instance().taggedFileFeatures());
0667   tagCfg.setDefaultPluginOrder();
0668   FileConfig fileCfg;
0669   UserActionsConfig userActionsCfg;
0670   userActionsCfg.setDefaultUserActions();
0671   GuiConfig guiCfg;
0672   NetworkConfig networkCfg;
0673   networkCfg.setDefaultBrowser();
0674   ImportConfig importCfg;
0675   importCfg.setAvailablePlugins(ImportConfig::instance().availablePlugins());
0676   PlaylistConfig playlistCfg;
0677   setConfigs(fnCfg, id3Cfg, tagCfg, fileCfg, userActionsCfg, guiCfg, networkCfg,
0678             importCfg, playlistCfg);
0679 }
0680 
0681 /**
0682  * Set values in dialog from current configuration.
0683  */
0684 void ConfigDialogPages::setConfig()
0685 {
0686   const FormatConfig& fnCfg = FilenameFormatConfig::instance();
0687   const FormatConfig& id3Cfg = TagFormatConfig::instance();
0688   const TagConfig& tagCfg = TagConfig::instance();
0689   const FileConfig& fileCfg = FileConfig::instance();
0690   const UserActionsConfig& userActionsCfg = UserActionsConfig::instance();
0691   const GuiConfig& guiCfg = GuiConfig::instance();
0692   const NetworkConfig& networkCfg = NetworkConfig::instance();
0693   const ImportConfig& importCfg = ImportConfig::instance();
0694   const PlaylistConfig& playlistCfg = PlaylistConfig::instance();
0695   setConfigs(fnCfg, id3Cfg, tagCfg, fileCfg, userActionsCfg, guiCfg, networkCfg,
0696             importCfg, playlistCfg);
0697 }
0698 
0699 /**
0700  * Set values in dialog from given configurations.
0701  */
0702 void ConfigDialogPages::setConfigs(
0703     const FormatConfig& fnCfg, const FormatConfig& id3Cfg,
0704     const TagConfig& tagCfg, const FileConfig& fileCfg,
0705     const UserActionsConfig& userActionsCfg, const GuiConfig& guiCfg,
0706     const NetworkConfig& networkCfg, const ImportConfig& importCfg,
0707     const PlaylistConfig& playlistCfg)
0708 {
0709   m_fnFormatBox->fromFormatConfig(fnCfg);
0710   m_tagFormatBox->fromFormatConfig(id3Cfg);
0711   m_markTruncationsCheckBox->setChecked(tagCfg.markTruncations());
0712   m_totalNumTracksCheckBox->setChecked(tagCfg.enableTotalNumberOfTracks());
0713   m_loadLastOpenedFileCheckBox->setChecked(fileCfg.loadLastOpenedFile());
0714   m_preserveTimeCheckBox->setChecked(fileCfg.preserveTime());
0715   m_markChangesCheckBox->setChecked(fileCfg.markChanges());
0716   m_coverFileNameLineEdit->setText(fileCfg.defaultCoverFileName());
0717   m_nameFilterComboBox->setCurrentIndex(
0718         m_nameFilterComboBox->findData(fileCfg.nameFilter()));
0719   m_includeFoldersLineEdit->setText(
0720         folderPatternListToString(fileCfg.includeFolders(), true));
0721   m_excludeFoldersLineEdit->setText(
0722         folderPatternListToString(fileCfg.excludeFolders(), false));
0723   m_showHiddenFilesCheckBox->setChecked(fileCfg.showHiddenFiles());
0724   m_fileTextEncodingComboBox->setCurrentIndex(fileCfg.textEncodingIndex());
0725   m_toFilenameFormats = fileCfg.toFilenameFormats();
0726   m_fromFilenameFormats = fileCfg.fromFilenameFormats();
0727   m_playlistFileNameFormats = playlistCfg.fileNameFormats();
0728   m_onlyCustomGenresCheckBox->setChecked(tagCfg.onlyCustomGenres());
0729   m_genresEditModel->setStringList(tagCfg.customGenres());
0730   m_customFramesEditModel->setStringList(
0731         TagConfig::customFrameNamesToDisplayNames(tagCfg.customFrames()));
0732   m_starRatingMappingsModel->setMappings(tagCfg.starRatingMappings());
0733   setQuickAccessFramesConfig(tagCfg.quickAccessFrameOrder(), tagCfg.quickAccessFrames());
0734   m_commandsTableModel->setCommandList(userActionsCfg.contextMenuCommands());
0735   int idx = m_commentNameComboBox->findText(tagCfg.commentName());
0736   if (idx >= 0) {
0737     m_commentNameComboBox->setCurrentIndex(idx);
0738   } else {
0739     m_commentNameComboBox->addItem(tagCfg.commentName());
0740     m_commentNameComboBox->setCurrentIndex(m_commentNameComboBox->count() - 1);
0741   }
0742   m_pictureNameComboBox->setCurrentIndex(tagCfg.pictureNameIndex());
0743   m_genreNotNumericCheckBox->setChecked(tagCfg.genreNotNumeric());
0744   m_lowercaseId3ChunkCheckBox->setChecked(tagCfg.lowercaseId3RiffChunk());
0745   m_markStandardViolationsCheckBox->setChecked(tagCfg.markStandardViolations());
0746   m_textEncodingV1ComboBox->setCurrentIndex(tagCfg.textEncodingV1Index());
0747   m_textEncodingComboBox->setCurrentIndex(tagCfg.textEncoding());
0748   m_id3v2VersionComboBox->setCurrentIndex(
0749         m_id3v2VersionComboBox->findData(tagCfg.id3v2Version()));
0750   m_trackNumberDigitsSpinBox->setValue(tagCfg.trackNumberDigits());
0751   m_markOversizedPicturesCheckBox->setChecked(tagCfg.markOversizedPictures());
0752   m_maximumPictureSizeSpinBox->setValue(tagCfg.maximumPictureSize());
0753   idx = m_trackNameComboBox->findText(tagCfg.riffTrackName());
0754   if (idx >= 0) {
0755     m_trackNameComboBox->setCurrentIndex(idx);
0756   } else {
0757     m_trackNameComboBox->addItem(tagCfg.riffTrackName());
0758     m_trackNameComboBox->setCurrentIndex(m_trackNameComboBox->count() - 1);
0759   }
0760   m_browserLineEdit->setText(networkCfg.browser());
0761   m_playOnDoubleClickCheckBox->setChecked(guiCfg.playOnDoubleClick());
0762   m_selectFileOnPlayCheckBox->setChecked(guiCfg.selectFileOnPlayEnabled());
0763 #if defined HAVE_QTMULTIMEDIA && QT_VERSION >= 0x060200
0764   int audioOutputIndex = 0;
0765   QString text = guiCfg.preferredAudioOutput();
0766   if (text.endsWith(QLatin1Char(']'))) {
0767     int idPos = text.lastIndexOf(QLatin1Char('['));
0768     if (idPos != -1) {
0769       audioOutputIndex = m_audioOutputComboBox->findData(
0770           text.mid(idPos + 1, text.length() - idPos - 2).toLatin1());
0771       if (audioOutputIndex == -1) {
0772         audioOutputIndex = 0;
0773       }
0774     }
0775   }
0776   m_audioOutputComboBox->setCurrentIndex(audioOutputIndex);
0777 #endif
0778   m_proxyCheckBox->setChecked(networkCfg.useProxy());
0779   m_proxyLineEdit->setText(networkCfg.proxy());
0780   m_proxyAuthenticationCheckBox->setChecked(networkCfg.useProxyAuthentication());
0781   m_proxyUserNameLineEdit->setText(networkCfg.proxyUserName());
0782   m_proxyPasswordLineEdit->setText(networkCfg.proxyPassword());
0783 
0784   QStringList metadataPlugins;
0785   if (QStringList pluginOrder = tagCfg.pluginOrder(); !pluginOrder.isEmpty()) {
0786     for (int i = 0; i < pluginOrder.size(); ++i) {
0787       metadataPlugins.append(QString()); // clazy:exclude=reserve-candidates
0788     }
0789     const auto pluginNames = tagCfg.availablePlugins();
0790     for (const QString& pluginName : pluginNames) {
0791       if (int pluginIdx = pluginOrder.indexOf(pluginName); pluginIdx >= 0) {
0792         metadataPlugins[pluginIdx] = pluginName;
0793       } else {
0794         metadataPlugins.append(pluginName); // clazy:exclude=reserve-candidates
0795       }
0796     }
0797     metadataPlugins.removeAll(QString());
0798   } else {
0799     metadataPlugins = tagCfg.availablePlugins();
0800   }
0801   quint64 metadataPluginsMask = 0;
0802   quint64 mask = 1;
0803   QStringList disabledTagPlugins = tagCfg.disabledPlugins();
0804   for (int i = 0; i < metadataPlugins.size(); ++i, mask <<= 1) {
0805     if (!disabledTagPlugins.contains(metadataPlugins.at(i))) {
0806       metadataPluginsMask |= mask;
0807     }
0808   }
0809   m_enabledMetadataPluginsModel->setStringList(metadataPlugins);
0810   m_enabledMetadataPluginsModel->setBitMask(metadataPluginsMask);
0811 
0812   QStringList importPlugins = importCfg.availablePlugins();
0813   quint64 importPluginsMask = 0;
0814   mask = 1;
0815   QStringList disabledPlugins = importCfg.disabledPlugins();
0816   for (int i = 0; i < importPlugins.size(); ++i, mask <<= 1) {
0817     if (!disabledPlugins.contains(importPlugins.at(i))) {
0818       importPluginsMask |= mask;
0819     }
0820   }
0821   m_enabledPluginsModel->setStringList(importPlugins);
0822   m_enabledPluginsModel->setBitMask(importPluginsMask);
0823 
0824   if (!guiCfg.configWindowGeometry().isEmpty()) {
0825     if (QWidget* configDialog = qobject_cast<QWidget*>(parent())) {
0826       configDialog->restoreGeometry(guiCfg.configWindowGeometry());
0827     }
0828   }
0829 }
0830 
0831 /**
0832  * Get values from dialog and store them in the current configuration.
0833  */
0834 void ConfigDialogPages::getConfig() const
0835 {
0836   FormatConfig& fnCfg = FilenameFormatConfig::instance();
0837   FormatConfig& id3Cfg = TagFormatConfig::instance();
0838   TagConfig& tagCfg = TagConfig::instance();
0839   FileConfig& fileCfg = FileConfig::instance();
0840   UserActionsConfig& userActionsCfg = UserActionsConfig::instance();
0841   GuiConfig& guiCfg = GuiConfig::instance();
0842   NetworkConfig& networkCfg = NetworkConfig::instance();
0843   ImportConfig& importCfg = ImportConfig::instance();
0844   PlaylistConfig& playlistCfg = PlaylistConfig::instance();
0845 
0846   m_fnFormatBox->toFormatConfig(fnCfg);
0847   m_tagFormatBox->toFormatConfig(id3Cfg);
0848   tagCfg.setMarkTruncations(m_markTruncationsCheckBox->isChecked());
0849   tagCfg.setEnableTotalNumberOfTracks(m_totalNumTracksCheckBox->isChecked());
0850   fileCfg.setLoadLastOpenedFile(m_loadLastOpenedFileCheckBox->isChecked());
0851   fileCfg.setPreserveTime(m_preserveTimeCheckBox->isChecked());
0852   fileCfg.setMarkChanges(m_markChangesCheckBox->isChecked());
0853   fileCfg.setDefaultCoverFileName(m_coverFileNameLineEdit->text());
0854   fileCfg.setNameFilter(m_nameFilterComboBox->currentData().toString());
0855   fileCfg.setIncludeFolders(
0856         folderPatternListFromString(m_includeFoldersLineEdit->text(), true));
0857   fileCfg.setExcludeFolders(
0858         folderPatternListFromString(m_excludeFoldersLineEdit->text(), false));
0859   fileCfg.setShowHiddenFiles(m_showHiddenFilesCheckBox->isChecked());
0860   fileCfg.setTextEncodingIndex(m_fileTextEncodingComboBox->currentIndex());
0861   fileCfg.setToFilenameFormats(m_toFilenameFormats);
0862   fileCfg.setFromFilenameFormats(m_fromFilenameFormats);
0863   playlistCfg.setFileNameFormats(m_playlistFileNameFormats);
0864   tagCfg.setOnlyCustomGenres(m_onlyCustomGenresCheckBox->isChecked());
0865   tagCfg.setCustomGenres(m_genresEditModel->stringList());
0866   tagCfg.setCustomFrames(TagConfig::customFrameNamesFromDisplayNames(
0867                            m_customFramesEditModel->stringList()));
0868   tagCfg.setStarRatingMappings(m_starRatingMappingsModel->getMappings());
0869   QList<int> frameTypes;
0870   quint64 frameMask = 0;
0871   getQuickAccessFramesConfig(frameTypes, frameMask);
0872   tagCfg.setQuickAccessFrames(frameMask);
0873   tagCfg.setQuickAccessFrameOrder(frameTypes);
0874   userActionsCfg.setContextMenuCommands(m_commandsTableModel->getCommandList());
0875   tagCfg.setCommentName(m_commentNameComboBox->currentText());
0876   tagCfg.setPictureNameIndex(m_pictureNameComboBox->currentIndex());
0877   tagCfg.setGenreNotNumeric(m_genreNotNumericCheckBox->isChecked());
0878   tagCfg.setLowercaseId3RiffChunk(m_lowercaseId3ChunkCheckBox->isChecked());
0879   tagCfg.setMarkStandardViolations(m_markStandardViolationsCheckBox->isChecked());
0880   tagCfg.setTextEncodingV1Index(m_textEncodingV1ComboBox->currentIndex());
0881   tagCfg.setTextEncoding(m_textEncodingComboBox->currentIndex());
0882   tagCfg.setId3v2Version(m_id3v2VersionComboBox->itemData(
0883         m_id3v2VersionComboBox->currentIndex()).toInt());
0884   tagCfg.setTrackNumberDigits(m_trackNumberDigitsSpinBox->value());
0885   tagCfg.setMarkOversizedPictures(m_markOversizedPicturesCheckBox->isChecked());
0886   tagCfg.setMaximumPictureSize(m_maximumPictureSizeSpinBox->value());
0887   tagCfg.setRiffTrackName(m_trackNameComboBox->currentText());
0888   networkCfg.setBrowser(m_browserLineEdit->text());
0889   guiCfg.setPlayOnDoubleClick(m_playOnDoubleClickCheckBox->isChecked());
0890   guiCfg.setSelectFileOnPlayEnabled(m_selectFileOnPlayCheckBox->isChecked());
0891 #if defined HAVE_QTMULTIMEDIA && QT_VERSION >= 0x060200
0892   guiCfg.setPreferredAudioOutput(m_audioOutputComboBox->currentData().isNull()
0893     ? QString()
0894     : m_audioOutputComboBox->currentText() + QLatin1String(" [") +
0895         QLatin1String(m_audioOutputComboBox->currentData().toByteArray()) +
0896         QLatin1Char(']'));
0897 #endif
0898   networkCfg.setUseProxy(m_proxyCheckBox->isChecked());
0899   networkCfg.setProxy(m_proxyLineEdit->text());
0900   networkCfg.setUseProxyAuthentication(m_proxyAuthenticationCheckBox->isChecked());
0901   networkCfg.setProxyUserName(m_proxyUserNameLineEdit->text());
0902   networkCfg.setProxyPassword(m_proxyPasswordLineEdit->text());
0903 
0904   QStringList pluginOrder, disabledPlugins;
0905   const int numPlugins = m_enabledMetadataPluginsModel->rowCount();
0906   pluginOrder.reserve(numPlugins);
0907   for (int row = 0; row < numPlugins; ++row) {
0908     QString pluginName =
0909         m_enabledMetadataPluginsModel->index(row).data().toString();
0910     pluginOrder.append(pluginName);
0911     if (m_enabledMetadataPluginsModel->index(row).data(Qt::CheckStateRole)
0912         .toInt() != Qt::Checked) {
0913       disabledPlugins.append(pluginName); // clazy:exclude=reserve-candidates
0914     }
0915   }
0916   tagCfg.setPluginOrder(pluginOrder);
0917   tagCfg.setDisabledPlugins(disabledPlugins);
0918 
0919   disabledPlugins.clear();
0920   for (int row = 0; row < m_enabledPluginsModel->rowCount(); ++row) {
0921     if (m_enabledPluginsModel->index(row).data(Qt::CheckStateRole)
0922         .toInt() != Qt::Checked) {
0923       disabledPlugins.append(
0924             m_enabledPluginsModel->index(row).data().toString());
0925     }
0926   }
0927   importCfg.setDisabledPlugins(disabledPlugins);
0928 
0929   if (QWidget* configDialog = qobject_cast<QWidget*>(parent())) {
0930     guiCfg.setConfigWindowGeometry(configDialog->saveGeometry());
0931   }
0932 }
0933 
0934 void ConfigDialogPages::onCustomFramesEditModelChanged()
0935 {
0936   QList<int> frameTypes;
0937   quint64 frameMask = 0;
0938   getQuickAccessFramesConfig(frameTypes, frameMask);
0939   setQuickAccessFramesConfig(frameTypes, frameMask);
0940 }
0941 
0942 void ConfigDialogPages::getQuickAccessFramesConfig(QList<int>& frameTypes,
0943                                                    quint64& frameMask) const
0944 {
0945   const int numQuickAccessTags = m_quickAccessTagsModel->rowCount();
0946   QVariantList namesSelected;
0947   namesSelected.reserve(numQuickAccessTags);
0948   for (int row = 0; row < numQuickAccessTags; ++row) {
0949     QModelIndex index = m_quickAccessTagsModel->index(row, 0);
0950     auto name = index.data().toString();
0951     auto frameType = index.data(Qt::UserRole).toInt();
0952     auto selected = m_quickAccessTagsModel->data(
0953           index, Qt::CheckStateRole).toInt() == Qt::Checked;
0954     namesSelected.append(
0955           QVariantMap{{QLatin1String("name"), name},
0956                       {QLatin1String("type"), frameType},
0957                       {QLatin1String("selected"), selected}});
0958   }
0959   TagConfig::setQuickAccessFrameSelection(namesSelected, frameTypes, frameMask);
0960 }
0961 
0962 void ConfigDialogPages::setQuickAccessFramesConfig(const QList<int>& types,
0963                                                    quint64 frameMask)
0964 {
0965   const QVariantList namesSelected = TagConfig::getQuickAccessFrameSelection(
0966         types, frameMask, m_customFramesEditModel->stringList());
0967   m_quickAccessTagsModel->clear();
0968   for (const QVariant& var : namesSelected) {
0969     auto map = var.toMap();
0970     auto name = map.value(QLatin1String("name")).toString();
0971     auto frameType = map.value(QLatin1String("type")).toInt();
0972     auto selected = map.value(QLatin1String("selected")).toBool();
0973     auto item = new QStandardItem(name);
0974     item->setData(frameType, Qt::UserRole);
0975     item->setCheckable(true);
0976     item->setCheckState(selected ? Qt::Checked : Qt::Unchecked);
0977     item->setDropEnabled(false);
0978     m_quickAccessTagsModel->appendRow(item);
0979   }
0980 }