#include "./settingsdialog.h" #include "./optioncategorymodel.h" #include "./optioncategoryfiltermodel.h" #include "./optioncategory.h" #include "./optionpage.h" #include "../misc/dialogutils.h" #include "ui_settingsdialog.h" #include #include #include #include #include namespace Dialogs { /*! * \class Dialogs::SettingsDialog * \brief The SettingsDialog class provides a framework for creating settings dialogs with different categories and subcategories. */ /*! * \brief Constructs a settings dialog. * \param parent Specifies the parent widget. */ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), m_ui(new Ui::SettingsDialog), m_categoryModel(new OptionCategoryModel(this)), m_categoryFilterModel(new OptionCategoryFilterModel(this)), m_currentCategory(nullptr), m_tabBarAlwaysVisible(true), m_categoriesAlwaysVisible(true) { m_ui->setupUi(this); makeHeading(m_ui->headingLabel); setStyleSheet(dialogStyle()); // setup models m_categoryFilterModel->setSourceModel(m_categoryModel); m_ui->categoriesListView->setModel(m_categoryFilterModel); // connect signals and slots // selection models connect(m_ui->categoriesListView->selectionModel(), &QItemSelectionModel::currentChanged, this, &SettingsDialog::currentCategoryChanged); // buttons connect(m_ui->abortPushButton, &QPushButton::clicked, this, &SettingsDialog::reject); connect(m_ui->applyPushButton, &QPushButton::clicked, this, &SettingsDialog::apply); connect(m_ui->okPushButton, &QPushButton::clicked, this, &SettingsDialog::accept); // dialog connect(this, &SettingsDialog::accepted, this, &SettingsDialog::apply); connect(this, &SettingsDialog::rejected, this, &SettingsDialog::reset); // misc connect(m_ui->filterLineEdit, &QLineEdit::textChanged, m_categoryFilterModel, &OptionCategoryFilterModel::setFilterFixedString); connect(m_ui->filterLineEdit, &QLineEdit::textChanged, this, &SettingsDialog::updateTabWidget); } /*! * \brief Destroys the settings dialog. */ SettingsDialog::~SettingsDialog() {} /*! * \brief Sets whether the tab bar is always visible. * \sa SettingsDialog::isTabBarAlwaysVisible() */ void SettingsDialog::setTabBarAlwaysVisible(bool value) { m_tabBarAlwaysVisible = value; if(m_currentCategory) { m_ui->pagesTabWidget->tabBar()->setHidden(!value && m_currentCategory->pages().size() == 1); } } /*! * \brief Sets whether the category selection is always visible. * \sa SettingsDialog::areCategoriesAlwaysVisible() */ void SettingsDialog::setCategoriesAlwaysVisible(bool value) { m_categoriesAlwaysVisible = value; bool visible = value || m_categoryModel->rowCount(); m_ui->filterLineEdit->setVisible(visible); m_ui->categoriesListView->setVisible(visible); if(!visible) { m_ui->filterLineEdit->clear(); } } /*! * \brief Returns the category for the specified \a categoryIndex. * * The settings dialog keeps ownership over the returned category. * If no category exists for the specified index a null pointer is returned. */ OptionCategory *SettingsDialog::category(int categoryIndex) const { return m_categoryModel->category(categoryIndex); } /*! * \brief Returns the page for the specified \a categoryIndex and the specified \a pageIndex. * * The settings dialog keeps ownership over the returned category. * If no page for the specified indices a null pointer is returned. */ OptionPage *SettingsDialog::page(int categoryIndex, int pageIndex) const { if(OptionCategory *category = this->category(categoryIndex)) { if(pageIndex < category->pages().length()) { return category->pages()[pageIndex]; } } return nullptr; } /*! * \brief Resets all pages before the dialog is shown by the application. */ void SettingsDialog::showEvent(QShowEvent *event) { if(!event->spontaneous()) { for(OptionCategory *category : m_categoryModel->categories()) { for(OptionPage *page : category->pages()) { page->reset(); } } } } /*! * \brief Shows the selected category specified by its model \a index in the category model. * * This private slot is called when m_ui->categoriesListView->selectionModel()->currentChanged() is emitted. */ void SettingsDialog::currentCategoryChanged(const QModelIndex &index) { showCategory(m_categoryModel->category(m_categoryFilterModel->mapToSource(index))); } /*! * \brief Sets the current category to the specified \a category and updates the relevant widgets to show it. */ void SettingsDialog::showCategory(OptionCategory *category) { if(category) { if(m_currentCategory != category) { m_currentCategory = category; m_ui->headingLabel->setText(category->displayName()); } } else { m_currentCategory = nullptr; m_ui->headingLabel->setText(tr("No category selected")); } updateTabWidget(); } /*! * \brief Updates the tab widget to show the pages for the current category. */ void SettingsDialog::updateTabWidget() { if(m_currentCategory) { m_ui->pagesTabWidget->setUpdatesEnabled(false); QString searchKeyWord = m_ui->filterLineEdit->text(); int index = 0; for(OptionPage *page : m_currentCategory->pages()) { if(page->matches(searchKeyWord)) { QScrollArea *scrollArea; if(index < m_ui->pagesTabWidget->count()) { scrollArea = qobject_cast(m_ui->pagesTabWidget->widget(index)); scrollArea->takeWidget(); m_ui->pagesTabWidget->setTabText(index, page->widget()->windowTitle()); } else { scrollArea = new QScrollArea(m_ui->pagesTabWidget); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setBackgroundRole(QPalette::Base); scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); scrollArea->setWidgetResizable(true); m_ui->pagesTabWidget->addTab(scrollArea, page->widget()->windowTitle()); } if(page->widget()->layout()) { page->widget()->layout()->setAlignment(Qt::AlignTop | Qt::AlignLeft); } scrollArea->setWidget(page->widget()); } ++index; } while(index < m_ui->pagesTabWidget->count()) { QScrollArea *scrollArea = qobject_cast(m_ui->pagesTabWidget->widget(index)); scrollArea->takeWidget(); m_ui->pagesTabWidget->removeTab(index); delete scrollArea; } m_ui->pagesTabWidget->tabBar()->setHidden(!m_tabBarAlwaysVisible && m_ui->pagesTabWidget->count() == 1); m_ui->pagesTabWidget->setUpdatesEnabled(true); } else { m_ui->pagesTabWidget->clear(); } } /*! * \brief Applies all changes. Calls OptionCategory::applyAllPages() for each category. */ bool SettingsDialog::apply() { QString errorMessage; for(OptionCategory *category : m_categoryModel->categories()) { for(OptionPage *page : category->pages()) { if(!page->apply()) { if(errorMessage.isEmpty()) { errorMessage = tr("

Errors occured when applying changes.

    "); } if(const_cast(page)->errors().isEmpty()) { errorMessage.append(QStringLiteral("
  • ") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle() % QStringLiteral(": ") % tr("unknonw error") % QStringLiteral("
  • ")); } else { for(const QString &error : const_cast(page)->errors()) { errorMessage.append(QStringLiteral("
  • ") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle() % QStringLiteral(": ") % error % QStringLiteral("
  • ")); } } } } } if(!errorMessage.isEmpty()) { errorMessage.append(QStringLiteral("
")); QMessageBox::warning(this, windowTitle(), errorMessage); } emit applied(); return errorMessage.isEmpty(); } /*! * \brief Resets all changes. Calls OptionCategory::resetAllPages() for each category. */ void SettingsDialog::reset() { for(OptionCategory *category : m_categoryModel->categories()) { category->resetAllPages(); } emit resetted(); } }