dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
settingsdialog.cpp
Go to the documentation of this file.
1 
13 /*
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  * for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, see <http://www.gnu.org/licenses/>
26  */
27 
28 #include "settingsdialog.h"
29 
31 #include "icore.h"
34 //#include "coreimpl.h"
35 
36 #include <QtCore/QDebug>
37 #include <QtCore/QSettings>
38 #include <QHeaderView>
39 #include <QLabel>
40 #include <QPushButton>
41 
42 namespace {
43 struct PageData
44 {
45  int index;
46  QString category;
47  QString id;
48 };
49 }
50 
51 Q_DECLARE_METATYPE(::PageData)
52 
53 using namespace Core;
54 using namespace Core::Internal;
55 
56 // Helpers to sort by category. id
57 bool optionsPageLessThan(const IOptionsPage *p1, const IOptionsPage *p2)
58 {
59  const UAVGadgetOptionsPageDecorator *gp1 =
60  qobject_cast<const UAVGadgetOptionsPageDecorator *>(p1);
61  const UAVGadgetOptionsPageDecorator *gp2 =
62  qobject_cast<const UAVGadgetOptionsPageDecorator *>(p2);
63  if (gp1 && (gp2 == NULL))
64  return false;
65 
66  if (gp2 && (gp1 == NULL))
67  return true;
68 
69  if (const int cc = QString::localeAwareCompare(p1->trCategory(), p2->trCategory()))
70  return cc < 0;
71 
72  return QString::localeAwareCompare(p1->trName(), p2->trName()) < 0;
73 }
74 
75 static inline QList<Core::IOptionsPage *> sortedOptionsPages()
76 {
78  ExtensionSystem::PluginManager::instance()->getObjects<IOptionsPage>();
79  std::stable_sort(rc.begin(), rc.end(), optionsPageLessThan);
80  return rc;
81 }
82 
83 SettingsDialog::SettingsDialog(QWidget *parent, const QString &categoryId, const QString &pageId)
84  : QDialog(parent)
85  , m_applied(false)
86  , m_windowWidth(0)
87  , m_windowHeight(0)
88 {
89  setupUi(this);
90 #ifdef Q_OS_MAC
91  setWindowTitle(tr("Preferences"));
92 #else
93  setWindowTitle(tr("Options"));
94 #endif
95  QString initialCategory = categoryId;
96  QString initialPage = pageId;
97  qDebug() << "SettingsDialog constructor initial category: " << initialCategory
98  << ", initial page: " << initialPage;
99  if (initialCategory.isEmpty() && initialPage.isEmpty()) {
100  QSettings *settings = ICore::instance()->settings();
101  initialCategory =
102  settings->value("General/LastPreferenceCategory", QVariant(QString())).toString();
103  initialPage = settings->value("General/LastPreferencePage", QVariant(QString())).toString();
104  qDebug() << "SettingsDialog settings initial category: " << initialCategory
105  << ", initial page: " << initialPage;
106  m_windowWidth = settings->value("General/SettingsWindowWidth", 0).toInt();
107  m_windowHeight = settings->value("General/SettingsWindowHeight", 0).toInt();
108  }
109  if (m_windowWidth > 0 && m_windowHeight > 0)
110  resize(m_windowWidth, m_windowHeight);
111 
112  buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
113 
114  connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply()));
115 
116  m_instanceManager = Core::ICore::instance()->uavGadgetInstanceManager();
117 
118  connect(this, SIGNAL(settingsDialogShown(Core::Internal::SettingsDialog *)), m_instanceManager,
120  connect(this, SIGNAL(settingsDialogRemoved()), m_instanceManager,
121  SLOT(settingsDialogRemoved()));
122  connect(this, SIGNAL(categoryItemSelected()), this,
123  SLOT(categoryItemSelectedShowChildInstead()), Qt::QueuedConnection);
124 
125  splitter->setCollapsible(0, false);
126  splitter->setCollapsible(1, false);
127  pageTree->header()->setVisible(false);
128  // pageTree->setIconSize(QSize(24, 24));
129 
130  connect(pageTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this,
131  SLOT(pageSelected()));
132 
133  QMap<QString, QTreeWidgetItem *> categories;
134 
135  QList<IOptionsPage *> pages = sortedOptionsPages();
136 
137  int index = 0;
138  bool firstUavGadgetOptionsPageFound = false;
139  QTreeWidgetItem *initialItem = nullptr;
140  foreach (IOptionsPage *page, pages) {
141  PageData pageData;
142  pageData.index = index;
143  pageData.category = page->category();
144  pageData.id = page->id();
145 
146  QTreeWidgetItem *item = new QTreeWidgetItem;
147  item->setText(0, page->trName());
148  item->setData(0, Qt::UserRole, qVariantFromValue(pageData));
149 
150  QString trCategories = page->trCategory();
151  QString currentCategory = page->category();
152 
153  QTreeWidgetItem *categoryItem;
154  if (!categories.contains(currentCategory)) {
155  // Above the first gadget option we insert a separator
156  if (!firstUavGadgetOptionsPageFound) {
158  qobject_cast<UAVGadgetOptionsPageDecorator *>(page);
159  if (pd) {
160  firstUavGadgetOptionsPageFound = true;
161  QTreeWidgetItem *separator = new QTreeWidgetItem(pageTree);
162  separator->setFlags(separator->flags() & ~Qt::ItemIsSelectable
163  & ~Qt::ItemIsEnabled);
164  separator->setText(0, QString(30, 0xB7));
165  }
166  }
167  categoryItem = new QTreeWidgetItem(pageTree);
168  categoryItem->setIcon(0, page->icon());
169  categoryItem->setText(0, trCategories);
170  categoryItem->setData(0, Qt::UserRole, qVariantFromValue(pageData));
171  categories.insert(currentCategory, categoryItem);
172  }
173 
174  QList<QTreeWidgetItem *> *categoryItemList = m_categoryItemsMap.value(currentCategory);
175  if (!categoryItemList) {
176  categoryItemList = new QList<QTreeWidgetItem *>();
177  m_categoryItemsMap.insert(currentCategory, categoryItemList);
178  }
179  categoryItemList->append(item);
180 
181  m_pages.append(page);
182 
183  // creating all option pages upfront is slow, so we create place holder widgets instead
184  // the real option page widget will be created later when the user selects it
185  // the place holder is a QLabel and we assume that no option page will be a QLabel...
186  QLabel *placeholderWidget = new QLabel(stackedPages);
187  stackedPages->addWidget(placeholderWidget);
188 
189  if (page->id() == initialPage && currentCategory == initialCategory) {
190  initialItem = item;
191  }
192 
193  index++;
194  }
195 
196  foreach (QString category, m_categoryItemsMap.keys()) {
197  QList<QTreeWidgetItem *> *categoryItemList = m_categoryItemsMap.value(category);
198  if (categoryItemList->size() > 1) {
199  foreach (QTreeWidgetItem *item, *categoryItemList) {
200  QTreeWidgetItem *categoryItem = categories.value(category);
201  categoryItem->addChild(item);
202  }
203  }
204  }
205 
206  if (initialItem) {
207  if (!initialItem->parent()) {
208  // item has no parent, meaning it is single child
209  // so select category item instead as single child are not added to the tree
210  initialItem = categories.value(initialCategory);
211  }
212  pageTree->setCurrentItem(initialItem);
213  }
214 
215  QList<int> sizes;
216  sizes << 150 << 300;
217  splitter->setSizes(sizes);
218 
219  splitter->setStretchFactor(splitter->indexOf(pageTree), 0);
220  splitter->setStretchFactor(splitter->indexOf(layoutWidget), 1);
221 }
222 
224 {
225  foreach (QString category, m_categoryItemsMap.keys()) {
226  QList<QTreeWidgetItem *> *categoryItemList = m_categoryItemsMap.value(category);
227  delete categoryItemList;
228  }
229  // delete place holders
230  for (int i = 0; i < stackedPages->count(); i++) {
231  QLabel *widget = dynamic_cast<QLabel *>(stackedPages->widget(i));
232  if (widget) {
233  delete widget;
234  }
235  }
236 }
237 
238 void SettingsDialog::pageSelected()
239 {
240  QTreeWidgetItem *item = pageTree->currentItem();
241  if (!item)
242  return;
243 
244  PageData data = item->data(0, Qt::UserRole).value<PageData>();
245  int index = data.index;
246  m_currentCategory = data.category;
247  m_currentPage = data.id;
248  // check if we are looking at a place holder or not
249  QWidget *widget = dynamic_cast<QLabel *>(stackedPages->widget(index));
250  if (widget) {
251  // place holder found, get rid of it...
252  stackedPages->removeWidget(widget);
253  delete widget;
254  // and replace place holder with actual option page
255  IOptionsPage *page = m_pages.at(index);
256  stackedPages->insertWidget(index, page->createPage(stackedPages));
257  }
258  stackedPages->setCurrentIndex(index);
259  // If user selects a toplevel item, select the first child for them
260  // I.e. Top level items are not really selectable
261  if ((pageTree->indexOfTopLevelItem(item) >= 0) && (item->childCount() > 0)) {
262  emit categoryItemSelected();
263  }
264 }
265 
266 void SettingsDialog::categoryItemSelectedShowChildInstead()
267 {
268  QTreeWidgetItem *item = pageTree->currentItem();
269  item->setExpanded(true);
270  pageTree->setCurrentItem(item->child(0), 0, QItemSelectionModel::SelectCurrent);
271 }
272 
274 {
275  QTreeWidgetItem *item = pageTree->currentItem();
276  PageData data = item->data(0, Qt::UserRole).value<PageData>();
277  QString category = data.category;
278  QList<QTreeWidgetItem *> *categoryItemList = m_categoryItemsMap.value(category);
279  QTreeWidgetItem *parentItem = item->parent();
280  parentItem->removeChild(item);
281  categoryItemList->removeOne(item);
282  if (parentItem->childCount() == 1) {
283  parentItem->removeChild(parentItem->child(0));
284  }
285  pageSelected();
286 }
287 
289 {
290  PageData pageData;
291  pageData.index = m_pages.count();
292  pageData.category = page->category();
293  pageData.id = page->id();
294 
295  QTreeWidgetItem *categoryItem = nullptr;
296  for (int i = 0; i < pageTree->topLevelItemCount(); ++i) {
297  QTreeWidgetItem *tw = pageTree->topLevelItem(i);
298  PageData data = tw->data(0, Qt::UserRole).value<PageData>();
299  if (data.category == page->category()) {
300  categoryItem = tw;
301  break;
302  }
303  }
304  if (!categoryItem)
305  return;
306 
307  // If this category has no child right now
308  // we need to add the "default child"
309  QList<QTreeWidgetItem *> *categoryItemList = m_categoryItemsMap.value(page->category());
310  if (categoryItem->childCount() == 0) {
311  QTreeWidgetItem *defaultItem = categoryItemList->at(0);
312  categoryItem->addChild(defaultItem);
313  }
314 
315  QTreeWidgetItem *item = new QTreeWidgetItem;
316  item->setText(0, page->trName());
317  item->setData(0, Qt::UserRole, qVariantFromValue(pageData));
318 
319  categoryItem->addChild(item);
320  categoryItemList->append(item);
321 
322  m_pages.append(page);
323  stackedPages->addWidget(page->createPage(stackedPages));
324 
325  stackedPages->setCurrentIndex(stackedPages->count());
326  pageTree->setCurrentItem(item);
327 }
328 
329 void SettingsDialog::updateText(QString text)
330 {
331  QTreeWidgetItem *item = pageTree->currentItem();
332  item->setText(0, text);
333 }
334 
336 {
337  buttonBox->button(QDialogButtonBox::Apply)->setDisabled(disable);
338  buttonBox->button(QDialogButtonBox::Ok)->setDisabled(disable);
339 }
340 
341 void SettingsDialog::accept()
342 {
343  m_applied = true;
344  for (int i = 0; i < m_pages.size(); i++) {
345  QWidget *widget = dynamic_cast<QLabel *>(stackedPages->widget(i));
346  if (!widget) {
347  IOptionsPage *page = m_pages.at(i);
348  page->apply();
349  page->finish();
350  }
351  }
352  done(QDialog::Accepted);
353 }
354 
355 void SettingsDialog::reject()
356 {
357  for (int i = 0; i < m_pages.size(); i++) {
358  QWidget *widget = dynamic_cast<QLabel *>(stackedPages->widget(i));
359  if (!widget) {
360  IOptionsPage *page = m_pages.at(i);
361  page->finish();
362  }
363  }
364  done(QDialog::Rejected);
365 }
366 
367 void SettingsDialog::apply()
368 {
369  for (int i = 0; i < m_pages.size(); i++) {
370  QWidget *widget = dynamic_cast<QLabel *>(stackedPages->widget(i));
371  if (!widget) {
372  IOptionsPage *page = m_pages.at(i);
373  page->apply();
374  }
375  }
376  m_applied = true;
377 }
378 
380 {
381  m_applied = false;
382  emit settingsDialogShown(this);
383  exec();
384  emit settingsDialogRemoved();
385  return m_applied;
386 }
387 
388 void SettingsDialog::done(int val)
389 {
390  QSettings *settings = ICore::instance()->settings();
391  settings->setValue("General/LastPreferenceCategory", m_currentCategory);
392  settings->setValue("General/LastPreferencePage", m_currentPage);
393  settings->setValue("General/SettingsWindowWidth", this->width());
394  settings->setValue("General/SettingsWindowHeight", this->height());
395  QDialog::done(val);
396 }
virtual QString category() const
Definition: ioptionspage.h:61
virtual QString id() const
Definition: ioptionspage.h:59
for i
Definition: OPPlots.m:140
DataFields data
Q_DECLARE_METATYPE(::PageData) using namespace Core
static ICore * instance()
Definition: coreimpl.cpp:46
virtual void apply()=0
virtual QString trName() const
Definition: ioptionspage.h:60
bool optionsPageLessThan(const IOptionsPage *p1, const IOptionsPage *p2)
virtual QWidget * createPage(QWidget *parent)=0
virtual QSettings * settings(QSettings::Scope scope=QSettings::UserScope) const =0
Returns the application's main settings object.
virtual QString trCategory() const
Definition: ioptionspage.h:62
virtual void finish()=0
QString id
QString category
void insertPage(IOptionsPage *page)
The IOptionsPage is an interface for providing options pages.
Definition: ioptionspage.h:42
void settingsDialogShown(Core::Internal::SettingsDialog *)
virtual UAVGadgetInstanceManager * uavGadgetInstanceManager() const =0