Qt Utilities  5.7.1
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  page->reset();
115  }
116  }
117  }
118 }
119 
127 void SettingsDialog::currentCategoryChanged(const QModelIndex &index)
128 {
129  showCategory(m_categoryModel->category(m_categoryFilterModel->mapToSource(index)));
130 }
131 
137 {
138  if (m_currentCategory) {
139  m_currentCategory->setCurrentIndex(m_ui->pagesTabWidget->currentIndex());
140  }
141  if (category) {
142  if (m_currentCategory != category) {
143  m_currentCategory = category;
144  m_ui->headingLabel->setText(category->displayName());
145  }
146  } else {
147  m_currentCategory = nullptr;
148  m_ui->headingLabel->setText(tr("No category selected"));
149  }
150  updateTabWidget();
151 }
152 
163 {
164  bool hasSingleCategory = singleCategory != nullptr;
165  m_ui->filterLineEdit->setHidden(hasSingleCategory);
166  m_ui->categoriesListView->setHidden(hasSingleCategory);
167  m_ui->headingLabel->setHidden(hasSingleCategory);
168  if (hasSingleCategory) {
169  m_ui->filterLineEdit->clear();
170  categoryModel()->setCategories(QList<OptionCategory *>() << singleCategory);
171  showCategory(singleCategory);
172  }
173 }
174 
178 void SettingsDialog::updateTabWidget()
179 {
180  if (m_currentCategory) {
181  m_ui->pagesTabWidget->setUpdatesEnabled(false);
182  const QString searchKeyWord = m_ui->filterLineEdit->text();
183  int index = 0, pageIndex = 0;
184  for (OptionPage *page : m_currentCategory->pages()) {
185  if (page->matches(searchKeyWord)) {
186  QScrollArea *scrollArea;
187  if (index < m_ui->pagesTabWidget->count()) {
188  scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
189  scrollArea->takeWidget();
190  m_ui->pagesTabWidget->setTabText(index, page->widget()->windowTitle());
191  m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
192  } else {
193  scrollArea = new QScrollArea(m_ui->pagesTabWidget);
194  scrollArea->setFrameStyle(QFrame::NoFrame);
195  scrollArea->setBackgroundRole(QPalette::Base);
196  scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
197  scrollArea->setWidgetResizable(true);
198  m_ui->pagesTabWidget->addTab(scrollArea, page->widget()->windowTitle());
199  m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
200  }
201  if (page->widget()->layout()) {
202  page->widget()->layout()->setAlignment(Qt::AlignTop | Qt::AlignLeft);
203  }
204  scrollArea->setWidget(page->widget());
205  ++index;
206  }
207  if (pageIndex == m_currentCategory->currentIndex()) {
208  m_ui->pagesTabWidget->setCurrentIndex(pageIndex);
209  }
210  ++pageIndex;
211  }
212  while (index < m_ui->pagesTabWidget->count()) {
213  QScrollArea *scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
214  scrollArea->takeWidget();
215  m_ui->pagesTabWidget->removeTab(index);
216  delete scrollArea;
217  }
218  m_ui->pagesTabWidget->tabBar()->setHidden(!m_tabBarAlwaysVisible && m_ui->pagesTabWidget->count() == 1);
219  m_ui->pagesTabWidget->setUpdatesEnabled(true);
220  } else {
221  m_ui->pagesTabWidget->clear();
222  }
223 }
224 
229 bool SettingsDialog::apply()
230 {
231  QString errorMessage;
232  for (OptionCategory *category : m_categoryModel->categories()) {
233  for (OptionPage *page : category->pages()) {
234  if (!page->apply()) {
235  if (errorMessage.isEmpty()) {
236  errorMessage = tr("<p><b>Errors occured when applying changes:</b></p><ul>");
237  }
238  QStringList &errors = const_cast<OptionPage *>(page)->errors();
239  if (errors.isEmpty()) {
240  errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
241  % QStringLiteral("</i>: ") % tr("unknonw error") % QStringLiteral("</li>"));
242  } else {
243  for (const QString &error : errors) {
244  errorMessage.append(QStringLiteral("<li><i>") % category->displayName() % QLatin1Char('/') % page->widget()->windowTitle()
245  % QStringLiteral("</i>: ") % error % QStringLiteral("</li>"));
246  }
247  errors.clear();
248  }
249  }
250  }
251  }
252  if (!errorMessage.isEmpty()) {
253  errorMessage.append(QStringLiteral("</ul>"));
254  QMessageBox::warning(this, windowTitle(), errorMessage);
255  }
256  emit applied();
257  return errorMessage.isEmpty();
258 }
259 
264 void SettingsDialog::reset()
265 {
266  for (OptionCategory *category : m_categoryModel->categories()) {
268  }
269  emit resetted();
270 }
271 }
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.
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.