File indexing completed on 2024-05-12 04:55:01

0001 /**
0002  * \file configdialog.cpp
0003  * 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 "configdialog.h"
0028 
0029 #include <QPushButton>
0030 #include <QLabel>
0031 #include <QString>
0032 #include <QCheckBox>
0033 #include <QComboBox>
0034 #include <QTabWidget>
0035 #include <QVBoxLayout>
0036 #include <QHBoxLayout>
0037 #include <QApplication>
0038 #include <QFontDialog>
0039 #include <QStyleFactory>
0040 #include <QTreeView>
0041 #include <QAction>
0042 #include <QHeaderView>
0043 #include "shortcutsmodel.h"
0044 #include "shortcutsdelegate.h"
0045 #include "contexthelp.h"
0046 #include "mainwindowconfig.h"
0047 #include "configdialogpages.h"
0048 
0049 /**
0050  * Constructor.
0051  *
0052  * @param platformTools platform specific tools
0053  * @param parent  parent widget
0054  * @param caption dialog title
0055  * @param shortcutsModel shortcuts model
0056  */
0057 ConfigDialog::ConfigDialog(IPlatformTools* platformTools, QWidget* parent,
0058                            const QString& caption, ShortcutsModel* shortcutsModel)
0059   : QDialog(parent),
0060     m_pages(new ConfigDialogPages(platformTools, this)),
0061     m_shortcutsModel(shortcutsModel)
0062 {
0063   setObjectName(QLatin1String("ConfigDialog"));
0064   setWindowTitle(caption);
0065   setSizeGripEnabled(true);
0066   auto topLayout = new QVBoxLayout(this);
0067   auto tabWidget = new QTabWidget(this);
0068   tabWidget->setUsesScrollButtons(false);
0069 
0070   tabWidget->addTab(m_pages->createTagsPage(), tr("&Tags"));
0071   tabWidget->addTab(m_pages->createFilesPage(), tr("&Files"));
0072   tabWidget->addTab(m_pages->createActionsPage(), tr("&User Actions"));
0073   tabWidget->addTab(m_pages->createNetworkPage(), tr("&Network"));
0074   tabWidget->addTab(m_pages->createPluginsPage(), tr("&Plugins"));
0075 
0076   {
0077     auto shortcutsPage = new QWidget;
0078     auto vlayout = new QVBoxLayout(shortcutsPage);
0079     m_shortcutsTreeView = new QTreeView;
0080     m_shortcutsTreeView->setSelectionMode(QAbstractItemView::NoSelection);
0081     m_shortcutsTreeView->setItemDelegateForColumn(
0082           ShortcutsModel::ShortcutColumn, new ShortcutsDelegate(this));
0083     vlayout->addWidget(m_shortcutsTreeView);
0084     m_shortcutAlreadyUsedLabel = new QLabel;
0085     vlayout->addWidget(m_shortcutAlreadyUsedLabel);
0086     tabWidget->addTab(shortcutsPage, tr("&Keyboard Shortcuts"));
0087 
0088     connect(m_shortcutsModel,
0089             &ShortcutsModel::shortcutAlreadyUsed,
0090             this,
0091             &ConfigDialog::warnAboutAlreadyUsedShortcut);
0092     connect(m_shortcutsModel,
0093             &ShortcutsModel::shortcutSet,
0094             this,
0095             &ConfigDialog::clearAlreadyUsedShortcutWarning);
0096     connect(this, &QDialog::rejected,
0097             m_shortcutsModel, &ShortcutsModel::discardChangedShortcuts);
0098     m_shortcutsTreeView->setModel(m_shortcutsModel);
0099     m_shortcutsTreeView->expandAll();
0100     m_shortcutsTreeView->resizeColumnToContents(ShortcutsModel::ActionColumn);
0101 #ifdef Q_OS_MAC
0102     m_shortcutsTreeView->header()->setStretchLastSection(false);
0103 #endif
0104   }
0105 
0106   {
0107     auto appearancePage = new QWidget;
0108     auto vlayout = new QVBoxLayout(appearancePage);
0109     auto fontStyleLayout = new QGridLayout;
0110 
0111     auto languageLabel = new QLabel(tr("&Language"), appearancePage);
0112     m_languageComboBox = new QComboBox(appearancePage);
0113     m_languageComboBox->addItem(tr("System"));
0114     const auto languages = MainWindowConfig::instance().availableLanguages();
0115     for (const auto& language : languages) {
0116       m_languageComboBox->addItem(language);
0117     }
0118     languageLabel->setBuddy(m_languageComboBox);
0119     fontStyleLayout->addWidget(languageLabel, 0, 0);
0120     fontStyleLayout->addWidget(m_languageComboBox, 0, 1);
0121     m_useApplicationFontCheckBox =
0122         new QCheckBox(tr("Use custom app&lication font"), appearancePage);
0123     m_applicationFontButton =
0124         new QPushButton(tr("A&pplication Font..."), appearancePage);
0125     m_useApplicationStyleCheckBox =
0126         new QCheckBox(tr("Use custom application &style"), appearancePage);
0127     m_applicationStyleComboBox = new QComboBox(appearancePage);
0128     fontStyleLayout->addWidget(m_useApplicationFontCheckBox, 1, 0);
0129     fontStyleLayout->addWidget(m_applicationFontButton, 1, 1);
0130     fontStyleLayout->addWidget(m_useApplicationStyleCheckBox, 2, 0);
0131     fontStyleLayout->addWidget(m_applicationStyleComboBox, 2, 1);
0132     m_applicationStyleComboBox->addItem(tr("Unknown"));
0133     m_applicationStyleComboBox->addItems(QStyleFactory::keys());
0134     connect(m_applicationFontButton, &QAbstractButton::clicked,
0135             this, &ConfigDialog::slotSelectFont);
0136 #if QT_VERSION >= 0x050f00
0137     connect(m_applicationStyleComboBox, &QComboBox::textActivated,
0138             this, &ConfigDialog::slotSelectStyle);
0139 #else
0140     connect(m_applicationStyleComboBox,
0141             static_cast<void (QComboBox::*)(const QString&)>(&QComboBox::activated),
0142             this, &ConfigDialog::slotSelectStyle);
0143 #endif
0144     connect(m_useApplicationFontCheckBox, &QAbstractButton::toggled,
0145             m_applicationFontButton, &QWidget::setEnabled);
0146     connect(m_useApplicationStyleCheckBox, &QAbstractButton::toggled,
0147             m_applicationStyleComboBox, &QWidget::setEnabled);
0148     vlayout->addLayout(fontStyleLayout);
0149 
0150     m_useNativeDialogsCheckBox =
0151         new QCheckBox(tr("Use native system file &dialogs"), appearancePage);
0152     vlayout->addWidget(m_useNativeDialogsCheckBox);
0153     auto vspacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
0154     vlayout->addItem(vspacer);
0155     tabWidget->addTab(appearancePage, tr("&Appearance"));
0156   }
0157   m_fontChanged = false;
0158   m_styleChanged = false;
0159 
0160   topLayout->addWidget(tabWidget);
0161   auto hlayout = new QHBoxLayout;
0162   auto hspacer = new QSpacerItem(16, 0, QSizePolicy::Expanding,
0163                                          QSizePolicy::Minimum);
0164   auto helpButton = new QPushButton(tr("&Help"), this);
0165   auto defaultsButton = new QPushButton(tr("Restore Defaults"), this);
0166   auto okButton = new QPushButton(tr("&OK"), this);
0167   auto cancelButton = new QPushButton(tr("&Cancel"), this);
0168   hlayout->addWidget(helpButton);
0169   hlayout->addWidget(defaultsButton);
0170   hlayout->addItem(hspacer);
0171   hlayout->addWidget(okButton);
0172   hlayout->addWidget(cancelButton);
0173   okButton->setDefault(true);
0174   connect(helpButton, &QAbstractButton::clicked, this, &ConfigDialog::slotHelp);
0175   connect(defaultsButton, &QAbstractButton::clicked,
0176           m_pages, &ConfigDialogPages::setDefaultConfig);
0177   connect(defaultsButton, &QAbstractButton::clicked,
0178           this, &ConfigDialog::setDefaultConfig);
0179   connect(okButton, &QAbstractButton::clicked, this, &QDialog::accept);
0180   connect(cancelButton, &QAbstractButton::clicked, this, &QDialog::reject);
0181   connect(cancelButton, &QAbstractButton::clicked,
0182           this, &ConfigDialog::slotRevertFontAndStyle);
0183   topLayout->addLayout(hlayout);
0184 }
0185 
0186 /**
0187  * Set values in dialog from current configuration.
0188  */
0189 void ConfigDialog::setConfig()
0190 {
0191   m_pages->setConfig();
0192 
0193   const MainWindowConfig& mainWindowConfig = MainWindowConfig::instance();
0194   setConfigs(mainWindowConfig);
0195 }
0196 
0197 /**
0198  * Set values in dialog from given configuration.
0199  */
0200 void ConfigDialog::setConfigs(const MainWindowConfig& mainWindowConfig)
0201 {
0202   const QString language = mainWindowConfig.language();
0203   m_languageComboBox->setCurrentText(
0204         language.isEmpty() ? tr("System") : language);
0205   m_useApplicationFontCheckBox->setChecked(mainWindowConfig.useFont());
0206   m_applicationFontButton->setEnabled(mainWindowConfig.useFont());
0207   if (mainWindowConfig.style().isEmpty()) {
0208     m_useApplicationStyleCheckBox->setChecked(false);
0209     m_applicationStyleComboBox->setEnabled(false);
0210     m_applicationStyleComboBox->setCurrentIndex(0);
0211   } else {
0212     m_useApplicationStyleCheckBox->setChecked(true);
0213     m_applicationStyleComboBox->setEnabled(true);
0214     if (int idx = m_applicationStyleComboBox->findText(mainWindowConfig.style());
0215         idx >= 0) {
0216       m_applicationStyleComboBox->setCurrentIndex(idx);
0217     }
0218   }
0219 
0220   // store current font and style
0221   m_font = QApplication::font();
0222   m_style = mainWindowConfig.style();
0223   m_fontChanged = false;
0224   m_styleChanged = false;
0225 
0226   m_useNativeDialogsCheckBox->setChecked(!mainWindowConfig.dontUseNativeDialogs());
0227 }
0228 
0229 /**
0230  * Get values from dialog and store them in the current configuration.
0231  */
0232 void ConfigDialog::getConfig() const
0233 {
0234   m_pages->getConfig();
0235 
0236   MainWindowConfig& mainWindowConfig = MainWindowConfig::instance();
0237   m_shortcutsModel->assignChangedShortcuts();
0238   const QString language = m_languageComboBox->currentText();
0239   mainWindowConfig.setLanguage(language != tr("System") ? language : QString());
0240   if (m_useApplicationFontCheckBox->isChecked()) {
0241     QFont font = QApplication::font();
0242     mainWindowConfig.setFontFamily(font.family());
0243     mainWindowConfig.setFontSize(font.pointSize());
0244     mainWindowConfig.setUseFont(true);
0245   } else {
0246     mainWindowConfig.setUseFont(false);
0247   }
0248   if (!m_useApplicationStyleCheckBox->isChecked() ||
0249       m_applicationStyleComboBox->currentIndex() == 0) {
0250     mainWindowConfig.setStyle(QLatin1String(""));
0251   } else {
0252     mainWindowConfig.setStyle(m_applicationStyleComboBox->currentText());
0253   }
0254   mainWindowConfig.setDontUseNativeDialogs(
0255       !m_useNativeDialogsCheckBox->isChecked());
0256 }
0257 
0258 /**
0259  * Show help.
0260  */
0261 void ConfigDialog::slotHelp()
0262 {
0263   ContextHelp::displayHelp(QLatin1String("configure-kid3"));
0264 }
0265 
0266 /**
0267  * Display warning that keyboard shortcut is already used.
0268  *
0269  * @param key string representation of key sequence
0270  * @param context context of action
0271  * @param action action using @a key
0272  */
0273 void ConfigDialog::warnAboutAlreadyUsedShortcut(
0274     const QString& key, const QString& context, const QAction* action)
0275 {
0276   QKeySequence keySequence =
0277       QKeySequence::fromString(key, QKeySequence::PortableText);
0278   m_shortcutAlreadyUsedLabel->setText(
0279         tr("The keyboard shortcut '%1' is already assigned to '%2'.")
0280         .arg(keySequence.toString(QKeySequence::NativeText),
0281              context + QLatin1Char('/') +
0282             (action ? action->text().remove(QLatin1Char('&'))
0283                     : QLatin1String("?"))));
0284 }
0285 
0286 /**
0287  * Clear warning about already used keyboard shortcut.
0288  */
0289 void ConfigDialog::clearAlreadyUsedShortcutWarning()
0290 {
0291   m_shortcutAlreadyUsedLabel->clear();
0292 }
0293 
0294 /**
0295  * Set additional configurations to their defaults.
0296  */
0297 void ConfigDialog::setDefaultConfig()
0298 {
0299   m_shortcutsModel->clearShortcuts();
0300   m_shortcutsTreeView->expandAll();
0301 
0302   MainWindowConfig mainWindowConfig;
0303   setConfigs(mainWindowConfig);
0304 }
0305 
0306 /**
0307  * Select custom application font.
0308  */
0309 void ConfigDialog::slotSelectFont()
0310 {
0311   bool ok;
0312   QFont font = QFontDialog::getFont(&ok, QApplication::font(), this);
0313   if (ok) {
0314     font.setWeight(QFont::Normal);
0315     font.setItalic(false);
0316     font.setBold(false);
0317     font.setUnderline(false);
0318     font.setOverline(false);
0319     font.setStrikeOut(false);
0320     QApplication::setFont(font);
0321     m_fontChanged = true;
0322   }
0323 }
0324 
0325 /**
0326  * Select custom application style.
0327  *
0328  * @param key style key
0329  */
0330 void ConfigDialog::slotSelectStyle(const QString& key)
0331 {
0332   if (key != tr("Unknown") &&
0333       QApplication::setStyle(key)) {
0334     m_styleChanged = true;
0335   }
0336 }
0337 
0338 /**
0339  * Revert the font and style to the values in the settings.
0340  */
0341 void ConfigDialog::slotRevertFontAndStyle()
0342 {
0343   if (m_fontChanged) {
0344     QApplication::setFont(m_font);
0345     m_fontChanged = false;
0346   }
0347   if (m_styleChanged && !m_style.isEmpty()) {
0348     QApplication::setStyle(m_style);
0349     m_styleChanged = false;
0350   }
0351 }