2 ******************************************************************************
4 * @file settingsdialog.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
7 * @addtogroup GCSPlugins GCS Plugins
9 * @addtogroup CorePlugin Core Plugin
11 * @brief The Core GCS plugin
12 *****************************************************************************/
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.
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
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "settingsdialog.h"
31 #include <extensionsystem/pluginmanager.h>
33 #include "coreplugin/uavgadgetinstancemanager.h"
34 #include "coreplugin/uavgadgetoptionspagedecorator.h"
38 #include <QHeaderView>
40 #include <QPushButton>
43 using namespace Core::Internal
;
52 // helper to sort by translated category and name
53 bool compareOptionsPageByCategoryAndNameTr(const IOptionsPage
*p1
, const IOptionsPage
*p2
)
55 const UAVGadgetOptionsPageDecorator
*gp1
= qobject_cast
<const UAVGadgetOptionsPageDecorator
*>(p1
);
56 const UAVGadgetOptionsPageDecorator
*gp2
= qobject_cast
<const UAVGadgetOptionsPageDecorator
*>(p2
);
64 if (const int cc
= QString::localeAwareCompare(p1
->trCategory(), p2
->trCategory())) {
67 return QString::localeAwareCompare(p1
->trName(), p2
->trName()) < 0;
70 // helper to sort by category and id
71 bool compareOptionsPageByCategoryAndId(const IOptionsPage
*p1
, const IOptionsPage
*p2
)
73 const UAVGadgetOptionsPageDecorator
*gp1
= qobject_cast
<const UAVGadgetOptionsPageDecorator
*>(p1
);
74 const UAVGadgetOptionsPageDecorator
*gp2
= qobject_cast
<const UAVGadgetOptionsPageDecorator
*>(p2
);
82 if (const int cc
= QString::localeAwareCompare(p1
->category(), p2
->category())) {
85 return QString::localeAwareCompare(p1
->id(), p2
->id()) < 0;
89 Q_DECLARE_METATYPE(::PageData
) SettingsDialog::SettingsDialog(QWidget
*parent
, const QString
&categoryId
, const QString
&pageId
) :
90 QDialog(parent
), m_applied(false)
94 setWindowTitle(tr("Preferences"));
96 setWindowTitle(tr("Options"));
101 settings
.beginGroup("General");
102 settings
.beginGroup("Settings");
104 // restore last displayed category and page
105 // this is done only if no category or page was provided through the constructor
106 QString initialCategory
= categoryId
;
107 QString initialPage
= pageId
;
108 qDebug() << "SettingsDialog constructor initial category:" << initialCategory
<< ", initial page:" << initialPage
;
109 if (initialCategory
.isEmpty() && initialPage
.isEmpty()) {
110 initialCategory
= settings
.value("LastPreferenceCategory", QVariant(QString())).toString();
111 initialPage
= settings
.value("LastPreferencePage", QVariant(QString())).toString();
112 qDebug() << "SettingsDialog settings initial category:" << initialCategory
<< ", initial page: " << initialPage
;
115 // restore window size
116 int windowWidth
= settings
.value("WindowWidth", 0).toInt();
117 int windowHeight
= settings
.value("WindowHeight", 0).toInt();
118 qDebug() << "SettingsDialog window width :" << windowWidth
<< ", height:" << windowHeight
;
119 if (windowWidth
> 0 && windowHeight
> 0) {
120 resize(windowWidth
, windowHeight
);
123 // restore splitter size
124 int splitterPosition
= settings
.value("SplitterPosition", 350).toInt();
125 qDebug() << "SettingsDialog splitter position:" << splitterPosition
;
127 sizes
<< splitterPosition
<< 400;
128 splitter
->setSizes(sizes
);
133 // all extra space must go to the option page and none to the tree
134 splitter
->setStretchFactor(0, 0);
135 splitter
->setStretchFactor(1, 1);
137 buttonBox
->button(QDialogButtonBox::Ok
)->setDefault(true);
139 connect(buttonBox
->button(QDialogButtonBox::Apply
), SIGNAL(clicked()), this, SLOT(apply()));
141 m_instanceManager
= Core::ICore::instance()->uavGadgetInstanceManager();
143 connect(this, SIGNAL(settingsDialogShown(Core::Internal::SettingsDialog
*)), m_instanceManager
,
144 SLOT(settingsDialogShown(Core::Internal::SettingsDialog
*)));
145 connect(this, SIGNAL(settingsDialogRemoved()), m_instanceManager
, SLOT(settingsDialogRemoved()));
147 // needs to be queued to be able to change the selection from the selection change signal call
148 connect(this, SIGNAL(categoryItemSelected()), this, SLOT(onCategorySelected()), Qt::QueuedConnection
);
150 splitter
->setCollapsible(0, false);
151 splitter
->setCollapsible(1, false);
152 pageTree
->header()->setVisible(false);
154 connect(pageTree
, SIGNAL(currentItemChanged(QTreeWidgetItem
*, QTreeWidgetItem
*)), this, SLOT(onItemSelected()));
156 QList
<Core::IOptionsPage
*> pluginPages
;
157 QList
<Core::IOptionsPage
*> gadgetPages
;
159 // get all pages and split them between plugin and gadget list
160 QList
<Core::IOptionsPage
*> pages
= ExtensionSystem::PluginManager::instance()->getObjects
<IOptionsPage
>();
161 foreach(IOptionsPage
* page
, pages
) {
162 if (qobject_cast
<UAVGadgetOptionsPageDecorator
*>(page
)) {
163 gadgetPages
.append(page
);
165 pluginPages
.append(page
);
169 // the plugin options page list is sorted by untranslated category and names
170 // this is done to facilitate access to the language settings when GCS is not running in a language understood by the user.
171 qStableSort(pluginPages
.begin(), pluginPages
.end(), compareOptionsPageByCategoryAndId
);
173 // the plugin options page list is sorted by translated names
174 qStableSort(gadgetPages
.begin(), gadgetPages
.end(), compareOptionsPageByCategoryAndNameTr
);
176 // will hold the initially selected item if any
177 QTreeWidgetItem
*initialItem
= 0;
180 foreach(IOptionsPage
* page
, pluginPages
) {
181 QTreeWidgetItem
*item
= addPage(page
);
183 // automatically expand all plugin categories
184 item
->parent()->setExpanded(true);
185 if (page
->id() == initialPage
&& page
->category() == initialCategory
) {
190 // insert separator between plugin and gadget pages
191 QTreeWidgetItem
*separator
= new QTreeWidgetItem(pageTree
);
192 separator
->setFlags(separator
->flags() & ~Qt::ItemIsSelectable
& ~Qt::ItemIsEnabled
);
193 separator
->setText(0, QString(30, 0xB7));
196 foreach(IOptionsPage
* page
, gadgetPages
) {
197 QTreeWidgetItem
*item
= addPage(page
);
199 if (page
->id() == initialPage
&& page
->category() == initialCategory
) {
204 // handle initially selected item
206 if (initialItem
->isHidden()) {
207 // item is hidden, meaning it is single child
208 // so select parent category item instead
209 initialItem
= initialItem
->parent();
211 pageTree
->setCurrentItem(initialItem
);
215 SettingsDialog::~SettingsDialog()
217 foreach(QString category
, m_categoryItemsMap
.keys()) {
218 QList
<QTreeWidgetItem
*> *categoryItemList
= m_categoryItemsMap
.value(category
, NULL
);
219 delete categoryItemList
;
221 // delete place holders
222 for (int i
= 0; i
< stackedPages
->count(); i
++) {
223 QLabel
*widget
= dynamic_cast<QLabel
*>(stackedPages
->widget(i
));
230 QTreeWidgetItem
*SettingsDialog::addPage(IOptionsPage
*page
)
234 pageData
.index
= m_pages
.count();
235 pageData
.category
= page
->category();
236 pageData
.id
= page
->id();
238 QString category
= page
->category();
240 QList
<QTreeWidgetItem
*> *categoryItemList
= m_categoryItemsMap
.value(category
, NULL
);
241 if (!categoryItemList
) {
242 categoryItemList
= new QList
<QTreeWidgetItem
*>();
243 m_categoryItemsMap
.insert(category
, categoryItemList
);
246 QTreeWidgetItem
*categoryItem
= NULL
;
247 for (int i
= 0; i
< pageTree
->topLevelItemCount(); ++i
) {
248 QTreeWidgetItem
*tw
= pageTree
->topLevelItem(i
);
249 PageData data
= tw
->data(0, Qt::UserRole
).value
<PageData
>();
250 if (data
.category
== page
->category()) {
256 categoryItem
= new QTreeWidgetItem(pageTree
);
257 categoryItem
->setIcon(0, page
->icon());
258 categoryItem
->setText(0, page
->trCategory());
259 categoryItem
->setData(0, Qt::UserRole
, qVariantFromValue(pageData
));
262 QTreeWidgetItem
*item
= new QTreeWidgetItem(categoryItem
);
263 item
->setText(0, page
->trName());
264 item
->setData(0, Qt::UserRole
, qVariantFromValue(pageData
));
266 switch (categoryItemList
->size()) {
268 item
->setHidden(true);
271 categoryItemList
->at(0)->setHidden(false);
277 categoryItemList
->append(item
);
279 m_pages
.append(page
);
281 // creating all option pages upfront is slow, so we create place holder widgets instead
282 // the real option page widget will be created later when the user selects it
283 // the place holder is a QLabel and we assume that no option page will be a QLabel...
284 QLabel
*placeholderWidget
= new QLabel(stackedPages
);
285 stackedPages
->addWidget(placeholderWidget
);
290 void SettingsDialog::onItemSelected()
292 QTreeWidgetItem
*item
= pageTree
->currentItem();
298 if (pageTree
->indexOfTopLevelItem(item
) >= 0) {
299 if (item
->childCount() == 1) {
300 // single child : category will not be expanded
301 item
= item
->child(0);
302 } else if (item
->childCount() > 1) {
303 // multiple children : expand category and select 1st child
304 emit
categoryItemSelected();
310 PageData data
= item
->data(0, Qt::UserRole
).value
<PageData
>();
311 int index
= data
.index
;
312 m_currentCategory
= data
.category
;
313 m_currentPage
= data
.id
;
315 // check if we are looking at a place holder or not
316 QWidget
*widget
= dynamic_cast<QLabel
*>(stackedPages
->widget(index
));
318 // place holder found, get rid of it...
319 stackedPages
->removeWidget(widget
);
321 // and replace place holder with actual option page
322 IOptionsPage
*page
= m_pages
.at(index
);
323 stackedPages
->insertWidget(index
, page
->createPage(stackedPages
));
326 IOptionsPage
*page
= m_pages
.at(index
);
329 stackedPages
->setCurrentIndex(index
);
332 void SettingsDialog::onCategorySelected()
334 QTreeWidgetItem
*item
= pageTree
->currentItem();
336 if (item
->childCount() > 1) {
337 item
->setExpanded(true);
338 pageTree
->setCurrentItem(item
->child(0), 0, QItemSelectionModel::SelectCurrent
);
342 void SettingsDialog::deletePage()
344 QTreeWidgetItem
*item
= pageTree
->currentItem();
346 PageData data
= item
->data(0, Qt::UserRole
).value
<PageData
>();
347 QString category
= data
.category
;
349 QList
<QTreeWidgetItem
*> *categoryItemList
= m_categoryItemsMap
.value(category
, NULL
);
350 if (categoryItemList
) {
351 categoryItemList
->removeOne(item
);
352 QTreeWidgetItem
*parentItem
= item
->parent();
353 parentItem
->removeChild(item
);
354 if (parentItem
->childCount() == 1) {
355 parentItem
->child(0)->setHidden(true);
356 pageTree
->setCurrentItem(parentItem
, 0, QItemSelectionModel::SelectCurrent
);
361 // TODO duplicates a lot of the addPage code...
362 void SettingsDialog::insertPage(IOptionsPage
*page
)
366 pageData
.index
= m_pages
.count();
367 pageData
.category
= page
->category();
368 pageData
.id
= page
->id();
370 QTreeWidgetItem
*categoryItem
= 0;
371 for (int i
= 0; i
< pageTree
->topLevelItemCount(); ++i
) {
372 QTreeWidgetItem
*tw
= pageTree
->topLevelItem(i
);
373 PageData data
= tw
->data(0, Qt::UserRole
).value
<PageData
>();
374 if (data
.category
== page
->category()) {
383 // If this category has no child right now
384 // we need to add the "default child"
385 QList
<QTreeWidgetItem
*> *categoryItemList
= m_categoryItemsMap
.value(page
->category(), NULL
);
386 if (categoryItem
->childCount() == 1) {
387 QTreeWidgetItem
*defaultItem
= categoryItemList
->at(0);
388 defaultItem
->setHidden(false);
391 QTreeWidgetItem
*item
= new QTreeWidgetItem
;
392 item
->setText(0, page
->trName());
393 item
->setData(0, Qt::UserRole
, qVariantFromValue(pageData
));
395 categoryItem
->addChild(item
);
396 categoryItemList
->append(item
);
398 m_pages
.append(page
);
399 stackedPages
->addWidget(page
->createPage(stackedPages
));
401 stackedPages
->setCurrentIndex(stackedPages
->count());
402 pageTree
->setCurrentItem(item
);
405 void SettingsDialog::updateText(QString text
)
407 QTreeWidgetItem
*item
= pageTree
->currentItem();
409 item
->setText(0, text
);
412 void SettingsDialog::disableApplyOk(bool disable
)
414 buttonBox
->button(QDialogButtonBox::Apply
)->setDisabled(disable
);
415 buttonBox
->button(QDialogButtonBox::Ok
)->setDisabled(disable
);
418 void SettingsDialog::accept()
421 for (int i
= 0; i
< m_pages
.size(); i
++) {
422 QWidget
*widget
= dynamic_cast<QLabel
*>(stackedPages
->widget(i
));
424 IOptionsPage
*page
= m_pages
.at(i
);
429 done(QDialog::Accepted
);
432 void SettingsDialog::reject()
434 for (int i
= 0; i
< m_pages
.size(); i
++) {
435 QWidget
*widget
= dynamic_cast<QLabel
*>(stackedPages
->widget(i
));
437 IOptionsPage
*page
= m_pages
.at(i
);
441 done(QDialog::Rejected
);
444 void SettingsDialog::apply()
446 for (int i
= 0; i
< m_pages
.size(); i
++) {
447 QWidget
*widget
= dynamic_cast<QLabel
*>(stackedPages
->widget(i
));
449 IOptionsPage
*page
= m_pages
.at(i
);
456 bool SettingsDialog::execDialog()
459 emit
settingsDialogShown(this);
461 emit
settingsDialogRemoved();
465 void SettingsDialog::done(int val
)
469 settings
.beginGroup("General");
470 settings
.beginGroup("Settings");
472 settings
.setValue("LastPreferenceCategory", m_currentCategory
);
473 settings
.setValue("LastPreferencePage", m_currentPage
);
475 settings
.setValue("WindowWidth", this->width());
476 settings
.setValue("WindowHeight", this->height());
478 QList
<int> sizes
= splitter
->sizes();
479 settings
.setValue("SplitterPosition", sizes
[0]);