Qt Utilities  5.10.0
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 
18 namespace Dialogs {
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  // setup models
42  m_categoryFilterModel->setSourceModel(m_categoryModel);
43  m_ui->categoriesListView->setModel(m_categoryFilterModel);
44  // connect signals and slots
45  // selection models
46  connect(m_ui->categoriesListView->selectionModel(), &QItemSelectionModel::currentChanged, this, &SettingsDialog::currentCategoryChanged);
47  // buttons
48  connect(m_ui->abortPushButton, &QPushButton::clicked, this, &SettingsDialog::reject);
49  connect(m_ui->applyPushButton, &QPushButton::clicked, this, &SettingsDialog::apply);
50  connect(m_ui->okPushButton, &QPushButton::clicked, this, &SettingsDialog::accept);
51  // dialog
52  connect(this, &SettingsDialog::accepted, this, &SettingsDialog::apply);
53  connect(this, &SettingsDialog::rejected, this, &SettingsDialog::reset);
54  // misc
55  connect(m_ui->filterLineEdit, &QLineEdit::textChanged, m_categoryFilterModel, &OptionCategoryFilterModel::setFilterFixedString);
56  connect(m_ui->filterLineEdit, &QLineEdit::textChanged, this, &SettingsDialog::updateTabWidget);
57 }
58 
63 {
64 }
65 
71 {
72  m_tabBarAlwaysVisible = value;
73  if (m_currentCategory) {
74  m_ui->pagesTabWidget->tabBar()->setHidden(!value && m_currentCategory->pages().size() == 1);
75  }
76 }
77 
84 OptionCategory *SettingsDialog::category(int categoryIndex) const
85 {
86  return m_categoryModel->category(categoryIndex);
87 }
88 
96 OptionPage *SettingsDialog::page(int categoryIndex, int pageIndex) const
97 {
98  if (OptionCategory *category = this->category(categoryIndex)) {
99  if (pageIndex < category->pages().length()) {
100  return category->pages()[pageIndex];
101  }
102  }
103  return nullptr;
104 }
105 
109 void SettingsDialog::showEvent(QShowEvent *event)
110 {
111  if (!event->spontaneous()) {
112  for (OptionCategory *category : m_categoryModel->categories()) {
113  for (OptionPage *page : category->pages()) {
114  if (page->hasBeenShown()) {
115  page->reset();
116  }
117  }
118  }
119  }
120 }
121 
129 void SettingsDialog::currentCategoryChanged(const QModelIndex &index)
130 {
131  showCategory(m_categoryModel->category(m_categoryFilterModel->mapToSource(index)));
132 }
133 
139 {
140  if (m_currentCategory) {
141  m_currentCategory->setCurrentIndex(m_ui->pagesTabWidget->currentIndex());
142  }
143  if (category) {
144  if (m_currentCategory != category) {
145  m_currentCategory = category;
146  m_ui->headingLabel->setText(category->displayName());
147  }
148  } else {
149  m_currentCategory = nullptr;
150  m_ui->headingLabel->setText(tr("No category selected"));
151  }
152  updateTabWidget();
153 }
154 
165 {
166  bool hasSingleCategory = singleCategory != nullptr;
167  m_ui->filterLineEdit->setHidden(hasSingleCategory);
168  m_ui->categoriesListView->setHidden(hasSingleCategory);
169  m_ui->headingLabel->setHidden(hasSingleCategory);
170  if (hasSingleCategory) {
171  m_ui->filterLineEdit->clear();
172  categoryModel()->setCategories(QList<OptionCategory *>() << singleCategory);
173  showCategory(singleCategory);
174  }
175 }
176 
180 void SettingsDialog::updateTabWidget()
181 {
182  if (m_currentCategory) {
183  m_ui->pagesTabWidget->setUpdatesEnabled(false);
184  const QString searchKeyWord = m_ui->filterLineEdit->text();
185  int index = 0, pageIndex = 0;
186  for (OptionPage *page : m_currentCategory->pages()) {
187  if (page->matches(searchKeyWord)) {
188  QScrollArea *scrollArea;
189  if (index < m_ui->pagesTabWidget->count()) {
190  scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
191  scrollArea->takeWidget();
192  m_ui->pagesTabWidget->setTabText(index, page->widget()->windowTitle());
193  m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
194  } else {
195  scrollArea = new QScrollArea(m_ui->pagesTabWidget);
196  scrollArea->setFrameStyle(QFrame::NoFrame);
197  scrollArea->setBackgroundRole(QPalette::Base);
198  scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
199  scrollArea->setWidgetResizable(true);
200  m_ui->pagesTabWidget->addTab(scrollArea, page->widget()->windowTitle());
201  m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
202  }
203  if (page->widget()->layout()) {
204  page->widget()->layout()->setAlignment(Qt::AlignTop | Qt::AlignLeft);
205  }
206  scrollArea->setWidget(page->widget());
207  ++index;
208  }
209  if (pageIndex == m_currentCategory->currentIndex()) {
210  m_ui->pagesTabWidget->setCurrentIndex(pageIndex);
211  }
212  ++pageIndex;
213  }
214  while (index < m_ui->pagesTabWidget->count()) {
215  QScrollArea *scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
216  scrollArea->takeWidget();
217  m_ui->pagesTabWidget->removeTab(index);
218  delete scrollArea;
219  }
220  m_ui->pagesTabWidget->tabBar()->setHidden(!m_tabBarAlwaysVisible && m_ui->pagesTabWidget->count() == 1);
221  m_ui->pagesTabWidget->setUpdatesEnabled(true);
222  } else {
223  m_ui->pagesTabWidget->clear();
224  }
225 }
226 
232 bool SettingsDialog::apply()
233 {
234  // apply each page in each category and gather error messages
235  QString errorMessage;
236  for (OptionCategory *category : m_categoryModel->categories()) {
237  for (OptionPage *page : category->pages()) {
238  if (!page->hasBeenShown() || page->apply()) {
239  // nothing to apply or no error
240  continue;
241  }
242 
243  // add error message
244  if (errorMessage.isEmpty()) {
245  errorMessage = tr("<p><b>Errors occured when applying changes:</b></p><ul>");
246  }
247  QStringList &errors = const_cast<OptionPage *>(page)->errors();
248  if (errors.isEmpty()) {
249  errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
250  % QStringLiteral("</i>: ") % tr("unknonw error") % QStringLiteral("</li>"));
251  } else {
252  for (const QString &error : errors) {
253  errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
254  % QStringLiteral("</i>: ") % error % QStringLiteral("</li>"));
255  }
256  errors.clear();
257  }
258  }
259  }
260 
261  // show error messages (if errors occured)
262  if (!errorMessage.isEmpty()) {
263  errorMessage.append(QStringLiteral("</ul>"));
264  QMessageBox::warning(this, windowTitle(), errorMessage);
265  }
266 
267  // return status
268  emit applied();
269  return errorMessage.isEmpty();
270 }
271 
276 void SettingsDialog::reset()
277 {
278  for (OptionCategory *category : m_categoryModel->categories()) {
280  }
281  emit resetted();
282 }
283 } // namespace Dialogs
QString displayName
Returns the display name of the category.
QWidget * widget()
Returns the widget for the option page.
Definition: optionpage.cpp:45
The OptionCategoryModel class is used by SettingsDialog to store and display option categories...
bool matches(const QString &searchKeyWord)
Returns whether the pages matches the specified searchKeyWord.
Definition: optionpage.cpp:61
The OptionCategory class wraps associated option pages.
The OptionPage class is the base class for SettingsDialog pages.
Definition: optionpage.h:15
void setCategories(const QList< OptionCategory *> categories)
Sets the categories for the model.
OptionPage * page(int categoryIndex, int pageIndex) const
Returns the page for the specified categoryIndex and the specified pageIndex.
OptionCategory * category(const QModelIndex &index) const
Returns the category for the specified model index.
OptionCategory * category(int categoryIndex) const
Returns the category for the specified categoryIndex.
const QList< OptionCategory * > & categories() const
Returns the categories.
~SettingsDialog()
Destroys the settings dialog.
void setSingleCategory(OptionCategory *singleCategory)
Enables single-category mode to show only the specified singleCategory.
bool hasBeenShown() const
Returns an indication whether the option page has been shown yet.
Definition: optionpage.h:56
Provides common dialogs such as AboutDialog, EnterPasswordDialog and SettingsDialog.
Definition: dialogutils.h:12
void resetAllPages()
Resets all pages.
int currentIndex() const
Returns the index of the currently shown page.
SettingsDialog(QWidget *parent=nullptr)
Constructs a settings dialog.
QList< OptionPage * > pages
Returns the assigned pages.
void showEvent(QShowEvent *event)
Resets all pages before the dialog is shown by the application.
void setTabBarAlwaysVisible(bool value)
Sets whether the tab bar is always visible.
virtual void reset()=0
Discards altered settings and resets relevant widgets.
virtual bool apply()=0
Applies altered settings.
The SettingsDialog class provides a framework for creating settings dialogs with different categories...
void showCategory(OptionCategory *category)
Sets the current category to the specified category and updates the relevant widgets to show it...
OptionCategoryModel * categoryModel()
Returns the category model used by the settings dialog to manage the categories.
void setCurrentIndex(int currentIndex)
Sets the current index.
The OptionCategoryFilterModel class is used by SettingsDialog to filter option categories.