Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • sw/armarx/robot-api
  • uwkce_singer/robot-api
  • untcg_hofmann/robot-api
  • ulqba_korosakov/RobotAPI
4 results
Show changes
Commits on Source (102)
Showing
with 1185 additions and 873 deletions
......@@ -143,21 +143,12 @@ ArmarX.ArMemExampleMemory.tpc.pub.MemoryListener = MemoryUpdates
# ArmarX.ExampleMemory.mem.MemoryName = Example
# ArmarX.ExampleMemory.mem.ltm..buffer.storeFreq: Frequency to store the buffer to the LTM in Hz.
# ArmarX.ExampleMemory.mem.ltm.configuration:
# Attributes:
# - Default: 10
# - Default: {}
# - Case sensitivity: yes
# - Required: no
# ArmarX.ExampleMemory.mem.ltm..buffer.storeFreq = 10
# ArmarX.ExampleMemory.mem.ltm.depthImageExtractor.Enabled:
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.ExampleMemory.mem.ltm.depthImageExtractor.Enabled = true
# ArmarX.ExampleMemory.mem.ltm.configuration = {}
# ArmarX.ExampleMemory.mem.ltm.enabled:
......@@ -169,100 +160,6 @@ ArmarX.ArMemExampleMemory.tpc.pub.MemoryListener = MemoryUpdates
# ArmarX.ExampleMemory.mem.ltm.enabled = false
# ArmarX.ExampleMemory.mem.ltm.exrConverter.Enabled:
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.ExampleMemory.mem.ltm.exrConverter.Enabled = true
# ArmarX.ExampleMemory.mem.ltm.imageExtractor.Enabled:
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.ExampleMemory.mem.ltm.imageExtractor.Enabled = true
# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.Enabled:
# Attributes:
# - Default: false
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.Enabled = false
# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.WaitingTime: Waiting time in MS after each LTM update.
# Attributes:
# - Default: -1
# - Case sensitivity: yes
# - Required: no
# ArmarX.ExampleMemory.mem.ltm.memFreqFilter.WaitingTime = -1
# ArmarX.ExampleMemory.mem.ltm.pngConverter.Enabled:
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.ExampleMemory.mem.ltm.pngConverter.Enabled = true
# ArmarX.ExampleMemory.mem.ltm.sizeToCompressDataInMegaBytes: The size in MB to compress away the current export. Exports are numbered (lower number means newer).
# Attributes:
# - Default: 1024
# - Case sensitivity: yes
# - Required: no
# ArmarX.ExampleMemory.mem.ltm.sizeToCompressDataInMegaBytes = 1024
# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.Enabled:
# Attributes:
# - Default: false
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.Enabled = false
# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.MaxWaitingTime: Max Waiting time in MS after each Entity update.
# Attributes:
# - Default: -1
# - Case sensitivity: yes
# - Required: no
# ArmarX.ExampleMemory.mem.ltm.snapEqFilter.MaxWaitingTime = -1
# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.Enabled:
# Attributes:
# - Default: false
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.Enabled = false
# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.WaitingTime: Waiting time in MS after each Entity update.
# Attributes:
# - Default: -1
# - Case sensitivity: yes
# - Required: no
# ArmarX.ExampleMemory.mem.ltm.snapFreqFilter.WaitingTime = -1
# ArmarX.ExampleMemory.mem.ltm.storagepath: The path to the memory storage (the memory will be stored in a seperate subfolder).
# Attributes:
# - Default: Default value not mapped.
# - Case sensitivity: yes
# - Required: no
# ArmarX.ExampleMemory.mem.ltm.storagepath = Default value not mapped.
# ArmarX.ExampleMemory.mns.MemoryNameSystemEnabled: Whether to use (and depend on) the Memory Name System (MNS).
# Set to false to use this memory as a stand-alone.
# Attributes:
......
......@@ -167,21 +167,12 @@
# ArmarX.SkillMemory.mem.MemoryName = Skill
# ArmarX.SkillMemory.mem.ltm..buffer.storeFreq: Frequency to store the buffer to the LTM in Hz.
# ArmarX.SkillMemory.mem.ltm.configuration:
# Attributes:
# - Default: 10
# - Default: {}
# - Case sensitivity: yes
# - Required: no
# ArmarX.SkillMemory.mem.ltm..buffer.storeFreq = 10
# ArmarX.SkillMemory.mem.ltm.depthImageExtractor.Enabled:
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.SkillMemory.mem.ltm.depthImageExtractor.Enabled = true
# ArmarX.SkillMemory.mem.ltm.configuration = {}
# ArmarX.SkillMemory.mem.ltm.enabled:
......@@ -193,100 +184,6 @@
# ArmarX.SkillMemory.mem.ltm.enabled = false
# ArmarX.SkillMemory.mem.ltm.exrConverter.Enabled:
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.SkillMemory.mem.ltm.exrConverter.Enabled = true
# ArmarX.SkillMemory.mem.ltm.imageExtractor.Enabled:
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.SkillMemory.mem.ltm.imageExtractor.Enabled = true
# ArmarX.SkillMemory.mem.ltm.memFreqFilter.Enabled:
# Attributes:
# - Default: false
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.SkillMemory.mem.ltm.memFreqFilter.Enabled = false
# ArmarX.SkillMemory.mem.ltm.memFreqFilter.WaitingTime: Waiting time in MS after each LTM update.
# Attributes:
# - Default: -1
# - Case sensitivity: yes
# - Required: no
# ArmarX.SkillMemory.mem.ltm.memFreqFilter.WaitingTime = -1
# ArmarX.SkillMemory.mem.ltm.pngConverter.Enabled:
# Attributes:
# - Default: true
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.SkillMemory.mem.ltm.pngConverter.Enabled = true
# ArmarX.SkillMemory.mem.ltm.sizeToCompressDataInMegaBytes: The size in MB to compress away the current export. Exports are numbered (lower number means newer).
# Attributes:
# - Default: 1024
# - Case sensitivity: yes
# - Required: no
# ArmarX.SkillMemory.mem.ltm.sizeToCompressDataInMegaBytes = 1024
# ArmarX.SkillMemory.mem.ltm.snapEqFilter.Enabled:
# Attributes:
# - Default: false
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.SkillMemory.mem.ltm.snapEqFilter.Enabled = false
# ArmarX.SkillMemory.mem.ltm.snapEqFilter.MaxWaitingTime: Max Waiting time in MS after each Entity update.
# Attributes:
# - Default: -1
# - Case sensitivity: yes
# - Required: no
# ArmarX.SkillMemory.mem.ltm.snapEqFilter.MaxWaitingTime = -1
# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.Enabled:
# Attributes:
# - Default: false
# - Case sensitivity: yes
# - Required: no
# - Possible values: {0, 1, false, no, true, yes}
# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.Enabled = false
# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.WaitingTime: Waiting time in MS after each Entity update.
# Attributes:
# - Default: -1
# - Case sensitivity: yes
# - Required: no
# ArmarX.SkillMemory.mem.ltm.snapFreqFilter.WaitingTime = -1
# ArmarX.SkillMemory.mem.ltm.storagepath: The path to the memory storage (the memory will be stored in a seperate subfolder).
# Attributes:
# - Default: Default value not mapped.
# - Case sensitivity: yes
# - Required: no
# ArmarX.SkillMemory.mem.ltm.storagepath = Default value not mapped.
# ArmarX.SkillMemory.mns.MemoryNameSystemEnabled: Whether to use (and depend on) the Memory Name System (MNS).
# Set to false to use this memory as a stand-alone.
# Attributes:
......
......@@ -107,9 +107,9 @@ namespace armarx::viz
float angle = std::acos(naturalDir.dot(dir));
if (cross.squaredNorm() < 1.0e-12f)
{
// Directions are almost colinear ==> Do no rotation
// Directions are almost colinear ==> Angle is either 0 or 180 deg
cross = Eigen::Vector3f::UnitX();
angle = 0.0f;
// Keep angle
}
Eigen::Vector3f axis = cross.normalized();
Eigen::Quaternionf ori(Eigen::AngleAxisf(angle, axis));
......
......@@ -275,13 +275,18 @@ namespace armarx
void fillExampleLayer(viz::Layer& layer, double timeInSeconds)
{
for (int i = 0; i < 6; ++i)
{
Eigen::Vector3f pos = Eigen::Vector3f::Zero();
pos.z() = +300.0f;
Eigen::Vector3f pos = Eigen::Vector3f(-200.0, 200.0, 300);
pos.x() += -300 * i;
Eigen::Vector3f normal = Eigen::Vector3f::Zero();
normal(i / 2) = (i % 2 == 0 ? 1.0 : -1.0);
viz::ArrowCircle circle = viz::ArrowCircle("circle")
viz::ArrowCircle circle = viz::ArrowCircle("circle " + std::to_string(i))
.position(pos)
.radius(100.0f)
.normal(normal)
.width(10.0f)
.color(viz::Color::fromRGBA(255, 0, 255));
......
......@@ -20,6 +20,8 @@ namespace armarx::skills::provider
default_params.some_float = 5;
default_params.some_int = 42;
default_params.some_text = "YOLO";
default_params.some_list_of_matrices.push_back(Eigen::Matrix3f::Zero());
//default_params.some_matrix = Eigen::Matrix3f::Zero();
return SkillDescription{
"HelloWorld",
......
<?xml version="1.0" encoding="UTF-8" ?>
<AronTypeDefinition>
<GenerateTypes>
<IntEnum name="HelloWorldInteEnum">
<EnumValue key="INT_ENUM_VALUE_0" value="0" />
<EnumValue key="INT_ENUM_VALUE_1" value="1" />
<EnumValue key="INT_ENUM_VALUE_2" value="2" />
<EnumValue key="INT_ENUM_VALUE_3" value="3" />
<EnumValue key="INT_ENUM_VALUE_4" value="4" />
<EnumValue key="INT_ENUM_VALUE_5" value="5" />
<EnumValue key="INT_ENUM_VALUE_6" value="6" />
<EnumValue key="INT_ENUM_VALUE_7" value="7" />
<EnumValue key="INT_ENUM_VALUE_8" value="8" />
</IntEnum>
<Object name='armarx::skills::Example::HelloWorldAcceptedType'>
<ObjectChild key='some_int'>
<Int />
......@@ -11,6 +22,23 @@
<ObjectChild key='some_text'>
<String />
</ObjectChild>
<ObjectChild key='some_list_of_matrices'>
<List>
<Matrix rows="3" cols="3" type="float32" />
</List>
</ObjectChild>
<ObjectChild key='some_dict_of_matrices'>
<Dict>
<Matrix rows="3" cols="3" type="float32" />
</Dict>
</ObjectChild>
<ObjectChild key='some_matrix'>
<Matrix rows="3" cols="3" type="float32" />
</ObjectChild>
</Object>
</GenerateTypes>
......
......@@ -71,10 +71,18 @@ namespace armarx::RobotUnitModule
"RTLogging_MaxMessageBufferSize", 16 * 1024 * 1024,
"Max number of bytes that can be logged in the control thread");
defineOptionalProperty<bool>(
"RTLogging_EnableBacklog", true,
"Enable/Disable the backlog (SensorValues, ControlTargets, Messages) that is kept"
"and can be dumped in case of an error.");
defineOptionalProperty<std::size_t>(
"RTLogging_KeepIterationsForMs", 60 * 1000,
"All logging data (SensorValues, ControlTargets, Messages) is kept for this duration "
"and can be dumped in case of an error.");
defineOptionalProperty<std::size_t>(
"RTLogging_MaxBacklogSize", 5000,
"Maximum size of the backlog (SensorValues, ControlTargets, Messages) that is kept"
"and can be dumped in case of an error.");
defineOptionalProperty<std::size_t>(
"RTLogging_StreamingDataMaxClientConnectionFailures", 10,
......@@ -301,8 +309,12 @@ namespace armarx::RobotUnitModule
std::size_t messageBufferMaxNumberEntries {0};
/// @brief The logging thread's period
std::size_t rtLoggingTimestepMs {0};
/// @brief The time an entry shold remain in the backlog.
/// @brief The time an entry should remain in the backlog.
IceUtil::Time rtLoggingBacklogRetentionTime;
/// @brief The maximum number of entries in the backlog.
std::size_t rtLoggingBacklogMaxSize;
/// @brief Enable/disable the backlog.
bool rtLoggingBacklogEnabled;
/// @brief
bool logAllEntries = true;
......
......@@ -31,6 +31,9 @@
#include <RobotAPI/components/units/RobotUnit/RobotUnitModules/RobotUnitModuleControlThreadDataBuffer.h>
#include <RobotAPI/components/units/RobotUnit/NJointControllers/NJointControllerRegistry.h>
#include "ArmarXCore/core/exceptions/local/ExpressionException.h"
#include "ArmarXCore/core/logging/Logging.h"
#include "ArmarXCore/core/util/StringHelpers.h"
#include <ArmarXCore/core/ArmarXObjectScheduler.h>
namespace armarx::RobotUnitModule
......@@ -312,6 +315,7 @@ namespace armarx::RobotUnitModule
SensorDeviceStatus status;
status.deviceName = DevicesAttorneyForPublisher::GetSensorDeviceName(this, sensidx);
ARMARX_TRACE;
if (observerPublishSensorValues && publishToObserver)
{
for (const auto& pair : variants)
......
......@@ -445,11 +445,13 @@ namespace armarx
messages {other.messages, minimize},
buffer(other.buffer.size(), 0)
{
ARMARX_TRACE;
void* place = buffer.data();
std::size_t space = buffer.size();
auto getAlignedPlace = [&space, &place, this](std::size_t bytes, std::size_t alignment)
{
ARMARX_TRACE;
ARMARX_CHECK_EXPRESSION(std::align(alignment, bytes, place, space));
ARMARX_CHECK_LESS(bytes, space);
const auto resultPlace = place;
......@@ -463,6 +465,7 @@ namespace armarx
sensors.reserve(other.sensors.size());
for (const SensorValueBase* sv : other.sensors)
{
ARMARX_TRACE;
sensors.emplace_back(sv->_placementCopyConstruct(getAlignedPlace(sv->_sizeof(), sv->_alignof())));
}
......@@ -470,6 +473,7 @@ namespace armarx
control.reserve(other.control.size());
for (const auto& cdctargs : other.control)
{
ARMARX_TRACE;
control.emplace_back();
auto& ctargs = control.back();
ctargs.reserve(cdctargs.size());
......
......@@ -9,15 +9,22 @@ set(SOURCES
aronTreeWidget/visitors/AronTreeWidgetConverter.cpp
aronTreeWidget/visitors/AronTreeWidgetSetter.cpp
aronTreeWidget/visitors/AronTreeWidgetModalCreator.cpp
aronTreeWidget/visitors/AronTreeWidgetContextMenu.cpp
aronTreeWidget/Data.cpp
aronTreeWidget/widgets/CustomWidget.cpp
aronTreeWidget/widgets/EditMatrixWidget.cpp
aronTreeWidget/widgets/IntEnumWidget.cpp
aronTreeWidget/ListDictHelper.cpp
aronTreeWidget/widgets/QuaternionWidget.cpp
aronTreeWidget/AronTreeWidgetItem.cpp
aronTreeWidget/AronTreeWidgetController.cpp
aronTreeWidget/modal/AronTreeWidgetModal.cpp
aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.cpp
aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp
aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.cpp
aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.cpp
aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.cpp
aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.cpp
aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.cpp
aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.cpp
aronTreeWidget/modal/AronTreeWidgetModal.cpp
ColorPalettes.cpp
SkillManagerMonitorWidgetController.cpp
)
......@@ -26,25 +33,29 @@ set(HEADERS
aronTreeWidget/visitors/AronTreeWidgetConverter.h
aronTreeWidget/visitors/AronTreeWidgetSetter.h
aronTreeWidget/visitors/AronTreeWidgetModalCreator.h
aronTreeWidget/visitors/AronTreeWidgetContextMenu.h
aronTreeWidget/Data.h
aronTreeWidget/widgets/NDArrayHelper.h
aronTreeWidget/widgets/EditMatrixWidget.h
aronTreeWidget/widgets/CustomWidget.h
aronTreeWidget/widgets/IntEnumWidget.h
aronTreeWidget/ListDictHelper.h
aronTreeWidget/widgets/QuaternionWidget.h
aronTreeWidget/AronTreeWidgetItem.h
aronTreeWidget/AronTreeWidgetController.h
aronTreeWidget/modal/AronTreeWidgetModal.h
aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.h
aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.h
aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.h
aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.h
aronTreeWidget/modal/dict/AronTreeWidgetDictInputModalController.h
aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModalController.h
aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModalController.h
aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModalController.h
ColorPalettes.h
SkillManagerMonitorWidgetController.h
)
set(GUI_UIS
SkillManagerMonitorWidget.ui
aronTreeWidget/modal/int_long/AronTreeWidgetIntInputModal.ui
aronTreeWidget/modal/float_double/AronTreeWidgetFloatInputModal.ui
aronTreeWidget/modal/bool/AronTreeWidgetBoolInputModal.ui
aronTreeWidget/modal/text/AronTreeWidgetTextInputModal.ui
aronTreeWidget/modal/dict/AronTreeWidgetDictInputModal.ui
)
# Add more libraries you depend on here, e.g. ${QT_LIBRARIES}.
......
#include "ColorPalettes.h"
namespace armarx::gui_color_palette
{
QPalette
getErrorPalette()
{
QPalette errorPalette;
errorPalette.setColor(QPalette::Base, Qt::red);
return errorPalette;
}
QPalette
getNormalPalette()
{
QPalette normalPalette;
normalPalette.setColor(QPalette::Base, Qt::white);
return normalPalette;
}
QPalette
getIndirectErrorPalette()
{
QPalette indirectErr;
static QColor orange = QColor::fromRgb(255, 165, 0);
// orange color
indirectErr.setColor(QPalette::Base, orange);
return indirectErr;
}
} // namespace armarx::gui_color_palette
#pragma once
#include <QPalette>
namespace armarx::gui_color_palette
{
QPalette getNormalPalette();
QPalette getErrorPalette();
QPalette getIndirectErrorPalette();
} // namespace armarx::gui_color_palette
......@@ -6,145 +6,187 @@
<rect>
<x>0</x>
<y>0</y>
<width>1015</width>
<height>498</height>
<width>1060</width>
<height>657</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>SkillManagerMonitorWidget</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBoxActiveSkills">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QSplitter" name="splitter_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Active Skills</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QListWidget" name="listWidgetActiveSkills">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="childrenCollapsible">
<bool>false</bool>
</property>
<widget class="QGroupBox" name="groupBoxSkills">
<widget class="QGroupBox" name="groupBoxActiveSkills">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Manager</string>
<string>Active Skills</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Update Frequency:</string>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QListWidget" name="listWidgetActiveSkills">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QTreeWidget" name="treeWidgetSkills">
<column>
</layout>
</widget>
<widget class="QSplitter" name="splitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QGroupBox" name="groupBoxSkills">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Manager</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Skill</string>
<string>Update Frequency:</string>
</property>
</column>
<column>
<property name="text">
<string>HasType</string>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QTreeWidget" name="treeWidgetSkills">
<column>
<property name="text">
<string>Skill</string>
</property>
</column>
<column>
<property name="text">
<string>HasType</string>
</property>
</column>
<column>
<property name="text">
<string>State</string>
</property>
</column>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxUpdateFreq"/>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="groupBoxSkillDetails">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Skill Details</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0" colspan="4">
<widget class="QTreeWidget" name="treeWidgetSkillDetails">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
</property>
</column>
<column>
<column>
<property name="text">
<string>Key</string>
</property>
</column>
<column>
<property name="text">
<string>Value</string>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>defaultValue</string>
</property>
</column>
</widget>
</item>
<item row="6" column="3">
<widget class="QPushButton" name="pushButtonExecuteSkill">
<property name="text">
<string>State</string>
<string>Request Execution</string>
</property>
</column>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxUpdateFreq"/>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="groupBoxSkillDetails">
<property name="title">
<string>Skill Details</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0" colspan="4">
<widget class="QTreeWidget" name="treeWidgetSkillDetails">
<column>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="pushButtonPaste">
<property name="text">
<string>Key</string>
<string>Set from clipboard</string>
</property>
</column>
<column>
</widget>
</item>
<item row="6" column="0">
<widget class="QPushButton" name="pushButtonStopSkill">
<property name="text">
<string>Value</string>
<string>Stop current skill</string>
</property>
</column>
<column>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="pushButtonReset">
<property name="text">
<string>Type</string>
<string>Reset args</string>
</property>
</column>
<column>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pushButtonCopy">
<property name="text">
<string>defaultValue</string>
<string>Copy args to clipboard</string>
</property>
</column>
</widget>
</item>
<item row="6" column="3">
<widget class="QPushButton" name="pushButtonExecuteSkill">
<property name="text">
<string>Request Execution</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="pushButtonPaste">
<property name="text">
<string>Set from clipboard</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QPushButton" name="pushButtonStopSkill">
<property name="text">
<string>Stop current skill</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="pushButtonReset">
<property name="text">
<string>Reset args</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pushButtonCopy">
<property name="text">
<string>Copy args to clipboard</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
......
......@@ -20,52 +20,57 @@
* GNU General Public License
*/
#include "SkillManagerMonitorWidgetController.h"
#include <string>
#include "SkillManagerMonitorWidgetController.h"
#include <RobotAPI/libraries/skills/provider/Skill.h>
#include "aronTreeWidget/visitors/AronTreeWidgetCreator.h"
#include "aronTreeWidget/visitors/AronTreeWidgetConverter.h"
#include "aronTreeWidget/visitors/AronTreeWidgetCreator.h"
#include "aronTreeWidget/visitors/AronTreeWidgetModalCreator.h"
#include <RobotAPI/libraries/skills/provider/Skill.h>
// modals
#include "aronTreeWidget/modal/text/AronTreeWidgetTextInputModalController.h"
// debug
#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
#include <QDoubleSpinBox>
#include <QClipboard>
#include <QDoubleSpinBox>
#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
#include "aronTreeWidget/Data.h"
//config
namespace armarx
{
QPointer<QDialog> SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent)
QPointer<QDialog>
SkillManagerMonitorWidgetController::getConfigDialog(QWidget* parent)
{
if (!dialog)
{
dialog = new SimpleConfigDialog(parent);
dialog->addProxyFinder<skills::manager::dti::SkillManagerInterfacePrx>("SkillManager", "", "Skill*");
dialog->addProxyFinder<skills::manager::dti::SkillManagerInterfacePrx>(
"SkillManager", "", "Skill*");
}
return qobject_cast<SimpleConfigDialog*>(dialog);
}
void SkillManagerMonitorWidgetController::configured()
void
SkillManagerMonitorWidgetController::configured()
{
observerName = dialog->getProxyName("SkillManager");
}
void SkillManagerMonitorWidgetController::loadSettings(QSettings* settings)
void
SkillManagerMonitorWidgetController::loadSettings(QSettings* settings)
{
observerName = settings->value("SkillManager", "SkillManager").toString().toStdString();
}
void SkillManagerMonitorWidgetController::saveSettings(QSettings* settings)
void
SkillManagerMonitorWidgetController::saveSettings(QSettings* settings)
{
settings->setValue("SkillManager", QString::fromStdString(observerName));
}
}
} // namespace armarx
// Others
namespace armarx
......@@ -81,29 +86,40 @@ namespace armarx
widget.doubleSpinBoxUpdateFreq->setSuffix(" Hz");
refreshSkillsResultTimer = new QTimer(this);
refreshSkillsResultTimer->setInterval(1000 / 5); // Keep this stable.
refreshSkillsResultTimer->setInterval(1000 / 5); // Keep this stable.
refreshSkillsResultTimer->start();
connect(widget.doubleSpinBoxUpdateFreq, &QDoubleSpinBox::editingFinished,
this, &SkillManagerMonitorWidgetController::updateTimerFrequency);
connect(refreshSkillsResultTimer, &QTimer::timeout,
this, &SkillManagerMonitorWidgetController::refreshSkills);
connect(widget.pushButtonCopy, &QPushButton::clicked,
this, &SkillManagerMonitorWidgetController::copyCurrentConfig);
connect(widget.pushButtonPaste, &QPushButton::clicked,
this, &SkillManagerMonitorWidgetController::pasteCurrentConfig);
connect(widget.pushButtonExecuteSkill, &QPushButton::clicked,
this, &SkillManagerMonitorWidgetController::executeSkill);
connect(widget.pushButtonStopSkill, &QPushButton::clicked,
this, &SkillManagerMonitorWidgetController::stopSkill);
connect(widget.treeWidgetSkills, &QTreeWidget::currentItemChanged,
this, &SkillManagerMonitorWidgetController::skillSelectionChanged);
connect(widget.treeWidgetSkillDetails, &QTreeWidget::itemDoubleClicked,
this, &SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked);
connect(widget.doubleSpinBoxUpdateFreq,
&QDoubleSpinBox::editingFinished,
this,
&SkillManagerMonitorWidgetController::updateTimerFrequency);
connect(refreshSkillsResultTimer,
&QTimer::timeout,
this,
&SkillManagerMonitorWidgetController::refreshSkills);
connect(widget.pushButtonCopy,
&QPushButton::clicked,
this,
&SkillManagerMonitorWidgetController::copyCurrentConfig);
connect(widget.pushButtonPaste,
&QPushButton::clicked,
this,
&SkillManagerMonitorWidgetController::pasteCurrentConfig);
connect(widget.pushButtonExecuteSkill,
&QPushButton::clicked,
this,
&SkillManagerMonitorWidgetController::executeSkill);
connect(widget.pushButtonStopSkill,
&QPushButton::clicked,
this,
&SkillManagerMonitorWidgetController::stopSkill);
connect(widget.treeWidgetSkills,
&QTreeWidget::currentItemChanged,
this,
&SkillManagerMonitorWidgetController::skillSelectionChanged);
}
SkillManagerMonitorWidgetController::~SkillManagerMonitorWidgetController()
......@@ -111,25 +127,38 @@ namespace armarx
}
void SkillManagerMonitorWidgetController::onInitComponent()
void
SkillManagerMonitorWidgetController::reconnectToSkillManager()
{
if (connected)
{
getProxy(manager, observerName, 1000);
}
}
void
SkillManagerMonitorWidgetController::onInitComponent()
{
usingProxy(observerName);
}
void SkillManagerMonitorWidgetController::onConnectComponent()
void
SkillManagerMonitorWidgetController::onConnectComponent()
{
getProxy(manager, observerName);
widget.groupBoxSkills->setTitle(QString::fromStdString(observerName));
widget.treeWidgetSkillDetails->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers);
widget.treeWidgetSkillDetails->setEditTriggers(
QAbstractItemView::EditTrigger::NoEditTriggers);
widget.treeWidgetSkillDetails->setColumnHidden(3, true);
connected = true;
}
void SkillManagerMonitorWidgetController::onDisconnectComponent()
void
SkillManagerMonitorWidgetController::onDisconnectComponent()
{
connected = false;
manager = nullptr;
// reset all
skills.clear();
......@@ -140,25 +169,30 @@ namespace armarx
selectedSkill.skillName = "";
}
void SkillManagerMonitorWidgetController::updateTimerFrequency()
void
SkillManagerMonitorWidgetController::updateTimerFrequency()
{
int f = static_cast<int>(std::round(1000 / widget.doubleSpinBoxUpdateFreq->value()));
refreshSkillsResultTimer->setInterval(f);
}
void SkillManagerMonitorWidgetController::refreshSkills()
void
SkillManagerMonitorWidgetController::refreshSkills()
{
static std::map<skills::provider::dto::Execution::Status, std::string> ExecutionStatus2String = {
{skills::provider::dto::Execution::Status::Aborted, "Aborted"},
{skills::provider::dto::Execution::Status::Failed, "Failed"},
{skills::provider::dto::Execution::Status::Idle, "Not yet started"},
{skills::provider::dto::Execution::Status::Running, "Running"},
{skills::provider::dto::Execution::Status::Scheduled, "Scheduled"},
{skills::provider::dto::Execution::Status::Succeeded, "Succeeded"}
};
if (!connected)
static std::map<skills::provider::dto::Execution::Status, std::string>
ExecutionStatus2String = {
{skills::provider::dto::Execution::Status::Aborted, "Aborted"},
{skills::provider::dto::Execution::Status::Failed, "Failed"},
{skills::provider::dto::Execution::Status::Idle, "Not yet started"},
{skills::provider::dto::Execution::Status::Running, "Running"},
{skills::provider::dto::Execution::Status::Scheduled, "Scheduled"},
{skills::provider::dto::Execution::Status::Succeeded, "Succeeded"}};
if (!manager)
{
reconnectToSkillManager();
return;
}
/* CHECK OWN SKILLS LIST */
// remove non-existing ones
......@@ -196,7 +230,9 @@ namespace armarx
while (i < widget.treeWidgetSkills->topLevelItemCount())
{
QTreeWidgetItem* item = widget.treeWidgetSkills->topLevelItem(i);
if (std::find(removedProviders.begin(), removedProviders.end(), item->text(0).toStdString()) != removedProviders.end())
if (std::find(removedProviders.begin(),
removedProviders.end(),
item->text(0).toStdString()) != removedProviders.end())
{
delete widget.treeWidgetSkills->takeTopLevelItem(i);
}
......@@ -209,7 +245,8 @@ namespace armarx
// add new providers
for (const auto& [providerName, providerSkills] : skills)
{
if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName); it != newProviders.end())
if (auto it = std::find(newProviders.begin(), newProviders.end(), providerName);
it != newProviders.end())
{
auto item = new QTreeWidgetItem(widget.treeWidgetSkills);
item->setText(0, QString::fromStdString(providerName));
......@@ -225,7 +262,7 @@ namespace armarx
// update status and active skills window
std::map<skills::SkillID, std::string> activeSkillsAndPrefixes;
auto managerStatuses = manager->getSkillExecutionStatuses();
for (int i = 0; i < widget.treeWidgetSkills->topLevelItemCount(); ++i)
for (int i = 0; i < widget.treeWidgetSkills->topLevelItemCount(); ++i)
{
try
{
......@@ -240,11 +277,15 @@ namespace armarx
skills::SkillID currentSkillId(providerName, skillItem->text(0).toStdString());
auto statusForSkill = allStatusesForProvider.at(currentSkillId.skillName);
skillItem->setText(2, QString::fromStdString(ExecutionStatus2String.at(statusForSkill.header.status)));
skillItem->setText(2,
QString::fromStdString(ExecutionStatus2String.at(
statusForSkill.header.status)));
if (not statusForSkill.header.executorName.empty()) // it means that the skill was called by someone
if (not statusForSkill.header.executorName
.empty()) // it means that the skill was called by someone
{
activeSkillsAndPrefixes.insert({currentSkillId, statusForSkill.header.executorName});
activeSkillsAndPrefixes.insert(
{currentSkillId, statusForSkill.header.executorName});
}
}
}
......@@ -261,7 +302,8 @@ namespace armarx
{
auto prefixedStr = id.toString(prefix);
bool longest = true;
for (const auto& [id2, prefix2] : activeSkillsAndPrefixes) // check if there is a deeper skill currently executing
for (const auto& [id2, prefix2] :
activeSkillsAndPrefixes) // check if there is a deeper skill currently executing
{
auto prefixedStr2 = id.toString(prefix2);
if (prefixedStr == prefixedStr2)
......@@ -278,12 +320,14 @@ namespace armarx
if (longest)
{
widget.listWidgetActiveSkills->addItem(QString::fromStdString(id.toString() + ": " + id.toString(prefix)));
widget.listWidgetActiveSkills->addItem(
QString::fromStdString(id.toString() + ": " + id.toString(prefix)));
}
}
}
void SkillManagerMonitorWidgetController::executeSkill()
void
SkillManagerMonitorWidgetController::executeSkill()
{
if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty())
{
......@@ -307,12 +351,14 @@ namespace armarx
exInfo.skillId = {selectedSkill.providerName, selectedSkill.skillName};
exInfo.params = aron::data::Dict::ToAronDictDTO(data);
ARMARX_IMPORTANT << "Executing skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName << ". The data was: " << data;
ARMARX_IMPORTANT << "Executing skill from GUI: " << selectedSkill.providerName << "/"
<< selectedSkill.skillName << ". The data was: " << data;
// Note that we execute the skill in a seperate thread so that the GUI thread does not freeze.
manager->begin_executeSkill(exInfo);
}
void SkillManagerMonitorWidgetController::stopSkill()
void
SkillManagerMonitorWidgetController::stopSkill()
{
if (selectedSkill.providerName.empty() or selectedSkill.skillName.empty())
{
......@@ -325,11 +371,14 @@ namespace armarx
return;
}
ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.providerName << "/" << selectedSkill.skillName;
ARMARX_INFO << "Stopping skill from GUI: " << selectedSkill.providerName << "/"
<< selectedSkill.skillName;
manager->abortSkill(selectedSkill.providerName, selectedSkill.skillName);
}
void SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current, QTreeWidgetItem*)
void
SkillManagerMonitorWidgetController::skillSelectionChanged(QTreeWidgetItem* current,
QTreeWidgetItem*)
{
widget.groupBoxSkillDetails->setEnabled(false);
......@@ -352,10 +401,12 @@ namespace armarx
newSelectedSkill.skillName = current->text(0).toStdString();
// setup groupBox
widget.groupBoxSkillDetails->setTitle(QString::fromStdString(newSelectedSkill.providerName + "/" + newSelectedSkill.skillName));
widget.groupBoxSkillDetails->setTitle(QString::fromStdString(
newSelectedSkill.providerName + "/" + newSelectedSkill.skillName));
widget.groupBoxSkillDetails->setEnabled(true);
if (newSelectedSkill.providerName == selectedSkill.providerName and newSelectedSkill.skillName == selectedSkill.skillName)
if (newSelectedSkill.providerName == selectedSkill.providerName and
newSelectedSkill.skillName == selectedSkill.skillName)
{
return;
}
......@@ -370,37 +421,46 @@ namespace armarx
auto skillDesc = skills.at(selectedSkill.providerName).at(selectedSkill.skillName);
{
auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
{QString::fromStdString("Name"), QString::fromStdString(skillDesc.skillName)});
auto it = new QTreeWidgetItem(
widget.treeWidgetSkillDetails,
{QString::fromStdString("Name"), QString::fromStdString(skillDesc.skillName)});
widget.treeWidgetSkillDetails->addTopLevelItem(it);
}
{
auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
{QString::fromStdString("Robot"), QString::fromStdString(simox::alg::join(skillDesc.robots, ", "))});
auto it = new QTreeWidgetItem(
widget.treeWidgetSkillDetails,
{QString::fromStdString("Robot"),
QString::fromStdString(simox::alg::join(skillDesc.robots, ", "))});
widget.treeWidgetSkillDetails->addTopLevelItem(it);
}
{
auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
{QString::fromStdString("Description"), QString::fromStdString(skillDesc.description)});
{QString::fromStdString("Description"),
QString::fromStdString(skillDesc.description)});
widget.treeWidgetSkillDetails->addTopLevelItem(it);
}
{
auto it = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
{QString::fromStdString("Timeout"), QString::fromStdString(std::to_string(skillDesc.timeoutMs)) + " ms"});
auto it = new QTreeWidgetItem(
widget.treeWidgetSkillDetails,
{QString::fromStdString("Timeout"),
QString::fromStdString(std::to_string(skillDesc.timeoutMs)) + " ms"});
widget.treeWidgetSkillDetails->addTopLevelItem(it);
}
skillsArgumentsTreeWidgetItem = new QTreeWidgetItem(widget.treeWidgetSkillDetails, {QString::fromStdString("Arguments")});
skillsArgumentsTreeWidgetItem = new QTreeWidgetItem(widget.treeWidgetSkillDetails,
{QString::fromStdString("Arguments")});
auto aron_args = aron::type::Object::FromAronObjectDTO(skillDesc.acceptedType);
auto default_args = aron::data::Dict::FromAronDictDTO(skillDesc.defaultParams);
aronTreeWidgetController = std::make_shared<AronTreeWidgetController>(widget.treeWidgetSkillDetails, skillsArgumentsTreeWidgetItem, aron_args, default_args);
aronTreeWidgetController = std::make_shared<AronTreeWidgetController>(
widget.treeWidgetSkillDetails, skillsArgumentsTreeWidgetItem, aron_args, default_args);
}
aron::data::DictPtr SkillManagerMonitorWidgetController::getConfigAsAron() const
aron::data::DictPtr
SkillManagerMonitorWidgetController::getConfigAsAron() const
{
// create argument aron (if there is an accepted type set)
if (aronTreeWidgetController)
......@@ -410,7 +470,8 @@ namespace armarx
return nullptr;
}
void SkillManagerMonitorWidgetController::copyCurrentConfig()
void
SkillManagerMonitorWidgetController::copyCurrentConfig()
{
auto data = getConfigAsAron();
if (!data)
......@@ -423,7 +484,8 @@ namespace armarx
clipboard->setText(QString::fromStdString(json.dump(2)));
}
void SkillManagerMonitorWidgetController::pasteCurrentConfig()
void
SkillManagerMonitorWidgetController::pasteCurrentConfig()
{
QClipboard* clipboard = QApplication::clipboard();
std::string s = clipboard->text().toStdString();
......@@ -438,34 +500,10 @@ namespace armarx
aronTreeWidgetController->setFromAron(data);
}
void SkillManagerMonitorWidgetController::resetCurrentConfig()
void
SkillManagerMonitorWidgetController::resetCurrentConfig()
{
// TODO
}
void SkillManagerMonitorWidgetController::onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column)
{
if (!item)
{
return;
}
if (column == 1)
{
if (item->flags() & Qt::ItemIsEditable) // we use the flag to indicate whether the item is editable or not
{
// we assume its aron item
AronTreeWidgetItem* aItem = AronTreeWidgetItem::DynamicCastAndCheck(item);
std::string name = aItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME).toStdString();
std::string type = aItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_TYPE).toStdString();
// why visitor?!?!?
AronTreeWidgetModalCreatorVisitor v(name, aItem, widget.treeWidgetSkillDetails);
aron::type::visit(v, aItem->aronType);
auto modal = v.createdModal;
modal->exec();
}
}
}
}
} // namespace armarx
......@@ -22,25 +22,24 @@
#pragma once
#include <stack>
#include <vector>
#include <thread>
#include <vector>
#include <QTimer>
#include <ArmarXCore/core/system/ImportExportComponent.h>
#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h>
#include <RobotAPI/interface/skills/SkillMemoryInterface.h>
#include <RobotAPI/gui-plugins/SkillManagerPlugin/ui_SkillManagerMonitorWidget.h>
#include "aronTreeWidget/AronTreeWidgetController.h"
#include <RobotAPI/libraries/aron/core/type/variant/All.h>
#include <RobotAPI/interface/skills/SkillMemoryInterface.h>
#include <RobotAPI/libraries/aron/core/data/variant/All.h>
#include <RobotAPI/libraries/aron/core/type/variant/All.h>
#include <RobotAPI/libraries/aron/core/type/visitor/variant/VariantVisitor.h>
#include <QTimer>
#include "aronTreeWidget/AronTreeWidgetController.h"
namespace armarx
{
......@@ -71,6 +70,8 @@ namespace armarx
return "Skills.Manager";
}
void reconnectToSkillManager();
void onInitComponent() override;
void onConnectComponent() override;
void onDisconnectComponent() override;
......@@ -88,7 +89,6 @@ namespace armarx
void pasteCurrentConfig();
void resetCurrentConfig();
void onTreeWidgetItemDoubleClicked(QTreeWidgetItem * item, int column);
private:
aron::data::DictPtr getConfigAsAron() const;
......@@ -120,11 +120,13 @@ namespace armarx
AronTreeWidgetControllerPtr aronTreeWidgetController = nullptr;
// others
std::atomic_bool connected = false;
QTimer* refreshSkillsResultTimer;
// skillExecutions
std::vector<std::thread> executions;
// connected flag
std::atomic_bool connected = false;
};
}
......
- keep set values around to not loose precision of values that have not been manipulated (in AronTreeWidgetItem, as well as Matrix and Quaternion)
- get rid of any todos present
#include "AronTreeWidgetController.h"
#include <RobotAPI/gui-plugins/SkillManagerPlugin/aronTreeWidget/visitors/AronTreeWidgetModalCreator.h>
#include "visitors/AronTreeWidgetContextMenu.h"
#include "visitors/AronTreeWidgetConverter.h"
#include "visitors/AronTreeWidgetSetter.h"
namespace armarx
{
AronTreeWidgetController::AronTreeWidgetController(QTreeWidget* tree, QTreeWidgetItem* parent, const aron::type::ObjectPtr& type, const aron::data::DictPtr& data):
parent(parent),
tree(tree),
type(type)
AronTreeWidgetController::AronTreeWidgetController(QTreeWidget* tree,
QTreeWidgetItem* parent,
const aron::type::ObjectPtr& type,
const aron::data::DictPtr& data) :
parent(parent), tree(tree), type(type)
{
if (type) // if there is a type set, we create a tree widget from the typp
connect(tree,
SIGNAL(customContextMenuRequested(const QPoint&)),
this,
SLOT(ShowContextMenu(const QPoint&)));
connect(tree,
&QTreeWidget::itemDoubleClicked,
this,
&AronTreeWidgetController::onTreeWidgetItemDoubleClicked);
if (type) // if there is a type set, we create a tree widget from the type
{
AronTreeWidgetCreatorVisitor v;
AronTreeWidgetCreatorVisitor v(parent);
v.setTopLevelWidget(tree);
aron::type::visit(v, type);
if (v.createdQWidgetItem)
{
parent->addChild(v.createdQWidgetItem);
}
if (data) // check if there is a default argument set. Prefill the GUI with it
{
setFromAron(data);
}
}
else if(data) // there is no type but a default configuration. Prefill the GUI with the default arguments
// there is no type but a default configuration. Prefill the GUI with the default arguments
else if (data)
{
// TODO: There is no visitor for that (yet)...
// create type from data, ...
}
else
{
new QTreeWidgetItem(parent, {QString::fromStdString("No args")});
}
// connect change handling after args init
connect(tree,
&QTreeWidget::itemChanged,
this,
&AronTreeWidgetController::onTreeWidgetItemChanged);
}
aron::data::DictPtr AronTreeWidgetController::convertToAron() const
aron::data::DictPtr
AronTreeWidgetController::convertToAron() const
{
if (parent)
if (parent && type)
{
AronTreeWidgetConverterVisitor v(parent, 0);
aron::type::visit(v, type);
......@@ -48,7 +67,8 @@ namespace armarx
return nullptr;
}
void AronTreeWidgetController::setFromAron(const aron::data::DictPtr& data)
void
AronTreeWidgetController::setFromAron(const aron::data::DictPtr& data)
{
if (parent)
{
......@@ -56,4 +76,87 @@ namespace armarx
aron::data::visit(v, data);
}
}
}
void
AronTreeWidgetController::ShowContextMenu(const QPoint& pos)
{
tree->blockSignals(true);
auto idx = tree->indexAt(pos);
AronTreeWidgetItem* clickedItem = AronTreeWidgetItem::DynamicCast(tree->itemAt(pos));
if (clickedItem)
{
AronTreeWidgetContextMenuVisitor visitor(clickedItem, pos, tree, idx.row());
aron::type::visit(visitor, clickedItem->aronType);
visitor.showMenuAndExecute();
}
tree->blockSignals(false);
}
void
AronTreeWidgetController::onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column)
{
if (!item)
{
return;
}
tree->blockSignals(true);
auto* aronItem = AronTreeWidgetItem::DynamicCast(item);
if (column == 1 && aronItem)
{
std::string name =
aronItem->text(aron_tree_widget::constantes::TREE_WIDGET_ITEM_NAME).toStdString();
// depending on aron type, create extra gui element.
AronTreeWidgetModalCreatorVisitor v(name, aronItem, tree);
aron::type::visit(v, aronItem->aronType);
auto modal = v.createdModal;
// if no modal is created, we instead use the edit field directly
if (modal)
{
modal->exec();
}
else if (aronItem->col1Editable)
{
item->treeWidget()->editItem(item, column);
}
}
else if (column == 0 && aronItem && aronItem->col0Editable)
{
item->treeWidget()->editItem(item, column);
}
tree->blockSignals(false);
}
void
AronTreeWidgetController::onTreeWidgetItemChanged(QTreeWidgetItem* item, int column)
{
tree->blockSignals(true);
auto* aronElem = AronTreeWidgetItem::DynamicCast(item);
if (aronElem)
{
aronElem->onUserChange(column);
}
// start conversion for entire tree -- this also sets the highlighting
if (parent->childCount() == 1)
{
auto* aronTreeRoot = AronTreeWidgetItem::DynamicCast(parent->child(0));
aronTreeRoot->resetError();
if (aronTreeRoot)
{
AronTreeWidgetConverterVisitor v(parent, 0);
aron::type::visit(v, type);
aronTreeRoot->setValueErrorState(v.hasDirectError(), v.onlyChildFailedConversion());
}
}
// else perhaps the GUI was stopped or died.
tree->blockSignals(false);
}
} // namespace armarx
#pragma once
#include <stack>
#include <ArmarXCore/core/system/ImportExportComponent.h>
#include "Data.h"
#include <QTreeWidget>
#include <ArmarXCore/core/system/ImportExportComponent.h>
#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXComponentWidgetController.h>
#include <ArmarXGui/libraries/ArmarXGuiBase/ArmarXGuiPlugin.h>
#include <QTreeWidget>
#include "visitors/AronTreeWidgetCreator.h"
#include "AronTreeWidgetItem.h"
#include "Data.h"
#include "visitors/AronTreeWidgetCreator.h"
namespace armarx
{
class AronTreeWidgetController
// Main controller for any AronTreeWidget GUI. It attaches itself to the parent and needs the active widget.
// It's responsible to handle all signals for non-widget fields and click events.
class AronTreeWidgetController : public QObject
{
Q_OBJECT
public:
AronTreeWidgetController(QTreeWidget* tree, QTreeWidgetItem* parent, const aron::type::ObjectPtr& type, const aron::data::DictPtr& data = nullptr);
AronTreeWidgetController(QTreeWidget* tree,
QTreeWidgetItem* parent,
const aron::type::ObjectPtr& type,
const aron::data::DictPtr& data = nullptr);
aron::data::DictPtr convertToAron() const;
void setFromAron(const aron::data::DictPtr&);
......@@ -28,7 +34,19 @@ namespace armarx
QTreeWidget* tree;
aron::type::ObjectPtr type;
private slots:
// allows most primitive fields to be directly editable in the tree
// only String will open up a new widget
void onTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column);
// check the new user input. Maybe undo if the field must not be edited.
// Also highlight if the input cannot be parsed. (Or the errors are now fixed)
void onTreeWidgetItemChanged(QTreeWidgetItem* item, int column);
public slots:
// hook for items to show a context menu (add / delete element)
void ShowContextMenu(const QPoint&);
};
using AronTreeWidgetControllerPtr = std::shared_ptr<AronTreeWidgetController>;
}
} // namespace armarx
#include "AronTreeWidgetItem.h"
#include <QAction>
#include <QMenu>
#include <RobotAPI/libraries/aron/core/type/variant/All.h>
#include "../ColorPalettes.h"
#include "visitors/AronTreeWidgetConverter.h"
#include "widgets/CustomWidget.h"
namespace armarx
{
AronTreeWidgetItem* AronTreeWidgetItem::DynamicCast(QTreeWidgetItem* i)
AronTreeWidgetItem*
AronTreeWidgetItem::DynamicCast(QTreeWidgetItem* i)
{
return dynamic_cast<AronTreeWidgetItem*>(i);
}
AronTreeWidgetItem* AronTreeWidgetItem::copy()
{
AronTreeWidgetItem* ret = new AronTreeWidgetItem(*this);
return ret;
}
AronTreeWidgetItem* AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem* i)
AronTreeWidgetItem*
AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem* i)
{
if (!i)
{
......@@ -25,4 +28,174 @@ namespace armarx
ARMARX_CHECK_NOT_NULL(c);
return c;
}
}
bool
AronTreeWidgetItem::isValueErrorneous()
{
return itemValueError;
}
void
AronTreeWidgetItem::setValueErrorState(bool isErrorSource, bool isTransitiveError)
{
itemValueError |= isErrorSource;
transitiveValueError |= isTransitiveError;
if (CustomWidget::DynamicCast(treeWidget()->itemWidget(this, 1)))
{
// The widgets handle errors themselves
return;
}
auto palette = gui_color_palette::getNormalPalette();
if (itemValueError)
{
palette = gui_color_palette::getErrorPalette();
}
else if (transitiveValueError)
{
palette = gui_color_palette::getIndirectErrorPalette();
}
QTreeWidgetItem::setBackground(1, QBrush(palette.color(QPalette::Base)));
}
void
AronTreeWidgetItem::setKeyErrorState(bool hasError)
{
ARMARX_CHECK(col0Editable); //only editable keys should call this function!
auto palette =
hasError ? gui_color_palette::getErrorPalette() : gui_color_palette::getNormalPalette();
keyValueError = hasError;
QTreeWidgetItem::setBackground(1, QBrush(palette.color(QPalette::Base)));
}
void
AronTreeWidgetItem::resetError()
{
keyValueError = false;
itemValueError = false;
transitiveValueError = false;
// also reset children
for (int i = 0; i < childCount(); ++i)
{
auto* arChild = AronTreeWidgetItem::DynamicCastAndCheck(QTreeWidgetItem::child(i));
arChild->resetError();
}
}
void
AronTreeWidgetItem::checkKeyValidityOfChildren()
{
ARMARX_CHECK(aronType->getDescriptor() == aron::type::Descriptor::DICT);
// return if check failed
if (aronType->getDescriptor() != aron::type::Descriptor::DICT)
{
return;
}
// iterate through children; memorize keys
std::map<QString, std::vector<int>> found_keys;
auto numChildren = childCount();
for (int i = 0; i < numChildren; ++i)
{
auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i));
if (!casted)
{
// soft error here, we already report it above. - Definetly programming error
continue;
}
auto& vec = found_keys[casted->text(0)];
vec.push_back(i);
}
// highlight keys that conflict
// memorize children that are not ok
std::set<int> errorneous_indices;
for (auto [key, vals] : found_keys)
{
if (vals.size() > 1)
{
for (int i : vals)
{
auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i));
if (!casted)
{
// soft error here, we already report it above. - Definetly programming error
continue;
}
casted->setKeyErrorState(true);
errorneous_indices.emplace(i);
}
}
}
// clear potential error state of other elements
for (int i = 0; i < numChildren; ++i)
{
if (errorneous_indices.find(i) != errorneous_indices.end())
{
continue;
}
auto* casted = AronTreeWidgetItem::DynamicCastAndCheck(child(i));
if (!casted)
{
// soft error here, we already report it above. - Definetly programming error
continue;
}
casted->setKeyErrorState(false);
}
}
void
AronTreeWidgetItem::onUserChange(int changedColumn)
{
QTreeWidgetItem* qParent = QTreeWidgetItem::parent();
ARMARX_CHECK(qParent);
AronTreeWidgetItem* aronParent = DynamicCast(qParent);
if (changedColumn == 0)
{
if (col0Editable)
{
// Topmost should always be an Object and col0 is not editable in the child then...
// -> aronParent should never be nullptr
ARMARX_CHECK(aronParent);
// check if the element is child of a dict. If so, validate uniqueness of keys
if (aronParent->aronType->getDescriptor() == aron::type::Descriptor::DICT)
{
aronParent->checkKeyValidityOfChildren();
}
}
else
{
// maybe while editing keys, we try to edit a key that should not change by tabbing.
// Catch that here and undo the edit
preventIllegalKeyChange();
}
}
}
void
AronTreeWidgetItem::preventIllegalKeyChange()
{
if (!col0Editable)
{
setText(0, unchangeableKey);
}
}
AronTreeWidgetItem::AronTreeWidgetItem(bool editKey,
bool editVal,
QString key,
aron::type::VariantPtr type) :
aronType(type), col0Editable(editKey), col1Editable(editVal)
{
this->setText(0, key);
// add hook to check for edited keys for children of dictionaries
if (!editKey)
{
unchangeableKey = std::move(key);
}
}
} // namespace armarx