Qt Utilities  5.6.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 
5 #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 <QShowEvent>
14 #include <QScrollArea>
15 #include <QStringBuilder>
16 #include <QMessageBox>
17 
18 namespace Dialogs {
19 
30  QDialog(parent),
31  m_ui(new Ui::SettingsDialog),
32  m_categoryModel(new OptionCategoryModel(this)),
33  m_categoryFilterModel(new OptionCategoryFilterModel(this)),
34  m_currentCategory(nullptr),
35  m_tabBarAlwaysVisible(true)
36 {
37  m_ui->setupUi(this);
38  makeHeading(m_ui->headingLabel);
39  setStyleSheet(dialogStyle());
40  // setup models
41  m_categoryFilterModel->setSourceModel(m_categoryModel);
42  m_ui->categoriesListView->setModel(m_categoryFilterModel);
43  // connect signals and slots
44  // selection models
45  connect(m_ui->categoriesListView->selectionModel(), &QItemSelectionModel::currentChanged, this, &SettingsDialog::currentCategoryChanged);
46  // buttons
47  connect(m_ui->abortPushButton, &QPushButton::clicked, this, &SettingsDialog::reject);
48  connect(m_ui->applyPushButton, &QPushButton::clicked, this, &SettingsDialog::apply);
49  connect(m_ui->okPushButton, &QPushButton::clicked, this, &SettingsDialog::accept);
50  // dialog
51  connect(this, &SettingsDialog::accepted, this, &SettingsDialog::apply);
52  connect(this, &SettingsDialog::rejected, this, &SettingsDialog::reset);
53  // misc
54  connect(m_ui->filterLineEdit, &QLineEdit::textChanged, m_categoryFilterModel, &OptionCategoryFilterModel::setFilterFixedString);
55  connect(m_ui->filterLineEdit, &QLineEdit::textChanged, this, &SettingsDialog::updateTabWidget);
56 }
57 
62 {}
63 
69 {
70  m_tabBarAlwaysVisible = value;
71  if(m_currentCategory) {
72  m_ui->pagesTabWidget->tabBar()->setHidden(!value && m_currentCategory->pages().size() == 1);
73  }
74 }
75 
82 OptionCategory *SettingsDialog::category(int categoryIndex) const
83 {
84  return m_categoryModel->category(categoryIndex);
85 }
86 
93 OptionPage *SettingsDialog::page(int categoryIndex, int pageIndex) const
94 {
95  if(OptionCategory *category = this->category(categoryIndex)) {
96  if(pageIndex < category->pages().length()) {
97  return category->pages()[pageIndex];
98  }
99  }
100  return nullptr;
101 }
102 
106 void SettingsDialog::showEvent(QShowEvent *event)
107 {
108  if(!event->spontaneous()) {
109  for(OptionCategory *category : m_categoryModel->categories()) {
110  for(OptionPage *page : category->pages()) {
111  page->reset();
112  }
113  }
114  }
115 }
116 
122 void SettingsDialog::currentCategoryChanged(const QModelIndex &index)
123 {
124  showCategory(m_categoryModel->category(m_categoryFilterModel->mapToSource(index)));
125 }
126 
131 {
132  if(m_currentCategory) {
133  m_currentCategory->setCurrentIndex(m_ui->pagesTabWidget->currentIndex());
134  }
135  if(category) {
136  if(m_currentCategory != category) {
137  m_currentCategory = category;
138  m_ui->headingLabel->setText(category->displayName());
139  }
140  } else {
141  m_currentCategory = nullptr;
142  m_ui->headingLabel->setText(tr("No category selected"));
143  }
144  updateTabWidget();
145 }
146 
154 {
155  bool hasSingleCategory = singleCategory != nullptr;
156  m_ui->filterLineEdit->setHidden(hasSingleCategory);
157  m_ui->categoriesListView->setHidden(hasSingleCategory);
158  m_ui->headingLabel->setHidden(hasSingleCategory);
159  if(hasSingleCategory) {
160  m_ui->filterLineEdit->clear();
161  categoryModel()->setCategories(QList<OptionCategory *>() << singleCategory);
162  showCategory(singleCategory);
163  }
164 }
165 
169 void SettingsDialog::updateTabWidget()
170 {
171  if(m_currentCategory) {
172  m_ui->pagesTabWidget->setUpdatesEnabled(false);
173  const QString searchKeyWord = m_ui->filterLineEdit->text();
174  int index = 0, pageIndex = 0;
175  for(OptionPage *page : m_currentCategory->pages()) {
176  if(page->matches(searchKeyWord)) {
177  QScrollArea *scrollArea;
178  if(index < m_ui->pagesTabWidget->count()) {
179  scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
180  scrollArea->takeWidget();
181  m_ui->pagesTabWidget->setTabText(index, page->widget()->windowTitle());
182  m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
183  } else {
184  scrollArea = new QScrollArea(m_ui->pagesTabWidget);
185  scrollArea->setFrameStyle(QFrame::NoFrame);
186  scrollArea->setBackgroundRole(QPalette::Base);
187  scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
188  scrollArea->setWidgetResizable(true);
189  m_ui->pagesTabWidget->addTab(scrollArea, page->widget()->windowTitle());
190  m_ui->pagesTabWidget->setTabIcon(index, page->widget()->windowIcon());
191  }
192  if(page->widget()->layout()) {
193  page->widget()->layout()->setAlignment(Qt::AlignTop | Qt::AlignLeft);
194  }
195  scrollArea->setWidget(page->widget());
196  ++index;
197  }
198  if(pageIndex == m_currentCategory->currentIndex()) {
199  m_ui->pagesTabWidget->setCurrentIndex(pageIndex);
200  }
201  ++pageIndex;
202  }
203  while(index < m_ui->pagesTabWidget->count()) {
204  QScrollArea *scrollArea = qobject_cast<QScrollArea *>(m_ui->pagesTabWidget->widget(index));
205  scrollArea->takeWidget();
206  m_ui->pagesTabWidget->removeTab(index);
207  delete scrollArea;
208  }
209  m_ui->pagesTabWidget->tabBar()->setHidden(!m_tabBarAlwaysVisible && m_ui->pagesTabWidget->count() == 1);
210  m_ui->pagesTabWidget->setUpdatesEnabled(true);
211  } else {
212  m_ui->pagesTabWidget->clear();
213  }
214 }
215 
219 bool SettingsDialog::apply()
220 {
221  QString errorMessage;
222  for(OptionCategory *category : m_categoryModel->categories()) {
223  for(OptionPage *page : category->pages()) {
224  if(!page->apply()) {
225  if(errorMessage.isEmpty()) {
226  errorMessage = tr("<p><b>Errors occured when applying changes:</b></p><ul>");
227  }
228  QStringList &errors = const_cast<OptionPage *>(page)->errors();
229  if(errors.isEmpty()) {
230  errorMessage.append(QStringLiteral("<li><i>")
231  % category->displayName()
232  % QLatin1Char('/')
233  % page->widget()->windowTitle()
234  % QStringLiteral("</i>: ")
235  % tr("unknonw error")
236  % QStringLiteral("</li>"));
237  } else {
238  for(const QString &error : errors) {
239  errorMessage.append(QStringLiteral("<li><i>")
240  % category->displayName()
241  % QLatin1Char('/')
242  % page->widget()->windowTitle()
243  % QStringLiteral("</i>: ")
244  % error
245  % 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 
263 void SettingsDialog::reset()
264 {
265  for(OptionCategory *category : m_categoryModel->categories()) {
267  }
268  emit resetted();
269 }
270 
271 }
QString displayName
Returns the display name of the category.
QWidget * widget()
Returns the widget for the option page.
Definition: optionpage.cpp:42
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:58
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.
const QString QT_UTILITIES_EXPORT & dialogStyle()
Returns the stylesheet for dialogs and other windows used in my applications.
Definition: dialogutils.cpp:75
void setCurrentIndex(int currentIndex)
Sets the current index.
The OptionCategoryFilterModel class is used by SettingsDialog to filter option categories.