diff --git a/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.cpp b/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.cpp index 7c466cdacab7c4a95862d2a7e9508d2d8dda450f..0e2ae813fbef99c1ce24e35c8be0be63deeeff8b 100644 --- a/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.cpp +++ b/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.cpp @@ -110,7 +110,7 @@ namespace armarx::viz::coin << "\nFilename: " << element.filename; return true; } - IceUtil::Time time_load = IceUtil::Time::now(); + //IceUtil::Time time_load = IceUtil::Time::now(); bool drawStyleChanged = loadedDrawStyle != element.drawStyle; if (robotChanged || drawStyleChanged) @@ -118,7 +118,7 @@ namespace armarx::viz::coin recreateVisualizationNodes(element.drawStyle); loadedDrawStyle = element.drawStyle; } - IceUtil::Time time_style = IceUtil::Time::now(); + //IceUtil::Time time_style = IceUtil::Time::now(); // Set pose, configuration and so on @@ -132,33 +132,40 @@ namespace armarx::viz::coin // robot.setGlobalPose(pose, false); robot.setJointValues(element.jointValues); - IceUtil::Time time_set = IceUtil::Time::now(); + //IceUtil::Time time_set = IceUtil::Time::now(); if (loadedDrawStyle & data::ModelDrawStyle::OVERRIDE_COLOR) { - int numChildren = node->getNumChildren(); - for (int i = 0; i < numChildren; i++) + if (loadedColor.r != element.color.r + || loadedColor.g != element.color.g + || loadedColor.b != element.color.b + || loadedColor.a != element.color.a) { - SoSeparator* nodeSep = static_cast<SoSeparator*>(node->getChild(i)); - // The first entry must be a SoMaterial (see recreateVisualizationNodes) - SoMaterial* m = dynamic_cast<SoMaterial*>(nodeSep->getChild(0)); - if (!m) + int numChildren = node->getNumChildren(); + for (int i = 0; i < numChildren; i++) { - ARMARX_WARNING << "Error at node with index: " << i; - continue; + SoSeparator* nodeSep = static_cast<SoSeparator*>(node->getChild(i)); + // The first entry must be a SoMaterial (see recreateVisualizationNodes) + SoMaterial* m = dynamic_cast<SoMaterial*>(nodeSep->getChild(0)); + if (!m) + { + ARMARX_WARNING << "Error at node with index: " << i; + continue; + } + + auto color = element.color; + const float conv = 1.0f / 255.0f; + float a = color.a * conv; + SbColor coinColor(conv * color.r, conv * color.g, conv * color.b); + m->diffuseColor = coinColor; + m->ambientColor = coinColor; + m->transparency = 1.0f - a; + m->setOverride(true); } - - auto color = element.color; - const float conv = 1.0f / 255.0f; - float a = color.a * conv; - SbColor coinColor(conv * color.r, conv * color.g, conv * color.b); - m->diffuseColor = coinColor; - m->ambientColor = coinColor; - m->transparency = 1.0f - a; - m->setOverride(true); + loadedColor = element.color; } } - IceUtil::Time time_color = IceUtil::Time::now(); + //IceUtil::Time time_color = IceUtil::Time::now(); // Setting the joint angles takes > 0.5 ms! This is unexpected... // ARMARX_INFO << "Total: " << (time_color - time_start).toMilliSecondsDouble() diff --git a/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.h b/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.h index cb6699735a40b1783bb0e09270891910514278da..63aa3f1f8cabf92029b1d1b763d808f9b2123d77 100644 --- a/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.h +++ b/source/RobotAPI/components/ArViz/Coin/VisualizationRobot.h @@ -25,6 +25,7 @@ namespace armarx::viz::coin LoadedRobot loaded; int loadedDrawStyle = data::ModelDrawStyle::ORIGINAL; + armarx::viz::data::Color loadedColor{0, 0, 0, 0}; }; void clearRobotCache(); diff --git a/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp b/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp index f11c7aa9de6672cafcda2bbcfdb2e5114eb2be69..692800bc7d85488b4af3dc7090c6efabde509911 100644 --- a/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp +++ b/source/RobotAPI/components/ArViz/Coin/Visualizer.cpp @@ -143,8 +143,8 @@ namespace armarx::viz layerIt = layers.emplace(layerID, CoinLayer(coinNode)).first; } - IceUtil::Time time_start1 = IceUtil::Time::now(); - IceUtil::Time time_start = IceUtil::Time::now(); + //IceUtil::Time time_start1 = IceUtil::Time::now(); + //IceUtil::Time time_start = IceUtil::Time::now(); // Add or update the elements in the update CoinLayer& layer = layerIt->second; @@ -171,10 +171,10 @@ namespace armarx::viz continue; } coin::ElementVisualizer* visualizer = elementVisualizers[visuIndex].get(); - IceUtil::Time time_findVisu = IceUtil::Time::now(); + //IceUtil::Time time_findVisu = IceUtil::Time::now(); auto oldElementIter = layer.elements.find(updatedElement.id); - IceUtil::Time time_findElement = IceUtil::Time::now(); + //IceUtil::Time time_findElement = IceUtil::Time::now(); if (oldElementIter != layer.elements.end()) { // Element already exists @@ -238,7 +238,7 @@ namespace armarx::viz iter = layer.elements.erase(iter); } } - IceUtil::Time time_remove = IceUtil::Time::now(); + //IceUtil::Time time_remove = IceUtil::Time::now(); // if (update.name == "Example") // { @@ -290,7 +290,7 @@ namespace armarx::viz { case CoinVisualizerUpdateResult::SUCCESS: { - IceUtil::Time time_start = IceUtil::Time::now(); + //IceUtil::Time time_start = IceUtil::Time::now(); // We should restart the pull for updates so it can run in parallel data::LayerUpdates currentUpdates = pulledUpdates; @@ -299,20 +299,20 @@ namespace armarx::viz auto layerIDsBefore = getLayerIDs(); - IceUtil::Time time_afterPull = IceUtil::Time::now(); + //IceUtil::Time time_afterPull = IceUtil::Time::now(); for (data::LayerUpdate const& update : currentUpdates.updates) { apply(update); } - IceUtil::Time time_afterApply = IceUtil::Time::now(); + //IceUtil::Time time_afterApply = IceUtil::Time::now(); auto layerIDsAfter = getLayerIDs(); if (layerIDsAfter != layerIDsBefore) { emitLayersChanged(layerIDsAfter); } - IceUtil::Time time_afterLayersChanged = IceUtil::Time::now(); + //IceUtil::Time time_afterLayersChanged = IceUtil::Time::now(); // Most of the time is spent in apply // ARMARX_INFO << "Updates: " << pulledUpdates.updates.size() diff --git a/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidget.ui b/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidget.ui index 8d4e7919a123d4fe736a68de36dc19a10f6daa84..8b4af8524ff6102e7230794f12fdaac64b07a876 100644 --- a/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidget.ui +++ b/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidget.ui @@ -14,12 +14,6 @@ <string>RobotUnitPluginWidget</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> - <property name="topMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> <item> <widget class="QSplitter" name="splitter"> <property name="orientation"> @@ -101,6 +95,116 @@ </property> </layout> </widget> + <widget class="QGroupBox" name="groupBoxLogging"> + <property name="title"> + <string>Logging</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0" colspan="2"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Filter</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEditLoggingFilter"/> + </item> + </layout> + </item> + <item row="1" column="0" colspan="2"> + <widget class="QTreeWidget" name="treeWidgetLoggingNames"> + <column> + <property name="text"> + <string/> + </property> + </column> + </widget> + </item> + <item row="3" column="0" colspan="2"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Save path</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEditLoggingPath"> + <property name="toolTip"> + <string><html><head/><body><p>Accepts patterns:</p><p>{LEFT<span style=" color:#c0c0c0;"/>CURLY}<span style=" color:#c0c0c0;"/>-&gt;<span style=" color:#c0c0c0;"/>{</p><p><span style=" font-family:'monospace';">{RIGHT</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">CURLY}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">}</span></p><p><span style=" font-family:'monospace';">{year</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">/</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Year}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">year</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">(</span><span style=" font-family:'monospace'; color:#000080;">2</span><span style=" font-family:'monospace';">/</span><span style=" font-family:'monospace'; color:#000080;">4</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">digits)</span></p><p><span style=" font-family:'monospace';">{month}</span></p><p><span style=" font-family:'monospace';">{day}</span></p><p><span style=" font-family:'monospace';">{hour}</span></p><p><span style=" font-family:'monospace';">{minute}</span></p><p><span style=" font-family:'monospace';">{second}</span></p><p><span style=" font-family:'monospace';">{Date}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">YYYY-MM-DD</span></p><p><span style=" font-family:'monospace';">{Time}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">HH-MM-SS</span></p><p><span style=" font-family:'monospace';">{DateTime}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">{Date}_{Time}</span></p><p><span style=" font-family:'monospace';">{time-since-epoch}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">nanoseconds</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">since</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">epoch</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">(can</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">be</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">used</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">as</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">uuid)</span></p><p><span style=" font-family:'monospace';">{PackageDir:...}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Directory</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">of</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">the</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">given</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">package</span></p><p><span style=" font-family:'monospace';">{ScenarioDir:...}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Scenario</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Directory</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">of</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">the</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">given</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">package</span></p><p><span style=" font-family:'monospace';">{DataDir:...}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Data</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Directory</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">of</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">the</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">given</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">package</span></p><p><span style=" font-family:'monospace';">{BinaryeDir:...}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Binary</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Directory</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">of</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">the</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">given</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">package</span></p><p><span style=" font-family:'monospace';">{CMakeDir:...}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">CMake</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Directory</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">of</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">the</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">given</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">package</span></p><p><span style=" font-family:'monospace';">{BuildDir:...}</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">-&gt;</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Build</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">Directory</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">of</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">the</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">given</span><span style=" font-family:'monospace'; color:#c0c0c0;"/><span style=" font-family:'monospace';">package</span></p></body></html></string> + </property> + <property name="text"> + <string>/tmp/logging/{DateTime}.csv</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButtonLoggingStart"> + <property name="text"> + <string>Start</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButtonLoggingStop"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Stop</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="5" column="0" colspan="2"> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLineEdit" name="lineEditLoggingMark1"> + <property name="text"> + <string>Start</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLineEdit" name="lineEditLoggingMark2"> + <property name="text"> + <string>Stop</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLineEdit" name="lineEditLoggingMark3"/> + </item> + <item row="1" column="1"> + <widget class="QPushButton" name="pushButtonLoggingMark2"> + <property name="text"> + <string>Set Mark</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QPushButton" name="pushButtonLoggingMark1"> + <property name="text"> + <string>Set Mark</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPushButton" name="pushButtonLoggingMark3"> + <property name="text"> + <string>Set Mark</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> </widget> </item> </layout> diff --git a/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidgetController.cpp b/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidgetController.cpp index 076dfbbcebef9b02331fe6943fb7ba18943aa6c3..9f6229c5105a523109babbc9f2b7121ace039e42 100644 --- a/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidgetController.cpp @@ -24,13 +24,14 @@ #include "../QWidgets/StyleSheets.h" #include <string> - +#include <regex> #include <filesystem> #include <QDir> #include <QSortFilterProxyModel> #include <QAction> +#include <ArmarXCore/util/CPPUtility/Iterator.h> #include <ArmarXCore/core/system/cmake/CMakePackageFinder.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> @@ -72,6 +73,21 @@ RobotUnitPluginWidgetController::RobotUnitPluginWidgetController() nJointControllerClasses->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); nJointControllerClasses->setVisible(false); } + //update logging + { + widget.groupBoxLogging->setVisible(false); + widget.groupBoxLogging->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); + + connect(widget.pushButtonLoggingStart, SIGNAL(clicked()), this, SLOT(on_pushButtonLoggingStart_clicked())); + connect(widget.pushButtonLoggingStop, SIGNAL(clicked()), this, SLOT(on_pushButtonLoggingStop_clicked())); + connect(widget.pushButtonLoggingMark1, SIGNAL(clicked()), this, SLOT(on_pushButtonLoggingMark1_clicked())); + connect(widget.pushButtonLoggingMark2, SIGNAL(clicked()), this, SLOT(on_pushButtonLoggingMark2_clicked())); + connect(widget.pushButtonLoggingMark3, SIGNAL(clicked()), this, SLOT(on_pushButtonLoggingMark3_clicked())); + connect(widget.lineEditLoggingFilter, SIGNAL(textChanged(const QString&)), + this, SLOT(on_lineEditLoggingFilter_textChanged(const QString&))); + connect(widget.treeWidgetLoggingNames, SIGNAL(itemChanged(QTreeWidgetItem*, int)), + this, SLOT(on_treeWidgetLoggingNames_itemChanged(QTreeWidgetItem*, int))); + } updateToolBarActionCheckedState(); } @@ -195,6 +211,14 @@ QPointer<QWidget> RobotUnitPluginWidgetController::getCustomTitlebarWidget(QWidg customToolbar->addAction(showNJointClasses); customToolbar->addSeparator(); + customToolbar->addAction(QIcon(":/icons/view-refresh-7.png"), "", this, SLOT(refreshLogging())); + showLogging = new QAction {"Logging", customToolbar}; + showLogging->setCheckable(true); + showLogging->setToolTip("Hide/Show the logging pane"); + connect(showLogging, SIGNAL(toggled(bool)), widget.groupBoxLogging, SLOT(setVisible(bool))); + customToolbar->addAction(showLogging); + customToolbar->addSeparator(); + customToolbar->addAction(QIcon(":/icons/document-save.svg"), "Write log", this, SLOT(writeLogClicked())) ->setToolTip("Writes the log to /tmp/"); } @@ -285,6 +309,263 @@ void armarx::RobotUnitPluginWidgetController::timerEvent(QTimerEvent*) refreshNJointControllerClassesClicked(); refreshControlDevicesClicked(); refreshSensorDevicesClicked(); + refreshLogging(); killTimer(onConnectTimerId); } } + +void armarx::RobotUnitPluginWidgetController::refreshLogging() +{ + on_pushButtonLoggingStop_clicked(); + + widget.treeWidgetLoggingNames->clear(); + loggingData.allItems.clear(); + + const auto allLoggingNames = robotUnitPrx->getLoggingNames(); + + std::map<std::string, QTreeWidgetItem*> separators; + auto add = [&](const std::string & name, const std::string & display, auto parent) + { + QTreeWidgetItem* i = new QTreeWidgetItem(parent); + i->setText(0, QString::fromStdString(display) + "*"); + i->setData(0, Qt::ToolTipRole, QString::fromStdString(name)); + separators[name] = i; + loggingData.allItems.emplace_back(i); + i->setCheckState(0, Qt::Unchecked); + }; + add("", "", widget.treeWidgetLoggingNames); + loggingData.top = loggingData.allItems.front(); + + for (const auto& name : allLoggingNames) + { + const auto parts = Split(name, ".", true, true); + std::string reassembled; + for (const auto& p : parts) + { + ARMARX_CHECK_EXPRESSION(separators.count(reassembled)); + auto parent = separators.at(reassembled); + reassembled += (reassembled.empty() ? p : "." + p) ; + if (!separators.count(reassembled)) + { + add(reassembled, p, parent); + } + } + loggingData.allItems.back()->setText(0, QString::fromStdString(parts.back())); + } + +} + +void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingStart_clicked() +{ + if (!robotUnitPrx || loggingData.handle) + { + return; + } + std::vector<std::string> loggingNames; + std::function<void(QTreeWidgetItem*)> recurseChildren = [&](auto it) + { + switch (it->checkState(0)) + { + case Qt::Checked: + loggingNames.emplace_back(it->data(0, Qt::ToolTipRole).toString().toStdString()); + break; + case Qt::Unchecked: + break; + case Qt::PartiallyChecked: + for (int i = 0; i < it->childCount(); ++i) + { + recurseChildren(it->child(i)); + } + break; + } + }; + recurseChildren(loggingData.top); + ARMARX_INFO << "start logging " << loggingNames; + + loggingData.handle = robotUnitPrx->startRtLogging( + widget.lineEditLoggingPath->text().toStdString(), + loggingNames); + widget.pushButtonLoggingStart->setEnabled(false); + widget.pushButtonLoggingStop->setEnabled(true); + widget.pushButtonLoggingMark1->setEnabled(true); + widget.pushButtonLoggingMark2->setEnabled(true); + widget.pushButtonLoggingMark3->setEnabled(true); +} + +void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingStop_clicked() +{ + widget.pushButtonLoggingStart->setEnabled(true); + widget.pushButtonLoggingStop->setEnabled(false); + widget.pushButtonLoggingMark1->setEnabled(false); + widget.pushButtonLoggingMark2->setEnabled(false); + widget.pushButtonLoggingMark3->setEnabled(false); + if (!loggingData.handle) + { + return; + } + robotUnitPrx->stopRtLogging(loggingData.handle); + loggingData.handle = nullptr; +} + +void armarx::RobotUnitPluginWidgetController::on_lineEditLoggingFilter_textChanged(const QString& arg1) +{ + std::regex reg; + try + { + reg = std::regex{arg1.toStdString()}; + } + catch (...) + { + //broken regex + widget.lineEditLoggingFilter->setStyleSheet("QLineEdit { background: rgb(255, 150, 150); selection-background-color: rgb(255, 0, 0); }"); + return; + } + widget.lineEditLoggingFilter->setStyleSheet("QLineEdit {}"); + + std::function<void(QTreeWidgetItem* item)> setVisible = [&](auto it) + { + it->setHidden(false); + auto parent = it->parent(); + //set parent state depending on its childrens state + if (!parent) + { + return; + } + setVisible(parent); + }; + for (auto item : loggingData.allItems) + { + item->setHidden(true); + } + for (auto item : loggingData.allItems) + { + const auto str = item->data(0, Qt::ToolTipRole).toString().toStdString(); + std::smatch match; + if (std::regex_search(str, match, reg)) + { + setVisible(item); + } + } + widget.treeWidgetLoggingNames->blockSignals(true); + for (auto item : MakeReversedRange(loggingData.allItems)) + { + loggingData.updateCheckStateUpward(item, false); + } + widget.treeWidgetLoggingNames->blockSignals(false); +} + +void armarx::RobotUnitPluginWidgetController::on_treeWidgetLoggingNames_itemChanged(QTreeWidgetItem* item, int) +{ + widget.treeWidgetLoggingNames->blockSignals(true); + loggingData.updateCheckStateDownward(item, item->checkState(0), true); + loggingData.updateCheckStateUpward(item->parent(), true); + widget.treeWidgetLoggingNames->blockSignals(false); +} + +void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingMark1_clicked() +{ + if (!loggingData.handle) + { + return; + } + const auto mark = widget.lineEditLoggingMark1->text().toStdString(); + ARMARX_INFO << "set mark " << mark; + robotUnitPrx->addMarkerToRtLog(loggingData.handle, mark); +} + +void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingMark2_clicked() +{ + if (!loggingData.handle) + { + return; + } + const auto mark = widget.lineEditLoggingMark2->text().toStdString(); + ARMARX_INFO << "set mark " << mark; + robotUnitPrx->addMarkerToRtLog(loggingData.handle, mark); +} + +void armarx::RobotUnitPluginWidgetController::on_pushButtonLoggingMark3_clicked() +{ + if (!loggingData.handle) + { + return; + } + const auto mark = widget.lineEditLoggingMark3->text().toStdString(); + ARMARX_INFO << "set mark " << mark; + robotUnitPrx->addMarkerToRtLog(loggingData.handle, mark); +} + +void RobotUnitPluginWidgetController::LoggingData::updateCheckStateUpward(QTreeWidgetItem* item, bool recurseParents) +{ + //set item state depending on its childrens state and maybe recurse parent + for (; item; item = recurseParents ? item->parent() : nullptr) + { + if (item->isHidden()) + { + continue; + } + bool anyChecked = false; + bool anyUnchecked = false; + bool anyTri = false; + for (int i = 0; i < item->childCount(); ++i) + { + auto c = item->child(i); + if (c->isHidden()) + { + continue; + } + switch (c->checkState(0)) + { + case Qt::Checked: + anyChecked = true; + break; + case Qt::Unchecked: + anyUnchecked = true; + break; + case Qt::PartiallyChecked: + anyTri = true; + break; + } + if (anyChecked + anyUnchecked + anyTri > 1 || anyTri) + { + item->setCheckState(0, Qt::PartiallyChecked); + } + else if (anyChecked) + { + item->setCheckState(0, Qt::Checked); + } + else if (anyUnchecked) + { + item->setCheckState(0, Qt::Unchecked); + } + //case all false -> leaf -> do nothing + } + } +} + +void RobotUnitPluginWidgetController::LoggingData::updateCheckStateDownward( + QTreeWidgetItem* item, + Qt::CheckState state, + bool recurseChildren) +{ + if (item->isHidden()) + { + return; + } + item->setCheckState(0, state); + + if (!recurseChildren) + { + return; + } + for (int i = 0; i < item->childCount(); ++i) + { + auto c = item->child(i); + if (c->isHidden()) + { + continue; + } + c->setCheckState(0, state); + updateCheckStateDownward(c, state, true); + } +} diff --git a/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidgetController.h b/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidgetController.h index 9b57ef2d510a9c2ce896e86a36dbab461e9e7a12..06270ecbc7e9c7280fac72f6dac959e504db26bd 100644 --- a/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidgetController.h +++ b/source/RobotAPI/gui-plugins/RobotUnitPlugin/RobotUnitPlugin/RobotUnitPluginWidgetController.h @@ -132,11 +132,21 @@ namespace armarx void refreshNJointControllerClassesClicked(); void refreshControlDevicesClicked(); void refreshSensorDevicesClicked(); + void refreshLogging(); void writeLogClicked(); void startOnConnectTimer(); + //logging + void on_lineEditLoggingFilter_textChanged(const QString& arg1); + void on_pushButtonLoggingStop_clicked(); + void on_pushButtonLoggingStart_clicked(); + void on_treeWidgetLoggingNames_itemChanged(QTreeWidgetItem* item, int column); + void on_pushButtonLoggingMark1_clicked(); + void on_pushButtonLoggingMark2_clicked(); + void on_pushButtonLoggingMark3_clicked(); + private: void timerEvent(QTimerEvent*) override; void updateToolBarActionCheckedState(); @@ -162,6 +172,17 @@ namespace armarx QPointer<QAction> showSDevs; QPointer<QAction> showNJoint; QPointer<QAction> showNJointClasses; + QPointer<QAction> showLogging; + + struct LoggingData + { + QTreeWidgetItem* top; + std::vector<QTreeWidgetItem*> allItems; + RemoteReferenceCounterBasePtr handle; + static void updateCheckStateUpward(QTreeWidgetItem* item, bool recurseParents); + static void updateCheckStateDownward(QTreeWidgetItem* item, Qt::CheckState state, bool recurseChildren); + }; + LoggingData loggingData; int onConnectTimerId; };