Qt Utilities 6.6.2
Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models
settingsdialog.cpp
Go to the documentation of this file.
1#include "./settingsdialog.h"
2
3#include "./optioncategory.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
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(dialogStyle());
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
65{
66}
67
73{
74 m_tabBarAlwaysVisible = value;
75 if (m_currentCategory) {
76 m_ui->pagesTabWidget->tabBar()->setHidden(!value && m_currentCategory->pages().size() == 1);
77 }
78}
79
87{
88 return m_categoryModel->category(categoryIndex);
89}
90
98OptionPage *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
111void 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
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
168{
169 const bool hasSingleCategory = singleCategory != nullptr;
170 m_ui->filterLineEdit->setHidden(hasSingleCategory);
171 m_ui->categoriesListView->setHidden(hasSingleCategory);
172 m_ui->headingLabel->setHidden(hasSingleCategory);
173 if (hasSingleCategory) {
174 m_ui->filterLineEdit->clear();
175 categoryModel()->setCategories(QList<OptionCategory *>({ singleCategory }));
176 showCategory(singleCategory);
177 }
178}
179
183void SettingsDialog::updateTabWidget()
184{
185 if (!m_currentCategory) {
186 m_ui->pagesTabWidget->clear();
187 return;
188 }
189 m_ui->pagesTabWidget->setUpdatesEnabled(false);
190 const QString searchKeyWord = m_ui->filterLineEdit->text();
191 int index = 0, pageIndex = 0;
192 for (OptionPage *const page : m_currentCategory->pages()) {
193 if (page->matches(searchKeyWord)) {
194 QScrollArea *scrollArea;
195 if (index < m_ui->pagesTabWidget->count()) {
196 scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
197 scrollArea->takeWidget();
198 m_ui->pagesTabWidget->setTabText(index, page->widget()->windowTitle());
199 m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
200 } else {
201 scrollArea = new QScrollArea(m_ui->pagesTabWidget);
202 scrollArea->setFrameStyle(QFrame::NoFrame);
203 scrollArea->setBackgroundRole(QPalette::Base);
204 scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
205 scrollArea->setWidgetResizable(true);
206 m_ui->pagesTabWidget->addTab(scrollArea, page->widget()->windowTitle());
207 m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
208 }
209 if (page->widget()->layout()) {
210 page->widget()->layout()->setAlignment(Qt::AlignTop | Qt::AlignLeft);
211 }
212 scrollArea->setWidget(page->widget());
213 ++index;
214 }
215 if (pageIndex == m_currentCategory->currentIndex()) {
216 m_ui->pagesTabWidget->setCurrentIndex(pageIndex);
217 }
218 ++pageIndex;
219 }
220 while (index < m_ui->pagesTabWidget->count()) {
221 QScrollArea *const scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
222 scrollArea->takeWidget();
223 m_ui->pagesTabWidget->removeTab(index);
224 delete scrollArea;
225 }
226 m_ui->pagesTabWidget->tabBar()->setHidden(!m_tabBarAlwaysVisible && m_ui->pagesTabWidget->count() == 1);
227 m_ui->pagesTabWidget->setUpdatesEnabled(true);
228}
229
235bool SettingsDialog::apply()
236{
237 // apply each page in each category and gather error messages
238 QString errorMessage;
239 for (OptionCategory *const category : m_categoryModel->categories()) {
240 for (OptionPage *const page : category->pages()) {
241 if (!page->hasBeenShown() || page->apply()) {
242 // nothing to apply or no error
243 continue;
244 }
245
246 // add error message
247 if (errorMessage.isEmpty()) {
248 errorMessage = tr("<p><b>Errors occurred when applying changes:</b></p><ul>");
249 }
250 QStringList &errors = const_cast<OptionPage *>(page)->errors();
251 if (errors.isEmpty()) {
252 errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
253 % QStringLiteral("</i>: ") % tr("unknown error") % QStringLiteral("</li>"));
254 } else {
255 for (const QString &error : errors) {
256 errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
257 % QStringLiteral("</i>: ") % error % QStringLiteral("</li>"));
258 }
259 errors.clear();
260 }
261 }
262 }
263
264 // show error messages (if errors occurred)
265 if (!errorMessage.isEmpty()) {
266 errorMessage.append(QStringLiteral("</ul>"));
267 QMessageBox::warning(this, windowTitle(), errorMessage);
268 }
269
270 // return status
271 emit applied();
272 return errorMessage.isEmpty();
273}
274
279void SettingsDialog::reset()
280{
281 for (OptionCategory *const category : m_categoryModel->categories()) {
283 }
284 emit resetted();
285}
286} // namespace QtUtilities
The OptionCategoryFilterModel class is used by SettingsDialog to filter option categories.
The OptionCategoryModel class is used by SettingsDialog to store and display option categories.
OptionCategory * category(const QModelIndex &index) const
Returns the category for the specified model index.
QList< OptionCategory * > categories
void setCategories(const QList< OptionCategory * > &categories)
Sets the categories for the model.
The OptionCategory class wraps associated option pages.
void setCurrentIndex(int currentIndex)
Sets the current index.
int currentIndex() const
Returns the index of the currently shown page.
void resetAllPages()
Resets all pages.
QList< OptionPage * > pages
The OptionPage class is the base class for SettingsDialog pages.
Definition: optionpage.h:15
virtual bool apply()=0
Applies altered settings.
virtual void reset()=0
Discards altered settings and resets relevant widgets.
bool matches(const QString &searchKeyWord)
Returns whether the pages matches the specified searchKeyWord.
Definition: optionpage.cpp:61
bool hasBeenShown() const
Returns an indication whether the option page has been shown yet.
Definition: optionpage.h:56
QWidget * widget()
Returns the widget for the option page.
Definition: optionpage.cpp:45
The SettingsDialog class provides a framework for creating settings dialogs with different categories...
OptionCategoryModel * categoryModel()
Returns the category model used by the settings dialog to manage the categories.
void setTabBarAlwaysVisible(bool value)
Sets whether the tab bar is always visible.
OptionCategory * category(int categoryIndex) const
Returns the category for the specified categoryIndex.
SettingsDialog(QWidget *parent=nullptr)
Constructs a settings dialog.
void showCategory(OptionCategory *category)
Sets the current category to the specified category and updates the relevant widgets to show it.
OptionPage * page(int categoryIndex, int pageIndex) const
Returns the page for the specified categoryIndex and the specified pageIndex.
~SettingsDialog() override
Destroys the settings dialog.
void showEvent(QShowEvent *event) override
Resets all pages before the dialog is shown by the application.
void setSingleCategory(OptionCategory *singleCategory)
Enables single-category mode to show only the specified singleCategory.