Qt Utilities  6.0.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 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 
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 
132 void 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 
183 void 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 
235 bool 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("unknonw 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 
279 void SettingsDialog::reset()
280 {
281  for (OptionCategory *const category : m_categoryModel->categories()) {
283  }
284  emit resetted();
285 }
286 } // namespace QtUtilities
settingsdialog.h
QtUtilities::SettingsDialog::showEvent
void showEvent(QShowEvent *event) override
Resets all pages before the dialog is shown by the application.
Definition: settingsdialog.cpp:111
optionpage.h
optioncategory.h
QtUtilities::OptionCategory::resetAllPages
void resetAllPages()
Resets all pages.
Definition: optioncategory.cpp:53
QtUtilities::OptionPage::hasBeenShown
bool hasBeenShown() const
Returns an indication whether the option page has been shown yet.
Definition: optionpage.h:56
optioncategoryfiltermodel.h
QtUtilities::SettingsDialog::category
OptionCategory * category(int categoryIndex) const
Returns the category for the specified categoryIndex.
Definition: settingsdialog.cpp:86
QtUtilities::OptionCategoryFilterModel
The OptionCategoryFilterModel class is used by SettingsDialog to filter option categories.
Definition: optioncategoryfiltermodel.h:8
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::~SettingsDialog
~SettingsDialog() override
Destroys the settings dialog.
Definition: settingsdialog.cpp:64
optioncategorymodel.h
QtUtilities::OptionPage::reset
virtual void reset()=0
Discards altered settings and resets relevant widgets.
QtUtilities::OptionCategoryModel::setCategories
void setCategories(const QList< OptionCategory * > &categories)
Sets the categories for the model.
Definition: optioncategorymodel.cpp:50
QtUtilities::SettingsDialog::applied
void applied()
QtUtilities::OptionCategoryModel::categories
QList< OptionCategory * > categories
Returns the categories.
Definition: optioncategorymodel.h:16
QtUtilities::OptionCategory::displayName
QString displayName
Returns the display name of the category.
Definition: optioncategory.h:16
QtUtilities::SettingsDialog::setSingleCategory
void setSingleCategory(OptionCategory *singleCategory)
Enables single-category mode to show only the specified singleCategory.
Definition: settingsdialog.cpp:167
QtUtilities
!
Definition: trylocker.h:8
QtUtilities::OptionCategory::pages
QList< OptionPage * > pages
Returns the assigned pages.
Definition: optioncategory.h:18
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::OptionCategory
The OptionCategory class wraps associated option pages.
Definition: optioncategory.h:14
QtUtilities::OptionPage::widget
QWidget * widget()
Returns the widget for the option page.
Definition: optionpage.cpp:45
QtUtilities::OptionPage::apply
virtual bool apply()=0
Applies altered settings.
QtUtilities::OptionCategory::setCurrentIndex
void setCurrentIndex(int currentIndex)
Sets the current index.
Definition: optioncategory.h:102
QtUtilities::OptionCategoryModel::category
OptionCategory * category(const QModelIndex &index) const
Returns the category for the specified model index.
Definition: optioncategorymodel.h:52
QtUtilities::OptionCategoryModel
The OptionCategoryModel class is used by SettingsDialog to store and display option categories.
Definition: optioncategorymodel.h:14
QtUtilities::OptionPage::matches
bool matches(const QString &searchKeyWord)
Returns whether the pages matches the specified searchKeyWord.
Definition: optionpage.cpp:61
QtUtilities::SettingsDialog::SettingsDialog
SettingsDialog(QWidget *parent=nullptr)
Constructs a settings dialog.
Definition: settingsdialog.cpp:30
QtUtilities::OptionPage
The OptionPage class is the base class for SettingsDialog pages.
Definition: optionpage.h:15
QtUtilities::OptionCategory::currentIndex
int currentIndex() const
Returns the index of the currently shown page.
Definition: optioncategory.h:93
QtUtilities::SettingsDialog
The SettingsDialog class provides a framework for creating settings dialogs with different categories...
Definition: settingsdialog.h:21
QtUtilities::SettingsDialog::categoryModel
OptionCategoryModel * categoryModel()
Returns the category model used by the settings dialog to manage the categories.
Definition: settingsdialog.h:74
QtUtilities::SettingsDialog::resetted
void resetted()
QtUtilities::SettingsDialog::setTabBarAlwaysVisible
void setTabBarAlwaysVisible(bool value)
Sets whether the tab bar is always visible.
Definition: settingsdialog.cpp:72