Qt Utilities: settingsdialog/settingsdialog.cpp Source File

Qt Utilities 6.19.1 Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models

Loading...
Searching...
No Matches
settingsdialog.cpp
Go to the documentation of this file.
1#include "./settingsdialog.h"
2
3#include "./optioncategory.h"
4#include "./optioncategoryfiltermodel.h"
5#include "./optioncategorymodel.h"
6#include "./optionpage.h"
7
8#include "../misc/dialogutils.h"
9
10#include "ui_settingsdialog.h"
11
12#include <QItemSelectionModel>
13#include <QMessageBox>
14#include <QScrollArea>
15#include <QShowEvent>
16#include <QStringBuilder>
17
18namespace QtUtilities {
19
25
30SettingsDialog::SettingsDialog(QWidget *parent)
31 : QDialog(parent)
32 , m_ui(new Ui::SettingsDialog)
33 , m_categoryModel(new OptionCategoryModel(this))
34 , m_categoryFilterModel(new OptionCategoryFilterModel(this))
35 , m_currentCategory(nullptr)
36 , m_tabBarAlwaysVisible(true)
37{
38 m_ui->setupUi(this);
39 makeHeading(m_ui->headingLabel);
40 setStyleSheet(dialogStyleForPalette(palette()));
41
42 // setup models
43 m_categoryFilterModel->setSourceModel(m_categoryModel);
44 m_ui->categoriesListView->setModel(m_categoryFilterModel);
45
46 // connect signals and slots
47 // selection models
48 connect(m_ui->categoriesListView->selectionModel(), &QItemSelectionModel::currentChanged, this, &SettingsDialog::currentCategoryChanged);
49 // buttons
50 connect(m_ui->abortPushButton, &QPushButton::clicked, this, &SettingsDialog::reject);
51 connect(m_ui->applyPushButton, &QPushButton::clicked, this, &SettingsDialog::apply);
52 connect(m_ui->okPushButton, &QPushButton::clicked, this, &SettingsDialog::accept);
53 // dialog
54 connect(this, &SettingsDialog::accepted, this, &SettingsDialog::apply);
55 connect(this, &SettingsDialog::rejected, this, &SettingsDialog::reset);
56 // misc
57 connect(m_ui->filterLineEdit, &QLineEdit::textChanged, m_categoryFilterModel, &OptionCategoryFilterModel::setFilterFixedString);
58 connect(m_ui->filterLineEdit, &QLineEdit::textChanged, this, &SettingsDialog::updateTabWidget);
59}
60
64SettingsDialog::~SettingsDialog()
65{
66}
67
72 void SettingsDialog::setTabBarAlwaysVisible(bool value)
73{
74 m_tabBarAlwaysVisible = value;
75 if (m_currentCategory) {
76 m_ui->pagesTabWidget->tabBar()->setHidden(!value && m_currentCategory->pages().size() == 1);
77 }
78}
79
86 OptionCategory *SettingsDialog::category(int categoryIndex) const
87{
88 return m_categoryModel->category(categoryIndex);
89}
90
98 OptionPage *SettingsDialog::page(int categoryIndex, int pageIndex) const
99{
100 if (OptionCategory *const category = this->category(categoryIndex)) {
101 if (pageIndex < category->pages().length()) {
102 return category->pages()[pageIndex];
103 }
104 }
105 return nullptr;
106}
107
111 void SettingsDialog::showEvent(QShowEvent *event)
112{
113 if (event->spontaneous()) {
114 return;
115 }
116 for (OptionCategory *const category : m_categoryModel->categories()) {
117 for (OptionPage *const page : category->pages()) {
118 if (page->hasBeenShown()) {
119 page->reset();
120 }
121 }
122 }
123}
124
132void SettingsDialog::currentCategoryChanged(const QModelIndex &index)
133{
134 showCategory(m_categoryModel->category(m_categoryFilterModel->mapToSource(index)));
135}
136
141 void SettingsDialog::showCategory(OptionCategory *category)
142{
143 if (m_currentCategory) {
144 m_currentCategory->setCurrentIndex(m_ui->pagesTabWidget->currentIndex());
145 }
146 if (category) {
147 if (m_currentCategory != category) {
148 m_currentCategory = category;
149 m_ui->headingLabel->setText(category->displayName());
150 }
151 } else {
152 m_currentCategory = nullptr;
153 m_ui->headingLabel->setText(tr("No category selected"));
154 }
155 updateTabWidget();
156}
157
165 void SettingsDialog::translateCategory(OptionCategory *category, const std::function<QString()> &translator)
166{
167 category->setDisplayName(translator());
168 connect(this, &SettingsDialog::retranslationRequired, category,
169 [category, translator = std::move(translator)] { category->setDisplayName(translator()); });
170}
171
181 void SettingsDialog::setSingleCategory(OptionCategory *singleCategory)
182{
183 const bool hasSingleCategory = singleCategory != nullptr;
184 m_ui->filterLineEdit->setHidden(hasSingleCategory);
185 m_ui->categoriesListView->setHidden(hasSingleCategory);
186 m_ui->headingLabel->setHidden(hasSingleCategory);
187 if (hasSingleCategory) {
188 m_ui->filterLineEdit->clear();
189 categoryModel()->setCategories(QList<OptionCategory *>({ singleCategory }));
190 showCategory(singleCategory);
191 }
192}
193
197QWidget *SettingsDialog::cornerWidget(Qt::Corner corner) const
198{
199 return m_ui->pagesTabWidget->cornerWidget(corner);
200}
201
205 void SettingsDialog::setCornerWidget(QWidget *widget, Qt::Corner corner)
206{
207 m_ui->pagesTabWidget->setCornerWidget(widget, corner);
208}
209
213 void SettingsDialog::addHeadingWidget(QWidget *widget)
214{
215 m_ui->headingLayout->addWidget(widget);
216}
217
221 void SettingsDialog::selectPage(int categoryIndex, int pageIndex)
222{
223 m_categoryFilterModel->setFilterFixedString(QString());
224 m_ui->filterLineEdit->clear();
225 showCategory(m_categoryModel->category(categoryIndex));
226 m_ui->categoriesListView->selectionModel()->select(
227 m_categoryFilterModel->mapFromSource(m_categoryModel->index(categoryIndex)), QItemSelectionModel::ClearAndSelect);
228 m_ui->pagesTabWidget->setCurrentIndex(pageIndex);
229}
230
234void SettingsDialog::updateTabWidget()
235{
236 if (!m_currentCategory) {
237 m_ui->pagesTabWidget->clear();
238 return;
239 }
240 m_ui->pagesTabWidget->setUpdatesEnabled(false);
241
242 const auto searchKeyWord = m_ui->filterLineEdit->text();
243 int index = 0, pageIndex = 0;
244 for (OptionPage *const page : m_currentCategory->pages()) {
245 if (page->matches(searchKeyWord)) {
246 // ensure the page's widget has no parent anymore; otherwise windowIcon() might return the parent's icon
247 auto *const widget = page->widget();
248 widget->setParent(nullptr);
249
250 // add the widget to the tab widget within a scroll area
251 QScrollArea *scrollArea;
252 if (index < m_ui->pagesTabWidget->count()) {
253 scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
254 scrollArea->takeWidget();
255 m_ui->pagesTabWidget->setTabText(index, widget->windowTitle());
256 m_ui->pagesTabWidget->setTabIcon(index, widget->windowIcon());
257 } else {
258 scrollArea = new QScrollArea(m_ui->pagesTabWidget);
259 scrollArea->setFrameStyle(QFrame::NoFrame);
260 scrollArea->setBackgroundRole(QPalette::Base);
261 scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
262 scrollArea->setWidgetResizable(true);
263 m_ui->pagesTabWidget->addTab(scrollArea, widget->windowTitle());
264 m_ui->pagesTabWidget->setTabIcon(index, widget->windowIcon());
265 }
266 if (auto *const layout = widget->layout()) {
267 layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
268 }
269 scrollArea->setWidget(widget);
270 ++index;
271 }
272 if (pageIndex == m_currentCategory->currentIndex()) {
273 m_ui->pagesTabWidget->setCurrentIndex(pageIndex);
274 }
275 ++pageIndex;
276 }
277
278 // remove surplus tabs
279 while (index < m_ui->pagesTabWidget->count()) {
280 auto *const scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
281 scrollArea->takeWidget();
282 m_ui->pagesTabWidget->removeTab(index);
283 delete scrollArea;
284 }
285
286 m_ui->pagesTabWidget->tabBar()->setHidden(!m_tabBarAlwaysVisible && m_ui->pagesTabWidget->count() == 1);
287 m_ui->pagesTabWidget->setUpdatesEnabled(true);
288}
289
293void SettingsDialog::retranslateTabWidget()
294{
295 for (auto index = 0; index < m_ui->pagesTabWidget->count(); ++index) {
296 const auto *const scrollArea = qobject_cast<const QScrollArea *>(m_ui->pagesTabWidget->widget(index));
297 const auto *const widget = scrollArea->widget();
298 m_ui->pagesTabWidget->setTabText(index, widget->windowTitle());
299 }
300}
301
307 bool SettingsDialog::apply()
308{
309 // apply each page in each category and gather error messages
310 QString errorMessage;
311 for (OptionCategory *const category : m_categoryModel->categories()) {
312 for (OptionPage *const page : category->pages()) {
313 if (!page->hasBeenShown() || page->apply()) {
314 // nothing to apply or no error
315 continue;
316 }
317
318 // add error message
319 if (errorMessage.isEmpty()) {
320 errorMessage = tr("<p><b>Errors occurred when applying changes:</b></p><ul>");
321 }
322 QStringList &errors = const_cast<OptionPage *>(page)->errors();
323 if (errors.isEmpty()) {
324 errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
325 % QStringLiteral("</i>: ") % tr("unknown error") % QStringLiteral("</li>"));
326 } else {
327 for (const QString &error : errors) {
328 errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
329 % QStringLiteral("</i>: ") % error % QStringLiteral("</li>"));
330 }
331 errors.clear();
332 }
333 }
334 }
335
336 // show error messages (if errors occurred)
337 if (!errorMessage.isEmpty()) {
338 errorMessage.append(QStringLiteral("</ul>"));
339 QMessageBox::warning(this, windowTitle(), errorMessage);
340 }
341
342 // return status
343 emit applied();
344 return errorMessage.isEmpty();
345}
346
351 void SettingsDialog::reset()
352{
353 for (OptionCategory *const category : m_categoryModel->categories()) {
354 category->resetAllPages();
355 }
356 emit resetted();
357}
358
359 bool SettingsDialog::event(QEvent *event)
360{
361 const auto res = QDialog::event(event);
362 switch (event->type()) {
363 case QEvent::PaletteChange:
364 setStyleSheet(dialogStyleForPalette(palette()));
365 break;
366 case QEvent::LanguageChange:
367 m_ui->retranslateUi(this);
368 retranslateTabWidget();
369 emit retranslationRequired();
370 break;
371 default:;
372 }
373 return res;
374}
375
376} // namespace QtUtilities
QtUtilities::OptionCategoryFilterModel
The OptionCategoryFilterModel class is used by SettingsDialog to filter option categories.
Definition optioncategoryfiltermodel.h:8
QtUtilities::OptionCategoryModel
The OptionCategoryModel class is used by SettingsDialog to store and display option categories.
Definition optioncategorymodel.h:14
QtUtilities::OptionCategoryModel::category
OptionCategory * category(const QModelIndex &index) const
Returns the category for the specified model index.
Definition optioncategorymodel.h:52
QtUtilities::OptionCategoryModel::setCategories
void setCategories(const QList< OptionCategory * > &categories)
Sets the categories for the model.
Definition optioncategorymodel.cpp:52
QtUtilities::OptionCategory
The OptionCategory class wraps associated option pages.
Definition optioncategory.h:18
QtUtilities::OptionCategory::pages
QList< OptionPage * > pages
Definition optioncategory.h:22
QtUtilities::OptionPage
The OptionPage class is the base class for SettingsDialog pages.
Definition optionpage.h:34
QtUtilities::OptionPage::matches
bool matches(const QString &searchKeyWord)
Returns whether the pages matches the specified searchKeyWord.
Definition optionpage.cpp:64
QtUtilities::OptionPage::widget
QWidget * widget()
Returns the widget for the option page.
Definition optionpage.cpp:48
QtUtilities::SettingsDialog::categoryModel
OptionCategoryModel * categoryModel()
Returns the category model used by the settings dialog to manage the categories.
Definition settingsdialog.h:83
QtUtilities::SettingsDialog::applied
void applied()
QtUtilities::SettingsDialog::setTabBarAlwaysVisible
void setTabBarAlwaysVisible(bool value)
Sets whether the tab bar is always visible.
Definition settingsdialog.cpp:72
QtUtilities::SettingsDialog::category
OptionCategory * category(int categoryIndex) const
Returns the category for the specified categoryIndex.
Definition settingsdialog.cpp:86
QtUtilities::SettingsDialog::SettingsDialog
SettingsDialog(QWidget *parent=nullptr)
Constructs a settings dialog.
Definition settingsdialog.cpp:30
QtUtilities::SettingsDialog::retranslationRequired
void retranslationRequired()
QtUtilities::SettingsDialog::showCategory
void showCategory(OptionCategory *category)
Sets the current category to the specified category and updates the relevant widgets to show it.
Definition settingsdialog.cpp:141
QtUtilities::SettingsDialog::event
bool event(QEvent *event) override
Definition settingsdialog.cpp:359
QtUtilities::SettingsDialog::page
OptionPage * page(int categoryIndex, int pageIndex) const
Returns the page for the specified categoryIndex and the specified pageIndex.
Definition settingsdialog.cpp:98
QtUtilities::SettingsDialog::resetted
void resetted()
QtUtilities::SettingsDialog::reset
void reset()
Resets all changes.
Definition settingsdialog.cpp:351
QtUtilities::SettingsDialog::apply
bool apply()
Applies all changes.
Definition settingsdialog.cpp:307
QtUtilities::SettingsDialog::addHeadingWidget
void addHeadingWidget(QWidget *widget)
Adds a widget next to the heading.
Definition settingsdialog.cpp:213
QtUtilities::SettingsDialog::cornerWidget
QWidget * cornerWidget(Qt::Corner corner=Qt::TopRightCorner) const
Returns the tab-widget's corner widget.
Definition settingsdialog.cpp:197
QtUtilities::SettingsDialog::~SettingsDialog
~SettingsDialog() override
Destroys the settings dialog.
Definition settingsdialog.cpp:64
QtUtilities::SettingsDialog::translateCategory
void translateCategory(OptionCategory *category, const std::function< QString()> &translator)
Allows to set the categories display name so that it is retranslated as needed.
Definition settingsdialog.cpp:165
QtUtilities::SettingsDialog::showEvent
void showEvent(QShowEvent *event) override
Resets all pages before the dialog is shown by the application.
Definition settingsdialog.cpp:111
QtUtilities::SettingsDialog::setSingleCategory
void setSingleCategory(OptionCategory *singleCategory)
Enables single-category mode to show only the specified singleCategory.
Definition settingsdialog.cpp:181
QtUtilities::SettingsDialog::setCornerWidget
void setCornerWidget(QWidget *widget, Qt::Corner corner=Qt::TopRightCorner)
Sets the tab-widget's corner widget.
Definition settingsdialog.cpp:205
QtUtilities::SettingsDialog::selectPage
void selectPage(int categoryIndex, int pageIndex)
Selects the specified page within the specified category.
Definition settingsdialog.cpp:221
dialogutils.h
QtUtilities::Ui
Definition aboutdialog.h:14
QtUtilities
!
Definition trylocker.h:8
optioncategory.h
optioncategoryfiltermodel.h
optioncategorymodel.h
optionpage.h
settingsdialog.h