2 ******************************************************************************
4 * @file configtaskwidget.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * @addtogroup GCSPlugins GCS Plugins
8 * @addtogroup UAVObjectWidgetUtils Plugin
10 * @brief Utility plugin for UAVObject to Widget relation management
11 *****************************************************************************/
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "configtaskwidget.h"
29 #include <uavtalk/telemetrymanager.h>
30 #include "uavsettingsimportexport/uavsettingsimportexportfactory.h"
34 #include <QToolButton>
36 ConfigTaskWidget::ConfigTaskWidget(QWidget
*parent
) : QWidget(parent
), m_currentBoardId(-1), m_isConnected(false), m_isWidgetUpdatesAllowed(true),
37 m_saveButton(NULL
), m_isDirty(false), m_outOfLimitsStyle("background-color: rgb(255, 0, 0);"), m_realtimeUpdateTimer(NULL
)
39 m_pluginManager
= ExtensionSystem::PluginManager::instance();
40 TelemetryManager
*telMngr
= m_pluginManager
->getObject
<TelemetryManager
>();
41 m_objectUtilManager
= m_pluginManager
->getObject
<UAVObjectUtilManager
>();
42 connect(telMngr
, SIGNAL(connected()), this, SLOT(onAutopilotConnect()), Qt::UniqueConnection
);
43 connect(telMngr
, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect()), Qt::UniqueConnection
);
44 connect(telMngr
, SIGNAL(connected()), this, SIGNAL(autoPilotConnected()), Qt::UniqueConnection
);
45 connect(telMngr
, SIGNAL(disconnected()), this, SIGNAL(autoPilotDisconnected()), Qt::UniqueConnection
);
46 UAVSettingsImportExportFactory
*importexportplugin
= m_pluginManager
->getObject
<UAVSettingsImportExportFactory
>();
47 connect(importexportplugin
, SIGNAL(importAboutToBegin()), this, SLOT(invalidateObjects()));
50 void ConfigTaskWidget::addWidget(QWidget
*widget
)
52 addWidgetBinding("", "", widget
);
55 void ConfigTaskWidget::addUAVObject(QString objectName
, QList
<int> *reloadGroups
)
57 addWidgetBinding(objectName
, "", NULL
, 0, 1, false, reloadGroups
);
60 void ConfigTaskWidget::addUAVObject(UAVObject
*objectName
, QList
<int> *reloadGroups
)
62 addUAVObject(objectName
? objectName
->getName() : QString(), reloadGroups
);
65 int ConfigTaskWidget::fieldIndexFromElementName(QString objectName
, QString fieldName
, QString elementName
)
67 if (elementName
.isEmpty() || objectName
.isEmpty()) {
71 QString singleObjectName
= mapObjectName(objectName
).split(",").at(0);
72 UAVObject
*object
= getObject(singleObjectName
);
75 UAVObjectField
*field
= object
->getField(fieldName
);
78 return field
->getElementNames().indexOf(elementName
);
81 void ConfigTaskWidget::addWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, QString elementName
)
83 addWidgetBinding(objectName
, fieldName
, widget
, fieldIndexFromElementName(objectName
, fieldName
, elementName
));
86 void ConfigTaskWidget::addWidgetBinding(UAVObject
*object
, UAVObjectField
*field
, QWidget
*widget
, QString elementName
)
88 addWidgetBinding(object
? object
->getName() : QString(), field
? field
->getName() : QString(), widget
, elementName
);
91 void ConfigTaskWidget::addWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, QString elementName
, double scale
,
92 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
94 addWidgetBinding(objectName
, fieldName
, widget
, fieldIndexFromElementName(objectName
, fieldName
, elementName
),
95 scale
, isLimited
, reloadGroupIDs
, instID
);
98 void ConfigTaskWidget::addWidgetBinding(UAVObject
*object
, UAVObjectField
*field
, QWidget
*widget
, QString elementName
, double scale
,
99 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
101 addWidgetBinding(object
? object
->getName() : QString(), field
? field
->getName() : QString(), widget
, elementName
, scale
,
102 isLimited
, reloadGroupIDs
, instID
);
105 void ConfigTaskWidget::addWidgetBinding(UAVObject
*object
, UAVObjectField
*field
, QWidget
*widget
, int index
, double scale
,
106 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
108 addWidgetBinding(object
? object
->getName() : QString(), field
? field
->getName() : QString(), widget
, index
, scale
,
109 isLimited
, reloadGroupIDs
, instID
);
112 void ConfigTaskWidget::addWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, int index
, double scale
,
113 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
115 QString mappedObjectName
= mapObjectName(objectName
);
117 // If object name is comma separated list of objects, call one time per objectName
118 foreach(QString singleObjectName
, mappedObjectName
.split(",")) {
119 doAddWidgetBinding(singleObjectName
, fieldName
, widget
, index
, scale
, isLimited
, reloadGroupIDs
, instID
);
123 void ConfigTaskWidget::doAddWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, int index
, double scale
,
124 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
126 if (addShadowWidgetBinding(objectName
, fieldName
, widget
, index
, scale
, isLimited
, reloadGroupIDs
, instID
)) {
130 UAVObject
*object
= NULL
;
131 UAVObjectField
*field
= NULL
;
132 if (!objectName
.isEmpty()) {
133 object
= getObject(QString(objectName
), instID
);
135 m_updatedObjects
.insert(object
, true);
136 connect(object
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(objectUpdated(UAVObject
*)));
137 connect(object
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(refreshWidgetsValues(UAVObject
*)), Qt::UniqueConnection
);
140 if (!fieldName
.isEmpty() && object
) {
141 field
= object
->getField(QString(fieldName
));
145 WidgetBinding
*binding
= new WidgetBinding(widget
, object
, field
, index
, scale
, isLimited
);
146 // Only the first binding per widget can be enabled.
147 binding
->setIsEnabled(m_widgetBindingsPerWidget
.count(widget
) == 0);
148 m_widgetBindingsPerWidget
.insert(widget
, binding
);
151 m_widgetBindingsPerObject
.insert(object
, binding
);
153 m_saveButton
->addObject((UAVDataObject
*)object
);
158 if (reloadGroupIDs
&& object
) {
159 foreach(int groupId
, *reloadGroupIDs
) {
160 m_reloadGroups
.insert(groupId
, binding
);
164 connectWidgetUpdatesToSlot(widget
, SLOT(widgetsContentsChanged()));
165 if (reloadGroupIDs
) {
166 addWidgetToReloadGroups(widget
, reloadGroupIDs
);
168 if (binding
->isEnabled()) {
169 loadWidgetLimits(widget
, field
, index
, isLimited
, scale
);
174 void ConfigTaskWidget::setWidgetBindingObjectEnabled(QString objectName
, bool enabled
)
176 UAVObject
*object
= getObject(objectName
);
180 bool dirtyBack
= isDirty();
182 foreach(WidgetBinding
* binding
, m_widgetBindingsPerObject
.values(object
)) {
183 binding
->setIsEnabled(enabled
);
185 if (binding
->value().isValid() && !binding
->value().isNull()) {
186 setWidgetFromVariant(binding
->widget(), binding
->value(), binding
);
188 setWidgetFromField(binding
->widget(), binding
->field(), binding
);
195 ConfigTaskWidget::~ConfigTaskWidget()
200 QSet
<WidgetBinding
*> deleteSet
= m_widgetBindingsPerWidget
.values().toSet();
201 foreach(WidgetBinding
* binding
, deleteSet
) {
206 if (m_realtimeUpdateTimer
) {
207 delete m_realtimeUpdateTimer
;
208 m_realtimeUpdateTimer
= NULL
;
212 bool ConfigTaskWidget::isComboboxOptionSelected(QComboBox
*combo
, int optionValue
)
215 int value
= combo
->currentData().toInt(&ok
);
217 return ok
? value
== optionValue
: false;
220 int ConfigTaskWidget::getComboboxSelectedOption(QComboBox
*combo
)
223 int index
= combo
->currentData().toInt(&ok
);
225 return ok
? index
: combo
->currentIndex();
228 void ConfigTaskWidget::setComboboxSelectedOption(QComboBox
*combo
, int optionValue
)
230 int index
= combo
->findData(QVariant(optionValue
));
233 combo
->setCurrentIndex(index
);
235 combo
->setCurrentIndex(optionValue
);
239 int ConfigTaskWidget::getComboboxIndexForOption(QComboBox
*combo
, int optionValue
)
241 return combo
->findData(QVariant(optionValue
));
244 void ConfigTaskWidget::enableComboBoxOptionItem(QComboBox
*combo
, int optionValue
, bool enable
)
246 combo
->model()->setData(combo
->model()->index(getComboboxIndexForOption(combo
, optionValue
), 0),
247 !enable
? QVariant(0) : QVariant(1 | 32), Qt::UserRole
- 1);
250 void ConfigTaskWidget::saveObjectToSD(UAVObject
*obj
)
252 // saveObjectToSD is now handled by the UAVUtils plugin in one
253 // central place (and one central queue)
254 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
255 UAVObjectUtilManager
*utilMngr
= pm
->getObject
<UAVObjectUtilManager
>();
257 utilMngr
->saveObjectToSD(obj
);
260 UAVObjectManager
*ConfigTaskWidget::getObjectManager()
262 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
263 UAVObjectManager
*objMngr
= pm
->getObject
<UAVObjectManager
>();
270 void ConfigTaskWidget::onAutopilotDisconnect()
272 m_isConnected
= false;
274 // Reset board ID and clear bound combo box lists to force repopulation
275 // when we get another connected signal. This means that we get the
276 // correct values in combo boxes bound to fields with limits applied.
277 m_currentBoardId
= -1;
279 foreach(WidgetBinding
* binding
, m_widgetBindingsPerObject
) {
282 if (binding
->widget() && (cb
= qobject_cast
<QComboBox
*>(binding
->widget()))) {
287 enableControls(false);
291 // dynamic widgets don't recieve the connected signal. This should be called instead.
292 void ConfigTaskWidget::forceConnectedState()
294 if (m_objectUtilManager
) {
295 m_currentBoardId
= m_objectUtilManager
->getBoardModel();
297 m_isConnected
= true;
301 void ConfigTaskWidget::onAutopilotConnect()
303 if (m_objectUtilManager
) {
304 m_currentBoardId
= m_objectUtilManager
->getBoardModel();
307 m_isConnected
= true;
309 enableControls(true);
310 refreshWidgetsValues();
313 void ConfigTaskWidget::populateWidgets()
315 bool dirtyBack
= isDirty();
316 emit
populateWidgetsRequested();
318 foreach(WidgetBinding
* binding
, m_widgetBindingsPerObject
) {
319 if (binding
->isEnabled() && binding
->object() != NULL
&& binding
->field() != NULL
&& binding
->widget() != NULL
) {
320 setWidgetFromField(binding
->widget(), binding
->field(), binding
);
326 void ConfigTaskWidget::refreshWidgetsValues(UAVObject
*obj
)
328 if (!m_isWidgetUpdatesAllowed
) {
332 bool dirtyBack
= isDirty();
333 emit
refreshWidgetsValuesRequested();
334 QList
<WidgetBinding
*> bindings
= obj
== NULL
? m_widgetBindingsPerObject
.values() : m_widgetBindingsPerObject
.values(obj
);
335 foreach(WidgetBinding
* binding
, bindings
) {
336 if (binding
->field() != NULL
&& binding
->widget() != NULL
) {
337 if (binding
->isEnabled()) {
338 setWidgetFromField(binding
->widget(), binding
->field(), binding
);
340 binding
->updateValueFromObjectField();
347 void ConfigTaskWidget::updateObjectsFromWidgets()
349 emit
updateObjectsFromWidgetsRequested();
351 foreach(WidgetBinding
* binding
, m_widgetBindingsPerObject
) {
352 if (binding
->object() != NULL
&& binding
->field() != NULL
) {
353 binding
->updateObjectFieldFromValue();
358 void ConfigTaskWidget::helpButtonPressed()
360 QString url
= m_helpButtons
.value((QPushButton
*)sender(), QString());
362 if (!url
.isEmpty()) {
363 QDesktopServices::openUrl(QUrl(url
, QUrl::StrictMode
));
367 void ConfigTaskWidget::addApplySaveButtons(QPushButton
*update
, QPushButton
*save
)
370 m_saveButton
= new SmartSaveButton(this);
371 connect(m_saveButton
, SIGNAL(preProcessOperations()), this, SLOT(updateObjectsFromWidgets()));
372 connect(m_saveButton
, SIGNAL(saveSuccessfull()), this, SLOT(clearDirty()));
373 connect(m_saveButton
, SIGNAL(beginOp()), this, SLOT(disableObjectUpdates()));
374 connect(m_saveButton
, SIGNAL(endOp()), this, SLOT(enableObjectUpdates()));
376 if (update
&& save
) {
377 m_saveButton
->addButtons(save
, update
);
379 m_saveButton
->addApplyButton(update
);
381 m_saveButton
->addSaveButton(save
);
383 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
384 m_saveButton
->addObject((UAVDataObject
*)binding
->object());
386 updateEnableControls();
389 void ConfigTaskWidget::enableControls(bool enable
)
392 m_saveButton
->enableControls(enable
);
395 foreach(QPushButton
* button
, m_reloadButtons
) {
396 button
->setEnabled(enable
);
399 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
400 if (binding
->isEnabled() && binding
->widget()) {
401 binding
->widget()->setEnabled(enable
);
402 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
403 shadow
->widget()->setEnabled(enable
);
407 emit
enableControlsChanged(enable
);
410 bool ConfigTaskWidget::shouldObjectBeSaved(UAVObject
*object
)
416 void ConfigTaskWidget::forceShadowUpdates()
418 foreach(WidgetBinding
* binding
, m_widgetBindingsPerObject
) {
419 if (!binding
->isEnabled()) {
422 QVariant widgetValue
= getVariantFromWidget(binding
->widget(), binding
);
424 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
425 disconnectWidgetUpdatesToSlot(shadow
->widget(), SLOT(widgetsContentsChanged()));
427 checkWidgetsLimits(shadow
->widget(), binding
->field(), binding
->index(), shadow
->isLimited(), widgetValue
, shadow
->scale());
429 WidgetBinding
tmpBinding(shadow
->widget(), binding
->object(), binding
->field(), binding
->index(), shadow
->scale(), shadow
->isLimited());
430 setWidgetFromVariant(shadow
->widget(), widgetValue
, &tmpBinding
);
432 emit
widgetContentsChanged(shadow
->widget());
433 connectWidgetUpdatesToSlot(shadow
->widget(), SLOT(widgetsContentsChanged()));
439 void ConfigTaskWidget::widgetsContentsChanged()
441 QWidget
*emitter
= ((QWidget
*)sender());
442 emit
widgetContentsChanged(emitter
);
445 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
.values(emitter
)) {
446 if (binding
&& binding
->isEnabled()) {
447 if (binding
->widget() == emitter
) {
448 value
= getVariantFromWidget(emitter
, binding
);
449 checkWidgetsLimits(emitter
, binding
->field(), binding
->index(), binding
->isLimited(), value
, binding
->scale());
451 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
452 if (shadow
->widget() == emitter
) {
453 WidgetBinding
tmpBinding(shadow
->widget(), binding
->object(), binding
->field(),
454 binding
->index(), shadow
->scale(), shadow
->isLimited());
455 value
= getVariantFromWidget(emitter
, &tmpBinding
);
456 checkWidgetsLimits(emitter
, binding
->field(), binding
->index(), shadow
->isLimited(), value
, shadow
->scale());
460 binding
->setValue(value
);
462 if (binding
->widget() != emitter
) {
463 disconnectWidgetUpdatesToSlot(binding
->widget(), SLOT(widgetsContentsChanged()));
465 checkWidgetsLimits(binding
->widget(), binding
->field(), binding
->index(), binding
->isLimited(),
466 value
, binding
->scale());
467 setWidgetFromVariant(binding
->widget(), value
, binding
);
468 emit
widgetContentsChanged(binding
->widget());
470 connectWidgetUpdatesToSlot(binding
->widget(), SLOT(widgetsContentsChanged()));
472 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
473 if (shadow
->widget() != emitter
) {
474 disconnectWidgetUpdatesToSlot(shadow
->widget(), SLOT(widgetsContentsChanged()));
476 checkWidgetsLimits(shadow
->widget(), binding
->field(), binding
->index(), shadow
->isLimited(),
477 value
, shadow
->scale());
478 WidgetBinding
tmp(shadow
->widget(), binding
->object(), binding
->field(), binding
->index(), shadow
->scale(), shadow
->isLimited());
479 setWidgetFromVariant(shadow
->widget(), value
, &tmp
);
480 emit
widgetContentsChanged(shadow
->widget());
482 connectWidgetUpdatesToSlot(shadow
->widget(), SLOT(widgetsContentsChanged()));
488 m_saveButton
->resetIcons();
493 void ConfigTaskWidget::clearDirty()
498 void ConfigTaskWidget::setDirty(bool value
)
503 bool ConfigTaskWidget::isDirty()
512 void ConfigTaskWidget::disableObjectUpdates()
514 m_isWidgetUpdatesAllowed
= false;
515 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
516 if (binding
->object()) {
517 disconnect(binding
->object(), SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(refreshWidgetsValues(UAVObject
*)));
522 void ConfigTaskWidget::enableObjectUpdates()
524 m_isWidgetUpdatesAllowed
= true;
525 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
526 if (binding
->object()) {
527 connect(binding
->object(), SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(refreshWidgetsValues(UAVObject
*)), Qt::UniqueConnection
);
532 void ConfigTaskWidget::objectUpdated(UAVObject
*object
)
534 m_updatedObjects
[object
] = true;
537 bool ConfigTaskWidget::allObjectsUpdated()
541 foreach(UAVObject
* object
, m_updatedObjects
.keys()) {
542 result
= result
& m_updatedObjects
[object
];
547 void ConfigTaskWidget::addHelpButton(QPushButton
*button
, QString url
)
549 m_helpButtons
.insert(button
, url
);
550 connect(button
, SIGNAL(clicked()), this, SLOT(helpButtonPressed()));
553 void ConfigTaskWidget::invalidateObjects()
555 foreach(UAVObject
* obj
, m_updatedObjects
.keys()) {
556 m_updatedObjects
[obj
] = false;
560 void ConfigTaskWidget::apply()
563 m_saveButton
->apply();
567 void ConfigTaskWidget::save()
570 m_saveButton
->save();
574 bool ConfigTaskWidget::addShadowWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, int index
, double scale
, bool isLimited
,
575 QList
<int> *defaultReloadGroups
, quint32 instID
)
577 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
578 if (!binding
->object() || !binding
->widget() || !binding
->field()) {
581 if (binding
->matches(objectName
, fieldName
, index
, instID
)) {
582 binding
->addShadow(widget
, scale
, isLimited
);
584 m_widgetBindingsPerWidget
.insert(widget
, binding
);
585 connectWidgetUpdatesToSlot(widget
, SLOT(widgetsContentsChanged()));
586 if (defaultReloadGroups
) {
587 addWidgetToReloadGroups(widget
, defaultReloadGroups
);
589 if (binding
->isEnabled()) {
590 loadWidgetLimits(widget
, binding
->field(), binding
->index(), isLimited
, scale
);
598 void ConfigTaskWidget::autoLoadWidgets()
600 QPushButton
*saveButtonWidget
= NULL
;
601 QPushButton
*applyButtonWidget
= NULL
;
603 foreach(QWidget
* widget
, this->findChildren
<QWidget
*>()) {
604 QVariant info
= widget
->property("objrelation");
606 if (info
.isValid()) {
607 bindingStruct uiRelation
;
608 uiRelation
.buttonType
= none
;
609 uiRelation
.scale
= 1;
610 uiRelation
.index
= -1;
611 uiRelation
.elementName
= QString();
612 uiRelation
.haslimits
= false;
613 foreach(QString str
, info
.toStringList()) {
614 QString prop
= str
.split(":").at(0);
615 QString value
= str
.split(":").at(1);
617 if (prop
== "objname") {
618 uiRelation
.objectName
= value
;
619 } else if (prop
== "fieldname") {
620 uiRelation
.fieldName
= value
;
621 } else if (prop
== "element") {
622 uiRelation
.elementName
= value
;
623 } else if (prop
== "index") {
624 uiRelation
.index
= value
.toInt();
625 } else if (prop
== "scale") {
626 if (value
== "null") {
627 uiRelation
.scale
= 1;
629 uiRelation
.scale
= value
.toDouble();
631 } else if (prop
== "haslimits") {
632 if (value
== "yes") {
633 uiRelation
.haslimits
= true;
635 uiRelation
.haslimits
= false;
637 } else if (prop
== "button") {
638 if (value
== "save") {
639 uiRelation
.buttonType
= save_button
;
640 } else if (value
== "apply") {
641 uiRelation
.buttonType
= apply_button
;
642 } else if (value
== "reload") {
643 uiRelation
.buttonType
= reload_button
;
644 } else if (value
== "default") {
645 uiRelation
.buttonType
= default_button
;
646 } else if (value
== "help") {
647 uiRelation
.buttonType
= help_button
;
649 } else if (prop
== "buttongroup") {
650 foreach(QString s
, value
.split(",")) {
651 uiRelation
.buttonGroup
.append(s
.toInt());
653 } else if (prop
== "url") {
654 uiRelation
.url
= str
.mid(str
.indexOf(":") + 1);
657 if (!(uiRelation
.buttonType
== none
)) {
658 QPushButton
*button
= NULL
;
659 switch (uiRelation
.buttonType
) {
661 saveButtonWidget
= qobject_cast
<QPushButton
*>(widget
);
662 if (saveButtonWidget
) {
663 addApplySaveButtons(NULL
, saveButtonWidget
);
667 applyButtonWidget
= qobject_cast
<QPushButton
*>(widget
);
668 if (applyButtonWidget
) {
669 addApplySaveButtons(applyButtonWidget
, NULL
);
673 button
= qobject_cast
<QPushButton
*>(widget
);
675 addDefaultButton(button
, uiRelation
.buttonGroup
.at(0));
679 button
= qobject_cast
<QPushButton
*>(widget
);
681 addReloadButton(button
, uiRelation
.buttonGroup
.at(0));
685 button
= qobject_cast
<QPushButton
*>(widget
);
687 addHelpButton(button
, uiRelation
.url
);
695 QWidget
*wid
= qobject_cast
<QWidget
*>(widget
);
697 if (uiRelation
.index
!= -1) {
698 addWidgetBinding(uiRelation
.objectName
, uiRelation
.fieldName
, wid
, uiRelation
.index
, uiRelation
.scale
, uiRelation
.haslimits
, &uiRelation
.buttonGroup
);
700 addWidgetBinding(uiRelation
.objectName
, uiRelation
.fieldName
, wid
, uiRelation
.elementName
, uiRelation
.scale
, uiRelation
.haslimits
, &uiRelation
.buttonGroup
);
706 refreshWidgetsValues();
707 forceShadowUpdates();
710 foreach(WidgetBinding * binding, m_widgetBindingsPerObject) {
711 if (binding->widget()) {
712 qDebug() << "Binding :" << binding->widget()->objectName();
713 qDebug() << " Object :" << binding->object()->getName();
714 qDebug() << " Field :" << binding->field()->getName();
715 qDebug() << " Scale :" << binding->scale();
716 qDebug() << " Enabled:" << binding->isEnabled();
718 foreach(ShadowWidgetBinding * shadow, binding->shadows()) {
719 if (shadow->widget()) {
720 qDebug() << " Shadow:" << shadow->widget()->objectName();
721 qDebug() << " Scale :" << shadow->scale();
728 void ConfigTaskWidget::addWidgetToReloadGroups(QWidget
*widget
, QList
<int> *reloadGroupIDs
)
730 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
731 bool addBinding
= false;
733 if (binding
->widget() == widget
) {
736 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
737 if (shadow
->widget() == widget
) {
743 foreach(int groupID
, *reloadGroupIDs
) {
744 m_reloadGroups
.insert(groupID
, binding
);
750 void ConfigTaskWidget::addDefaultButton(QPushButton
*button
, int buttonGroup
)
752 button
->setProperty("group", buttonGroup
);
753 connect(button
, SIGNAL(clicked()), this, SLOT(defaultButtonClicked()));
756 void ConfigTaskWidget::addReloadButton(QPushButton
*button
, int buttonGroup
)
758 button
->setProperty("group", buttonGroup
);
759 m_reloadButtons
.append(button
);
760 connect(button
, SIGNAL(clicked()), this, SLOT(reloadButtonClicked()));
763 void ConfigTaskWidget::defaultButtonClicked()
765 int groupID
= sender()->property("group").toInt();
766 emit
defaultRequested(groupID
);
768 QList
<WidgetBinding
*> bindings
= m_reloadGroups
.values(groupID
);
769 foreach(WidgetBinding
* binding
, bindings
) {
770 if (!binding
->isEnabled() || !binding
->object() || !binding
->field()) {
773 UAVDataObject
*temp
= ((UAVDataObject
*)binding
->object())->dirtyClone();
774 setWidgetFromField(binding
->widget(), temp
->getField(binding
->field()->getName()), binding
);
778 void ConfigTaskWidget::reloadButtonClicked()
780 if (m_realtimeUpdateTimer
) {
783 int groupID
= sender()->property("group").toInt();
784 QList
<WidgetBinding
*> bindings
= m_reloadGroups
.values(groupID
);
785 if (bindings
.isEmpty()) {
788 ObjectPersistence
*objper
= dynamic_cast<ObjectPersistence
*>(getObjectManager()->getObject(ObjectPersistence::NAME
));
789 m_realtimeUpdateTimer
= new QTimer(this);
790 QEventLoop
*eventLoop
= new QEventLoop(this);
791 connect(m_realtimeUpdateTimer
, SIGNAL(timeout()), eventLoop
, SLOT(quit()));
792 connect(objper
, SIGNAL(objectUpdated(UAVObject
*)), eventLoop
, SLOT(quit()));
794 QList
<objectComparator
> temp
;
795 foreach(WidgetBinding
* binding
, bindings
) {
796 if (binding
->isEnabled() && binding
->object() != NULL
) {
797 objectComparator value
;
798 value
.objid
= binding
->object()->getObjID();
799 value
.objinstid
= binding
->object()->getInstID();
800 if (temp
.contains(value
)) {
805 ObjectPersistence::DataFields data
;
806 data
.Operation
= ObjectPersistence::OPERATION_LOAD
;
807 data
.Selection
= ObjectPersistence::SELECTION_SINGLEOBJECT
;
808 data
.ObjectID
= binding
->object()->getObjID();
809 data
.InstanceID
= binding
->object()->getInstID();
810 objper
->setData(data
);
812 m_realtimeUpdateTimer
->start(500);
814 if (m_realtimeUpdateTimer
->isActive()) {
815 binding
->object()->requestUpdate();
816 if (binding
->widget()) {
817 setWidgetFromField(binding
->widget(), binding
->field(), binding
);
820 m_realtimeUpdateTimer
->stop();
827 if (m_realtimeUpdateTimer
) {
828 delete m_realtimeUpdateTimer
;
829 m_realtimeUpdateTimer
= NULL
;
833 void ConfigTaskWidget::connectWidgetUpdatesToSlot(QWidget
*widget
, const char *function
)
838 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
839 connect(cb
, SIGNAL(currentIndexChanged(int)), this, function
, Qt::UniqueConnection
);
840 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
841 connect(cb
, SIGNAL(valueChanged(int)), this, function
, Qt::UniqueConnection
);
842 } else if (MixerCurveWidget
* cb
= qobject_cast
<MixerCurveWidget
*>(widget
)) {
843 connect(cb
, SIGNAL(curveUpdated()), this, function
, Qt::UniqueConnection
);
844 } else if (QTableWidget
* cb
= qobject_cast
<QTableWidget
*>(widget
)) {
845 connect(cb
, SIGNAL(cellChanged(int, int)), this, function
, Qt::UniqueConnection
);
846 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
847 connect(cb
, SIGNAL(valueChanged(int)), this, function
, Qt::UniqueConnection
);
848 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
849 connect(cb
, SIGNAL(valueChanged(double)), this, function
, Qt::UniqueConnection
);
850 } else if (QLineEdit
* cb
= qobject_cast
<QLineEdit
*>(widget
)) {
851 connect(cb
, SIGNAL(textChanged(QString
)), this, function
, Qt::UniqueConnection
);
852 } else if (QCheckBox
* cb
= qobject_cast
<QCheckBox
*>(widget
)) {
853 connect(cb
, SIGNAL(stateChanged(int)), this, function
, Qt::UniqueConnection
);
854 } else if (QPushButton
* cb
= qobject_cast
<QPushButton
*>(widget
)) {
855 connect(cb
, SIGNAL(clicked()), this, function
, Qt::UniqueConnection
);
856 } else if (QToolButton
* cb
= qobject_cast
<QToolButton
*>(widget
)) {
857 connect(cb
, SIGNAL(clicked()), this, function
, Qt::UniqueConnection
);
859 qDebug() << __FUNCTION__
<< "widget binding not implemented" << widget
->metaObject()->className();
863 void ConfigTaskWidget::disconnectWidgetUpdatesToSlot(QWidget
*widget
, const char *function
)
868 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
869 disconnect(cb
, SIGNAL(currentIndexChanged(int)), this, function
);
870 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
871 disconnect(cb
, SIGNAL(valueChanged(int)), this, function
);
872 } else if (MixerCurveWidget
* cb
= qobject_cast
<MixerCurveWidget
*>(widget
)) {
873 disconnect(cb
, SIGNAL(curveUpdated()), this, function
);
874 } else if (QTableWidget
* cb
= qobject_cast
<QTableWidget
*>(widget
)) {
875 disconnect(cb
, SIGNAL(cellChanged(int, int)), this, function
);
876 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
877 disconnect(cb
, SIGNAL(valueChanged(int)), this, function
);
878 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
879 disconnect(cb
, SIGNAL(valueChanged(double)), this, function
);
880 } else if (QLineEdit
* cb
= qobject_cast
<QLineEdit
*>(widget
)) {
881 disconnect(cb
, SIGNAL(textChanged(double)), this, function
);
882 } else if (QCheckBox
* cb
= qobject_cast
<QCheckBox
*>(widget
)) {
883 disconnect(cb
, SIGNAL(stateChanged(int)), this, function
);
884 } else if (QPushButton
* cb
= qobject_cast
<QPushButton
*>(widget
)) {
885 disconnect(cb
, SIGNAL(clicked()), this, function
);
886 } else if (QToolButton
* cb
= qobject_cast
<QToolButton
*>(widget
)) {
887 disconnect(cb
, SIGNAL(clicked()), this, function
);
889 qDebug() << __FUNCTION__
<< "widget binding not implemented" << widget
->metaObject()->className();
893 QVariant
ConfigTaskWidget::getVariantFromWidget(QWidget
*widget
, WidgetBinding
*binding
)
895 double scale
= binding
->scale();
897 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
898 if (binding
->isInteger()) {
899 return QVariant(getComboboxSelectedOption(cb
));
901 return (QString
)cb
->currentText();
902 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
903 return (double)(cb
->value() * scale
);
904 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
905 return (double)(cb
->value() * scale
);
906 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
907 return (double)(cb
->value() * scale
);
908 } else if (QCheckBox
* cb
= qobject_cast
<QCheckBox
*>(widget
)) {
909 return (QString
)(cb
->isChecked() ? "TRUE" : "FALSE");
910 } else if (QLineEdit
* cb
= qobject_cast
<QLineEdit
*>(widget
)) {
911 QString value
= (QString
)cb
->displayText();
912 if (binding
->units() == "hex") {
914 return value
.toUInt(&ok
, 16);
923 bool ConfigTaskWidget::setWidgetFromVariant(QWidget
*widget
, QVariant value
, WidgetBinding
*binding
)
925 double scale
= binding
->scale();
927 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
929 if (binding
->isInteger()) {
930 setComboboxSelectedOption(cb
, value
.toInt(&ok
));
932 cb
->setCurrentIndex(cb
->findText(value
.toString()));
935 } else if (QLabel
* cb
= qobject_cast
<QLabel
*>(widget
)) {
937 cb
->setText(value
.toString());
939 cb
->setText(QString::number((value
.toDouble() / scale
)));
942 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
943 cb
->setValue((double)(value
.toDouble() / scale
));
945 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
946 cb
->setValue((int)qRound(value
.toDouble() / scale
));
948 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
949 cb
->setValue((int)qRound(value
.toDouble() / scale
));
951 } else if (QCheckBox
* cb
= qobject_cast
<QCheckBox
*>(widget
)) {
952 bool bvalue
= value
.toString() == "TRUE";
953 cb
->setChecked(bvalue
);
955 } else if (QLineEdit
* cb
= qobject_cast
<QLineEdit
*>(widget
)) {
956 if ((scale
== 0) || (scale
== 1)) {
957 if (binding
->units() == "hex") {
958 cb
->setText(QString::number(value
.toUInt(), 16).toUpper());
960 cb
->setText(value
.toString());
963 cb
->setText(QString::number((value
.toDouble() / scale
)));
971 bool ConfigTaskWidget::setWidgetFromField(QWidget
*widget
, UAVObjectField
*field
, WidgetBinding
*binding
)
973 if (!widget
|| !field
) {
976 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
977 if (cb
->count() == 0) {
978 loadWidgetLimits(cb
, field
, binding
->index(), binding
->isLimited(), binding
->scale());
981 QVariant value
= field
->getValue(binding
->index());
982 checkWidgetsLimits(widget
, field
, binding
->index(), binding
->isLimited(), value
, binding
->scale());
983 bool result
= setWidgetFromVariant(widget
, value
, binding
);
987 qDebug() << __FUNCTION__
<< "widget to uavobject relation not implemented" << widget
->metaObject()->className();
992 void ConfigTaskWidget::checkWidgetsLimits(QWidget
*widget
, UAVObjectField
*field
, int index
, bool hasLimits
, QVariant value
, double scale
)
997 if (!field
->isWithinLimits(value
, index
, m_currentBoardId
)) {
998 if (!widget
->property("styleBackup").isValid()) {
999 widget
->setProperty("styleBackup", widget
->styleSheet());
1001 widget
->setStyleSheet(m_outOfLimitsStyle
);
1002 widget
->setProperty("wasOverLimits", (bool)true);
1003 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
1004 if (cb
->findText(value
.toString()) == -1) {
1005 cb
->addItem(value
.toString());
1007 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
1008 if ((double)(value
.toDouble() / scale
) > cb
->maximum()) {
1009 cb
->setMaximum((double)(value
.toDouble() / scale
));
1010 } else if ((double)(value
.toDouble() / scale
) < cb
->minimum()) {
1011 cb
->setMinimum((double)(value
.toDouble() / scale
));
1013 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
1014 if ((int)qRound(value
.toDouble() / scale
) > cb
->maximum()) {
1015 cb
->setMaximum((int)qRound(value
.toDouble() / scale
));
1016 } else if ((int)qRound(value
.toDouble() / scale
) < cb
->minimum()) {
1017 cb
->setMinimum((int)qRound(value
.toDouble() / scale
));
1019 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
1020 if ((int)qRound(value
.toDouble() / scale
) > cb
->maximum()) {
1021 cb
->setMaximum((int)qRound(value
.toDouble() / scale
));
1022 } else if ((int)qRound(value
.toDouble() / scale
) < cb
->minimum()) {
1023 cb
->setMinimum((int)qRound(value
.toDouble() / scale
));
1026 } else if (widget
->property("wasOverLimits").isValid()) {
1027 if (widget
->property("wasOverLimits").toBool()) {
1028 widget
->setProperty("wasOverLimits", (bool)false);
1029 if (widget
->property("styleBackup").isValid()) {
1030 QString style
= widget
->property("styleBackup").toString();
1031 widget
->setStyleSheet(style
);
1033 loadWidgetLimits(widget
, field
, index
, hasLimits
, scale
);
1038 void ConfigTaskWidget::loadWidgetLimits(QWidget
*widget
, UAVObjectField
*field
, int index
, bool hasLimits
, double scale
)
1040 if (!widget
|| !field
) {
1043 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
1045 QStringList options
= field
->getOptions();
1047 for (int optionIndex
= 0; optionIndex
< options
.count(); optionIndex
++) {
1049 if (m_currentBoardId
> -1 && field
->isWithinLimits(options
.at(optionIndex
), index
, m_currentBoardId
)) {
1050 cb
->addItem(options
.at(optionIndex
), QVariant(optionIndex
));
1053 cb
->addItem(options
.at(optionIndex
), QVariant(optionIndex
));
1059 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
1060 if (field
->getMaxLimit(index
).isValid()) {
1061 cb
->setMaximum((double)(field
->getMaxLimit(index
, m_currentBoardId
).toDouble() / scale
));
1063 if (field
->getMinLimit(index
, m_currentBoardId
).isValid()) {
1064 cb
->setMinimum((double)(field
->getMinLimit(index
, m_currentBoardId
).toDouble() / scale
));
1066 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
1067 if (field
->getMaxLimit(index
, m_currentBoardId
).isValid()) {
1068 cb
->setMaximum((int)qRound(field
->getMaxLimit(index
, m_currentBoardId
).toDouble() / scale
));
1070 if (field
->getMinLimit(index
, m_currentBoardId
).isValid()) {
1071 cb
->setMinimum((int)qRound(field
->getMinLimit(index
, m_currentBoardId
).toDouble() / scale
));
1073 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
1074 if (field
->getMaxLimit(index
, m_currentBoardId
).isValid()) {
1075 cb
->setMaximum((int)qRound(field
->getMaxLimit(index
, m_currentBoardId
).toDouble() / scale
));
1077 if (field
->getMinLimit(index
, m_currentBoardId
).isValid()) {
1078 cb
->setMinimum((int)(field
->getMinLimit(index
, m_currentBoardId
).toDouble() / scale
));
1083 UAVObject
*ConfigTaskWidget::getObject(const QString name
, quint32 instId
)
1085 return m_pluginManager
->getObject
<UAVObjectManager
>()->getObject(name
, instId
);
1088 QString
ConfigTaskWidget::mapObjectName(const QString objectName
)
1093 void ConfigTaskWidget::updateEnableControls()
1095 TelemetryManager
*telMngr
= m_pluginManager
->getObject
<TelemetryManager
>();
1099 enableControls(telMngr
->isConnected());
1102 void ConfigTaskWidget::disableMouseWheelEvents()
1104 // Disable mouse wheel events
1105 foreach(QSpinBox
* sp
, findChildren
<QSpinBox
*>()) {
1106 sp
->installEventFilter(this);
1108 foreach(QDoubleSpinBox
* sp
, findChildren
<QDoubleSpinBox
*>()) {
1109 sp
->installEventFilter(this);
1111 foreach(QSlider
* sp
, findChildren
<QSlider
*>()) {
1112 sp
->installEventFilter(this);
1114 foreach(QComboBox
* sp
, findChildren
<QComboBox
*>()) {
1115 sp
->installEventFilter(this);
1119 bool ConfigTaskWidget::eventFilter(QObject
*obj
, QEvent
*evt
)
1121 // Filter all wheel events, and ignore them
1122 if (evt
->type() == QEvent::Wheel
&&
1123 (qobject_cast
<QAbstractSpinBox
*>(obj
) ||
1124 qobject_cast
<QComboBox
*>(obj
) ||
1125 qobject_cast
<QAbstractSlider
*>(obj
))) {
1129 return QWidget::eventFilter(obj
, evt
);
1132 WidgetBinding::WidgetBinding(QWidget
*widget
, UAVObject
*object
, UAVObjectField
*field
, int index
, double scale
, bool isLimited
) :
1133 ShadowWidgetBinding(widget
, scale
, isLimited
), m_isEnabled(true)
1140 WidgetBinding::~WidgetBinding()
1143 QString
WidgetBinding::units() const
1146 return m_field
->getUnits();
1151 QString
WidgetBinding::type() const
1154 return m_field
->getTypeAsString();
1159 bool WidgetBinding::isInteger() const
1162 return m_field
->isInteger();
1167 UAVObject
*WidgetBinding::object() const
1172 UAVObjectField
*WidgetBinding::field() const
1177 int WidgetBinding::index() const
1182 QList
<ShadowWidgetBinding
*> WidgetBinding::shadows() const
1187 void WidgetBinding::addShadow(QWidget
*widget
, double scale
, bool isLimited
)
1189 ShadowWidgetBinding
*shadow
= NULL
;
1191 // Prefer anything else to QLabel and prefer QDoubleSpinBox to anything else
1192 if ((qobject_cast
<QLabel
*>(m_widget
) && !qobject_cast
<QLabel
*>(widget
)) ||
1193 (!qobject_cast
<QDoubleSpinBox
*>(m_widget
) && qobject_cast
<QDoubleSpinBox
*>(widget
))) {
1194 shadow
= new ShadowWidgetBinding(m_widget
, m_scale
, m_isLimited
);
1195 m_isLimited
= isLimited
;
1199 shadow
= new ShadowWidgetBinding(widget
, scale
, isLimited
);
1201 m_shadows
.append(shadow
);
1204 bool WidgetBinding::matches(QString objectName
, QString fieldName
, int index
, quint32 instanceId
)
1206 if (m_object
&& m_field
) {
1207 return m_object
->getName() == objectName
&& m_object
->getInstID() == instanceId
&&
1208 m_field
->getName() == fieldName
&& m_index
== index
;
1214 bool WidgetBinding::isEnabled() const
1219 void WidgetBinding::setIsEnabled(bool isEnabled
)
1221 m_isEnabled
= isEnabled
;
1224 QVariant
WidgetBinding::value() const
1229 void WidgetBinding::setValue(const QVariant
&value
)
1233 if (m_object && m_field) {
1234 qDebug() << "WidgetBinding" << m_object->getName() << ":" << m_field->getName() << "value =" << value.toString();
1239 void WidgetBinding::updateObjectFieldFromValue()
1241 if (m_value
.isValid()) {
1242 m_field
->setValue(m_value
, m_index
);
1246 void WidgetBinding::updateValueFromObjectField()
1248 if (m_field
->getValue(m_index
).isValid()) {
1249 m_value
= m_field
->getValue(m_index
);
1253 ShadowWidgetBinding::ShadowWidgetBinding(QWidget
*widget
, double scale
, bool isLimited
)
1257 m_isLimited
= isLimited
;
1260 ShadowWidgetBinding::~ShadowWidgetBinding()
1263 QWidget
*ShadowWidgetBinding::widget() const
1268 double ShadowWidgetBinding::scale() const
1273 bool ShadowWidgetBinding::isLimited() const