24 #include "../QWidgets/StyleSheets.h"
31 #include <QSortFilterProxyModel>
47 widget.groupBoxCDev->layout()->addWidget(controlDevices);
48 widget.groupBoxCDev->setVisible(
false);
49 controlDevices->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
55 widget.groupBoxSDev->layout()->addWidget(sensorDevices);
56 widget.groupBoxSDev->setVisible(
false);
57 sensorDevices->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
63 widget.groupBoxNJointCtrl->layout()->addWidget(nJointControllers);
64 widget.groupBoxNJointCtrl->setVisible(
true);
65 nJointControllers->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
71 widget.groupBoxNJointCtrlClasses->layout()->addWidget(nJointControllerClasses);
72 widget.groupBoxNJointCtrlClasses->setVisible(
false);
73 nJointControllerClasses->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
78 widget.groupBoxLogging->setVisible(
false);
79 widget.groupBoxLogging->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
81 connect(widget.pushButtonLoggingStart, SIGNAL(clicked()),
this, SLOT(on_pushButtonLoggingStart_clicked()));
82 connect(widget.pushButtonLoggingStop, SIGNAL(clicked()),
this, SLOT(on_pushButtonLoggingStop_clicked()));
83 connect(widget.pushButtonLoggingMark1, SIGNAL(clicked()),
this, SLOT(on_pushButtonLoggingMark1_clicked()));
84 connect(widget.pushButtonLoggingMark2, SIGNAL(clicked()),
this, SLOT(on_pushButtonLoggingMark2_clicked()));
85 connect(widget.pushButtonLoggingMark3, SIGNAL(clicked()),
this, SLOT(on_pushButtonLoggingMark3_clicked()));
86 connect(widget.lineEditLoggingFilter, SIGNAL(textChanged(
const QString&)),
87 this, SLOT(on_lineEditLoggingFilter_textChanged(
const QString&)));
88 connect(widget.treeWidgetLoggingNames, SIGNAL(itemChanged(QTreeWidgetItem*,
int)),
89 this, SLOT(on_treeWidgetLoggingNames_itemChanged(QTreeWidgetItem*,
int)));
91 updateToolBarActionCheckedState();
97 robotUnitProxyName = settings->value(
"robotUnitProxyName", QString::fromStdString(robotUnitProxyName)).toString().toStdString();
102 widget.groupBoxCDev->setVisible(settings->value(
"cdevVisible",
false).toBool());
103 widget.groupBoxSDev->setVisible(settings->value(
"sdevVisible",
false).toBool());
104 widget.groupBoxNJointCtrl->setVisible(settings->value(
"ctrlVisible",
true).toBool());
105 widget.groupBoxNJointCtrlClasses->setVisible(settings->value(
"classVisible",
false).toBool());
106 updateToolBarActionCheckedState();
111 settings->setValue(
"robotUnitProxyName", QString::fromStdString(robotUnitProxyName));
116 settings->setValue(
"cdevVisible", widget.groupBoxCDev->isVisible());
117 settings->setValue(
"sdevVisible", widget.groupBoxSDev->isVisible());
118 settings->setValue(
"ctrlVisible", widget.groupBoxNJointCtrl->isVisible());
119 settings->setValue(
"classVisible", widget.groupBoxNJointCtrlClasses->isVisible());
126 QMetaObject::invokeMethod(
this,
"startOnConnectTimer", Qt::QueuedConnection);
130 QMetaObject::invokeMethod(
this,
"stopOnConnectTimer", Qt::QueuedConnection);
135 std::lock_guard guard{robotUnitPrxMutex};
136 robotUnitPrx = getProxy<RobotUnitInterfacePrx>(robotUnitProxyName);
137 listenerTopicName = robotUnitPrx->getRobotUnitListenerTopicName();
139 updateToolBarActionCheckedState();
140 timerLastIterationRuWasRunning =
false;
145 std::lock_guard guard{robotUnitPrxMutex};
147 robotUnitPrx =
nullptr;
148 QMetaObject::invokeMethod(
this,
"refreshNJointControllersClicked", Qt::QueuedConnection);
149 QMetaObject::invokeMethod(
this,
"refreshNJointControllerClassesClicked", Qt::QueuedConnection);
150 QMetaObject::invokeMethod(
this,
"refreshControlDevicesClicked", Qt::QueuedConnection);
151 QMetaObject::invokeMethod(
this,
"refreshSensorDevicesClicked", Qt::QueuedConnection);
161 return qobject_cast<SimpleConfigDialog*>(dialog);
166 robotUnitProxyName = dialog->getProxyName(
"RobotUnit");
173 customToolbar->setParent(parent);
177 customToolbar =
new QToolBar(parent);
178 customToolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
179 customToolbar->setIconSize(QSize(16, 16));
180 customToolbar->addAction(QIcon(
":/icons/view-refresh-7.png"),
"",
this, SLOT(refreshControlDevicesClicked()))
181 ->setToolTip(
"Update the list of Control Devices");
182 showCDevs =
new QAction {
"Control Devices", customToolbar};
183 showCDevs->setCheckable(
true);
184 showCDevs->setToolTip(
"Hide/Show the list of Control Devices");
185 connect(showCDevs, SIGNAL(toggled(
bool)), widget.groupBoxCDev, SLOT(setVisible(
bool)));
186 connect(showCDevs, SIGNAL(toggled(
bool)), controlDevices, SLOT(setVisible(
bool)));
187 customToolbar->addAction(showCDevs);
188 customToolbar->addSeparator();
190 customToolbar->addAction(QIcon(
":/icons/view-refresh-7.png"),
"",
this, SLOT(refreshSensorDevicesClicked()))
191 ->setToolTip(
"Update the list of Sensor Devices");
192 showSDevs =
new QAction {
"Sensor Devices", customToolbar};
193 showSDevs->setCheckable(
true);
194 showSDevs->setToolTip(
"Hide/Show the list of Sensor Devices");
195 connect(showSDevs, SIGNAL(toggled(
bool)), widget.groupBoxSDev, SLOT(setVisible(
bool)));
196 connect(showSDevs, SIGNAL(toggled(
bool)), sensorDevices, SLOT(setVisible(
bool)));
197 customToolbar->addAction(showSDevs);
198 customToolbar->addSeparator();
200 customToolbar->addAction(QIcon(
":/icons/view-refresh-7.png"),
"",
this, SLOT(refreshNJointControllersClicked()))
201 ->setToolTip(
"Update the list of NJointControllers");
202 showNJoint =
new QAction {
"NJointControllers", customToolbar};
203 showNJoint->setCheckable(
true);
204 showNJoint->setToolTip(
"Hide/Show the list of NJointControllers");
205 connect(showNJoint, SIGNAL(toggled(
bool)), widget.groupBoxNJointCtrl, SLOT(setVisible(
bool)));
206 connect(showNJoint, SIGNAL(toggled(
bool)), nJointControllers, SLOT(setVisible(
bool)));
207 customToolbar->addAction(showNJoint);
208 customToolbar->addSeparator();
210 customToolbar->addAction(QIcon(
":/icons/view-refresh-7.png"),
"",
this, SLOT(refreshNJointControllerClassesClicked()))
211 ->setToolTip(
"Update the list of NJointController Classes");
212 showNJointClasses =
new QAction {
"NJointController Classes", customToolbar};
213 showNJointClasses->setCheckable(
true);
214 showNJointClasses->setToolTip(
"Hide/Show the list of NJointControllers Classes");
215 connect(showNJointClasses, SIGNAL(toggled(
bool)), widget.groupBoxNJointCtrlClasses, SLOT(setVisible(
bool)));
216 connect(showNJointClasses, SIGNAL(toggled(
bool)), nJointControllerClasses, SLOT(setVisible(
bool)));
217 customToolbar->addAction(showNJointClasses);
218 customToolbar->addSeparator();
220 customToolbar->addAction(QIcon(
":/icons/view-refresh-7.png"),
"",
this, SLOT(refreshLogging()));
221 showLogging =
new QAction {
"Logging", customToolbar};
222 showLogging->setCheckable(
true);
223 showLogging->setToolTip(
"Hide/Show the logging pane");
224 connect(showLogging, SIGNAL(toggled(
bool)), widget.groupBoxLogging, SLOT(setVisible(
bool)));
225 customToolbar->addAction(showLogging);
226 customToolbar->addSeparator();
228 customToolbar->addAction(
229 QIcon(
":/icons/document-save.svg"),
"Write log",
232 std::lock_guard guard{robotUnitPrxMutex};
233 robotUnitPrx->writeRecentIterationsToFile(
"/tmp/RobotUnitLog-{DateTime}");
236 ->setToolTip(
"Writes the log to /tmp/");
238 updateToolBarActionCheckedState();
239 return customToolbar.data();
272 void RobotUnitPluginWidgetController::refreshNJointControllersClicked()
274 std::lock_guard guard{robotUnitPrxMutex};
275 nJointControllers->
reset(robotUnitPrx);
278 void RobotUnitPluginWidgetController::refreshNJointControllerClassesClicked()
280 std::lock_guard guard{robotUnitPrxMutex};
281 nJointControllerClasses->
reset(robotUnitPrx);
284 void RobotUnitPluginWidgetController::refreshControlDevicesClicked()
286 std::lock_guard guard{robotUnitPrxMutex};
287 controlDevices->
reset(robotUnitPrx);
290 void RobotUnitPluginWidgetController::refreshSensorDevicesClicked()
292 std::lock_guard guard{robotUnitPrxMutex};
293 sensorDevices->
reset(robotUnitPrx);
296 void RobotUnitPluginWidgetController::startOnConnectTimer()
300 timerId = startTimer(100);
303 void RobotUnitPluginWidgetController::stopOnConnectTimer()
312 void RobotUnitPluginWidgetController::updateToolBarActionCheckedState()
316 showCDevs->setChecked(widget.groupBoxCDev->isVisible());
317 showSDevs->setChecked(widget.groupBoxSDev->isVisible());
318 showNJoint->setChecked(widget.groupBoxNJointCtrl->isVisible());
319 showNJointClasses->setChecked(widget.groupBoxNJointCtrlClasses->isVisible());
323 void armarx::RobotUnitPluginWidgetController::timerEvent(QTimerEvent*)
325 std::lock_guard guard{robotUnitPrxMutex};
326 if (robotUnitPrx && robotUnitPrx->isRunning())
329 if (!timerLastIterationRuWasRunning)
331 refreshNJointControllersClicked();
332 refreshNJointControllerClassesClicked();
333 refreshControlDevicesClicked();
334 refreshSensorDevicesClicked();
339 loggingData.localLogging();
341 timerLastIterationRuWasRunning =
true;
345 timerLastIterationRuWasRunning =
false;
350 void armarx::RobotUnitPluginWidgetController::refreshLogging()
352 std::lock_guard guard{robotUnitPrxMutex};
353 on_pushButtonLoggingStop_clicked();
355 widget.treeWidgetLoggingNames->clear();
356 loggingData.allItems.clear();
358 const auto allLoggingNames = robotUnitPrx->getLoggingNames();
360 std::map<std::string, QTreeWidgetItem*> separators;
361 auto add = [&](
const std::string & name,
const std::string &
display,
auto parent)
363 QTreeWidgetItem* i =
new QTreeWidgetItem(parent);
364 i->setText(0, QString::fromStdString(
display) +
"*");
365 i->setData(0, Qt::ToolTipRole, QString::fromStdString(name));
366 separators[name] = i;
367 loggingData.allItems.emplace_back(i);
368 i->setCheckState(0, Qt::Unchecked);
370 add(
"",
"", widget.treeWidgetLoggingNames);
371 loggingData.top = loggingData.allItems.front();
373 for (
const auto& name : allLoggingNames)
375 const auto parts =
Split(name,
".",
true,
true);
376 std::string reassembled;
377 for (
const auto& p : parts)
380 auto parent = separators.at(reassembled);
381 reassembled += (reassembled.empty() ? p :
"." + p) ;
382 if (!separators.count(reassembled))
384 add(reassembled, p, parent);
387 loggingData.allItems.back()->setText(0, QString::fromStdString(parts.back()));
392 void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingStart_clicked()
394 std::lock_guard guard{robotUnitPrxMutex};
395 if (!robotUnitPrx || loggingData.handle || loggingData.streamingHandler)
399 std::vector<std::string> loggingNames;
400 std::function<void(QTreeWidgetItem*)> recurseChildren = [&](
auto it)
402 switch (it->checkState(0))
405 if (it->childCount() == 0)
407 loggingNames.emplace_back(it->data(0, Qt::ToolTipRole).toString().toStdString());
411 for (
int i = 0; i < it->childCount(); ++i)
413 recurseChildren(it->child(i));
419 case Qt::PartiallyChecked:
420 for (
int i = 0; i < it->childCount(); ++i)
422 recurseChildren(it->child(i));
427 recurseChildren(loggingData.top);
428 const std::string saveFormatString = widget.lineEditLoggingPath->text().toStdString();
429 if (widget.checkBoxLoggingStream->isChecked())
432 RobotUnitDataStreaming::Config cfg;
433 cfg.loggingNames = loggingNames;
434 loggingData.streamingHandler =
435 make_shared<RobotUnitDataStreamingReceiver>(
this, robotUnitPrx, cfg);
438 loggingData.logStream.open(pb.getPath());
439 loggingData.logStream <<
";iteration;timestamp;TimeSinceLastIteration";
440 const auto& entries = loggingData.streamingHandler->getDataDescription().entries;
441 std::stringstream
str;
442 str <<
"stream " << entries.size() <<
" values\n";
443 for (
const auto& [name, desc] : entries)
445 loggingData.logStream <<
';' << name;
447 <<
" -> type " << desc.type
448 <<
", index " << desc.index <<
'\n';
450 loggingData.logStream << std::endl;
456 loggingData.handle = robotUnitPrx->startRtLogging(saveFormatString, loggingNames);
457 widget.pushButtonLoggingMark1->setEnabled(
true);
458 widget.pushButtonLoggingMark2->setEnabled(
true);
459 widget.pushButtonLoggingMark3->setEnabled(
true);
461 widget.pushButtonLoggingStart->setEnabled(
false);
462 widget.pushButtonLoggingStop->setEnabled(
true);
465 void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingStop_clicked()
467 std::lock_guard guard{robotUnitPrxMutex};
468 widget.pushButtonLoggingStart->setEnabled(
true);
469 widget.pushButtonLoggingStop->setEnabled(
false);
470 widget.pushButtonLoggingMark1->setEnabled(
false);
471 widget.pushButtonLoggingMark2->setEnabled(
false);
472 widget.pushButtonLoggingMark3->setEnabled(
false);
473 if (loggingData.handle)
475 robotUnitPrx->stopRtLogging(loggingData.handle);
477 if (loggingData.logStream.is_open())
479 loggingData.logStream.close();
481 loggingData.handle =
nullptr;
482 loggingData.streamingHandler =
nullptr;
485 void armarx::RobotUnitPluginWidgetController::on_lineEditLoggingFilter_textChanged(
const QString& arg1)
490 reg = std::regex{arg1.toStdString()};
495 widget.lineEditLoggingFilter->setStyleSheet(
"QLineEdit { background: rgb(255, 150, 150); selection-background-color: rgb(255, 0, 0); }");
498 widget.lineEditLoggingFilter->setStyleSheet(
"QLineEdit {}");
500 std::function<void(QTreeWidgetItem* item)> setVisible = [&](
auto it)
502 it->setHidden(
false);
503 auto parent = it->parent();
511 for (
auto item : loggingData.allItems)
513 item->setHidden(
true);
515 for (
auto item : loggingData.allItems)
517 const auto str = item->data(0, Qt::ToolTipRole).toString().toStdString();
519 if (std::regex_search(
str, match, reg))
524 widget.treeWidgetLoggingNames->blockSignals(
true);
526 for (
auto iter = loggingData.allItems.rbegin(); iter != loggingData.allItems.rend(); ++iter)
528 QTreeWidgetItem* item = *iter;
529 loggingData.updateCheckStateUpward(item,
false);
531 widget.treeWidgetLoggingNames->blockSignals(
false);
534 void armarx::RobotUnitPluginWidgetController::on_treeWidgetLoggingNames_itemChanged(QTreeWidgetItem* item,
int)
536 widget.treeWidgetLoggingNames->blockSignals(
true);
537 loggingData.updateCheckStateDownward(item, item->checkState(0),
true);
538 loggingData.updateCheckStateUpward(item->parent(),
true);
539 widget.treeWidgetLoggingNames->blockSignals(
false);
542 void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingMark1_clicked()
544 if (!loggingData.handle)
548 const auto mark = widget.lineEditLoggingMark1->text().toStdString();
550 robotUnitPrx->addMarkerToRtLog(loggingData.handle, mark);
553 void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingMark2_clicked()
555 if (!loggingData.handle)
559 const auto mark = widget.lineEditLoggingMark2->text().toStdString();
561 robotUnitPrx->addMarkerToRtLog(loggingData.handle, mark);
564 void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingMark3_clicked()
566 if (!loggingData.handle)
570 const auto mark = widget.lineEditLoggingMark3->text().toStdString();
572 robotUnitPrx->addMarkerToRtLog(loggingData.handle, mark);
575 void RobotUnitPluginWidgetController::LoggingData::updateCheckStateUpward(QTreeWidgetItem* item,
bool recurseParents)
578 for (; item; item = recurseParents ? item->parent() :
nullptr)
580 if (item->isHidden())
584 bool anyChecked =
false;
585 bool anyUnchecked =
false;
587 for (
int i = 0; i < item->childCount(); ++i)
589 auto c = item->child(i);
594 switch (
c->checkState(0))
602 case Qt::PartiallyChecked:
606 if (anyChecked + anyUnchecked + anyTri > 1 || anyTri)
608 item->setCheckState(0, Qt::PartiallyChecked);
612 item->setCheckState(0, Qt::Checked);
614 else if (anyUnchecked)
616 item->setCheckState(0, Qt::Unchecked);
623 void RobotUnitPluginWidgetController::LoggingData::updateCheckStateDownward(
624 QTreeWidgetItem* item,
625 Qt::CheckState state,
626 bool recurseChildren)
628 if (item->isHidden())
632 item->setCheckState(0, state);
634 if (!recurseChildren)
638 for (
int i = 0; i < item->childCount(); ++i)
640 auto c = item->child(i);
645 c->setCheckState(0, state);
646 updateCheckStateDownward(
c, state,
true);
650 void RobotUnitPluginWidgetController::LoggingData::localLogging()
652 if (!streamingHandler)
658 auto&
data = streamingHandler->getDataBuffer();
662 <<
"No streaming data received!";
666 <<
"Writing " <<
data.size() <<
" timesteps";
667 const auto& descr = streamingHandler->getDataDescription();
668 for (
const auto& step :
data)
670 for (
const auto& [name, desc] : descr.entries)
672 logStream <<
';' << step.iterationId
673 <<
';' << step.timestampUSec
674 <<
';' << step.timesSinceLastIterationUSec;
675 using enum_t = RobotUnitDataStreaming::DataEntryType;
678 case enum_t::NodeTypeBool :
679 logStream <<
';' << step.bools .at(desc.index);
681 case enum_t::NodeTypeByte :
682 logStream <<
';' << step.bytes .at(desc.index);
684 case enum_t::NodeTypeShort :
685 logStream <<
';' << step.shorts .at(desc.index);
687 case enum_t::NodeTypeInt :
688 logStream <<
';' << step.ints .at(desc.index);
690 case enum_t::NodeTypeLong :
691 logStream <<
';' << step.longs .at(desc.index);
693 case enum_t::NodeTypeFloat :
694 logStream <<
';' << step.floats .at(desc.index);
696 case enum_t::NodeTypeDouble:
697 logStream <<
';' << step.doubles.at(desc.index);
701 logStream << std::endl;