qtutilities/settingsdialog/settingsdialog.cpp

284 lines
9.9 KiB
C++
Raw Normal View History

2015-09-06 20:19:21 +02:00
#include "./settingsdialog.h"
2015-09-06 15:36:04 +02:00
2015-09-06 20:19:21 +02:00
#include "./optioncategory.h"
2017-05-01 03:16:25 +02:00
#include "./optioncategoryfiltermodel.h"
#include "./optioncategorymodel.h"
2015-09-06 20:19:21 +02:00
#include "./optionpage.h"
2015-04-22 18:57:44 +02:00
#include "../misc/dialogutils.h"
2015-12-05 22:50:38 +01:00
#include "ui_settingsdialog.h"
2015-09-06 15:36:04 +02:00
2015-04-22 18:57:44 +02:00
#include <QItemSelectionModel>
2017-05-01 03:16:25 +02:00
#include <QMessageBox>
2015-04-22 18:57:44 +02:00
#include <QScrollArea>
2017-05-01 03:16:25 +02:00
#include <QShowEvent>
2016-04-04 14:49:40 +02:00
#include <QStringBuilder>
2015-04-22 18:57:44 +02:00
namespace Dialogs {
/*!
* \class Dialogs::SettingsDialog
2017-05-04 22:46:37 +02:00
* \brief The SettingsDialog class provides a framework for creating settings
* dialogs with different categories and subcategories.
2015-04-22 18:57:44 +02:00
*/
/*!
* \brief Constructs a settings dialog.
* \param parent Specifies the parent widget.
*/
2017-05-01 03:16:25 +02:00
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)
2015-04-22 18:57:44 +02:00
{
m_ui->setupUi(this);
makeHeading(m_ui->headingLabel);
setStyleSheet(dialogStyle());
2015-04-22 18:57:44 +02:00
// 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()
2017-05-01 03:16:25 +02:00
{
}
2015-04-22 18:57:44 +02:00
/*!
* \brief Sets whether the tab bar is always visible.
* \sa SettingsDialog::isTabBarAlwaysVisible()
*/
void SettingsDialog::setTabBarAlwaysVisible(bool value)
{
m_tabBarAlwaysVisible = value;
2017-05-01 03:16:25 +02:00
if (m_currentCategory) {
2015-04-22 18:57:44 +02:00
m_ui->pagesTabWidget->tabBar()->setHidden(!value && m_currentCategory->pages().size() == 1);
}
}
/*!
* \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);
}
/*!
2017-05-04 22:46:37 +02:00
* \brief Returns the page for the specified \a categoryIndex and the specified
* \a pageIndex.
2015-04-22 18:57:44 +02:00
*
* 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
{
2017-05-01 03:16:25 +02:00
if (OptionCategory *category = this->category(categoryIndex)) {
if (pageIndex < category->pages().length()) {
2015-04-22 18:57:44 +02:00
return category->pages()[pageIndex];
}
}
return nullptr;
}
/*!
* \brief Resets all pages before the dialog is shown by the application.
*/
void SettingsDialog::showEvent(QShowEvent *event)
{
2017-05-01 03:16:25 +02:00
if (!event->spontaneous()) {
for (OptionCategory *category : m_categoryModel->categories()) {
for (OptionPage *page : category->pages()) {
if (page->hasBeenShown()) {
page->reset();
}
2015-04-22 18:57:44 +02:00
}
}
}
}
/*!
2017-05-04 22:46:37 +02:00
* \brief Shows the selected category specified by its model \a index in the
* category filter model.
2015-04-22 18:57:44 +02:00
*
2017-05-04 22:46:37 +02:00
* This private slot is called when
* m_ui->categoriesListView->selectionModel()->currentChanged() is emitted.
2015-04-22 18:57:44 +02:00
*/
void SettingsDialog::currentCategoryChanged(const QModelIndex &index)
{
showCategory(m_categoryModel->category(m_categoryFilterModel->mapToSource(index)));
}
/*!
2017-05-04 22:46:37 +02:00
* \brief Sets the current category to the specified \a category and updates the
* relevant widgets to show it.
2015-04-22 18:57:44 +02:00
*/
void SettingsDialog::showCategory(OptionCategory *category)
{
2017-05-01 03:16:25 +02:00
if (m_currentCategory) {
m_currentCategory->setCurrentIndex(m_ui->pagesTabWidget->currentIndex());
}
2017-05-01 03:16:25 +02:00
if (category) {
if (m_currentCategory != category) {
2015-04-22 18:57:44 +02:00
m_currentCategory = category;
m_ui->headingLabel->setText(category->displayName());
2015-04-22 18:57:44 +02:00
}
} else {
m_currentCategory = nullptr;
m_ui->headingLabel->setText(tr("No category selected"));
2015-04-22 18:57:44 +02:00
}
updateTabWidget();
}
/*!
2017-05-04 22:46:37 +02:00
* \brief Enables *single-category mode* to show only the specified \a
* singleCategory.
* \remarks
2017-05-04 22:46:37 +02:00
* - In *single-category mode* category selection, filter and heading are
* hidden.
* - The *single-category mode* can be disabled again by setting \a
* singleCategory to nullptr.
*/
void SettingsDialog::setSingleCategory(OptionCategory *singleCategory)
{
bool hasSingleCategory = singleCategory != nullptr;
m_ui->filterLineEdit->setHidden(hasSingleCategory);
m_ui->categoriesListView->setHidden(hasSingleCategory);
m_ui->headingLabel->setHidden(hasSingleCategory);
2017-05-01 03:16:25 +02:00
if (hasSingleCategory) {
m_ui->filterLineEdit->clear();
categoryModel()->setCategories(QList<OptionCategory *>() << singleCategory);
showCategory(singleCategory);
}
}
2015-04-22 18:57:44 +02:00
/*!
* \brief Updates the tab widget to show the pages for the current category.
*/
void SettingsDialog::updateTabWidget()
{
2017-05-01 03:16:25 +02:00
if (m_currentCategory) {
2015-04-22 18:57:44 +02:00
m_ui->pagesTabWidget->setUpdatesEnabled(false);
2016-08-11 18:24:02 +02:00
const QString searchKeyWord = m_ui->filterLineEdit->text();
int index = 0, pageIndex = 0;
2017-05-01 03:16:25 +02:00
for (OptionPage *page : m_currentCategory->pages()) {
if (page->matches(searchKeyWord)) {
2015-04-22 18:57:44 +02:00
QScrollArea *scrollArea;
2017-05-01 03:16:25 +02:00
if (index < m_ui->pagesTabWidget->count()) {
2015-04-22 18:57:44 +02:00
scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
scrollArea->takeWidget();
2016-04-04 14:49:40 +02:00
m_ui->pagesTabWidget->setTabText(index, page->widget()->windowTitle());
2016-08-31 23:38:35 +02:00
m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
2015-04-22 18:57:44 +02:00
} else {
scrollArea = new QScrollArea(m_ui->pagesTabWidget);
scrollArea->setFrameStyle(QFrame::NoFrame);
scrollArea->setBackgroundRole(QPalette::Base);
scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
scrollArea->setWidgetResizable(true);
2016-04-04 14:49:40 +02:00
m_ui->pagesTabWidget->addTab(scrollArea, page->widget()->windowTitle());
2016-08-31 23:38:35 +02:00
m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
2015-04-22 18:57:44 +02:00
}
2017-05-01 03:16:25 +02:00
if (page->widget()->layout()) {
2015-04-22 18:57:44 +02:00
page->widget()->layout()->setAlignment(Qt::AlignTop | Qt::AlignLeft);
}
scrollArea->setWidget(page->widget());
2016-08-11 18:24:02 +02:00
++index;
2015-04-22 18:57:44 +02:00
}
2017-05-01 03:16:25 +02:00
if (pageIndex == m_currentCategory->currentIndex()) {
m_ui->pagesTabWidget->setCurrentIndex(pageIndex);
}
++pageIndex;
2015-04-22 18:57:44 +02:00
}
2017-05-01 03:16:25 +02:00
while (index < m_ui->pagesTabWidget->count()) {
2015-04-22 18:57:44 +02:00
QScrollArea *scrollArea = qobject_cast<QScrollArea *>(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.
* \remarks Pages which have not been shown yet must have not been initialized anyways
* and hence are skipped.
2015-04-22 18:57:44 +02:00
*/
bool SettingsDialog::apply()
{
// apply each page in each category and gather error messages
2016-04-04 14:49:40 +02:00
QString errorMessage;
2017-05-01 03:16:25 +02:00
for (OptionCategory *category : m_categoryModel->categories()) {
for (OptionPage *page : category->pages()) {
if (!page->hasBeenShown() || page->apply()) {
// nothing to apply or no error
continue;
}
// add error message
if (errorMessage.isEmpty()) {
2018-07-23 14:45:16 +02:00
errorMessage = tr("<p><b>Errors occurred when applying changes:</b></p><ul>");
}
QStringList &errors = const_cast<OptionPage *>(page)->errors();
if (errors.isEmpty()) {
errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
% QStringLiteral("</i>: ") % tr("unknonw error") % QStringLiteral("</li>"));
} else {
for (const QString &error : errors) {
2017-05-01 03:16:25 +02:00
errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
% QStringLiteral("</i>: ") % error % QStringLiteral("</li>"));
2016-04-04 14:49:40 +02:00
}
errors.clear();
2015-04-22 18:57:44 +02:00
}
}
}
2018-07-23 14:45:16 +02:00
// show error messages (if errors occurred)
2017-05-01 03:16:25 +02:00
if (!errorMessage.isEmpty()) {
2016-04-04 14:49:40 +02:00
errorMessage.append(QStringLiteral("</ul>"));
QMessageBox::warning(this, windowTitle(), errorMessage);
}
// return status
2015-04-22 18:57:44 +02:00
emit applied();
2016-04-04 14:49:40 +02:00
return errorMessage.isEmpty();
2015-04-22 18:57:44 +02:00
}
/*!
2017-05-04 22:46:37 +02:00
* \brief Resets all changes. Calls OptionCategory::resetAllPages() for each
* category.
2015-04-22 18:57:44 +02:00
*/
void SettingsDialog::reset()
{
2017-05-01 03:16:25 +02:00
for (OptionCategory *category : m_categoryModel->categories()) {
2015-04-22 18:57:44 +02:00
category->resetAllPages();
}
emit resetted();
}
} // namespace Dialogs