dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
configtaskwidget.cpp
Go to the documentation of this file.
1 
15 /*
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, see <http://www.gnu.org/licenses/>
28  *
29  * Additional note on redistribution: The copyright and license notices above
30  * must be maintained in each individual source file that is a derivative work
31  * of this source file; otherwise redistribution is prohibited.
32  */
33 #include "configtaskwidget.h"
34 #include "connectiondiagram.h"
35 #include "smartsavebutton.h"
36 #include "mixercurvewidget.h"
37 
39 #include <coreplugin/icore.h>
42 #include <utils/longlongspinbox.h>
43 
44 #include <QWidget>
45 #include <QLineEdit>
46 
51  : QWidget(parent)
52  , currentBoard(0)
53  , isConnected(false)
54  , allowWidgetUpdates(true)
55  , smartsave(NULL)
56  , dirty(false)
57  , outOfLimitsStyle("background-color: rgb(255, 180, 0);")
58  , timeOut(NULL)
59 {
60  pm = ExtensionSystem::PluginManager::instance();
61  objManager = pm->getObject<UAVObjectManager>();
62  TelemetryManager *telMngr = pm->getObject<TelemetryManager>();
63  utilMngr = pm->getObject<UAVObjectUtilManager>();
64  connect(telMngr, SIGNAL(connected()), this, SLOT(onAutopilotConnect()), Qt::UniqueConnection);
65  connect(telMngr, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect()),
66  Qt::UniqueConnection);
67  connect(telMngr, SIGNAL(connected()), this, SIGNAL(autoPilotConnected()), Qt::UniqueConnection);
68  connect(telMngr, SIGNAL(disconnected()), this, SIGNAL(autoPilotDisconnected()),
69  Qt::UniqueConnection);
70  UAVSettingsImportExportManager *importexportplugin =
71  pm->getObject<UAVSettingsImportExportManager>();
72  connect(importexportplugin, SIGNAL(importAboutToBegin()), this, SLOT(invalidateObjects()));
73 }
74 
79 void ConfigTaskWidget::addWidget(QWidget *widget)
80 {
81  addUAVObjectToWidgetRelation("", "", widget);
82 }
87 void ConfigTaskWidget::addUAVObject(QString objectName, QList<int> *reloadGroups)
88 {
89  addUAVObjectToWidgetRelation(objectName, "", NULL, 0, 1, false, false, reloadGroups);
90 }
91 
92 void ConfigTaskWidget::addUAVObject(UAVObject *objectName, QList<int> *reloadGroups)
93 {
94  QString objstr;
95  if (objectName)
96  objstr = objectName->getName();
97  addUAVObject(objstr, reloadGroups);
98 }
99 
113 void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString objectName, QString fieldName,
114  QWidget *widget, QString element, double scale,
115  bool isLimited, bool useUnits,
116  QList<int> *defaultReloadGroups, quint32 instID,
117  bool oneWayBind)
118 {
119  UAVObject *obj = objManager->getObject(objectName, instID);
120  if (!obj) {
121  Q_ASSERT(false);
122  qWarning() << "Failed to get object" << objectName;
123  return;
124  }
125 
126  // turn element string into index
127  int index = 0;
128  if (!fieldName.isEmpty() && !element.isEmpty()) {
129  const auto field = obj->getField(QString(fieldName));
130  if (!field) {
131  Q_ASSERT(false);
132  qWarning() << "Failed to get object field" << objectName << fieldName;
133  return;
134  }
135  index = field->getElementIndex(element);
136  }
137 
138  addUAVObjectToWidgetRelation(objectName, fieldName, widget, index, scale, isLimited, useUnits,
139  defaultReloadGroups, instID, oneWayBind);
140 }
141 
142 void ConfigTaskWidget::addUAVObjectToWidgetRelation(QString object, QString field, QWidget *widget,
143  int index, double scale, bool isLimited,
144  bool useUnits, QList<int> *defaultReloadGroups,
145  quint32 instID, bool oneWayBind)
146 {
147  if (addShadowWidget(object, field, widget, index, scale, isLimited, useUnits,
148  defaultReloadGroups, instID))
149  return;
150 
151  UAVObject *obj = NULL;
152  UAVObjectField *_field = NULL;
153  if (!object.isEmpty()) {
154  obj = objManager->getObject(QString(object), instID);
155  Q_ASSERT(obj);
156  objectUpdates.insert(obj, true);
157  connect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(objectUpdated(UAVObject *)));
158  connect(obj, SIGNAL(objectUpdated(UAVObject *)), this,
159  SLOT(refreshWidgetsValues(UAVObject *)), Qt::UniqueConnection);
160  UAVDataObject *dobj = dynamic_cast<UAVDataObject *>(obj);
161  if (dobj) {
162  connect(dobj, SIGNAL(presentOnHardwareChanged(UAVDataObject *)), this,
163  SLOT(doRefreshHiddenObjects(UAVDataObject *)), Qt::UniqueConnection);
164  if (widget)
165  setWidgetEnabledByObj(widget, dobj->getIsPresentOnHardware());
166  }
167  }
168  if (!field.isEmpty() && obj)
169  _field = obj->getField(QString(field));
170  objectToWidget *ow = new objectToWidget();
171  ow->field = _field;
172  ow->object = obj;
173  ow->widget = widget;
174  ow->index = index;
175  ow->scale = scale;
176  ow->isLimited = isLimited;
177  ow->useUnits = useUnits;
178  ow->oneWayBind = oneWayBind;
179  objOfInterest.append(ow);
180 
181  // QLabel is a one-way binding, don't try to save it
182  // This is duplicative with addApplySaveButtons, because we don't
183  // know which will be invoked first-- it depends on widget ordering
184  // in the .ui file.
185  if (smartsave && obj && !qobject_cast<QLabel *>(widget))
186  smartsave->addObject(static_cast<UAVDataObject *>(obj));
187 
188  if (!widget) {
189  if (defaultReloadGroups && obj) {
190  foreach (int i, *defaultReloadGroups) {
191  if (this->defaultReloadGroups.contains(i)) {
192  this->defaultReloadGroups.value(i)->append(ow);
193  } else {
194  this->defaultReloadGroups.insert(i, new QList<objectToWidget *>());
195  this->defaultReloadGroups.value(i)->append(ow);
196  }
197  }
198  }
199  } else {
200  connectWidgetUpdatesToSlot(widget, SLOT(widgetsContentsChanged()));
201  if (defaultReloadGroups)
202  addWidgetToDefaultReloadGroups(widget, defaultReloadGroups);
203  shadowsList.insert(widget, ow);
204  loadWidgetLimits(widget, _field, index, isLimited, useUnits, scale);
205  }
206 }
207 
213 {
214  UAVObject *obj = objManager->getObject(object);
215  Q_ASSERT(obj);
216  if (smartsave) {
217  smartsave->setNotMandatory(static_cast<UAVDataObject *>(obj));
218  }
219 }
220 
225 {
226  if (smartsave)
227  delete smartsave;
228  foreach (QList<objectToWidget *> *pointer, defaultReloadGroups.values()) {
229  if (pointer)
230  delete pointer;
231  }
232  foreach (objectToWidget *oTw, objOfInterest) {
233  if (oTw)
234  delete oTw;
235  }
236  if (timeOut) {
237  delete timeOut;
238  timeOut = NULL;
239  }
240 }
241 
243 {
244  // saveObjectToSD is now handled by the UAVUtils plugin in one
245  // central place (and one central queue)
246  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
248  utilMngr->saveObjectToFlash(obj);
249 }
250 
256 {
257  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
258  UAVObjectManager *objMngr = pm->getObject<UAVObjectManager>();
259  Q_ASSERT(objMngr);
260  return objMngr;
261 }
262 
269 {
270  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
272  Q_ASSERT(utilMngr);
273  return utilMngr;
274 }
275 
282 {
283  double accum = 0;
284  for (int i = 0; i < list.size(); i++)
285  accum += list[i];
286  return accum / list.size();
287 }
288 
295 {
296  double mean_accum = 0;
297  double var_accum = 0;
298  double mean;
299 
300  for (int i = 0; i < list.size(); i++)
301  mean_accum += list[i];
302  mean = mean_accum / list.size();
303 
304  for (int i = 0; i < list.size(); i++)
305  var_accum += (list[i] - mean) * (list[i] - mean);
306 
307  // Use unbiased estimator
308  return var_accum / (list.size() - 1);
309 }
310 
311 // ************************************
312 // telemetry start/stop connect/disconnect signals
313 
315 {
316  isConnected = false;
317  enableControls(false);
319  setDirty(false);
320 }
321 
322 void ConfigTaskWidget::forceConnectedState() // dynamic widgets don't recieve the connected signal.
323  // This should be called instead.
324 {
325  isConnected = true;
326  setDirty(false);
327 }
328 
330 {
331  if (utilMngr)
332  currentBoard = utilMngr->getBoardModel();
333 
335  isConnected = true;
336  loadAllLimits();
337  enableControls(true);
339  setDirty(false);
340 
341  emit autoPilotConnected();
342 }
343 
345 {
346  foreach (objectToWidget *ow, objOfInterest) {
347  loadWidgetLimits(ow->widget, ow->field, ow->index, ow->isLimited, ow->useUnits, ow->scale);
348  }
349 }
350 
356 {
357  bool dirtyBack = dirty;
359  foreach (objectToWidget *ow, objOfInterest) {
360  if (ow->object && ow->field && ow->widget)
361  setWidgetFromField(ow->widget, ow->field, ow->index, ow->scale, ow->isLimited,
362  ow->useUnits);
363  }
364  setDirty(dirtyBack);
365 }
372 {
373  if (!allowWidgetUpdates)
374  return;
375 
376  bool dirtyBack = dirty;
378  foreach (objectToWidget *ow, objOfInterest) {
379  if (ow->object && ow->field && ow->widget && (ow->object == obj || !obj))
380  setWidgetFromField(ow->widget, ow->field, ow->index, ow->scale, ow->isLimited,
381  ow->useUnits);
382  }
383  setDirty(dirtyBack);
384 }
385 
392 {
394  for (const auto ow : objOfInterest) {
395  if (ow->object && ow->field && !ow->oneWayBind)
396  setFieldFromWidget(ow->widget, ow->field, ow->index, ow->scale, ow->useUnits);
397  }
398 }
404 {
405  QString url = helpButtonList.value(dynamic_cast<QPushButton *>(sender()), QString());
406  if (!url.isEmpty())
407  QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode));
408 }
415 void ConfigTaskWidget::addApplySaveButtons(QPushButton *update, QPushButton *save)
416 {
417  if (!smartsave) {
418  smartsave = new smartSaveButton();
419  connect(smartsave, SIGNAL(preProcessOperations()), this, SLOT(updateObjectsFromWidgets()));
420  connect(smartsave, SIGNAL(saveSuccessfull()), this, SLOT(clearDirty()));
421  connect(smartsave, SIGNAL(beginOp()), this, SLOT(disableObjUpdates()));
422  connect(smartsave, SIGNAL(endOp()), this, SLOT(enableObjUpdates()));
423 
424  foreach (objectToWidget *oTw, objOfInterest) {
425  if (oTw->object && !qobject_cast<QLabel *>(oTw->widget)) {
426  smartsave->addObject(static_cast<UAVDataObject *>(oTw->object));
427  }
428  }
429  }
430  if (update && save)
431  smartsave->addButtons(save, update);
432  else if (update)
433  smartsave->addApplyButton(update);
434  else if (save)
435  smartsave->addSaveButton(save);
436 
437  TelemetryManager *telMngr = pm->getObject<TelemetryManager>();
438  if (telMngr->isConnected())
439  enableControls(true);
440  else
441  enableControls(false);
442 }
443 
450 {
451  if (smartsave)
452  smartsave->enableControls(enable);
453  for (QPushButton *button : reloadButtonList)
454  setWidgetEnabledByObj(button, enable);
455  for (QPushButton *button : rebootButtonList)
456  setWidgetEnabledByObj(button, enable);
457  for (QPushButton *button : connectionsButtonList)
458  setWidgetEnabledByObj(button, enable);
459 }
464 {
465  foreach (objectToWidget *oTw, objOfInterest) {
466  foreach (shadow *sh, oTw->shadowsList) {
467  disconnectWidgetUpdatesToSlot(sh->widget, SLOT(widgetsContentsChanged()));
468  checkWidgetsLimits(sh->widget, oTw->field, oTw->index, sh->isLimited, sh->useUnits,
469  getVariantFromWidget(oTw->widget, oTw->scale), sh->scale);
471  sh->scale, sh->useUnits ? oTw->field->getUnits() : "");
472  emit widgetContentsChanged(sh->widget);
473  connectWidgetUpdatesToSlot(sh->widget, SLOT(widgetsContentsChanged()));
474  }
475  }
476 }
481 {
482  emit widgetContentsChanged(dynamic_cast<QWidget *>(sender()));
483  double scale = 0;
484  objectToWidget *oTw = shadowsList.value(dynamic_cast<QWidget *>(sender()), NULL);
485  if (oTw) {
486  if (oTw->widget == dynamic_cast<QWidget *>(sender())) {
487  scale = oTw->scale;
488  checkWidgetsLimits(static_cast<QWidget *>(sender()), oTw->field, oTw->index,
489  oTw->isLimited, oTw->useUnits,
490  getVariantFromWidget(static_cast<QWidget *>(sender()), oTw->scale),
491  oTw->scale);
492  } else {
493  foreach (shadow *sh, oTw->shadowsList) {
494  if (sh->widget == static_cast<QWidget *>(sender())) {
495  scale = sh->scale;
497  static_cast<QWidget *>(sender()), oTw->field, oTw->index, sh->isLimited,
498  sh->useUnits, getVariantFromWidget(static_cast<QWidget *>(sender()), scale),
499  scale);
500  }
501  }
502  }
503  if (oTw->widget != static_cast<QWidget *>(sender())) {
504  disconnectWidgetUpdatesToSlot(oTw->widget, SLOT(widgetsContentsChanged()));
505  checkWidgetsLimits(oTw->widget, oTw->field, oTw->index, oTw->isLimited, oTw->useUnits,
506  getVariantFromWidget(static_cast<QWidget *>(sender()), scale),
507  oTw->scale);
509  getVariantFromWidget(static_cast<QWidget *>(sender()), scale),
510  oTw->scale, oTw->useUnits ? oTw->field->getUnits() : "");
511  emit widgetContentsChanged(oTw->widget);
512  connectWidgetUpdatesToSlot(oTw->widget, SLOT(widgetsContentsChanged()));
513  }
514  foreach (shadow *sh, oTw->shadowsList) {
515  if (sh->widget != static_cast<QWidget *>(sender())) {
516  disconnectWidgetUpdatesToSlot(sh->widget, SLOT(widgetsContentsChanged()));
517  checkWidgetsLimits(sh->widget, oTw->field, oTw->index, sh->isLimited, sh->useUnits,
518  getVariantFromWidget(static_cast<QWidget *>(sender()), scale),
519  sh->scale);
521  getVariantFromWidget(static_cast<QWidget *>(sender()), scale),
522  sh->scale, sh->useUnits ? oTw->field->getUnits() : "");
523  emit widgetContentsChanged(sh->widget);
524  connectWidgetUpdatesToSlot(sh->widget, SLOT(widgetsContentsChanged()));
525  }
526  }
527  }
528  if (smartsave)
529  smartsave->resetIcons();
530  setDirty(true);
531 }
536 {
537  setDirty(false);
538 }
544 {
545  dirty = value;
546 }
552 {
553  return dirty;
554 }
560 {
561  return isConnected;
562 }
563 
568 {
569  allowWidgetUpdates = false;
570  foreach (objectToWidget *obj, objOfInterest) {
571  if (obj->object)
572  disconnect(obj->object, SIGNAL(objectUpdated(UAVObject *)), this,
574  }
575 }
580 {
581  allowWidgetUpdates = true;
582  foreach (objectToWidget *obj, objOfInterest) {
583  if (obj->object)
584  connect(obj->object, SIGNAL(objectUpdated(UAVObject *)), this,
585  SLOT(refreshWidgetsValues(UAVObject *)), Qt::UniqueConnection);
586  }
587 }
592 void ConfigTaskWidget::objectUpdated(UAVObject *obj)
593 {
594  objectUpdates[obj] = true;
595 }
601 {
602  bool ret = true;
603  foreach (UAVObject *obj, objectUpdates.keys()) {
604  ret = ret & objectUpdates[obj];
605  }
606  return ret;
607 }
613 void ConfigTaskWidget::addHelpButton(QPushButton *button, QString url)
614 {
615  helpButtonList.insert(button, url);
616  connect(button, SIGNAL(clicked()), this, SLOT(helpButtonPressed()));
617 }
622 {
623  foreach (UAVObject *obj, objectUpdates.keys()) {
624  objectUpdates[obj] = false;
625  }
626 }
631 {
632  if (smartsave)
633  smartsave->apply();
634 }
639 {
640  if (smartsave)
641  smartsave->save();
642 }
652 bool ConfigTaskWidget::addShadowWidget(QString object, QString field, QWidget *widget, int index,
653  double scale, bool isLimited, bool useUnits,
654  QList<int> *defaultReloadGroups, quint32 instID)
655 {
656  /* TODO: This is n^2 with number of widgets */
657  foreach (objectToWidget *oTw, objOfInterest) {
658  if (!oTw->object || !oTw->widget || !oTw->field)
659  continue;
660  if (oTw->object->getName() == object && oTw->field->getName() == field
661  && oTw->index == index && oTw->object->getInstID() == instID) {
662  shadow *sh = NULL;
663  // prefer anything else to QLabel
664  if (qobject_cast<QLabel *>(oTw->widget) && !qobject_cast<QLabel *>(widget)) {
665  sh = new shadow;
666  sh->isLimited = oTw->isLimited;
667  sh->scale = oTw->scale;
668  sh->widget = oTw->widget;
669  sh->useUnits = oTw->useUnits;
670  oTw->isLimited = isLimited;
671  oTw->scale = scale;
672  oTw->widget = widget;
673  oTw->useUnits = useUnits;
674  }
675  // prefer QDoubleSpinBox to anything else
676  else if (!qobject_cast<QDoubleSpinBox *>(oTw->widget)
677  && qobject_cast<QDoubleSpinBox *>(widget)) {
678  sh = new shadow;
679  sh->isLimited = oTw->isLimited;
680  sh->scale = oTw->scale;
681  sh->widget = oTw->widget;
682  sh->useUnits = oTw->useUnits;
683  oTw->isLimited = isLimited;
684  oTw->scale = scale;
685  oTw->widget = widget;
686  oTw->useUnits = useUnits;
687  } else {
688  sh = new shadow;
689  sh->isLimited = isLimited;
690  sh->scale = scale;
691  sh->widget = widget;
692  sh->useUnits = useUnits;
693  }
694  shadowsList.insert(widget, oTw);
695  oTw->shadowsList.append(sh);
696  connectWidgetUpdatesToSlot(widget, SLOT(widgetsContentsChanged()));
697  if (defaultReloadGroups)
698  addWidgetToDefaultReloadGroups(widget, defaultReloadGroups);
699  loadWidgetLimits(widget, oTw->field, oTw->index, isLimited, useUnits, scale);
700  UAVDataObject *dobj = dynamic_cast<UAVDataObject *>(oTw->object);
701  if (dobj) {
702  connect(dobj, SIGNAL(presentOnHardwareChanged(UAVDataObject *)), this,
703  SLOT(doRefreshHiddenObjects(UAVDataObject *)), Qt::UniqueConnection);
704  if (widget)
705  setWidgetEnabledByObj(widget, dobj->getIsPresentOnHardware());
706  }
707  return true;
708  }
709  }
710  return false;
711 }
717 {
718  QPushButton *saveButtonWidget = NULL;
719  QPushButton *applyButtonWidget = NULL;
720  foreach (QWidget *widget, this->findChildren<QWidget *>()) {
721  QVariant info = widget->property("objrelation");
722  if (info.isValid()) {
723  uiRelationAutomation uiRelation;
724  uiRelation.buttonType = none;
725  uiRelation.scale = 1;
726  uiRelation.instanceId = 0;
727  uiRelation.element = QString();
728  uiRelation.haslimits = false;
729  uiRelation.useUnits = false;
730  uiRelation.oneWayBind = false;
731  foreach (QString str, info.toStringList()) {
732  QString prop = str.split(":").at(0);
733  QString value = str.split(":").at(1);
734  if (prop == "objname") {
735  uiRelation.objname = value;
736  } else if (prop == "fieldname") {
737  uiRelation.fieldname = value;
738  } else if (prop == "element") {
739  uiRelation.element = value;
740  } else if (prop == "scale") {
741  if (value == "null")
742  uiRelation.scale = 1;
743  else
744  uiRelation.scale = value.toDouble();
745  } else if (prop == "haslimits") {
746  if (value == "yes")
747  uiRelation.haslimits = true;
748  else
749  uiRelation.haslimits = false;
750  } else if (prop == "button") {
751  if (value == "save")
752  uiRelation.buttonType = save_button;
753  else if (value == "apply")
754  uiRelation.buttonType = apply_button;
755  else if (value == "reload")
756  uiRelation.buttonType = reload_button;
757  else if (value == "default")
758  uiRelation.buttonType = default_button;
759  else if (value == "help")
760  uiRelation.buttonType = help_button;
761  else if (value == "reboot")
762  uiRelation.buttonType = reboot_button;
763  else if (value == "connectiondiagram")
764  uiRelation.buttonType = connections_button;
765  } else if (prop == "buttongroup") {
766  foreach (QString s, value.split(","))
767  uiRelation.buttonGroup.append(s.toInt());
768  } else if (prop == "url") {
769  uiRelation.url = str.mid(str.indexOf(":") + 1);
770  } else if (prop == "checkedoption") {
771  widget->setProperty("checkedOption", value);
772  } else if (prop == "uncheckedoption") {
773  widget->setProperty("unCheckedOption", value);
774  } else if (prop == "useunits") {
775  uiRelation.useUnits = value == "yes";
776  } else if (prop == "onewaybind") {
777  uiRelation.oneWayBind = value == "yes";
778  } else if (prop == "instance") {
779  uiRelation.instanceId = value.toUInt();
780  }
781  }
782 
783  if (uiRelation.buttonType != none) {
784  QPushButton *button = NULL;
785  switch (uiRelation.buttonType) {
786  case save_button:
787  saveButtonWidget = qobject_cast<QPushButton *>(widget);
788  if (saveButtonWidget)
789  addApplySaveButtons(NULL, saveButtonWidget);
790  break;
791  case apply_button:
792  applyButtonWidget = qobject_cast<QPushButton *>(widget);
793  if (applyButtonWidget)
794  addApplySaveButtons(applyButtonWidget, NULL);
795  break;
796  case default_button:
797  button = qobject_cast<QPushButton *>(widget);
798  if (button) {
799  if (!uiRelation.buttonGroup.length()) {
800  qWarning() << "[autoLoadWidgets] No button group specified for default "
801  "button!";
802  uiRelation.buttonGroup.append(0);
803  }
804  addDefaultButton(button, uiRelation.buttonGroup.at(0));
805  }
806  break;
807  case reload_button:
808  button = qobject_cast<QPushButton *>(widget);
809  if (button) {
810  if (!uiRelation.buttonGroup.length()) {
811  qWarning()
812  << "[autoLoadWidgets] No button group specified for reload button!";
813  uiRelation.buttonGroup.append(0);
814  }
815  addReloadButton(button, uiRelation.buttonGroup.at(0));
816  }
817  break;
818  case help_button:
819  button = qobject_cast<QPushButton *>(widget);
820  if (button)
821  addHelpButton(button, uiRelation.url);
822  break;
823  case reboot_button:
824  button = qobject_cast<QPushButton *>(widget);
825  if (button)
826  addRebootButton(button);
827  break;
828  case connections_button:
829  button = qobject_cast<QPushButton *>(widget);
830  if (button)
831  addConnectionsButton(button);
832  break;
833  default:
834  break;
835  }
836  } else {
837  QWidget *wid = qobject_cast<QWidget *>(widget);
838  if (wid) {
840  uiRelation.objname, uiRelation.fieldname, wid, uiRelation.element,
841  uiRelation.scale, uiRelation.haslimits, uiRelation.useUnits,
842  &uiRelation.buttonGroup, uiRelation.instanceId, uiRelation.oneWayBind);
843  }
844  }
845  }
846  }
849 }
850 
859 {
860  foreach (objectToWidget *oTw, objOfInterest) {
861  bool addOTW = false;
862  if (oTw->widget == widget)
863  addOTW = true;
864  else {
865  foreach (shadow *sh, oTw->shadowsList) {
866  if (sh->widget == widget)
867  addOTW = true;
868  }
869  }
870  if (addOTW) {
871  foreach (int i, *groups) {
872  if (defaultReloadGroups.contains(i)) {
873  defaultReloadGroups.value(i)->append(oTw);
874  } else {
875  defaultReloadGroups.insert(i, new QList<objectToWidget *>());
876  defaultReloadGroups.value(i)->append(oTw);
877  }
878  }
879  }
880  }
881 }
887 void ConfigTaskWidget::addDefaultButton(QPushButton *button, int buttonGroup)
888 {
889  button->setProperty("group", buttonGroup);
890  connect(button, SIGNAL(clicked()), this, SLOT(defaultButtonClicked()));
891 }
897 void ConfigTaskWidget::addReloadButton(QPushButton *button, int buttonGroup)
898 {
899  button->setProperty("group", buttonGroup);
900  reloadButtonList.append(button);
901  connect(button, SIGNAL(clicked()), this, SLOT(reloadButtonClicked()));
902 }
908 void ConfigTaskWidget::addRebootButton(QPushButton *button)
909 {
910  rebootButtonList.append(button);
911  connect(button, SIGNAL(clicked()), this, SLOT(rebootButtonClicked()));
912 }
913 
914 void ConfigTaskWidget::addConnectionsButton(QPushButton *button)
915 {
916  connectionsButtonList.append(button);
917  connect(button, SIGNAL(clicked()), this, SLOT(connectionsButtonClicked()));
918 }
919 
923 void ConfigTaskWidget::defaultButtonClicked()
924 {
925  int group = sender()->property("group").toInt();
926  emit defaultRequested(group);
927  QList<objectToWidget *> *list = defaultReloadGroups.value(group);
928  foreach (objectToWidget *oTw, *list) {
929  if (oTw->object && oTw->field) {
930  UAVDataObject *temp = static_cast<UAVDataObject *>(oTw->object)->dirtyClone();
931  setWidgetFromField(oTw->widget, temp->getField(oTw->field->getName()), oTw->index,
932  oTw->scale, oTw->isLimited, oTw->useUnits);
933  }
934  }
935 }
936 
940 void ConfigTaskWidget::rebootButtonClicked()
941 {
942  QPointer<QPushButton> button(qobject_cast<QPushButton *>(sender()));
943  if (!button) {
944  qWarning() << "Invalid button";
945  return;
946  }
947 
948  setWidgetEnabledByObj(button, false);
949  button->setIcon(QIcon(":/uploader/images/system-run.svg"));
950 
951  FirmwareIAPObj *iapObj =
952  dynamic_cast<FirmwareIAPObj *>(getObjectManager()->getObject(FirmwareIAPObj::NAME));
954 
955  if (!conMngr->isConnected() || !iapObj->getIsPresentOnHardware()) {
956  setWidgetEnabledByObj(button, true);
957  button->setIcon(QIcon(":/uploader/images/error.svg"));
958  return;
959  }
960 
961  QEventLoop loop;
962  QTimer timeout;
963  timeout.setSingleShot(true);
964  iapObj->setBoardRevision(0);
965  iapObj->setBoardType(0);
966  connect(&timeout, &QTimer::timeout, &loop, &QEventLoop::quit);
970  connect(iapObj, QOverload<UAVObject *, bool>::of(&UAVObject::transactionCompleted), &loop,
971  &QEventLoop::quit);
972 
973  quint16 magicValue = 1122;
974  quint16 magicStep = 1111;
975  for (int i = 0; i < 3; ++i) {
976  // Firmware IAP module specifies that the timing between iap commands must be
977  // between 500 and 5000ms
978  timeout.start(600);
979  loop.exec();
980  iapObj->setCommand(magicValue);
981  magicValue += magicStep;
982  // 3344 = halt, 4455 = reboot
983  if (magicValue == 3344)
984  magicValue = 4455;
985  iapObj->updated();
986  timeout.start(1000);
987  loop.exec();
988 
989  // button should only be deleted by this (UI) thread so this weak check is okay,
990  // so long as setWidgetEnabledByObj doesn't signal anything that will delete it
991  if (!timeout.isActive() && button) {
992  setWidgetEnabledByObj(button, true);
993  button->setIcon(QIcon(":/uploader/images/error.svg"));
994  return;
995  }
996  timeout.stop();
997  }
998 
999  if (button) {
1000  setWidgetEnabledByObj(button, true);
1001  button->setIcon(QIcon(":/uploader/images/dialog-apply.svg"));
1002  }
1003 
1004  // this is safe even if already disconnected
1005  conMngr->disconnectDevice();
1006 }
1007 
1011 void ConfigTaskWidget::reloadButtonClicked()
1012 {
1013  if (timeOut)
1014  return;
1015  int group = sender()->property("group").toInt();
1016  QList<objectToWidget *> *list = defaultReloadGroups.value(group, NULL);
1017  if (!list)
1018  return;
1019  ObjectPersistence *objper =
1020  dynamic_cast<ObjectPersistence *>(getObjectManager()->getObject(ObjectPersistence::NAME));
1021  timeOut = new QTimer(this);
1022  QEventLoop *eventLoop = new QEventLoop(this);
1023  connect(timeOut, SIGNAL(timeout()), eventLoop, SLOT(quit()));
1024  connect(objper, SIGNAL(objectUpdated(UAVObject *)), eventLoop, SLOT(quit()));
1025 
1026  QList<temphelper> temp;
1027  foreach (objectToWidget *oTw, *list) {
1028  if (oTw->object != NULL) {
1029  UAVDataObject *dobj = dynamic_cast<UAVDataObject *>(oTw->object);
1030  if (dobj)
1031  if (!dobj->getIsPresentOnHardware())
1032  continue;
1033  temphelper value;
1034  value.objid = oTw->object->getObjID();
1035  value.objinstid = oTw->object->getInstID();
1036  if (temp.contains(value))
1037  continue;
1038  else
1039  temp.append(value);
1040  ObjectPersistence::DataFields data;
1041  data.Operation = ObjectPersistence::OPERATION_LOAD;
1042  data.ObjectID = oTw->object->getObjID();
1043  data.InstanceID = oTw->object->getInstID();
1044  objper->setData(data);
1045  objper->updated();
1046  timeOut->start(500);
1047  eventLoop->exec();
1048  if (timeOut->isActive()) {
1049  oTw->object->requestUpdate();
1050  if (oTw->widget)
1051  setWidgetFromField(oTw->widget, oTw->field, oTw->index, oTw->scale,
1052  oTw->isLimited, oTw->useUnits);
1053  }
1054  timeOut->stop();
1055  }
1056  }
1057  if (eventLoop) {
1058  delete eventLoop;
1059  eventLoop = NULL;
1060  }
1061  if (timeOut) {
1062  delete timeOut;
1063  timeOut = NULL;
1064  }
1065 }
1066 
1067 void ConfigTaskWidget::connectionsButtonClicked()
1068 {
1069  ConnectionDiagram diagram(this);
1070  diagram.exec();
1071 }
1072 
1073 void ConfigTaskWidget::doRefreshHiddenObjects(UAVDataObject *obj)
1074 {
1075  foreach (objectToWidget *ow, shadowsList.values()) {
1076  if (ow->object == NULL || ow->widget == NULL) {
1077  // do nothing
1078  } else {
1079  if (ow->object == obj) {
1080  foreach (QWidget *w, shadowsList.keys(ow))
1081  setWidgetEnabledByObj(w, obj->getIsPresentOnHardware());
1082  }
1083  }
1084  }
1085 }
1086 
1090 void ConfigTaskWidget::connectWidgetUpdatesToSlot(QWidget *widget, const char *function)
1091 {
1092  if (!widget)
1093  return;
1094  if (QComboBox *cb = qobject_cast<QComboBox *>(widget)) {
1095  connect(cb, SIGNAL(currentIndexChanged(int)), this, function);
1096  } else if (QSlider *cb = qobject_cast<QSlider *>(widget)) {
1097  connect(cb, SIGNAL(valueChanged(int)), this, function);
1098  } else if (MixerCurveWidget *cb = qobject_cast<MixerCurveWidget *>(widget)) {
1099  connect(cb, SIGNAL(curveUpdated()), this, function);
1100  } else if (QTableWidget *cb = qobject_cast<QTableWidget *>(widget)) {
1101  connect(cb, SIGNAL(cellChanged(int, int)), this, function);
1102  } else if (QSpinBox *cb = qobject_cast<QSpinBox *>(widget)) {
1103  connect(cb, SIGNAL(valueChanged(int)), this, function);
1104  } else if (LongLongSpinBox *cb = qobject_cast<LongLongSpinBox *>(widget)) {
1105  connect(cb, SIGNAL(valueChanged(qint64)), this, function);
1106  } else if (QDoubleSpinBox *cb = qobject_cast<QDoubleSpinBox *>(widget)) {
1107  connect(cb, SIGNAL(valueChanged(double)), this, function);
1108  } else if (QGroupBox *cb = qobject_cast<QGroupBox *>(widget)) {
1109  connect(cb, SIGNAL(toggled(bool)), this, function);
1110  } else if (QCheckBox *cb = qobject_cast<QCheckBox *>(widget)) {
1111  connect(cb, SIGNAL(stateChanged(int)), this, function);
1112  } else if (QPushButton *cb = qobject_cast<QPushButton *>(widget)) {
1113  connect(cb, SIGNAL(clicked()), this, function);
1114  } else if (qobject_cast<QLabel *>(widget)) { // Nothing to connect
1115  } else if (qobject_cast<QLineEdit *>(widget)) { // Nothing to connect
1116  } else
1117  qDebug() << __FUNCTION__ << "widget to uavobject relation not implemented for widget: "
1118  << widget->objectName() << "of class:" << widget->metaObject()->className();
1119 }
1123 void ConfigTaskWidget::disconnectWidgetUpdatesToSlot(QWidget *widget, const char *function)
1124 {
1125  if (!widget)
1126  return;
1127  if (QComboBox *cb = qobject_cast<QComboBox *>(widget)) {
1128  disconnect(cb, SIGNAL(currentIndexChanged(int)), this, function);
1129  } else if (QSlider *cb = qobject_cast<QSlider *>(widget)) {
1130  disconnect(cb, SIGNAL(valueChanged(int)), this, function);
1131  } else if (MixerCurveWidget *cb = qobject_cast<MixerCurveWidget *>(widget)) {
1132  disconnect(cb, SIGNAL(curveUpdated()), this, function);
1133  } else if (QTableWidget *cb = qobject_cast<QTableWidget *>(widget)) {
1134  disconnect(cb, SIGNAL(cellChanged(int, int)), this, function);
1135  } else if (QSpinBox *cb = qobject_cast<QSpinBox *>(widget)) {
1136  disconnect(cb, SIGNAL(valueChanged(int)), this, function);
1137  } else if (LongLongSpinBox *cb = qobject_cast<LongLongSpinBox *>(widget)) {
1138  disconnect(cb, SIGNAL(valueChanged(qint64)), this, function);
1139  } else if (QDoubleSpinBox *cb = qobject_cast<QDoubleSpinBox *>(widget)) {
1140  disconnect(cb, SIGNAL(valueChanged(double)), this, function);
1141  } else if (QGroupBox *cb = qobject_cast<QGroupBox *>(widget)) {
1142  disconnect(cb, SIGNAL(toggled(bool)), this, function);
1143  } else if (QCheckBox *cb = qobject_cast<QCheckBox *>(widget)) {
1144  disconnect(cb, SIGNAL(stateChanged(int)), this, function);
1145  } else if (QPushButton *cb = qobject_cast<QPushButton *>(widget)) {
1146  disconnect(cb, SIGNAL(clicked()), this, function);
1147  } else if (qobject_cast<QLabel *>(widget)) { // Nothing to disconnect
1148  } else if (qobject_cast<QLineEdit *>(widget)) { // Nothing to disconnect
1149  } else
1150  qDebug() << __FUNCTION__ << "widget to uavobject relation not implemented for widget: "
1151  << widget->objectName() << "of class:" << widget->metaObject()->className();
1152 }
1153 
1154 bool ConfigTaskWidget::widgetReadOnly(QWidget *widget) const
1155 {
1156  if (qobject_cast<QLabel *>(widget)) // Labels are readonly
1157  return true;
1158  if (auto le = qobject_cast<QLineEdit *>(widget))
1159  return le->isReadOnly();
1160  return false;
1161 }
1162 
1171 bool ConfigTaskWidget::setFieldFromWidget(QWidget *widget, UAVObjectField *field, int index,
1172  double scale, bool usesUnits)
1173 {
1174  if (!widget || !field || widgetReadOnly(widget))
1175  return false;
1176 
1177  QVariant ret = getVariantFromWidget(widget, scale, usesUnits);
1178  if (ret.isValid()) {
1179  field->setValue(ret, index);
1180  return true;
1181  } else {
1182  qDebug() << __FUNCTION__ << "widget to uavobject relation not implemented for widget: "
1183  << widget->objectName() << "of class:" << widget->metaObject()->className();
1184  return false;
1185  }
1186 }
1187 
1194 QVariant ConfigTaskWidget::getVariantFromWidget(QWidget *widget, double scale, bool usesUnits)
1195 {
1196  if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) {
1197  return comboBox->currentData();
1198  } else if (QDoubleSpinBox *dblSpinBox = qobject_cast<QDoubleSpinBox *>(widget)) {
1199  return (double)(dblSpinBox->value() * scale);
1200  } else if (QSpinBox *spinBox = qobject_cast<QSpinBox *>(widget)) {
1201  return (double)(spinBox->value() * scale);
1202  } else if (LongLongSpinBox *spinBox = qobject_cast<LongLongSpinBox *>(widget)) {
1203  return QVariant(spinBox->value() * scale);
1204  } else if (QSlider *slider = qobject_cast<QSlider *>(widget)) {
1205  return (double)(slider->value() * scale);
1206  } else if (QGroupBox *groupBox = qobject_cast<QGroupBox *>(widget)) {
1207  return getOptionFromChecked(widget, groupBox->isChecked());
1208  } else if (QCheckBox *checkBox = qobject_cast<QCheckBox *>(widget)) {
1209  return getOptionFromChecked(widget, checkBox->isChecked());
1210  } else if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget)) {
1211  if (usesUnits) {
1212  QStringList bits = lineEdit->displayText().split(' ');
1213  if (bits.length())
1214  bits.removeLast();
1215  return bits.join("");
1216  } else {
1217  return lineEdit->displayText();
1218  }
1219  } else {
1220  return QVariant();
1221  }
1222 }
1223 
1231 bool ConfigTaskWidget::setWidgetFromVariant(QWidget *widget, QVariant value, double scale,
1232  QString units)
1233 {
1234  units = units.trimmed();
1235  if (!units.startsWith("%")) {
1236  if (!units.isEmpty() && !qFuzzyCompare(1 + 1.0, 1 + scale) && scale != 0)
1237  units = applyScaleToUnits(units, scale);
1238  if (!units.isEmpty())
1239  units.prepend(' ');
1240  } else {
1241  /* We have a lot of things like % / 100 in the unit set.
1242  * Best to make them just %. (Assume they'll use scale properly)
1243  */
1244  units = QString("%");
1245  }
1246 
1247  if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) {
1248  comboBox->setCurrentIndex(comboBox->findData(value.toString()));
1249  return true;
1250  } else if (QLabel *label = qobject_cast<QLabel *>(widget)) {
1251  if ((scale == 0) || (scale == 1))
1252  label->setText(value.toString() + units);
1253  else
1254  label->setText(QString::number(value.toDouble() / scale, 'f', 1) + units);
1255  return true;
1256  } else if (QDoubleSpinBox *dblSpinBox = qobject_cast<QDoubleSpinBox *>(widget)) {
1257  dblSpinBox->setValue(value.toDouble() / scale);
1258  if (!units.isEmpty())
1259  dblSpinBox->setSuffix(units);
1260  return true;
1261  } else if (QSpinBox *spinBox = qobject_cast<QSpinBox *>(widget)) {
1262  spinBox->setValue(qRound(value.toDouble() / scale));
1263  if (!units.isEmpty())
1264  spinBox->setSuffix(units);
1265  return true;
1266  } else if (LongLongSpinBox *spinBox = qobject_cast<LongLongSpinBox *>(widget)) {
1267  spinBox->setValue(qRound64(value.toDouble() / scale));
1268  if (!units.isEmpty())
1269  spinBox->setSuffix(units);
1270  return true;
1271  } else if (QSlider *slider = qobject_cast<QSlider *>(widget)) {
1272  slider->setValue(qRound(value.toDouble() / scale));
1273  return true;
1274  } else if (QGroupBox *groupBox = qobject_cast<QGroupBox *>(widget)) {
1275  groupBox->setChecked(getCheckedFromOption(widget, value.toString()));
1276  return true;
1277  } else if (QCheckBox *checkBox = qobject_cast<QCheckBox *>(widget)) {
1278  checkBox->setChecked(getCheckedFromOption(widget, value.toString()));
1279  return true;
1280  } else if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget)) {
1281  // TODO: units, will need to peel off on the other side
1282  if (scale == 0)
1283  lineEdit->setText(value.toString() + units);
1284  else
1285  lineEdit->setText(QString::number((value.toDouble() / scale)) + units);
1286  return true;
1287  }
1288 
1289  return false;
1290 }
1291 
1292 bool ConfigTaskWidget::setWidgetFromField(QWidget *widget, UAVObjectField *field, int index,
1293  double scale, bool hasLimits, bool useUnits)
1294 {
1295  if (!widget || !field)
1296  return false;
1297 
1298  // use UAVO field description as tooltip if the widget doesn't already have one
1299  if (!widget->toolTip().length()) {
1300  QString desc = field->getDescription().trimmed().toHtmlEscaped();
1301  if (desc.length()) {
1302  // insert html tags to make this rich text so Qt will take care of wrapping
1303  desc.prepend("<span style='font-style: normal'>");
1304  desc.remove("@Ref", Qt::CaseInsensitive);
1305  desc.append("</span>");
1306  }
1307  widget->setToolTip(desc);
1308  }
1309 
1310  if (QComboBox *cb = qobject_cast<QComboBox *>(widget)) {
1311  if (cb->count() == 0)
1312  loadWidgetLimits(cb, field, index, hasLimits, useUnits, scale);
1313  }
1314 
1315  QVariant var = field->getValue(index);
1316  checkWidgetsLimits(widget, field, index, hasLimits, useUnits, var, scale);
1317  const QString units = useUnits ? field->getUnits() : "";
1318  bool ret = setWidgetFromVariant(widget, var, scale, units);
1319 
1320  if (!ret)
1321  qDebug() << __FUNCTION__ << "widget to uavobject relation not implemented for widget: "
1322  << widget->objectName() << "of class:" << widget->metaObject()->className();
1323  return ret;
1324 }
1325 
1326 void ConfigTaskWidget::checkWidgetsLimits(QWidget *widget, UAVObjectField *field, int index,
1327  bool hasLimits, bool useUnits, QVariant value,
1328  double scale)
1329 {
1330  if (!hasLimits)
1331  return;
1332  if (!field->isWithinLimits(value, index, currentBoard)) {
1333  if (!widget->property("styleBackup").isValid())
1334  widget->setProperty("styleBackup", widget->styleSheet());
1335  widget->setStyleSheet(outOfLimitsStyle);
1336  widget->setProperty("wasOverLimits", (bool)true);
1337  if (!widget->property("toolTipBackup").isValid()) {
1338  QString tip = widget->toolTip();
1339  if (tip.length() && !tip.startsWith("<"))
1340  tip = tip.prepend("<p>").append("</p>");
1341  widget->setProperty("toolTipBackup", tip);
1342  }
1343  widget->setToolTip(widget->property("toolTipBackup").toString()
1344  + tr("<p><strong>Warning:</strong> The value of this field exceeds the "
1345  "recommended limits! Please double-check before flying.</p>"));
1346  if (QComboBox *cb = qobject_cast<QComboBox *>(widget)) {
1347  if (cb->findData(value.toString()) == -1)
1348  cb->addItem(value.toString(), value);
1349  } else if (QDoubleSpinBox *cb = qobject_cast<QDoubleSpinBox *>(widget)) {
1350  if ((double)(value.toDouble() / scale) > cb->maximum()) {
1351  cb->setMaximum((double)(value.toDouble() / scale));
1352  } else if ((double)(value.toDouble() / scale) < cb->minimum()) {
1353  cb->setMinimum((double)(value.toDouble() / scale));
1354  }
1355 
1356  } else if (QSpinBox *cb = qobject_cast<QSpinBox *>(widget)) {
1357  if ((int)qRound(value.toDouble() / scale) > cb->maximum()) {
1358  cb->setMaximum((int)qRound(value.toDouble() / scale));
1359  } else if ((int)qRound(value.toDouble() / scale) < cb->minimum()) {
1360  cb->setMinimum((int)qRound(value.toDouble() / scale));
1361  }
1362  } else if (LongLongSpinBox *cb = qobject_cast<LongLongSpinBox *>(widget)) {
1363  if (qRound64(value.toDouble() / scale) > cb->maximum()) {
1364  cb->setMaximum(qRound64(value.toDouble() / scale));
1365  } else if (qRound64(value.toDouble() / scale) < cb->minimum()) {
1366  cb->setMinimum(qRound64(value.toDouble() / scale));
1367  }
1368  } else if (QSlider *cb = qobject_cast<QSlider *>(widget)) {
1369  if ((int)qRound(value.toDouble() / scale) > cb->maximum()) {
1370  cb->setMaximum((int)qRound(value.toDouble() / scale));
1371  } else if ((int)qRound(value.toDouble() / scale) < cb->minimum()) {
1372  cb->setMinimum((int)qRound(value.toDouble() / scale));
1373  }
1374  }
1375 
1376  } else if (widget->property("wasOverLimits").isValid()) {
1377  if (widget->property("wasOverLimits").toBool()) {
1378  widget->setProperty("wasOverLimits", (bool)false);
1379  if (widget->property("styleBackup").isValid()) {
1380  QString style = widget->property("styleBackup").toString();
1381  widget->setStyleSheet(style);
1382  }
1383 
1384  if (widget->property("toolTipBackup").isValid())
1385  widget->setToolTip(widget->property("toolTipBackup").toString());
1386  else
1387  widget->setToolTip("");
1388 
1389  loadWidgetLimits(widget, field, index, hasLimits, useUnits, scale);
1390  }
1391  }
1392 }
1393 
1394 void ConfigTaskWidget::loadWidgetLimits(QWidget *widget, UAVObjectField *field, int index,
1395  bool hasLimits, bool useUnits, double scale)
1396 {
1397  if (!widget || !field)
1398  return;
1399  if (QComboBox *cb = qobject_cast<QComboBox *>(widget)) {
1400  cb->clear();
1401  QStringList option = field->getOptions();
1402  foreach (QString str, option) {
1403  if (!hasLimits || field->isWithinLimits(str, index, currentBoard)) {
1404  if (useUnits)
1405  cb->addItem(str + " " + field->getUnits(), str);
1406  else
1407  cb->addItem(str, str);
1408  }
1409  }
1410  }
1411  if (!hasLimits)
1412  return;
1413  else if (QDoubleSpinBox *cb = qobject_cast<QDoubleSpinBox *>(widget)) {
1414  if (field->getMaxLimit(index).isValid()) {
1415  cb->setMaximum((double)(field->getMaxLimit(index, currentBoard).toDouble() / scale));
1416  }
1417  if (field->getMinLimit(index, currentBoard).isValid()) {
1418  cb->setMinimum((double)(field->getMinLimit(index, currentBoard).toDouble() / scale));
1419  }
1420  } else if (QSpinBox *cb = qobject_cast<QSpinBox *>(widget)) {
1421  if (field->getMaxLimit(index, currentBoard).isValid()) {
1422  cb->setMaximum((int)qRound(field->getMaxLimit(index, currentBoard).toDouble() / scale));
1423  }
1424  if (field->getMinLimit(index, currentBoard).isValid()) {
1425  cb->setMinimum((int)qRound(field->getMinLimit(index, currentBoard).toDouble() / scale));
1426  }
1427  } else if (LongLongSpinBox *cb = qobject_cast<LongLongSpinBox *>(widget)) {
1428  if (field->getMaxLimit(index, currentBoard).isValid()) {
1429  cb->setMaximum(qRound64(field->getMaxLimit(index, currentBoard).toDouble() / scale));
1430  }
1431  if (field->getMinLimit(index, currentBoard).isValid()) {
1432  cb->setMinimum(qRound(field->getMinLimit(index, currentBoard).toDouble() / scale));
1433  }
1434  } else if (QSlider *cb = qobject_cast<QSlider *>(widget)) {
1435  if (field->getMaxLimit(index, currentBoard).isValid()) {
1436  cb->setMaximum((int)qRound(field->getMaxLimit(index, currentBoard).toDouble() / scale));
1437  }
1438  if (field->getMinLimit(index, currentBoard).isValid()) {
1439  cb->setMinimum((int)(field->getMinLimit(index, currentBoard).toDouble() / scale));
1440  }
1441  }
1442 }
1443 
1445 {
1446  // Disable mouse wheel events
1447  foreach (QSpinBox *sp, findChildren<QSpinBox *>()) {
1448  sp->installEventFilter(this);
1449  }
1450  foreach (LongLongSpinBox *sp, findChildren<LongLongSpinBox *>()) {
1451  sp->installEventFilter(this);
1452  }
1453  foreach (QDoubleSpinBox *sp, findChildren<QDoubleSpinBox *>()) {
1454  sp->installEventFilter(this);
1455  }
1456  foreach (QSlider *sp, findChildren<QSlider *>()) {
1457  sp->installEventFilter(this);
1458  }
1459  foreach (QComboBox *sp, findChildren<QComboBox *>()) {
1460  sp->installEventFilter(this);
1461  }
1462 }
1463 
1464 bool ConfigTaskWidget::eventFilter(QObject *obj, QEvent *evt)
1465 {
1466  // Filter all wheel events, and ignore them
1467  if (evt->type() == QEvent::Wheel
1468  && (qobject_cast<QAbstractSpinBox *>(obj) || qobject_cast<QComboBox *>(obj)
1469  || qobject_cast<QAbstractSlider *>(obj))) {
1470  evt->ignore();
1471  return true;
1472  }
1473  return QWidget::eventFilter(obj, evt);
1474 }
1475 
1482 QString ConfigTaskWidget::getOptionFromChecked(QWidget *widget, bool checked)
1483 {
1484  if (checked)
1485  return widget->property("checkedOption").isValid()
1486  ? widget->property("checkedOption").toString()
1487  : "TRUE";
1488  else
1489  return widget->property("unCheckedOption").isValid()
1490  ? widget->property("unCheckedOption").toString()
1491  : "FALSE";
1492 }
1493 
1500 bool ConfigTaskWidget::getCheckedFromOption(QWidget *widget, QString option)
1501 {
1502  if (widget->property("checkedOption").isValid())
1503  return option == widget->property("checkedOption").toString();
1504  if (widget->property("unCheckedOption").isValid())
1505  return option != widget->property("unCheckedOption").toString();
1506  return option == "TRUE";
1507 }
1508 
1517 };
1518 
1519 QString ConfigTaskWidget::applyScaleToUnits(QString units, double scale)
1520 {
1521  // if no scaling is applied (scale 0 or 1), return units unchanged
1522  if (qFuzzyCompare(1, 1 + scale) || qFuzzyCompare(1.0, scale))
1523  return units;
1524 
1525  int len = units.length();
1526  // only consider basic units with length 1 (no prefix), or 2 atm
1527  if (!len || len > 2)
1528  return QString();
1529 
1530  int prefix = PREFIX_NONE;
1531  if (len > 1) {
1532  QChar p = units.at(0);
1533  if (p == 'n') // nano
1534  prefix = PREFIX_NANO;
1535  else if (p == 'u' || p == QString::fromLatin1("\xb5s")) // micro
1536  prefix = PREFIX_MICRO;
1537  else if (p == 'm') // milli
1538  prefix = PREFIX_MILLI;
1539  else if (p == 'k') // kilo
1540  prefix = PREFIX_KILO;
1541  else if (p == 'M') // Mega
1542  prefix = PREFIX_MEGA;
1543  else if (p == 'G') // Giga
1544  prefix = PREFIX_GIGA;
1545  else
1546  return QString();
1547  units = units.at(1);
1548  }
1549 
1550  if (qFuzzyCompare(1.0e-9, scale))
1551  prefix -= 3;
1552  else if (qFuzzyCompare(1.0e-6, scale))
1553  prefix -= 2;
1554  else if (qFuzzyCompare(1.0e-3, scale))
1555  prefix -= 1;
1556  else if (qFuzzyCompare(1.0e3, scale))
1557  prefix += 1;
1558  else if (qFuzzyCompare(1.0e6, scale))
1559  prefix += 2;
1560  else if (qFuzzyCompare(1.0e9, scale))
1561  prefix += 3;
1562  else
1563  return QString();
1564 
1565  switch (prefix) {
1566  case PREFIX_NANO:
1567  return "n" + units;
1568  case PREFIX_MICRO:
1569  return QString::fromLatin1("\xb5") + units;
1570  case PREFIX_MILLI:
1571  return "m" + units;
1572  case PREFIX_NONE:
1573  return units;
1574  case PREFIX_KILO:
1575  return "k" + units;
1576  case PREFIX_MEGA:
1577  return "M" + units;
1578  case PREFIX_GIGA:
1579  return "G" + units;
1580  default:
1581  return QString();
1582  }
1583 }
1584 
1586 {
1587  foreach (objectToWidget *ow, objOfInterest) {
1588  if (ow->widget == widget && ow->field)
1589  return setWidgetFromVariant(widget, ow->field->getDefaultValue(ow->index), ow->scale,
1590  ow->useUnits ? ow->field->getUnits() : "");
1591  }
1592  return false;
1593 }
1594 
1595 void ConfigTaskWidget::setWidgetProperty(QWidget *widget, const char *prop, const QVariant &value)
1596 {
1597  widget->setProperty(prop, value);
1598  widget->style()->unpolish(widget);
1599  widget->style()->polish(widget);
1600 }
1601 
1602 void ConfigTaskWidget::setWidgetEnabled(QWidget *widget, bool enabled)
1603 {
1604  bool objDisabled = false;
1605  objDisabled = widget->property("objDisabled").toBool();
1606  widget->setProperty("userDisabled", !enabled);
1607  widget->setEnabled(enabled && !objDisabled);
1608 }
1609 
1610 void ConfigTaskWidget::setWidgetEnabledByObj(QWidget *widget, bool enabled)
1611 {
1612  bool userDisabled = false;
1613  userDisabled = widget->property("userDisabled").toBool();
1614  widget->setProperty("objDisabled", !enabled);
1615  widget->setEnabled(enabled && !userDisabled);
1616 }
1617 
void addApplyButton(QPushButton *apply)
smartSaveButton::addApplyButton Called only by the ConfigTaskWidget when adding the smart save button...
virtual void widgetsContentsChanged()
void setDirty(bool value)
void addUAVObjectToWidgetRelation(QString object, QString field, QWidget *widget, int index=0, double scale=1, bool isLimited=false, bool useUnits=false, QList< int > *defaultReloadGroups=nullptr, quint32 instID=0, bool oneWayBind=false)
Add an UAVObject field to widget relation to the management system Note: This is the instance called ...
UAVObjectUtilManager * utilMngr
void addSaveButton(QPushButton *save)
smartSaveButton::addSaveButton Called only by the ConfigTaskWidget when adding the smart save buttons...
void refreshWidgetsValuesRequested()
bool resetWidgetToDefault(QWidget *widget)
resetWidgetToDefault Resets the widget to the default value for the associated field ...
void setNotMandatory(QString object)
QVariant getDefaultValue(int index=0) const
Get the default value (defined in the UAVO def) for the element.
void populateWidgetsRequested()
virtual void disableObjUpdates()
void addButtons(QPushButton *save, QPushButton *apply)
smartSaveButton::addButtons Called only by the ConfigTaskWidget when adding the smart save buttons...
void autoPilotConnected()
bool addShadowWidget(QString object, QString field, QWidget *widget, int index=0, double scale=1, bool isLimited=false, bool useUnits=false, QList< int > *defaultReloadGroups=NULL, quint32 instID=0)
void checkWidgetsLimits(QWidget *widget, UAVObjectField *field, int index, bool hasLimits, bool useUnits, QVariant value, double scale)
void addWidget(QWidget *widget)
virtual bool setWidgetFromVariant(QWidget *widget, QVariant value, double scale, QString units="")
ConfigTaskWidget(QWidget *parent=nullptr)
static double listMean(QList< double > list)
void enableControls(bool value)
void addHelpButton(QPushButton *button, QString url)
Core plugin system that manages the plugins, their life cycle and their registered objects...
Definition: pluginmanager.h:53
QVariant getValue(int index=0) const
virtual bool getCheckedFromOption(QWidget *widget, QString option)
Determine whether checkbox should be checked.
virtual void enableObjUpdates()
UAVDataObject * dirtyClone()
for i
Definition: OPPlots.m:140
virtual ConnectionManager * connectionManager() const =0
quint32 getInstID()
Definition: uavobject.cpp:115
DataFields data
void setWidgetProperty(QWidget *widget, const char *prop, const QVariant &value)
setWidgetProperty Sets a dynamic property on a widget and forces a re-evaluation of it's stylesheet N...
void updateObjectsFromWidgetsRequested()
void addObject(UAVDataObject *)
smartSaveButton::addObject The smartSaveButton contains a list of objects it will work with...
void forceShadowUpdates()
ConfigTaskWidget::forceShadowUpdates.
QString getDescription() const
QStringList getOptions() const
void addWidgetToDefaultReloadGroups(QWidget *widget, QList< int > *groups)
void saveObjectToFlash(UAVObject *obj)
UAVObjectUtilManager::saveObjectToSD Add a new object to save in the queue.
void setValue(const QVariant &data, int index=0)
void transactionCompleted(UAVObject *obj, bool success)
transactionCompleted. Triggered by a call to emitTransactionCompleted - done in telemetry.cpp whenever a transaction finishes.
static ICore * instance()
Definition: coreimpl.cpp:46
UAVObjectField * getField(const QString &name)
Definition: uavobject.cpp:236
virtual void clearDirty()
bool getIsPresentOnHardware() const
void autoPilotDisconnected()
QString getName() const
virtual QString getOptionFromChecked(QWidget *widget, bool checked)
Determine which enum option based on checkbox.
static double listVar(QList< double > list)
bool isAutopilotConnected()
ConfigTaskWidget::isAutopilotConnected Checks if the autopilot is connected.
quint32 getObjID()
Definition: uavobject.cpp:107
void saveObjectToSD(UAVObject *obj)
() NAME()
void setNotMandatory(UAVDataObject *)
QVariant getMinLimit(int index, int board=0) const
void addUAVObject(QString objectName, QList< int > *reloadGroups=NULL)
virtual QVariant getVariantFromWidget(QWidget *widget, double scale, bool usesUnits=false)
QString getUnits() const
virtual void populateWidgets()
QString getName()
Definition: uavobject.cpp:131
virtual void enableControls(bool enable)
virtual void updateObjectsFromWidgets()
virtual void refreshWidgetsValues(UAVObject *obj=NULL)
void widgetContentsChanged(QWidget *widget)
QVariant getMaxLimit(int index, int board=0) const
void addConnectionsButton(QPushButton *button)
addConnectionsButton Add connection diagram button
bool isWithinLimits(QVariant var, int index, int board=0) const
bool eventFilter(QObject *obj, QEvent *evt)
UAVObject * getObject(const QString &name, quint32 instId=0)
UAVObjectUtilManager * getObjectUtilManager()
ConfigTaskWidget::getObjectUtilManager Utility function to get a pointer to the object manager utilit...
virtual void helpButtonPressed()
UAVObjectManager * getObjectManager()
ConfigTaskWidget::getObjectManager Utility function to get a pointer to the object manager...
void defaultRequested(int group)
save(matfile $(SAVEOBJECTSCODE))
e
Definition: OPPlots.m:99
bool isConnected() const
void setWidgetEnabled(QWidget *widget, bool enabled=true)
setWidgetEnabled Enable/disable a widget controlled by a UAVO relation