2 ******************************************************************************
4 * @file configtaskwidget.cpp
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015.
6 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
7 * @addtogroup GCSPlugins GCS Plugins
9 * @addtogroup UAVObjectWidgetUtils Plugin
11 * @brief Utility plugin for UAVObject to Widget relation management
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
28 #include "configtaskwidget.h"
30 #include <coreplugin/generalsettings.h>
31 #include "uavobjectmanager.h"
32 #include "uavobject.h"
33 #include "uavobjectutilmanager.h"
34 #include "uavtalk/telemetrymanager.h"
35 #include "uavtalk/oplinkmanager.h"
36 #include "uavsettingsimportexport/uavsettingsimportexportfactory.h"
37 #include "smartsavebutton.h"
38 #include "mixercurvewidget.h"
42 #include <QDesktopServices>
46 #include <QProgressBar>
47 #include <QTableWidget>
48 #include <QToolButton>
52 ConfigTaskWidget::ConfigTaskWidget(QWidget
*parent
, ConfigTaskType configType
) : QWidget(parent
),
53 m_currentBoardId(-1), m_isConnected(false), m_isWidgetUpdatesAllowed(true), m_isDirty(false), m_refreshing(false),
54 m_wikiURL("Welcome"), m_saveButton(NULL
), m_outOfLimitsStyle("background-color: rgb(255, 0, 0);"), m_realtimeUpdateTimer(NULL
)
56 m_configType
= configType
;
58 m_pluginManager
= ExtensionSystem::PluginManager::instance();
60 m_objectUtilManager
= m_pluginManager
->getObject
<UAVObjectUtilManager
>();
62 if (m_configType
!= Child
) {
63 UAVSettingsImportExportFactory
*importexportplugin
= m_pluginManager
->getObject
<UAVSettingsImportExportFactory
>();
64 connect(importexportplugin
, SIGNAL(importAboutToBegin()), this, SLOT(invalidateObjects()));
66 m_saveButton
= new SmartSaveButton(this);
67 connect(m_saveButton
, SIGNAL(beginOp()), this, SLOT(disableObjectUpdates()));
68 connect(m_saveButton
, SIGNAL(preProcessOperations()), this, SLOT(updateObjectsFromWidgets()));
69 connect(m_saveButton
, SIGNAL(endOp()), this, SLOT(enableObjectUpdates()));
70 connect(m_saveButton
, SIGNAL(saveSuccessful()), this, SLOT(saveSuccessful()));
73 switch (m_configType
) {
76 // connect to telemetry manager
77 TelemetryManager
*tm
= m_pluginManager
->getObject
<TelemetryManager
>();
78 connect(tm
, SIGNAL(connected()), this, SLOT(onConnect()));
79 connect(tm
, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
84 // connect to oplink manager
85 OPLinkManager
*om
= m_pluginManager
->getObject
<OPLinkManager
>();
86 connect(om
, SIGNAL(connected()), this, SLOT(onConnect()));
87 connect(om
, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
97 ConfigTaskWidget::~ConfigTaskWidget()
102 QSet
<WidgetBinding
*> deleteSet
= m_widgetBindingsPerWidget
.values().toSet();
103 foreach(WidgetBinding
* binding
, deleteSet
) {
108 if (m_realtimeUpdateTimer
) {
109 delete m_realtimeUpdateTimer
;
110 m_realtimeUpdateTimer
= NULL
;
114 bool ConfigTaskWidget::expertMode() const
116 Core::Internal::GeneralSettings
*settings
= m_pluginManager
->getObject
<Core::Internal::GeneralSettings
>();
118 return settings
->useExpertMode();
122 void ConfigTaskWidget::addWidget(QWidget
*widget
)
124 addWidgetBinding("", "", widget
);
127 void ConfigTaskWidget::addUAVObject(QString objectName
, QList
<int> *reloadGroups
)
129 addWidgetBinding(objectName
, "", NULL
, 0, 1, false, reloadGroups
);
132 void ConfigTaskWidget::addUAVObject(UAVObject
*objectName
, QList
<int> *reloadGroups
)
134 addUAVObject(objectName
? objectName
->getName() : QString(), reloadGroups
);
137 int ConfigTaskWidget::fieldIndexFromElementName(QString objectName
, QString fieldName
, QString elementName
)
139 if (elementName
.isEmpty() || objectName
.isEmpty()) {
143 QString singleObjectName
= mapObjectName(objectName
).split(",").at(0);
144 UAVObject
*object
= getObject(singleObjectName
);
147 UAVObjectField
*field
= object
->getField(fieldName
);
150 return field
->getElementNames().indexOf(elementName
);
153 void ConfigTaskWidget::addWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, QString elementName
)
155 addWidgetBinding(objectName
, fieldName
, widget
, fieldIndexFromElementName(objectName
, fieldName
, elementName
));
158 void ConfigTaskWidget::addWidgetBinding(UAVObject
*object
, UAVObjectField
*field
, QWidget
*widget
, QString elementName
)
160 addWidgetBinding(object
? object
->getName() : QString(), field
? field
->getName() : QString(), widget
, elementName
);
163 void ConfigTaskWidget::addWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, QString elementName
, double scale
,
164 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
166 addWidgetBinding(objectName
, fieldName
, widget
, fieldIndexFromElementName(objectName
, fieldName
, elementName
),
167 scale
, isLimited
, reloadGroupIDs
, instID
);
170 void ConfigTaskWidget::addWidgetBinding(UAVObject
*object
, UAVObjectField
*field
, QWidget
*widget
, QString elementName
, double scale
,
171 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
173 addWidgetBinding(object
? object
->getName() : QString(), field
? field
->getName() : QString(), widget
, elementName
, scale
,
174 isLimited
, reloadGroupIDs
, instID
);
177 void ConfigTaskWidget::addWidgetBinding(UAVObject
*object
, UAVObjectField
*field
, QWidget
*widget
, int index
, double scale
,
178 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
180 addWidgetBinding(object
? object
->getName() : QString(), field
? field
->getName() : QString(), widget
, index
, scale
,
181 isLimited
, reloadGroupIDs
, instID
);
184 void ConfigTaskWidget::addWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, int index
, double scale
,
185 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
187 QString mappedObjectName
= mapObjectName(objectName
);
189 // If object name is comma separated list of objects, call one time per objectName
190 foreach(QString singleObjectName
, mappedObjectName
.split(",")) {
191 doAddWidgetBinding(singleObjectName
, fieldName
, widget
, index
, scale
, isLimited
, reloadGroupIDs
, instID
);
195 void ConfigTaskWidget::doAddWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, int index
, double scale
,
196 bool isLimited
, QList
<int> *reloadGroupIDs
, quint32 instID
)
198 // add a shadow binding to an existing binding (if any)
199 if (addShadowWidgetBinding(objectName
, fieldName
, widget
, index
, scale
, isLimited
, reloadGroupIDs
, instID
)) {
200 // no need to go further if successful
204 // qDebug() << "ConfigTaskWidget::doAddWidgetBinding - add binding for " << objectName << fieldName << widget;
206 UAVObject
*object
= NULL
;
207 UAVObjectField
*field
= NULL
;
208 if (!objectName
.isEmpty()) {
209 object
= getObject(QString(objectName
), instID
);
211 m_updatedObjects
.insert(object
, true);
212 connect(object
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(objectUpdated(UAVObject
*)));
213 connect(object
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(refreshWidgetsValues(UAVObject
*)), Qt::UniqueConnection
);
216 if (!fieldName
.isEmpty() && object
) {
217 field
= object
->getField(QString(fieldName
));
221 WidgetBinding
*binding
= new WidgetBinding(widget
, object
, field
, index
, scale
, isLimited
);
222 // Only the first binding per widget can be enabled.
223 binding
->setIsEnabled(m_widgetBindingsPerWidget
.count(widget
) == 0);
224 m_widgetBindingsPerWidget
.insert(widget
, binding
);
227 m_widgetBindingsPerObject
.insert(object
, binding
);
229 m_saveButton
->addObject((UAVDataObject
*)object
);
234 if (reloadGroupIDs
&& object
) {
235 foreach(int groupId
, *reloadGroupIDs
) {
236 m_reloadGroups
.insert(groupId
, binding
);
240 connectWidgetUpdatesToSlot(widget
, SLOT(widgetsContentsChanged()));
241 if (reloadGroupIDs
) {
242 addWidgetToReloadGroups(widget
, reloadGroupIDs
);
244 if (binding
->isEnabled()) {
245 loadWidgetLimits(widget
, field
, index
, isLimited
, scale
);
250 void ConfigTaskWidget::setWidgetBindingObjectEnabled(QString objectName
, bool enabled
)
252 UAVObject
*object
= getObject(objectName
);
256 bool isRefreshing
= m_refreshing
;
259 foreach(WidgetBinding
* binding
, m_widgetBindingsPerObject
.values(object
)) {
260 binding
->setIsEnabled(enabled
);
262 if (binding
->value().isValid() && !binding
->value().isNull()) {
263 setWidgetFromVariant(binding
->widget(), binding
->value(), binding
);
265 setWidgetFromField(binding
->widget(), binding
->field(), binding
);
270 m_refreshing
= isRefreshing
;
273 bool ConfigTaskWidget::isComboboxOptionSelected(QComboBox
*combo
, int optionValue
)
276 int value
= combo
->currentData().toInt(&ok
);
278 return ok
? value
== optionValue
: false;
281 int ConfigTaskWidget::getComboboxSelectedOption(QComboBox
*combo
)
284 int index
= combo
->currentData().toInt(&ok
);
286 return ok
? index
: combo
->currentIndex();
289 void ConfigTaskWidget::setComboboxSelectedOption(QComboBox
*combo
, int optionValue
)
291 int index
= combo
->findData(QVariant(optionValue
));
294 combo
->setCurrentIndex(index
);
296 combo
->setCurrentIndex(optionValue
);
300 int ConfigTaskWidget::getComboboxIndexForOption(QComboBox
*combo
, int optionValue
)
302 return combo
->findData(QVariant(optionValue
));
305 void ConfigTaskWidget::enableComboBoxOptionItem(QComboBox
*combo
, int optionValue
, bool enable
)
307 combo
->model()->setData(combo
->model()->index(getComboboxIndexForOption(combo
, optionValue
), 0),
308 !enable
? QVariant(0) : QVariant(1 | 32), Qt::UserRole
- 1);
311 UAVObjectManager
*ConfigTaskWidget::getObjectManager()
313 UAVObjectManager
*objMngr
= m_pluginManager
->getObject
<UAVObjectManager
>();
319 bool ConfigTaskWidget::isConnected() const
321 bool connected
= false;
323 switch (m_configType
) {
326 TelemetryManager
*tm
= m_pluginManager
->getObject
<TelemetryManager
>();
327 connected
= tm
->isConnected();
332 OPLinkManager
*om
= m_pluginManager
->getObject
<OPLinkManager
>();
333 connected
= om
->isConnected();
345 // dynamic widgets don't receive the connected signal. This should be called instead.
346 void ConfigTaskWidget::bind()
351 refreshWidgetsValues();
352 updateEnableControls();
356 void ConfigTaskWidget::onConnect()
358 if (m_configType
== AutoPilot
) {
359 m_currentBoardId
= m_objectUtilManager
->getBoardModel();
362 m_isConnected
= true;
367 updateEnableControls();
371 refreshWidgetsValues();
376 void ConfigTaskWidget::onDisconnect()
378 m_isConnected
= false;
382 updateEnableControls();
386 m_currentBoardId
= -1;
389 void ConfigTaskWidget::refreshWidgetsValues(UAVObject
*obj
)
391 if (!m_isWidgetUpdatesAllowed
) {
395 bool isRefreshing
= m_refreshing
;
398 QList
<WidgetBinding
*> bindings
= obj
== NULL
? m_widgetBindingsPerObject
.values() : m_widgetBindingsPerObject
.values(obj
);
399 foreach(WidgetBinding
* binding
, bindings
) {
400 if (binding
->field() && binding
->widget()) {
401 if (binding
->isEnabled()) {
402 setWidgetFromField(binding
->widget(), binding
->field(), binding
);
404 binding
->updateValueFromObjectField();
409 // call specific implementation
410 refreshWidgetsValuesImpl(obj
);
412 m_refreshing
= isRefreshing
;
415 void ConfigTaskWidget::updateObjectsFromWidgets()
417 foreach(WidgetBinding
* binding
, m_widgetBindingsPerObject
) {
418 if (binding
->object() && binding
->field()) {
419 binding
->updateObjectFieldFromValue();
423 // call specific implementation
424 updateObjectsFromWidgetsImpl();
427 void ConfigTaskWidget::saveSuccessful()
429 // refresh values to reflect saved values
430 refreshWidgetsValues(NULL
);
432 // in case of failure to save we do nothing, config stays "dirty" (unsaved changes are kept)
435 void ConfigTaskWidget::helpButtonPressed()
437 QString url
= m_helpButtons
.value((QPushButton
*)sender(), QString());
439 if (!url
.isEmpty()) {
440 QDesktopServices::openUrl(QUrl(url
, QUrl::StrictMode
));
444 void ConfigTaskWidget::addApplyButton(QPushButton
*button
)
446 button
->setVisible(expertMode());
447 m_saveButton
->addApplyButton(button
);
450 void ConfigTaskWidget::addSaveButton(QPushButton
*button
)
452 m_saveButton
->addSaveButton(button
);
455 void ConfigTaskWidget::enableControls(bool enable
)
458 m_saveButton
->enableControls(enable
);
461 foreach(QPushButton
* button
, m_reloadButtons
) {
462 button
->setEnabled(enable
);
465 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
466 if (binding
->isEnabled() && binding
->widget()) {
467 binding
->widget()->setEnabled(enable
);
468 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
469 shadow
->widget()->setEnabled(enable
);
474 emit
enableControlsChanged(enable
);
477 bool ConfigTaskWidget::shouldObjectBeSaved(UAVObject
*object
)
483 void ConfigTaskWidget::widgetsContentsChanged()
485 QWidget
*emitter
= ((QWidget
*)sender());
486 emit
widgetContentsChanged(emitter
);
489 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
.values(emitter
)) {
490 if (binding
&& binding
->isEnabled()) {
491 if (binding
->widget() == emitter
) {
492 value
= getVariantFromWidget(emitter
, binding
);
493 checkWidgetsLimits(emitter
, binding
->field(), binding
->index(), binding
->isLimited(), value
, binding
->scale());
495 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
496 if (shadow
->widget() == emitter
) {
497 WidgetBinding
tmpBinding(shadow
->widget(), binding
->object(), binding
->field(),
498 binding
->index(), shadow
->scale(), shadow
->isLimited());
499 value
= getVariantFromWidget(emitter
, &tmpBinding
);
500 checkWidgetsLimits(emitter
, binding
->field(), binding
->index(), shadow
->isLimited(), value
, shadow
->scale());
504 binding
->setValue(value
);
506 if (binding
->widget() != emitter
) {
507 disconnectWidgetUpdatesToSlot(binding
->widget(), SLOT(widgetsContentsChanged()));
509 checkWidgetsLimits(binding
->widget(), binding
->field(), binding
->index(), binding
->isLimited(),
510 value
, binding
->scale());
511 setWidgetFromVariant(binding
->widget(), value
, binding
);
512 emit
widgetContentsChanged(binding
->widget());
514 connectWidgetUpdatesToSlot(binding
->widget(), SLOT(widgetsContentsChanged()));
516 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
517 if (shadow
->widget() != emitter
) {
518 disconnectWidgetUpdatesToSlot(shadow
->widget(), SLOT(widgetsContentsChanged()));
520 checkWidgetsLimits(shadow
->widget(), binding
->field(), binding
->index(), shadow
->isLimited(),
521 value
, shadow
->scale());
522 WidgetBinding
tmp(shadow
->widget(), binding
->object(), binding
->field(), binding
->index(), shadow
->scale(), shadow
->isLimited());
523 setWidgetFromVariant(shadow
->widget(), value
, &tmp
);
524 emit
widgetContentsChanged(shadow
->widget());
526 connectWidgetUpdatesToSlot(shadow
->widget(), SLOT(widgetsContentsChanged()));
532 m_saveButton
->resetIcons();
537 bool ConfigTaskWidget::isDirty()
539 return m_isConnected
? m_isDirty
: false;
542 void ConfigTaskWidget::setDirty(bool value
)
550 void ConfigTaskWidget::clearDirty()
555 void ConfigTaskWidget::disableObjectUpdates()
557 m_isWidgetUpdatesAllowed
= false;
558 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
559 if (binding
->object()) {
560 disconnect(binding
->object(), SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(refreshWidgetsValues(UAVObject
*)));
565 void ConfigTaskWidget::enableObjectUpdates()
567 m_isWidgetUpdatesAllowed
= true;
568 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
569 if (binding
->object()) {
570 connect(binding
->object(), SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(refreshWidgetsValues(UAVObject
*)), Qt::UniqueConnection
);
575 void ConfigTaskWidget::objectUpdated(UAVObject
*object
)
577 m_updatedObjects
[object
] = true;
580 bool ConfigTaskWidget::allObjectsUpdated()
584 foreach(UAVObject
* object
, m_updatedObjects
.keys()) {
585 result
&= m_updatedObjects
[object
];
593 void ConfigTaskWidget::addHelpButton(QPushButton
*button
, QString url
)
595 m_helpButtons
.insert(button
, url
);
596 connect(button
, SIGNAL(clicked()), this, SLOT(helpButtonPressed()));
599 void ConfigTaskWidget::setWikiURL(QString url
)
604 void ConfigTaskWidget::invalidateObjects()
606 foreach(UAVObject
* obj
, m_updatedObjects
.keys()) {
607 m_updatedObjects
[obj
] = false;
611 void ConfigTaskWidget::apply()
614 m_saveButton
->apply();
618 void ConfigTaskWidget::save()
621 m_saveButton
->save();
625 bool ConfigTaskWidget::addShadowWidgetBinding(QString objectName
, QString fieldName
, QWidget
*widget
, int index
, double scale
, bool isLimited
,
626 QList
<int> *defaultReloadGroups
, quint32 instID
)
628 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
629 if (!binding
->object() || !binding
->widget() || !binding
->field()) {
632 if (binding
->matches(objectName
, fieldName
, index
, instID
)) {
633 // qDebug() << "ConfigTaskWidget::addShadowWidgetBinding - add shadow binding for " << objectName << fieldName << widget;
634 binding
->addShadow(widget
, scale
, isLimited
);
636 m_widgetBindingsPerWidget
.insert(widget
, binding
);
637 connectWidgetUpdatesToSlot(widget
, SLOT(widgetsContentsChanged()));
638 if (defaultReloadGroups
) {
639 addWidgetToReloadGroups(widget
, defaultReloadGroups
);
641 if (binding
->isEnabled()) {
642 loadWidgetLimits(widget
, binding
->field(), binding
->index(), isLimited
, scale
);
650 void ConfigTaskWidget::addAutoBindings()
652 // qDebug() << "ConfigTaskWidget::addAutoBindings() - auto binding" << this;
654 foreach(QWidget
* widget
, this->findChildren
<QWidget
*>()) {
655 QVariant info
= widget
->property("objrelation");
657 if (info
.isValid()) {
658 BindingStruct uiRelation
;
659 uiRelation
.buttonType
= None
;
660 uiRelation
.scale
= 1;
661 uiRelation
.index
= -1;
662 uiRelation
.elementName
= QString();
663 uiRelation
.haslimits
= false;
664 foreach(QString str
, info
.toStringList()) {
665 QString prop
= str
.split(":").at(0);
666 QString value
= str
.split(":").at(1);
668 if (prop
== "objname") {
669 uiRelation
.objectName
= value
;
670 } else if (prop
== "fieldname") {
671 uiRelation
.fieldName
= value
;
672 } else if (prop
== "element") {
673 uiRelation
.elementName
= value
;
674 } else if (prop
== "index") {
675 uiRelation
.index
= value
.toInt();
676 } else if (prop
== "scale") {
677 if (value
== "null") {
678 uiRelation
.scale
= 1;
680 uiRelation
.scale
= value
.toDouble();
682 } else if (prop
== "haslimits") {
683 if (value
== "yes") {
684 uiRelation
.haslimits
= true;
686 uiRelation
.haslimits
= false;
688 } else if (prop
== "button") {
689 if (value
== "save") {
690 uiRelation
.buttonType
= SaveButton
;
691 } else if (value
== "apply") {
692 uiRelation
.buttonType
= ApplyButton
;
693 } else if (value
== "reload") {
694 uiRelation
.buttonType
= ReloadButton
;
695 } else if (value
== "default") {
696 uiRelation
.buttonType
= DefaultButton
;
697 } else if (value
== "help") {
698 uiRelation
.buttonType
= HelpButton
;
700 } else if (prop
== "buttongroup") {
701 foreach(QString s
, value
.split(",")) {
702 uiRelation
.buttonGroup
.append(s
.toInt());
704 } else if (prop
== "url") {
705 uiRelation
.url
= str
.mid(str
.indexOf(":") + 1);
708 if (uiRelation
.buttonType
!= None
) {
709 QPushButton
*button
= NULL
;
710 switch (uiRelation
.buttonType
) {
712 button
= qobject_cast
<QPushButton
*>(widget
);
714 addSaveButton(button
);
718 button
= qobject_cast
<QPushButton
*>(widget
);
720 addApplyButton(button
);
724 button
= qobject_cast
<QPushButton
*>(widget
);
726 addDefaultButton(button
, uiRelation
.buttonGroup
.at(0));
730 button
= qobject_cast
<QPushButton
*>(widget
);
732 addReloadButton(button
, uiRelation
.buttonGroup
.at(0));
736 button
= qobject_cast
<QPushButton
*>(widget
);
738 addHelpButton(button
, WIKI_URL_ROOT
+ m_wikiURL
);
746 QWidget
*wid
= qobject_cast
<QWidget
*>(widget
);
748 if (uiRelation
.index
!= -1) {
749 addWidgetBinding(uiRelation
.objectName
, uiRelation
.fieldName
, wid
, uiRelation
.index
, uiRelation
.scale
, uiRelation
.haslimits
, &uiRelation
.buttonGroup
);
751 addWidgetBinding(uiRelation
.objectName
, uiRelation
.fieldName
, wid
, uiRelation
.elementName
, uiRelation
.scale
, uiRelation
.haslimits
, &uiRelation
.buttonGroup
);
756 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
757 if (binding
->object()) {
758 m_saveButton
->addObject((UAVDataObject
*)binding
->object());
762 // qDebug() << "ConfigTaskWidget::addAutoBindings() - auto binding done for" << this;
765 void ConfigTaskWidget::dumpBindings()
767 foreach(WidgetBinding
* binding
, m_widgetBindingsPerObject
) {
768 if (binding
->widget()) {
769 qDebug() << "Binding :" << binding
->widget()->objectName();
770 qDebug() << " Object :" << binding
->object()->getName();
771 qDebug() << " Field :" << binding
->field()->getName();
772 qDebug() << " Scale :" << binding
->scale();
773 qDebug() << " Enabled:" << binding
->isEnabled();
775 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
776 if (shadow
->widget()) {
777 qDebug() << " Shadow:" << shadow
->widget()->objectName();
778 qDebug() << " Scale :" << shadow
->scale();
784 void ConfigTaskWidget::addWidgetToReloadGroups(QWidget
*widget
, QList
<int> *reloadGroupIDs
)
786 foreach(WidgetBinding
* binding
, m_widgetBindingsPerWidget
) {
787 bool addBinding
= false;
789 if (binding
->widget() == widget
) {
792 foreach(ShadowWidgetBinding
* shadow
, binding
->shadows()) {
793 if (shadow
->widget() == widget
) {
799 foreach(int groupID
, *reloadGroupIDs
) {
800 m_reloadGroups
.insert(groupID
, binding
);
806 void ConfigTaskWidget::addDefaultButton(QPushButton
*button
, int buttonGroup
)
808 button
->setProperty("group", buttonGroup
);
809 connect(button
, SIGNAL(clicked()), this, SLOT(defaultButtonClicked()));
812 void ConfigTaskWidget::addReloadButton(QPushButton
*button
, int buttonGroup
)
814 button
->setProperty("group", buttonGroup
);
815 m_reloadButtons
.append(button
);
816 connect(button
, SIGNAL(clicked()), this, SLOT(reloadButtonClicked()));
819 void ConfigTaskWidget::defaultButtonClicked()
821 int groupID
= sender()->property("group").toInt();
822 emit
defaultRequested(groupID
);
824 QList
<WidgetBinding
*> bindings
= m_reloadGroups
.values(groupID
);
825 foreach(WidgetBinding
* binding
, bindings
) {
826 if (!binding
->isEnabled() || !binding
->object() || !binding
->field()) {
829 UAVDataObject
*temp
= ((UAVDataObject
*)binding
->object())->dirtyClone();
830 setWidgetFromField(binding
->widget(), temp
->getField(binding
->field()->getName()), binding
);
834 void ConfigTaskWidget::reloadButtonClicked()
836 if (m_realtimeUpdateTimer
) {
839 int groupID
= sender()->property("group").toInt();
840 QList
<WidgetBinding
*> bindings
= m_reloadGroups
.values(groupID
);
841 if (bindings
.isEmpty()) {
844 ObjectPersistence
*objper
= dynamic_cast<ObjectPersistence
*>(getObjectManager()->getObject(ObjectPersistence::NAME
));
845 m_realtimeUpdateTimer
= new QTimer(this);
846 QEventLoop
*eventLoop
= new QEventLoop(this);
847 connect(m_realtimeUpdateTimer
, SIGNAL(timeout()), eventLoop
, SLOT(quit()));
848 connect(objper
, SIGNAL(objectUpdated(UAVObject
*)), eventLoop
, SLOT(quit()));
850 QList
<ObjectComparator
> temp
;
851 foreach(WidgetBinding
* binding
, bindings
) {
852 if (binding
->isEnabled() && binding
->object()) {
853 ObjectComparator value
;
854 value
.objid
= binding
->object()->getObjID();
855 value
.objinstid
= binding
->object()->getInstID();
856 if (temp
.contains(value
)) {
861 ObjectPersistence::DataFields data
;
862 data
.Operation
= ObjectPersistence::OPERATION_LOAD
;
863 data
.Selection
= ObjectPersistence::SELECTION_SINGLEOBJECT
;
864 data
.ObjectID
= binding
->object()->getObjID();
865 data
.InstanceID
= binding
->object()->getInstID();
866 objper
->setData(data
);
868 m_realtimeUpdateTimer
->start(500);
870 if (m_realtimeUpdateTimer
->isActive()) {
871 binding
->object()->requestUpdate();
872 if (binding
->widget()) {
873 setWidgetFromField(binding
->widget(), binding
->field(), binding
);
876 m_realtimeUpdateTimer
->stop();
883 if (m_realtimeUpdateTimer
) {
884 delete m_realtimeUpdateTimer
;
885 m_realtimeUpdateTimer
= NULL
;
889 void ConfigTaskWidget::connectWidgetUpdatesToSlot(QWidget
*widget
, const char *function
)
894 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
895 connect(cb
, SIGNAL(currentIndexChanged(int)), this, function
, Qt::UniqueConnection
);
896 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
897 connect(cb
, SIGNAL(valueChanged(int)), this, function
, Qt::UniqueConnection
);
898 } else if (MixerCurveWidget
* cb
= qobject_cast
<MixerCurveWidget
*>(widget
)) {
899 connect(cb
, SIGNAL(curveUpdated()), this, function
, Qt::UniqueConnection
);
900 } else if (QTableWidget
* cb
= qobject_cast
<QTableWidget
*>(widget
)) {
901 connect(cb
, SIGNAL(cellChanged(int, int)), this, function
, Qt::UniqueConnection
);
902 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
903 connect(cb
, SIGNAL(valueChanged(int)), this, function
, Qt::UniqueConnection
);
904 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
905 connect(cb
, SIGNAL(valueChanged(double)), this, function
, Qt::UniqueConnection
);
906 } else if (QLineEdit
* cb
= qobject_cast
<QLineEdit
*>(widget
)) {
907 connect(cb
, SIGNAL(textChanged(QString
)), this, function
, Qt::UniqueConnection
);
908 } else if (QCheckBox
* cb
= qobject_cast
<QCheckBox
*>(widget
)) {
909 connect(cb
, SIGNAL(stateChanged(int)), this, function
, Qt::UniqueConnection
);
910 } else if (QPushButton
* cb
= qobject_cast
<QPushButton
*>(widget
)) {
911 connect(cb
, SIGNAL(clicked()), this, function
, Qt::UniqueConnection
);
912 } else if (QToolButton
* cb
= qobject_cast
<QToolButton
*>(widget
)) {
913 connect(cb
, SIGNAL(clicked()), this, function
, Qt::UniqueConnection
);
914 } else if (qobject_cast
<QLabel
*>(widget
)) {
916 } else if (qobject_cast
<QProgressBar
*>(widget
)) {
919 qDebug() << __FUNCTION__
<< "widget binding not implemented for" << widget
->metaObject()->className();
923 void ConfigTaskWidget::disconnectWidgetUpdatesToSlot(QWidget
*widget
, const char *function
)
928 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
929 disconnect(cb
, SIGNAL(currentIndexChanged(int)), this, function
);
930 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
931 disconnect(cb
, SIGNAL(valueChanged(int)), this, function
);
932 } else if (MixerCurveWidget
* cb
= qobject_cast
<MixerCurveWidget
*>(widget
)) {
933 disconnect(cb
, SIGNAL(curveUpdated()), this, function
);
934 } else if (QTableWidget
* cb
= qobject_cast
<QTableWidget
*>(widget
)) {
935 disconnect(cb
, SIGNAL(cellChanged(int, int)), this, function
);
936 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
937 disconnect(cb
, SIGNAL(valueChanged(int)), this, function
);
938 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
939 disconnect(cb
, SIGNAL(valueChanged(double)), this, function
);
940 } else if (QLineEdit
* cb
= qobject_cast
<QLineEdit
*>(widget
)) {
941 disconnect(cb
, SIGNAL(textChanged(double)), this, function
);
942 } else if (QCheckBox
* cb
= qobject_cast
<QCheckBox
*>(widget
)) {
943 disconnect(cb
, SIGNAL(stateChanged(int)), this, function
);
944 } else if (QPushButton
* cb
= qobject_cast
<QPushButton
*>(widget
)) {
945 disconnect(cb
, SIGNAL(clicked()), this, function
);
946 } else if (QToolButton
* cb
= qobject_cast
<QToolButton
*>(widget
)) {
947 disconnect(cb
, SIGNAL(clicked()), this, function
);
948 } else if (qobject_cast
<QLabel
*>(widget
)) {
950 } else if (qobject_cast
<QProgressBar
*>(widget
)) {
953 qDebug() << __FUNCTION__
<< "widget binding not implemented for" << widget
->metaObject()->className();
957 QVariant
ConfigTaskWidget::getVariantFromWidget(QWidget
*widget
, WidgetBinding
*binding
)
959 double scale
= binding
->scale();
961 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
962 if (binding
->isInteger()) {
963 return QVariant(getComboboxSelectedOption(cb
));
965 return cb
->currentText();
966 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
967 return (double)(cb
->value() * scale
);
968 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
969 return (double)(cb
->value() * scale
);
970 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
971 return (double)(cb
->value() * scale
);
972 } else if (QCheckBox
* cb
= qobject_cast
<QCheckBox
*>(widget
)) {
973 return cb
->isChecked() ? "True" : "False";
974 } else if (QLineEdit
* cb
= qobject_cast
<QLineEdit
*>(widget
)) {
975 QString value
= cb
->displayText();
976 if (binding
->units() == "hex") {
978 return value
.toUInt(&ok
, 16);
986 bool ConfigTaskWidget::setWidgetFromVariant(QWidget
*widget
, QVariant value
, WidgetBinding
*binding
)
988 double scale
= binding
->scale();
990 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
992 if (binding
->isInteger()) {
993 setComboboxSelectedOption(cb
, value
.toInt(&ok
));
995 cb
->setCurrentIndex(cb
->findText(value
.toString()));
998 } else if (QLabel
* cb
= qobject_cast
<QLabel
*>(widget
)) {
999 if ((scale
== 0) || (scale
== 1)) {
1000 if (binding
->units() == "hex") {
1001 if (value
.toUInt()) {
1002 cb
->setText(QString::number(value
.toUInt(), 16).toUpper());
1004 // display 0 as an empty string
1008 cb
->setText(value
.toString());
1011 cb
->setText(QString::number(value
.toDouble() / scale
));
1014 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
1015 cb
->setValue((double)(value
.toDouble() / scale
));
1017 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
1018 cb
->setValue((int)qRound(value
.toDouble() / scale
));
1020 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
1021 cb
->setValue((int)qRound(value
.toDouble() / scale
));
1023 } else if (QCheckBox
* cb
= qobject_cast
<QCheckBox
*>(widget
)) {
1024 cb
->setChecked(value
.toString() == "True");
1026 } else if (QLineEdit
* cb
= qobject_cast
<QLineEdit
*>(widget
)) {
1027 if ((scale
== 0) || (scale
== 1)) {
1028 if (binding
->units() == "hex") {
1029 if (value
.toUInt()) {
1030 cb
->setText(QString::number(value
.toUInt(), 16).toUpper());
1032 // display 0 as an empty string
1036 cb
->setText(value
.toString());
1039 cb
->setText(QString::number(value
.toDouble() / scale
));
1046 bool ConfigTaskWidget::setWidgetFromField(QWidget
*widget
, UAVObjectField
*field
, WidgetBinding
*binding
)
1048 if (!widget
|| !field
) {
1051 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
1052 if (cb
->count() == 0) {
1053 loadWidgetLimits(cb
, field
, binding
->index(), binding
->isLimited(), binding
->scale());
1056 QVariant value
= field
->getValue(binding
->index());
1057 checkWidgetsLimits(widget
, field
, binding
->index(), binding
->isLimited(), value
, binding
->scale());
1058 bool result
= setWidgetFromVariant(widget
, value
, binding
);
1062 qDebug() << __FUNCTION__
<< "widget to uavobject relation not implemented for" << widget
->metaObject()->className();
1067 void ConfigTaskWidget::resetLimits()
1069 // clear bound combo box lists to force repopulation
1070 // when we get another connected signal. This means that we get the
1071 // correct values in combo boxes bound to fields with limits applied.
1072 foreach(WidgetBinding
* binding
, m_widgetBindingsPerObject
) {
1075 if (binding
->widget() && (cb
= qobject_cast
<QComboBox
*>(binding
->widget()))) {
1081 void ConfigTaskWidget::checkWidgetsLimits(QWidget
*widget
, UAVObjectField
*field
, int index
, bool hasLimits
, QVariant value
, double scale
)
1086 if (!field
->isWithinLimits(value
, index
, m_currentBoardId
)) {
1087 if (!widget
->property("styleBackup").isValid()) {
1088 widget
->setProperty("styleBackup", widget
->styleSheet());
1090 widget
->setStyleSheet(m_outOfLimitsStyle
);
1091 widget
->setProperty("wasOverLimits", (bool)true);
1092 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
1093 if (cb
->findText(value
.toString()) == -1) {
1094 cb
->addItem(value
.toString());
1096 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
1097 if ((double)(value
.toDouble() / scale
) > cb
->maximum()) {
1098 cb
->setMaximum((double)(value
.toDouble() / scale
));
1099 } else if ((double)(value
.toDouble() / scale
) < cb
->minimum()) {
1100 cb
->setMinimum((double)(value
.toDouble() / scale
));
1102 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
1103 if ((int)qRound(value
.toDouble() / scale
) > cb
->maximum()) {
1104 cb
->setMaximum((int)qRound(value
.toDouble() / scale
));
1105 } else if ((int)qRound(value
.toDouble() / scale
) < cb
->minimum()) {
1106 cb
->setMinimum((int)qRound(value
.toDouble() / scale
));
1108 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
1109 if ((int)qRound(value
.toDouble() / scale
) > cb
->maximum()) {
1110 cb
->setMaximum((int)qRound(value
.toDouble() / scale
));
1111 } else if ((int)qRound(value
.toDouble() / scale
) < cb
->minimum()) {
1112 cb
->setMinimum((int)qRound(value
.toDouble() / scale
));
1115 } else if (widget
->property("wasOverLimits").isValid()) {
1116 if (widget
->property("wasOverLimits").toBool()) {
1117 widget
->setProperty("wasOverLimits", (bool)false);
1118 if (widget
->property("styleBackup").isValid()) {
1119 QString style
= widget
->property("styleBackup").toString();
1120 widget
->setStyleSheet(style
);
1122 loadWidgetLimits(widget
, field
, index
, hasLimits
, scale
);
1127 void ConfigTaskWidget::loadWidgetLimits(QWidget
*widget
, UAVObjectField
*field
, int index
, bool applyLimits
, double scale
)
1129 if (!widget
|| !field
) {
1132 if (QComboBox
* cb
= qobject_cast
<QComboBox
*>(widget
)) {
1134 buildOptionComboBox(cb
, field
, index
, applyLimits
);
1138 } else if (QDoubleSpinBox
* cb
= qobject_cast
<QDoubleSpinBox
*>(widget
)) {
1139 if (field
->getMaxLimit(index
).isValid()) {
1140 cb
->setMaximum((double)(field
->getMaxLimit(index
, m_currentBoardId
).toDouble() / scale
));
1142 if (field
->getMinLimit(index
, m_currentBoardId
).isValid()) {
1143 cb
->setMinimum((double)(field
->getMinLimit(index
, m_currentBoardId
).toDouble() / scale
));
1145 } else if (QSpinBox
* cb
= qobject_cast
<QSpinBox
*>(widget
)) {
1146 if (field
->getMaxLimit(index
, m_currentBoardId
).isValid()) {
1147 cb
->setMaximum((int)qRound(field
->getMaxLimit(index
, m_currentBoardId
).toDouble() / scale
));
1149 if (field
->getMinLimit(index
, m_currentBoardId
).isValid()) {
1150 cb
->setMinimum((int)qRound(field
->getMinLimit(index
, m_currentBoardId
).toDouble() / scale
));
1152 } else if (QSlider
* cb
= qobject_cast
<QSlider
*>(widget
)) {
1153 if (field
->getMaxLimit(index
, m_currentBoardId
).isValid()) {
1154 cb
->setMaximum((int)qRound(field
->getMaxLimit(index
, m_currentBoardId
).toDouble() / scale
));
1156 if (field
->getMinLimit(index
, m_currentBoardId
).isValid()) {
1157 cb
->setMinimum((int)(field
->getMinLimit(index
, m_currentBoardId
).toDouble() / scale
));
1162 UAVObject
*ConfigTaskWidget::getObject(const QString name
, quint32 instId
)
1164 return m_pluginManager
->getObject
<UAVObjectManager
>()->getObject(name
, instId
);
1167 QString
ConfigTaskWidget::mapObjectName(const QString objectName
)
1172 void ConfigTaskWidget::updateEnableControls()
1174 enableControls(isConnected());
1177 void ConfigTaskWidget::buildOptionComboBox(QComboBox
*combo
, UAVObjectField
*field
, int index
, bool applyLimits
)
1179 QStringList options
= field
->getOptions();
1181 // qDebug() << "buildOptionComboBox" << field << applyLimits << m_currentBoardId;
1182 for (int optionIndex
= 0; optionIndex
< options
.count(); optionIndex
++) {
1184 // qDebug() << " " << options.at(optionIndex) << field->isWithinLimits(options.at(optionIndex), index, m_currentBoardId);
1185 if (m_currentBoardId
> -1 && field
->isWithinLimits(options
.at(optionIndex
), index
, m_currentBoardId
)) {
1186 combo
->addItem(options
.at(optionIndex
), QVariant(optionIndex
));
1189 combo
->addItem(options
.at(optionIndex
), QVariant(optionIndex
));
1194 void ConfigTaskWidget::disableMouseWheelEvents()
1196 // Disable mouse wheel events
1197 foreach(QSpinBox
* sp
, findChildren
<QSpinBox
*>()) {
1198 sp
->installEventFilter(this);
1200 foreach(QDoubleSpinBox
* sp
, findChildren
<QDoubleSpinBox
*>()) {
1201 sp
->installEventFilter(this);
1203 foreach(QSlider
* sp
, findChildren
<QSlider
*>()) {
1204 sp
->installEventFilter(this);
1206 foreach(QComboBox
* sp
, findChildren
<QComboBox
*>()) {
1207 sp
->installEventFilter(this);
1211 bool ConfigTaskWidget::eventFilter(QObject
*obj
, QEvent
*evt
)
1213 // Filter all wheel events, and ignore them
1214 if (evt
->type() == QEvent::Wheel
&&
1215 (qobject_cast
<QAbstractSpinBox
*>(obj
) ||
1216 qobject_cast
<QComboBox
*>(obj
) ||
1217 qobject_cast
<QAbstractSlider
*>(obj
))) {
1221 return QWidget::eventFilter(obj
, evt
);
1224 WidgetBinding::WidgetBinding(QWidget
*widget
, UAVObject
*object
, UAVObjectField
*field
, int index
, double scale
, bool isLimited
) :
1225 ShadowWidgetBinding(widget
, scale
, isLimited
), m_isEnabled(true)
1232 WidgetBinding::~WidgetBinding()
1235 QString
WidgetBinding::units() const
1238 return m_field
->getUnits();
1243 QString
WidgetBinding::type() const
1246 return m_field
->getTypeAsString();
1251 bool WidgetBinding::isInteger() const
1254 return m_field
->isInteger();
1259 UAVObject
*WidgetBinding::object() const
1264 UAVObjectField
*WidgetBinding::field() const
1269 int WidgetBinding::index() const
1274 QList
<ShadowWidgetBinding
*> WidgetBinding::shadows() const
1279 void WidgetBinding::addShadow(QWidget
*widget
, double scale
, bool isLimited
)
1281 ShadowWidgetBinding
*shadow
= NULL
;
1283 // Prefer anything else to QLabel and prefer QDoubleSpinBox to anything else
1284 if ((qobject_cast
<QLabel
*>(m_widget
) && !qobject_cast
<QLabel
*>(widget
)) ||
1285 (!qobject_cast
<QDoubleSpinBox
*>(m_widget
) && qobject_cast
<QDoubleSpinBox
*>(widget
))) {
1286 shadow
= new ShadowWidgetBinding(m_widget
, m_scale
, m_isLimited
);
1287 m_isLimited
= isLimited
;
1291 shadow
= new ShadowWidgetBinding(widget
, scale
, isLimited
);
1293 m_shadows
.append(shadow
);
1296 bool WidgetBinding::matches(QString objectName
, QString fieldName
, int index
, quint32 instanceId
)
1298 if (m_object
&& m_field
) {
1299 return m_object
->getName() == objectName
&& m_object
->getInstID() == instanceId
&&
1300 m_field
->getName() == fieldName
&& m_index
== index
;
1306 bool WidgetBinding::isEnabled() const
1311 void WidgetBinding::setIsEnabled(bool isEnabled
)
1313 m_isEnabled
= isEnabled
;
1316 QVariant
WidgetBinding::value() const
1321 void WidgetBinding::setValue(const QVariant
&value
)
1326 void WidgetBinding::updateObjectFieldFromValue()
1328 if (m_value
.isValid()) {
1329 m_field
->setValue(m_value
, m_index
);
1333 void WidgetBinding::updateValueFromObjectField()
1335 if (m_field
->getValue(m_index
).isValid()) {
1336 m_value
= m_field
->getValue(m_index
);
1340 ShadowWidgetBinding::ShadowWidgetBinding(QWidget
*widget
, double scale
, bool isLimited
)
1344 m_isLimited
= isLimited
;
1347 ShadowWidgetBinding::~ShadowWidgetBinding()
1350 QWidget
*ShadowWidgetBinding::widget() const
1355 double ShadowWidgetBinding::scale() const
1360 bool ShadowWidgetBinding::isLimited() const