31 #include <QSortFilterProxyModel>
37 #include "../QWidgets/StyleSheets.h"
48 widget.groupBoxCDev->layout()->addWidget(controlDevices);
49 widget.groupBoxCDev->setVisible(
false);
50 controlDevices->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
56 widget.groupBoxSDev->layout()->addWidget(sensorDevices);
57 widget.groupBoxSDev->setVisible(
false);
58 sensorDevices->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
64 widget.groupBoxNJointCtrl->layout()->addWidget(nJointControllers);
65 widget.groupBoxNJointCtrl->setVisible(
true);
66 nJointControllers->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
72 widget.groupBoxNJointCtrlClasses->layout()->addWidget(nJointControllerClasses);
73 widget.groupBoxNJointCtrlClasses->setVisible(
false);
74 nJointControllerClasses->setSizePolicy(QSizePolicy::MinimumExpanding,
75 QSizePolicy::Expanding);
80 widget.groupBoxLogging->setVisible(
false);
81 widget.groupBoxLogging->setSizePolicy(QSizePolicy::MinimumExpanding,
82 QSizePolicy::Expanding);
84 connect(widget.pushButtonLoggingStart,
87 SLOT(on_pushButtonLoggingStart_clicked()));
88 connect(widget.pushButtonLoggingStop,
91 SLOT(on_pushButtonLoggingStop_clicked()));
92 connect(widget.pushButtonLoggingMark1,
95 SLOT(on_pushButtonLoggingMark1_clicked()));
96 connect(widget.pushButtonLoggingMark2,
99 SLOT(on_pushButtonLoggingMark2_clicked()));
100 connect(widget.pushButtonLoggingMark3,
103 SLOT(on_pushButtonLoggingMark3_clicked()));
104 connect(widget.lineEditLoggingFilter,
105 SIGNAL(textChanged(
const QString&)),
107 SLOT(on_lineEditLoggingFilter_textChanged(
const QString&)));
108 connect(widget.treeWidgetLoggingNames,
109 SIGNAL(itemChanged(QTreeWidgetItem*,
int)),
111 SLOT(on_treeWidgetLoggingNames_itemChanged(QTreeWidgetItem*,
int)));
113 updateToolBarActionCheckedState();
120 settings->value(
"robotUnitProxyName", QString::fromStdString(robotUnitProxyName))
127 widget.groupBoxCDev->setVisible(settings->value(
"cdevVisible",
false).toBool());
128 widget.groupBoxSDev->setVisible(settings->value(
"sdevVisible",
false).toBool());
129 widget.groupBoxNJointCtrl->setVisible(settings->value(
"ctrlVisible",
true).toBool());
130 widget.groupBoxNJointCtrlClasses->setVisible(settings->value(
"classVisible",
false).toBool());
131 updateToolBarActionCheckedState();
137 settings->setValue(
"robotUnitProxyName", QString::fromStdString(robotUnitProxyName));
142 settings->setValue(
"cdevVisible", widget.groupBoxCDev->isVisible());
143 settings->setValue(
"sdevVisible", widget.groupBoxSDev->isVisible());
144 settings->setValue(
"ctrlVisible", widget.groupBoxNJointCtrl->isVisible());
145 settings->setValue(
"classVisible", widget.groupBoxNJointCtrlClasses->isVisible());
153 QMetaObject::invokeMethod(
this,
"startOnConnectTimer", Qt::QueuedConnection);
159 QMetaObject::invokeMethod(
this,
"stopOnConnectTimer", Qt::QueuedConnection);
165 std::lock_guard guard{robotUnitPrxMutex};
166 robotUnitPrx = getProxy<RobotUnitInterfacePrx>(robotUnitProxyName);
167 listenerTopicName = robotUnitPrx->getRobotUnitListenerTopicName();
169 updateToolBarActionCheckedState();
170 timerLastIterationRuWasRunning =
false;
176 std::lock_guard guard{robotUnitPrxMutex};
178 robotUnitPrx =
nullptr;
179 QMetaObject::invokeMethod(
this,
"refreshNJointControllersClicked", Qt::QueuedConnection);
180 QMetaObject::invokeMethod(
this,
"refreshNJointControllerClassesClicked", Qt::QueuedConnection);
181 QMetaObject::invokeMethod(
this,
"refreshControlDevicesClicked", Qt::QueuedConnection);
182 QMetaObject::invokeMethod(
this,
"refreshSensorDevicesClicked", Qt::QueuedConnection);
193 return qobject_cast<SimpleConfigDialog*>(dialog);
199 robotUnitProxyName = dialog->getProxyName(
"RobotUnit");
207 customToolbar->setParent(parent);
211 customToolbar =
new QToolBar(parent);
212 customToolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
213 customToolbar->setIconSize(QSize(16, 16));
216 QIcon(
":/icons/view-refresh-7.png"),
"",
this, SLOT(refreshControlDevicesClicked()))
217 ->setToolTip(
"Update the list of Control Devices");
218 showCDevs =
new QAction{
"Control Devices", customToolbar};
219 showCDevs->setCheckable(
true);
220 showCDevs->setToolTip(
"Hide/Show the list of Control Devices");
221 connect(showCDevs, SIGNAL(toggled(
bool)), widget.groupBoxCDev, SLOT(setVisible(
bool)));
222 connect(showCDevs, SIGNAL(toggled(
bool)), controlDevices, SLOT(setVisible(
bool)));
223 customToolbar->addAction(showCDevs);
224 customToolbar->addSeparator();
228 QIcon(
":/icons/view-refresh-7.png"),
"",
this, SLOT(refreshSensorDevicesClicked()))
229 ->setToolTip(
"Update the list of Sensor Devices");
230 showSDevs =
new QAction{
"Sensor Devices", customToolbar};
231 showSDevs->setCheckable(
true);
232 showSDevs->setToolTip(
"Hide/Show the list of Sensor Devices");
233 connect(showSDevs, SIGNAL(toggled(
bool)), widget.groupBoxSDev, SLOT(setVisible(
bool)));
234 connect(showSDevs, SIGNAL(toggled(
bool)), sensorDevices, SLOT(setVisible(
bool)));
235 customToolbar->addAction(showSDevs);
236 customToolbar->addSeparator();
239 ->addAction(QIcon(
":/icons/view-refresh-7.png"),
242 SLOT(refreshNJointControllersClicked()))
243 ->setToolTip(
"Update the list of NJointControllers");
244 showNJoint =
new QAction{
"NJointControllers", customToolbar};
245 showNJoint->setCheckable(
true);
246 showNJoint->setToolTip(
"Hide/Show the list of NJointControllers");
248 showNJoint, SIGNAL(toggled(
bool)), widget.groupBoxNJointCtrl, SLOT(setVisible(
bool)));
249 connect(showNJoint, SIGNAL(toggled(
bool)), nJointControllers, SLOT(setVisible(
bool)));
250 customToolbar->addAction(showNJoint);
251 customToolbar->addSeparator();
254 ->addAction(QIcon(
":/icons/view-refresh-7.png"),
257 SLOT(refreshNJointControllerClassesClicked()))
258 ->setToolTip(
"Update the list of NJointController Classes");
259 showNJointClasses =
new QAction{
"NJointController Classes", customToolbar};
260 showNJointClasses->setCheckable(
true);
261 showNJointClasses->setToolTip(
"Hide/Show the list of NJointControllers Classes");
262 connect(showNJointClasses,
263 SIGNAL(toggled(
bool)),
264 widget.groupBoxNJointCtrlClasses,
265 SLOT(setVisible(
bool)));
266 connect(showNJointClasses,
267 SIGNAL(toggled(
bool)),
268 nJointControllerClasses,
269 SLOT(setVisible(
bool)));
270 customToolbar->addAction(showNJointClasses);
271 customToolbar->addSeparator();
273 customToolbar->addAction(
274 QIcon(
":/icons/view-refresh-7.png"),
"",
this, SLOT(refreshLogging()));
275 showLogging =
new QAction{
"Logging", customToolbar};
276 showLogging->setCheckable(
true);
277 showLogging->setToolTip(
"Hide/Show the logging pane");
278 connect(showLogging, SIGNAL(toggled(
bool)), widget.groupBoxLogging, SLOT(setVisible(
bool)));
279 customToolbar->addAction(showLogging);
280 customToolbar->addSeparator();
283 ->addAction(QIcon(
":/icons/document-save.svg"),
287 std::lock_guard guard{robotUnitPrxMutex};
288 robotUnitPrx->writeRecentIterationsToFile(
289 "/tmp/RobotUnitLog-{DateTime}");
291 ->setToolTip(
"Writes the log to /tmp/");
293 updateToolBarActionCheckedState();
294 return customToolbar.data();
299 const NJointControllerStatusSeq&
status,
341 RobotUnitPluginWidgetController::refreshNJointControllersClicked()
343 std::lock_guard guard{robotUnitPrxMutex};
344 nJointControllers->
reset(robotUnitPrx);
348 RobotUnitPluginWidgetController::refreshNJointControllerClassesClicked()
350 std::lock_guard guard{robotUnitPrxMutex};
351 nJointControllerClasses->
reset(robotUnitPrx);
355 RobotUnitPluginWidgetController::refreshControlDevicesClicked()
357 std::lock_guard guard{robotUnitPrxMutex};
358 controlDevices->
reset(robotUnitPrx);
362 RobotUnitPluginWidgetController::refreshSensorDevicesClicked()
364 std::lock_guard guard{robotUnitPrxMutex};
365 sensorDevices->
reset(robotUnitPrx);
369 RobotUnitPluginWidgetController::startOnConnectTimer()
373 timerId = startTimer(100);
378 RobotUnitPluginWidgetController::stopOnConnectTimer()
388 RobotUnitPluginWidgetController::updateToolBarActionCheckedState()
392 showCDevs->setChecked(widget.groupBoxCDev->isVisible());
393 showSDevs->setChecked(widget.groupBoxSDev->isVisible());
394 showNJoint->setChecked(widget.groupBoxNJointCtrl->isVisible());
395 showNJointClasses->setChecked(widget.groupBoxNJointCtrlClasses->isVisible());
400 armarx::RobotUnitPluginWidgetController::timerEvent(QTimerEvent*)
402 std::lock_guard guard{robotUnitPrxMutex};
403 if (robotUnitPrx && robotUnitPrx->isRunning())
406 if (!timerLastIterationRuWasRunning)
408 refreshNJointControllersClicked();
409 refreshNJointControllerClassesClicked();
410 refreshControlDevicesClicked();
411 refreshSensorDevicesClicked();
416 loggingData.localLogging();
418 timerLastIterationRuWasRunning =
true;
422 timerLastIterationRuWasRunning =
false;
428 armarx::RobotUnitPluginWidgetController::refreshLogging()
430 std::lock_guard guard{robotUnitPrxMutex};
431 on_pushButtonLoggingStop_clicked();
433 widget.treeWidgetLoggingNames->clear();
434 loggingData.allItems.clear();
436 const auto allLoggingNames = robotUnitPrx->getLoggingNames();
438 std::map<std::string, QTreeWidgetItem*> separators;
439 auto add = [&](
const std::string& name,
const std::string&
display,
auto parent)
441 QTreeWidgetItem* i =
new QTreeWidgetItem(parent);
442 i->setText(0, QString::fromStdString(
display) +
"*");
443 i->setData(0, Qt::ToolTipRole, QString::fromStdString(name));
444 separators[name] = i;
445 loggingData.allItems.emplace_back(i);
446 i->setCheckState(0, Qt::Unchecked);
448 add(
"",
"", widget.treeWidgetLoggingNames);
449 loggingData.top = loggingData.allItems.front();
451 for (
const auto& name : allLoggingNames)
453 const auto parts =
Split(name,
".",
true,
true);
454 std::string reassembled;
455 for (
const auto& p : parts)
458 auto parent = separators.at(reassembled);
459 reassembled += (reassembled.empty() ? p :
"." + p);
460 if (!separators.count(reassembled))
462 add(reassembled, p, parent);
465 loggingData.allItems.back()->setText(0, QString::fromStdString(parts.back()));
470 armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingStart_clicked()
472 std::lock_guard guard{robotUnitPrxMutex};
473 if (!robotUnitPrx || loggingData.handle || loggingData.streamingHandler)
477 std::vector<std::string> loggingNames;
478 std::function<void(QTreeWidgetItem*)> recurseChildren = [&](
auto it)
480 switch (it->checkState(0))
483 if (it->childCount() == 0)
485 loggingNames.emplace_back(
486 it->data(0, Qt::ToolTipRole).toString().toStdString());
490 for (
int i = 0; i < it->childCount(); ++i)
492 recurseChildren(it->child(i));
498 case Qt::PartiallyChecked:
499 for (
int i = 0; i < it->childCount(); ++i)
501 recurseChildren(it->child(i));
506 recurseChildren(loggingData.top);
507 const std::string saveFormatString = widget.lineEditLoggingPath->text().toStdString();
508 if (widget.checkBoxLoggingStream->isChecked())
511 RobotUnitDataStreaming::Config cfg;
512 cfg.loggingNames = loggingNames;
513 loggingData.streamingHandler =
514 make_shared<RobotUnitDataStreamingReceiver>(
this, robotUnitPrx, cfg);
517 loggingData.logStream.open(pb.getPath());
518 loggingData.logStream <<
";iteration;timestamp;TimeSinceLastIteration";
519 const auto& entries = loggingData.streamingHandler->getDataDescription().entries;
520 std::stringstream
str;
521 str <<
"stream " << entries.size() <<
" values\n";
522 for (
const auto& [name, desc] : entries)
524 loggingData.logStream <<
';' << name;
525 str <<
" " << name <<
" -> type " << desc.type <<
", index " << desc.index <<
'\n';
527 loggingData.logStream << std::endl;
533 loggingData.handle = robotUnitPrx->startRtLogging(saveFormatString, loggingNames);
534 widget.pushButtonLoggingMark1->setEnabled(
true);
535 widget.pushButtonLoggingMark2->setEnabled(
true);
536 widget.pushButtonLoggingMark3->setEnabled(
true);
538 widget.pushButtonLoggingStart->setEnabled(
false);
539 widget.pushButtonLoggingStop->setEnabled(
true);
543 armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingStop_clicked()
545 std::lock_guard guard{robotUnitPrxMutex};
546 widget.pushButtonLoggingStart->setEnabled(
true);
547 widget.pushButtonLoggingStop->setEnabled(
false);
548 widget.pushButtonLoggingMark1->setEnabled(
false);
549 widget.pushButtonLoggingMark2->setEnabled(
false);
550 widget.pushButtonLoggingMark3->setEnabled(
false);
551 if (loggingData.handle)
553 robotUnitPrx->stopRtLogging(loggingData.handle);
555 if (loggingData.logStream.is_open())
557 loggingData.logStream.close();
559 loggingData.handle =
nullptr;
560 loggingData.streamingHandler =
nullptr;
564 armarx::RobotUnitPluginWidgetController::on_lineEditLoggingFilter_textChanged(
const QString& arg1)
569 reg = std::regex{arg1.toStdString()};
574 widget.lineEditLoggingFilter->setStyleSheet(
575 "QLineEdit { background: rgb(255, 150, 150); selection-background-color: rgb(255, 0, "
579 widget.lineEditLoggingFilter->setStyleSheet(
"QLineEdit {}");
581 std::function<void(QTreeWidgetItem * item)> setVisible = [&](
auto it)
583 it->setHidden(
false);
584 auto parent = it->parent();
592 for (
auto item : loggingData.allItems)
594 item->setHidden(
true);
596 for (
auto item : loggingData.allItems)
598 const auto str = item->data(0, Qt::ToolTipRole).toString().toStdString();
600 if (std::regex_search(
str, match, reg))
605 widget.treeWidgetLoggingNames->blockSignals(
true);
607 for (
auto iter = loggingData.allItems.rbegin(); iter != loggingData.allItems.rend(); ++iter)
609 QTreeWidgetItem* item = *iter;
610 loggingData.updateCheckStateUpward(item,
false);
612 widget.treeWidgetLoggingNames->blockSignals(
false);
616 armarx::RobotUnitPluginWidgetController::on_treeWidgetLoggingNames_itemChanged(
617 QTreeWidgetItem* item,
620 widget.treeWidgetLoggingNames->blockSignals(
true);
621 loggingData.updateCheckStateDownward(item, item->checkState(0),
true);
622 loggingData.updateCheckStateUpward(item->parent(),
true);
623 widget.treeWidgetLoggingNames->blockSignals(
false);
627 armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingMark1_clicked()
629 if (!loggingData.handle)
633 const auto mark = widget.lineEditLoggingMark1->text().toStdString();
635 robotUnitPrx->addMarkerToRtLog(loggingData.handle, mark);
639 armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingMark2_clicked()
641 if (!loggingData.handle)
645 const auto mark = widget.lineEditLoggingMark2->text().toStdString();
647 robotUnitPrx->addMarkerToRtLog(loggingData.handle, mark);
651 armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingMark3_clicked()
653 if (!loggingData.handle)
657 const auto mark = widget.lineEditLoggingMark3->text().toStdString();
659 robotUnitPrx->addMarkerToRtLog(loggingData.handle, mark);
663 RobotUnitPluginWidgetController::LoggingData::updateCheckStateUpward(QTreeWidgetItem* item,
667 for (; item; item = recurseParents ? item->parent() :
nullptr)
669 if (item->isHidden())
673 bool anyChecked =
false;
674 bool anyUnchecked =
false;
676 for (
int i = 0; i < item->childCount(); ++i)
678 auto c = item->child(i);
683 switch (
c->checkState(0))
691 case Qt::PartiallyChecked:
695 if (anyChecked + anyUnchecked + anyTri > 1 || anyTri)
697 item->setCheckState(0, Qt::PartiallyChecked);
701 item->setCheckState(0, Qt::Checked);
703 else if (anyUnchecked)
705 item->setCheckState(0, Qt::Unchecked);
713 RobotUnitPluginWidgetController::LoggingData::updateCheckStateDownward(QTreeWidgetItem* item,
714 Qt::CheckState state,
715 bool recurseChildren)
717 if (item->isHidden())
721 item->setCheckState(0, state);
723 if (!recurseChildren)
727 for (
int i = 0; i < item->childCount(); ++i)
729 auto c = item->child(i);
734 c->setCheckState(0, state);
735 updateCheckStateDownward(
c, state,
true);
740 RobotUnitPluginWidgetController::LoggingData::localLogging()
742 if (!streamingHandler)
748 auto&
data = streamingHandler->getDataBuffer();
755 const auto& descr = streamingHandler->getDataDescription();
756 for (
const auto& step :
data)
758 for (
const auto& [name, desc] : descr.entries)
760 logStream <<
';' << step.iterationId <<
';' << step.timestampUSec <<
';'
761 << step.timesSinceLastIterationUSec;
762 using enum_t = RobotUnitDataStreaming::DataEntryType;
765 case enum_t::NodeTypeBool:
766 logStream <<
';' << step.bools.at(desc.index);
768 case enum_t::NodeTypeByte:
769 logStream <<
';' << step.bytes.at(desc.index);
771 case enum_t::NodeTypeShort:
772 logStream <<
';' << step.shorts.at(desc.index);
774 case enum_t::NodeTypeInt:
775 logStream <<
';' << step.ints.at(desc.index);
777 case enum_t::NodeTypeLong:
778 logStream <<
';' << step.longs.at(desc.index);
780 case enum_t::NodeTypeFloat:
781 logStream <<
';' << step.floats.at(desc.index);
783 case enum_t::NodeTypeDouble:
784 logStream <<
';' << step.doubles.at(desc.index);
788 logStream << std::endl;