/** * @RDE_HEADER@ * * Widget to dynamically show dds::core::xtypes::DynamicData. * * $Id$ * $HeadURL$ * $Author$ */ #include "detailview.h" #include "rw/rwwidgets.h" #include "sequences/tabsequencewidget.h" #include "sequences/listsequencewidget.h" #include #include #include #include #include #include #include #include #include #include #include #include "coorddetaildlg.h" #include "topic_tree_model.h" DetailView::DetailView(QWidget *parent) : QWidget(parent) , m_type(dds::core::xtypes::StructType("Unknown")) , m_readonly(RwMode::ReadWrite) , m_logger(DdsView::getLogger("DetailView")) { } DetailView::~DetailView() { } bool DetailView::init(const dds::core::xtypes::DynamicData &data, const QString &topicName, RwMode rwMode) { // Already initialized or no valid data... if (!init(data.type(), topicName, rwMode)) return false; return setData(data); } bool DetailView::init(const dds::core::xtypes::DynamicType &type, const QString &topicName, RwMode rwMode) { if (type.kind() != dds::core::xtypes::TypeKind::STRUCTURE_TYPE) return false; m_readonly = rwMode; if (m_type == type) return true; clear(); m_type = type; // Data from a specific Topic if (topicName.isEmpty()) m_topicName = QString::fromStdString(type.name()); else m_topicName = topicName; setWindowTitle(m_topicName); return generateUi(m_readonly, m_type, this, QString(), m_logger); } void DetailView::clear() { DEBUG_LOG(m_logger) << "Clear"; while (QWidget *w = findChild()) delete w; delete layout(); m_type = dds::core::xtypes::StructType("Unknown"); m_topicName.clear(); } bool DetailView::generateUi(const RwMode &readOnly, const dds::core::xtypes::DynamicType &type, QWidget *parentWidget, const QString &name, NGL::INGLLogger &logger, QGridLayout *grid) { if (type.kind() != dds::core::xtypes::TypeKind::STRUCTURE_TYPE) return false; const dds::core::xtypes::StructType &structType = static_cast(type); QGridLayout *gl = grid ? grid : new QGridLayout(parentWidget); //DEBUG_LOG(m_logger) << "generateUi(" << structType.name() << ")"; int row = gl->rowCount(); dds::core::xtypes::StructType typeCurrent = structType; bool hasBaseClass = true; while (hasBaseClass) { try { for (const dds::core::xtypes::Member &member : typeCurrent.members()) { QString memberName; if (name.length()) memberName += name + QLatin1Char('.'); memberName += QString::fromStdString(member.name()); QWidget *w = createWidget(readOnly, member.type(), memberName, logger); w->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); if (member.type().kind() == dds::core::xtypes::TypeKind::STRUCTURE_TYPE || // no label for groupboxes (which already contain a label) member.type().kind() == dds::core::xtypes::TypeKind::SEQUENCE_TYPE) gl->addWidget(w, row, 0, 1, 2); else { QLabel *newLabel = new QLabel(QString::fromStdString(member.name())); newLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); gl->addWidget(newLabel, row, 0, 1, 1); gl->addWidget(w, row, 1, 1, 1); } ++row; } if (typeCurrent.has_parent()) typeCurrent = typeCurrent.parent(); else hasBaseClass = false; } catch (const dds::core::Exception &) { // finished } } gl->addItem(new QSpacerItem(20, 4, QSizePolicy::Minimum, QSizePolicy::Expanding), row, 0, 1, 1); return true; } bool DetailView::setWidgetData(const dds::core::xtypes::DynamicData &data, const dds::core::xtypes::TypeKind &typeKind, uint32_t index, const QString &name, const QWidget *useOn, NGL::INGLLogger &logger) { DEBUG_LOG(logger) << "setWidgetData for " << name; if (!data.member_exists(index)) { DEBUG_LOG(logger) << "Member " << name << "is optional and does not exist"; return true; } switch (typeKind.underlying()) //info.member_kind().underlying()) { case dds::core::xtypes::TypeKind::CHAR_8_TYPE: setSpinBoxValue(useOn->findChild(name), data.value(index)); break; #if RTI_DDS_VERSION_MAJOR < 6 case dds::core::xtypes::TypeKind::CHAR_32_TYPE: #else case dds::core::xtypes::TypeKind::CHAR_16_TYPE: #endif setSpinBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::UINT_8_TYPE: setBitfieldValue(useOn->findChild(name),data.value(index)); break; case dds::core::xtypes::TypeKind::INT_16_TYPE: setSpinBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::UINT_16_TYPE: setSpinBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::INT_32_TYPE: setSpinBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::UINT_32_TYPE: setSpinBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::INT_64_TYPE: setSpinBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::UINT_64_TYPE: setSpinBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::FLOAT_32_TYPE: setSpinBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::FLOAT_64_TYPE: setSpinBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::ENUMERATION_TYPE: setComboBoxValue(useOn->findChild(name), data.value(index)); break; case dds::core::xtypes::TypeKind::BOOLEAN_TYPE: { RWCheckBox *w = useOn->findChild(name); if (!w) { WARNING_LOG(logger) << "setData: (BOOLEAN_TYPE) - can not find checkbox with name " << name; break; } DDS_Boolean val = data.value(index); w->setChecked(val); break; } case dds::core::xtypes::TypeKind::STRING_TYPE: { RWLineEdit *w = useOn->findChild(name); if (!w) { WARNING_LOG(logger) << "setData: (BOOLEAN_TYPE) - can not find lineedit with name " << name; break; } const dds::core::string tmp = data.value(index); if (tmp.c_str()) // unset -> nullptr w->setText(QString::fromUtf8(tmp.c_str())); break; } case dds::core::xtypes::TypeKind::STRUCTURE_TYPE: { if (!useOn->findChild(name)) { WARNING_LOG(logger) << "setData: (STRUCTURE_TYPE) - can not find groupbox/widget with name " << name; break; } const dds::core::xtypes::DynamicData inner = data.value(index); const dds::core::xtypes::StructType &innerType = static_cast(inner.type()); dds::core::xtypes::StructType innerTypeCopy = innerType; for (uint32_t inner_index = 1; inner_index <= inner.member_count(); ++inner_index) { const dds::core::xtypes::Member &member = TopicDataModel::memberFromType(innerType, innerTypeCopy, inner_index - 1); QString memberName; if (name.length()) memberName += name + QLatin1Char('.'); memberName += QString::fromStdString(member.name()); setWidgetData(inner, member.type().kind(), inner_index, memberName, useOn, logger); } break; } case dds::core::xtypes::TypeKind::SEQUENCE_TYPE: { AbstractSequenceWidget *seq = useOn->findChild(name); if (!seq) { WARNING_LOG(logger) << "setData: (SEQUENCE_TYPE) - can not find primitive sequence with name " << name; QLabel *lab = useOn->findChild(QLatin1String("LabelMcLabFace")); if (!lab) break; lab->setText(tr("Pssst. I can at least tell you,\nthere are %1 elements in that sequence!").arg(data.value(index).member_count())); break; } const dds::core::xtypes::DynamicData inner = data.value(index); seq->setMemberCount(inner.member_count()); for (uint32_t inner_index = 1; inner_index <= inner.member_count(); ++inner_index) seq->setValue(inner, inner_index, useOn); // DAS MUSS PRIMITIVE SEQUENCE SELBER AUFRUFEN - METHODE MUSS ALSO VON KLASSE GETRENNT WERDEN: setWidgetData(inner, seqType.kind(), inner_index, name + QLatin1String(".") + QString::number(inner_index)); break; } default: { WARNING_LOG(logger) << "setData: (" << QString::number(data.type_kind().underlying(), 16) << ") - no handler!"; return false; } } return true; } bool DetailView::setData(const dds::core::xtypes::DynamicData &data, const QString &name) { DEBUG_LOG(m_logger) << "setData for " << name; // Not initialized or no valid data... <= heisst ? if (m_type.kind() != dds::core::xtypes::TypeKind::STRUCTURE_TYPE) return false; for (uint32_t member_index = 1; member_index <= data.member_count(); ++member_index) { if (!data.member_exists(member_index)) { DEBUG_LOG(m_logger) << "member " << name << "." << member_index << " does not exist - optional."; continue; } const rti::core::xtypes::DynamicDataMemberInfo info = data.member_info(member_index); QString memberName; if (name.length()) memberName += name + QLatin1Char('.'); memberName += QString::fromStdString(info.member_name()); setWidgetData(data, info.member_kind(), member_index, memberName, this, m_logger); } return true; } template void DetailView::getSpinBoxValue(const QString &name, dds::core::xtypes::DynamicData &data, uint32_t member_index, const QWidget *useOn, NGL::INGLLogger &logger) { S *w = useOn->findChild(name); if (!w) { WARNING_LOG(logger) << "DetailView::getSpinBoxValue: Could not find widget with name '" << name << "'"; return; } const T val = w->value(); data.value(member_index, val); } void DetailView::getComboBoxValue(const QString &name, dds::core::xtypes::DynamicData &data, uint32_t member_index, const QWidget *useOn, NGL::INGLLogger &logger) { RWComboBox *w = useOn->findChild(name); if (!w) { WARNING_LOG(logger) << "DetailView::getComboBoxValue: Could not find widget with name '" << name << "'"; return; } int32_t val = w->currentValue(); data.value(member_index, val); } template void DetailView::getBitfieldValue(const QString &name, dds::core::xtypes::DynamicData &data, uint32_t member_index, const QWidget *useOn, NGL::INGLLogger &logger) { B *w = useOn->findChild(name); if (!w) { WARNING_LOG(logger) << "DetailView::getBitfieldValue: Could not find widget with name '" << name << "'"; return; } const T val = w->value(); data.value(member_index, val); } void DetailView::getWidgetData(dds::core::xtypes::DynamicData &data, const dds::core::xtypes::TypeKind &typeKind, uint32_t index, const QString &name, const QWidget *useOn, NGL::INGLLogger &logger) { switch (typeKind.underlying()) { case dds::core::xtypes::TypeKind::CHAR_8_TYPE: getSpinBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::UINT_8_TYPE: getBitfieldValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::INT_16_TYPE: getSpinBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::UINT_16_TYPE: getSpinBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::INT_32_TYPE: getSpinBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::UINT_32_TYPE: getSpinBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::INT_64_TYPE: getSpinBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::UINT_64_TYPE: getSpinBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::FLOAT_32_TYPE: getSpinBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::FLOAT_64_TYPE: getSpinBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::ENUMERATION_TYPE: getComboBoxValue(name, data, index, useOn, logger); break; case dds::core::xtypes::TypeKind::BOOLEAN_TYPE: { RWCheckBox *w = useOn->findChild(name); if (!w) { WARNING_LOG(logger) << "getData: (BOOLEAN_TYPE) - can not find checkbox with name " << name; break; } data.value(index, w->isChecked()); break; } case dds::core::xtypes::TypeKind::STRING_TYPE: { RWLineEdit *w = useOn->findChild(name); if (!w) { WARNING_LOG(logger) << "getData: (STRING_TYPE) - can not find lineedit with name " << name; break; } data.value(index, w->text().toStdString()); break; } case dds::core::xtypes::TypeKind::STRUCTURE_TYPE: // top level is always structure type ! <-- ...but top level wont get called here -jh { rti::core::xtypes::LoanedDynamicData innerLoaned = data.loan_value(index); dds::core::xtypes::DynamicData &inner = innerLoaned.get(); const dds::core::xtypes::StructType &innerType = static_cast(inner.type()); dds::core::xtypes::StructType innerTypeCopy = innerType; for(uint32_t member_index = 1; member_index <= inner.member_count(); ++member_index) { const dds::core::xtypes::Member &member = TopicDataModel::memberFromType(innerType, innerTypeCopy, member_index -1); QString findObjectName = name + QLatin1Char('.') + QString::fromStdString(member.name()); DEBUG_LOG(logger) << "structure " << findObjectName; getWidgetData(inner, member.type().kind(), member_index, findObjectName, useOn, logger); } break; } case dds::core::xtypes::TypeKind::SEQUENCE_TYPE: { AbstractSequenceWidget *seq = useOn->findChild(name); if (!seq) { WARNING_LOG(logger) << "getData: (SEQUENCE_TYPE) - can not find primitive sequence with name " << name; break; } rti::core::xtypes::LoanedDynamicData innerLoaned = data.loan_value(index); dds::core::xtypes::DynamicData &inner = innerLoaned.get(); for (uint32_t member_index = 1; member_index <= seq->getMemberCount(); ++member_index) { seq->getValue(name, inner, member_index, useOn); } break; } default: { WARNING_LOG(logger) << "getData: (" << QString::number(data.type_kind().underlying(), 16) << ") - no handler!"; break; } } } QSharedPointer DetailView::getData() const { QSharedPointer data(new dds::core::xtypes::DynamicData(m_type)); // data[n] runs from 1..count()! const dds::core::xtypes::StructType &innerType = static_cast(data->type()); dds::core::xtypes::StructType innerTypeCopy = innerType; for (uint32_t member_index = 1; member_index <= data->member_count(); ++member_index) { const dds::core::xtypes::Member &member = TopicDataModel::memberFromType(innerType, innerTypeCopy, member_index - 1); getWidgetData(*data, member.type().kind(), member_index, QString::fromStdString(member.name()), this, m_logger); } return data; } template void DetailView::setSpinBoxValue(S *b, const T &value) { Q_ASSERT(b); if (!b) return; b->setMinimum(std::numeric_limits::lowest()); b->setMaximum(std::numeric_limits::max()); b->setValue(value); } void DetailView::setComboBoxValue(RWComboBox *w, int ordinal) { Q_ASSERT(w); if (!w) return; w->setCurrentValue(ordinal); } template void DetailView::setBitfieldValue(B *b, const T &value) { Q_ASSERT(b); if (!b) return; b->setValue(value); } static QWidget *createSpinBox(const RwMode &readOnly, QWidget *parent, int min, int max) { RWSpinBox *w = new RWSpinBox(readOnly, parent); w->setMinimum(min); w->setMaximum(max); return w; } static QWidget *createDoubleSpinBox(const RwMode &readOnly, QWidget *parent, double min, double max, int prec) { RWDoubleSpinBox *w = new RWDoubleSpinBox(readOnly, parent); w->setMinimum(min); w->setMaximum(max); w->setDecimals(prec); return w; } QWidget *DetailView::createWidget(const RwMode &readOnly, const dds::core::xtypes::DynamicType &type, const QString &name, NGL::INGLLogger &logger) { QWidget *parent = nullptr; // TODO: remove parent var QWidget *g = nullptr; bool noNaming = false; switch (type.kind().underlying()) { case dds::core::xtypes::TypeKind::UINT_8_TYPE: g = new RWBitfieldWidget(readOnly,parent); break; case dds::core::xtypes::TypeKind::INT_16_TYPE: g = createSpinBox(readOnly, parent, std::numeric_limits::lowest(), std::numeric_limits::max()); break; case dds::core::xtypes::TypeKind::UINT_16_TYPE: g = createSpinBox(readOnly, parent, std::numeric_limits::lowest(), std::numeric_limits::max()); break; case dds::core::xtypes::TypeKind::INT_32_TYPE: g = createSpinBox(readOnly, parent, std::numeric_limits::lowest(), std::numeric_limits::max()); break; case dds::core::xtypes::TypeKind::UINT_32_TYPE: g = createDoubleSpinBox(readOnly, parent, std::numeric_limits::lowest(), std::numeric_limits::max(), 0); break; case dds::core::xtypes::TypeKind::UINT_64_TYPE: g = createDoubleSpinBox(readOnly, parent, std::numeric_limits::lowest(), std::numeric_limits::max(), 0); break; case dds::core::xtypes::TypeKind::INT_64_TYPE: g = createDoubleSpinBox(readOnly, parent, std::numeric_limits::lowest(), std::numeric_limits::max(), 0); break; case dds::core::xtypes::TypeKind::FLOAT_32_TYPE: g = createDoubleSpinBox(readOnly, parent, std::numeric_limits::lowest(), std::numeric_limits::max(), 6); break; case dds::core::xtypes::TypeKind::FLOAT_64_TYPE: g = createDoubleSpinBox(readOnly, parent, std::numeric_limits::lowest(), std::numeric_limits::max(), 13); break; case dds::core::xtypes::TypeKind::BOOLEAN_TYPE: g = new RWCheckBox(readOnly, parent); break; case dds::core::xtypes::TypeKind::ENUMERATION_TYPE: { const dds::core::xtypes::EnumType &enumType = static_cast(type); RWComboBox *w = new RWComboBox(readOnly, parent); for (const dds::core::xtypes::EnumMember &enumMember : enumType.members()) w->addItem(QString::fromStdString(enumMember.name()), enumMember.ordinal()); g = w; break; } case dds::core::xtypes::TypeKind::CHAR_8_TYPE: g = createSpinBox(readOnly, parent, std::numeric_limits::lowest(), std::numeric_limits::max()); break; case dds::core::xtypes::TypeKind::STRING_TYPE: { const dds::core::xtypes::StringType &stringType = static_cast(type); RWLineEdit *w = new RWLineEdit(readOnly, parent); w->setMaxLength(stringType.bounds()); g = w; break; } case dds::core::xtypes::TypeKind::STRUCTURE_TYPE: { //noNaming = true; g = name.contains(QRegExp(QLatin1String(".([0-9]*)$"))) ? new QWidget(parent) : new QGroupBox(name, parent); QGridLayout *gl = new QGridLayout(g); if (type.name() == "Core::GeoPosition" || type.name() == "Core::GeoPosition2D") { QPushButton *mgrsBtn = new QPushButton(tr("MGRS"), g); mgrsBtn->setObjectName(name); mgrsBtn->setProperty("memberName", name); QLabel *mgrsLabel = new QLabel(g); mgrsLabel->setObjectName(name); mgrsLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); CoordDetailDlg *coordDlg = new CoordDetailDlg(mgrsBtn); auto cbAccepted = [g, coordDlg, mgrsBtn]() { const QPointF p = coordDlg->coordinate(); const QString name = mgrsBtn->objectName(); RWDoubleSpinBox *sbLon = g->findChild(name + QLatin1String(".lon")); RWDoubleSpinBox *sbLat = g->findChild(name + QLatin1String(".lat")); if (sbLon) sbLon->setValue(p.x()); if (sbLat) sbLat->setValue(p.y()); }; connect(coordDlg, &CoordDetailDlg::accepted, mgrsBtn, cbAccepted); auto cbClicked = [g, mgrsBtn, coordDlg]() { const QString name = mgrsBtn->objectName(); RWDoubleSpinBox *sbLon = g->findChild(name + QLatin1String(".lon")); RWDoubleSpinBox *sbLat = g->findChild(name + QLatin1String(".lat")); if (sbLon && sbLat) coordDlg->setValues(sbLon->value(), sbLat->value()); coordDlg->exec(); }; connect(mgrsBtn, &QPushButton::clicked, g, cbClicked); gl->addWidget(mgrsBtn, 0, 0, 1, -1, Qt::AlignLeft); gl->addWidget(mgrsLabel, 0, 1, 1, -1); generateUi(readOnly, type, g, name, logger, gl); RWDoubleSpinBox *sbLon = g->findChild(name + QLatin1String(".lon")); RWDoubleSpinBox *sbLat = g->findChild(name + QLatin1String(".lat")); if (sbLon && sbLat) { auto cbUpdateLabel = [sbLon, sbLat, mgrsLabel]() { mgrsLabel->setText(LtsCoordTrans::mgrsFromGeographic(sbLon->value(), sbLat->value(), 7)); }; connect(sbLon, &RWDoubleSpinBox::valueChanged, mgrsLabel, cbUpdateLabel); connect(sbLat, &RWDoubleSpinBox::valueChanged, mgrsLabel, cbUpdateLabel); } } else generateUi(readOnly, type, g, name, logger, gl); break; } case dds::core::xtypes::TypeKind::SEQUENCE_TYPE: { const dds::core::xtypes::SequenceType &seqType = static_cast(type); AbstractSequenceWidget *seq; if(dds::core::xtypes::is_primitive_type(seqType.content_type())) seq = new ListSequenceWidget(readOnly, name, seqType.content_type(), logger, parent); else seq = new TabSequenceWidget(readOnly, name, seqType.content_type(), logger, parent); g = seq; break; } default: { break; } } if (g && !noNaming) g->setObjectName(name); DEBUG_LOG(logger) << "createWidget: new widget name: " << name; return g; } QWidget *DetailView::getWidget(const dds::core::xtypes::DynamicType &type, const QString &name) { QWidget *g = createWidget(m_readonly, type, name, m_logger); if (!g) { QMap unmappedKinds; // when one of these types gets implemented, it should be removed from this map unmappedKinds.insert(dds::core::xtypes::TypeKind::NO_TYPE, QLatin1String("NO_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::PRIMITIVE_TYPE, QLatin1String("PRIMITIVE_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::CONSTRUCTED_TYPE, QLatin1String("CONSTRUCTED_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::COLLECTION_TYPE, QLatin1String("COLLECTION_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::AGGREGATION_TYPE, QLatin1String("AGGREGATION_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::ANNOTATION_TYPE, QLatin1String("ANNOTATION_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::UINT_8_TYPE, QLatin1String("UINT_8_TYPE")); #if RTI_DDS_VERSION_MAJOR < 6 unmappedKinds.insert(dds::core::xtypes::TypeKind::CHAR_32_TYPE, QLatin1String("CHAR_32_TYPE")); #else unmappedKinds.insert(dds::core::xtypes::TypeKind::CHAR_16_TYPE, QLatin1String("CHAR_16_TYPE")); #endif unmappedKinds.insert(dds::core::xtypes::TypeKind::BITSET_TYPE, QLatin1String("BITSET_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::ALIAS_TYPE, QLatin1String("ALIAS_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::ARRAY_TYPE, QLatin1String("ARRAY_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::SEQUENCE_TYPE, QLatin1String("SEQUENCE_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::WSTRING_TYPE, QLatin1String("WSTRING_TYPE")); // misusing QT_VERSION_CHECK macro :) #if QT_VERSION_CHECK(RTI_DDS_VERSION_MAJOR, RTI_DDS_VERSION_MINOR, RTI_DDS_VERSION_RELEASE) <= QT_VERSION_CHECK(6, 0, 0) unmappedKinds.insert(dds::core::xtypes::TypeKind::MAP_TYPE, QLatin1String("MAP_TYPE")); #else unmappedKinds.insert(dds::core::xtypes::TypeKind::MAP_TYPE_OMG, QLatin1String("MAP_TYPE")); #endif unmappedKinds.insert(dds::core::xtypes::TypeKind::UNION_TYPE, QLatin1String("UNION_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::UNION_FWD_DECL_TYPE, QLatin1String("UNION_FWD_DECL_TYPE")); unmappedKinds.insert(dds::core::xtypes::TypeKind::STRUCTURE_FWD_DECL_TYPE, QLatin1String("STRUCTURE_FWD_DECL_TYPE")); QString kind; if (unmappedKinds.contains(type.kind().underlying())) kind = unmappedKinds.value(type.kind().underlying()); else kind = QLatin1String("unknown kind"); //FATAL_LOG(m_logger) << "TypeKind not mapped: " << kind; return nullptr; } RWWidget *w = qobject_cast(g); if (w) connect(w, &RWWidget::writableRequested, this, &DetailView::onWritableRequested); return g; } void DetailView::onWritableRequested() { const auto children = findChildren(); for (QWidget *child : children) { RWWidget *w = qobject_cast(child); if (w) w->onSetWritable(); } }