LP-56 - Better txpid option namings, fix tabs-spaces, tooltips. headers, variable...
[librepilot.git] / ground / openpilotgcs / src / plugins / uavobjectwidgetutils / configtaskwidget.cpp
blob1ba588a859baea1aec9717958081a1f564dcf9dd
1 /**
2 ******************************************************************************
4 * @file configtaskwidget.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * @addtogroup GCSPlugins GCS Plugins
7 * @{
8 * @addtogroup UAVObjectWidgetUtils Plugin
9 * @{
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
21 * for more details.
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"
32 #include <QWidget>
33 #include <QLineEdit>
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()) {
68 return 0;
71 QString singleObjectName = mapObjectName(objectName).split(",").at(0);
72 UAVObject *object = getObject(singleObjectName);
73 Q_ASSERT(object);
75 UAVObjectField *field = object->getField(fieldName);
76 Q_ASSERT(field);
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)) {
127 return;
130 UAVObject *object = NULL;
131 UAVObjectField *field = NULL;
132 if (!objectName.isEmpty()) {
133 object = getObject(QString(objectName), instID);
134 Q_ASSERT(object);
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));
142 Q_ASSERT(field);
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);
150 if (object) {
151 m_widgetBindingsPerObject.insert(object, binding);
152 if (m_saveButton) {
153 m_saveButton->addObject((UAVDataObject *)object);
157 if (!widget) {
158 if (reloadGroupIDs && object) {
159 foreach(int groupId, *reloadGroupIDs) {
160 m_reloadGroups.insert(groupId, binding);
163 } else {
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);
178 Q_ASSERT(object);
180 bool dirtyBack = isDirty();
182 foreach(WidgetBinding * binding, m_widgetBindingsPerObject.values(object)) {
183 binding->setIsEnabled(enabled);
184 if (enabled) {
185 if (binding->value().isValid() && !binding->value().isNull()) {
186 setWidgetFromVariant(binding->widget(), binding->value(), binding);
187 } else {
188 setWidgetFromField(binding->widget(), binding->field(), binding);
192 setDirty(dirtyBack);
195 ConfigTaskWidget::~ConfigTaskWidget()
197 if (m_saveButton) {
198 delete m_saveButton;
200 QSet<WidgetBinding *> deleteSet = m_widgetBindingsPerWidget.values().toSet();
201 foreach(WidgetBinding * binding, deleteSet) {
202 if (binding) {
203 delete binding;
206 if (m_realtimeUpdateTimer) {
207 delete m_realtimeUpdateTimer;
208 m_realtimeUpdateTimer = NULL;
212 bool ConfigTaskWidget::isComboboxOptionSelected(QComboBox *combo, int optionValue)
214 bool ok;
215 int value = combo->currentData().toInt(&ok);
217 return ok ? value == optionValue : false;
220 int ConfigTaskWidget::getComboboxSelectedOption(QComboBox *combo)
222 bool ok;
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));
232 if (index != -1) {
233 combo->setCurrentIndex(index);
234 } else {
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>();
265 Q_ASSERT(objMngr);
266 return objMngr;
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) {
280 QComboBox *cb;
282 if (binding->widget() && (cb = qobject_cast<QComboBox *>(binding->widget()))) {
283 cb->clear();
287 enableControls(false);
288 invalidateObjects();
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;
298 setDirty(false);
301 void ConfigTaskWidget::onAutopilotConnect()
303 if (m_objectUtilManager) {
304 m_currentBoardId = m_objectUtilManager->getBoardModel();
306 invalidateObjects();
307 m_isConnected = true;
308 setDirty(false);
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);
323 setDirty(dirtyBack);
326 void ConfigTaskWidget::refreshWidgetsValues(UAVObject *obj)
328 if (!m_isWidgetUpdatesAllowed) {
329 return;
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);
339 } else {
340 binding->updateValueFromObjectField();
344 setDirty(dirtyBack);
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)
369 if (!m_saveButton) {
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);
378 } else if (update) {
379 m_saveButton->addApplyButton(update);
380 } else if (save) {
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)
391 if (m_saveButton) {
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)
412 Q_UNUSED(object);
413 return true;
416 void ConfigTaskWidget::forceShadowUpdates()
418 foreach(WidgetBinding * binding, m_widgetBindingsPerObject) {
419 if (!binding->isEnabled()) {
420 continue;
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()));
436 setDirty(true);
439 void ConfigTaskWidget::widgetsContentsChanged()
441 QWidget *emitter = ((QWidget *)sender());
442 emit widgetContentsChanged(emitter);
443 QVariant value;
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());
450 } else {
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()));
487 if (m_saveButton) {
488 m_saveButton->resetIcons();
490 setDirty(true);
493 void ConfigTaskWidget::clearDirty()
495 setDirty(false);
498 void ConfigTaskWidget::setDirty(bool value)
500 m_isDirty = value;
503 bool ConfigTaskWidget::isDirty()
505 if (m_isConnected) {
506 return m_isDirty;
507 } else {
508 return false;
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()
539 bool result = true;
541 foreach(UAVObject * object, m_updatedObjects.keys()) {
542 result = result & m_updatedObjects[object];
544 return result;
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()
562 if (m_saveButton) {
563 m_saveButton->apply();
567 void ConfigTaskWidget::save()
569 if (m_saveButton) {
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()) {
579 continue;
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);
592 return true;
595 return false;
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;
628 } else {
629 uiRelation.scale = value.toDouble();
631 } else if (prop == "haslimits") {
632 if (value == "yes") {
633 uiRelation.haslimits = true;
634 } else {
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) {
660 case save_button:
661 saveButtonWidget = qobject_cast<QPushButton *>(widget);
662 if (saveButtonWidget) {
663 addApplySaveButtons(NULL, saveButtonWidget);
665 break;
666 case apply_button:
667 applyButtonWidget = qobject_cast<QPushButton *>(widget);
668 if (applyButtonWidget) {
669 addApplySaveButtons(applyButtonWidget, NULL);
671 break;
672 case default_button:
673 button = qobject_cast<QPushButton *>(widget);
674 if (button) {
675 addDefaultButton(button, uiRelation.buttonGroup.at(0));
677 break;
678 case reload_button:
679 button = qobject_cast<QPushButton *>(widget);
680 if (button) {
681 addReloadButton(button, uiRelation.buttonGroup.at(0));
683 break;
684 case help_button:
685 button = qobject_cast<QPushButton *>(widget);
686 if (button) {
687 addHelpButton(button, uiRelation.url);
689 break;
691 default:
692 break;
694 } else {
695 QWidget *wid = qobject_cast<QWidget *>(widget);
696 if (wid) {
697 if (uiRelation.index != -1) {
698 addWidgetBinding(uiRelation.objectName, uiRelation.fieldName, wid, uiRelation.index, uiRelation.scale, uiRelation.haslimits, &uiRelation.buttonGroup);
699 } else {
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) {
734 addBinding = true;
735 } else {
736 foreach(ShadowWidgetBinding * shadow, binding->shadows()) {
737 if (shadow->widget() == widget) {
738 addBinding = true;
742 if (addBinding) {
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()) {
771 continue;
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) {
781 return;
783 int groupID = sender()->property("group").toInt();
784 QList<WidgetBinding *> bindings = m_reloadGroups.values(groupID);
785 if (bindings.isEmpty()) {
786 return;
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)) {
801 continue;
802 } else {
803 temp.append(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);
811 objper->updated();
812 m_realtimeUpdateTimer->start(500);
813 eventLoop->exec();
814 if (m_realtimeUpdateTimer->isActive()) {
815 binding->object()->requestUpdate();
816 if (binding->widget()) {
817 setWidgetFromField(binding->widget(), binding->field(), binding);
820 m_realtimeUpdateTimer->stop();
823 if (eventLoop) {
824 delete eventLoop;
825 eventLoop = NULL;
827 if (m_realtimeUpdateTimer) {
828 delete m_realtimeUpdateTimer;
829 m_realtimeUpdateTimer = NULL;
833 void ConfigTaskWidget::connectWidgetUpdatesToSlot(QWidget *widget, const char *function)
835 if (!widget) {
836 return;
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);
858 } else {
859 qDebug() << __FUNCTION__ << "widget binding not implemented" << widget->metaObject()->className();
863 void ConfigTaskWidget::disconnectWidgetUpdatesToSlot(QWidget *widget, const char *function)
865 if (!widget) {
866 return;
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);
888 } else {
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") {
913 bool ok;
914 return value.toUInt(&ok, 16);
915 } else {
916 return value;
918 } else {
919 return QVariant();
923 bool ConfigTaskWidget::setWidgetFromVariant(QWidget *widget, QVariant value, WidgetBinding *binding)
925 double scale = binding->scale();
927 if (QComboBox * cb = qobject_cast<QComboBox *>(widget)) {
928 bool ok = true;
929 if (binding->isInteger()) {
930 setComboboxSelectedOption(cb, value.toInt(&ok));
931 } else {
932 cb->setCurrentIndex(cb->findText(value.toString()));
934 return ok;
935 } else if (QLabel * cb = qobject_cast<QLabel *>(widget)) {
936 if (scale == 0) {
937 cb->setText(value.toString());
938 } else {
939 cb->setText(QString::number((value.toDouble() / scale)));
941 return true;
942 } else if (QDoubleSpinBox * cb = qobject_cast<QDoubleSpinBox *>(widget)) {
943 cb->setValue((double)(value.toDouble() / scale));
944 return true;
945 } else if (QSpinBox * cb = qobject_cast<QSpinBox *>(widget)) {
946 cb->setValue((int)qRound(value.toDouble() / scale));
947 return true;
948 } else if (QSlider * cb = qobject_cast<QSlider *>(widget)) {
949 cb->setValue((int)qRound(value.toDouble() / scale));
950 return true;
951 } else if (QCheckBox * cb = qobject_cast<QCheckBox *>(widget)) {
952 bool bvalue = value.toString() == "TRUE";
953 cb->setChecked(bvalue);
954 return true;
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());
959 } else {
960 cb->setText(value.toString());
962 } else {
963 cb->setText(QString::number((value.toDouble() / scale)));
965 return true;
966 } else {
967 return false;
971 bool ConfigTaskWidget::setWidgetFromField(QWidget *widget, UAVObjectField *field, WidgetBinding *binding)
973 if (!widget || !field) {
974 return false;
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);
984 if (result) {
985 return true;
986 } else {
987 qDebug() << __FUNCTION__ << "widget to uavobject relation not implemented" << widget->metaObject()->className();
988 return false;
992 void ConfigTaskWidget::checkWidgetsLimits(QWidget *widget, UAVObjectField *field, int index, bool hasLimits, QVariant value, double scale)
994 if (!hasLimits) {
995 return;
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) {
1041 return;
1043 if (QComboBox * cb = qobject_cast<QComboBox *>(widget)) {
1044 cb->clear();
1045 QStringList options = field->getOptions();
1047 for (int optionIndex = 0; optionIndex < options.count(); optionIndex++) {
1048 if (hasLimits) {
1049 if (m_currentBoardId > -1 && field->isWithinLimits(options.at(optionIndex), index, m_currentBoardId)) {
1050 cb->addItem(options.at(optionIndex), QVariant(optionIndex));
1052 } else {
1053 cb->addItem(options.at(optionIndex), QVariant(optionIndex));
1057 if (!hasLimits) {
1058 return;
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)
1090 return objectName;
1093 void ConfigTaskWidget::updateEnableControls()
1095 TelemetryManager *telMngr = m_pluginManager->getObject<TelemetryManager>();
1097 Q_ASSERT(telMngr);
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))) {
1126 evt->ignore();
1127 return true;
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)
1135 m_object = object;
1136 m_field = field;
1137 m_index = index;
1140 WidgetBinding::~WidgetBinding()
1143 QString WidgetBinding::units() const
1145 if (m_field) {
1146 return m_field->getUnits();
1148 return QString();
1151 QString WidgetBinding::type() const
1153 if (m_field) {
1154 return m_field->getTypeAsString();
1156 return QString();
1159 bool WidgetBinding::isInteger() const
1161 if (m_field) {
1162 return m_field->isInteger();
1164 return false;
1167 UAVObject *WidgetBinding::object() const
1169 return m_object;
1172 UAVObjectField *WidgetBinding::field() const
1174 return m_field;
1177 int WidgetBinding::index() const
1179 return m_index;
1182 QList<ShadowWidgetBinding *> WidgetBinding::shadows() const
1184 return m_shadows;
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;
1196 m_scale = scale;
1197 m_widget = widget;
1198 } else {
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;
1209 } else {
1210 return false;
1214 bool WidgetBinding::isEnabled() const
1216 return m_isEnabled;
1219 void WidgetBinding::setIsEnabled(bool isEnabled)
1221 m_isEnabled = isEnabled;
1224 QVariant WidgetBinding::value() const
1226 return m_value;
1229 void WidgetBinding::setValue(const QVariant &value)
1231 m_value = 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)
1255 m_widget = widget;
1256 m_scale = scale;
1257 m_isLimited = isLimited;
1260 ShadowWidgetBinding::~ShadowWidgetBinding()
1263 QWidget *ShadowWidgetBinding::widget() const
1265 return m_widget;
1268 double ShadowWidgetBinding::scale() const
1270 return m_scale;
1273 bool ShadowWidgetBinding::isLimited() const
1275 return m_isLimited;