785 lines
27 KiB
C++
Executable File
785 lines
27 KiB
C++
Executable File
/**
|
|
* @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 <QGridLayout>
|
|
#include <QGroupBox>
|
|
#include <QtCore/QMap>
|
|
#include <QHBoxLayout>
|
|
#include <QTabWidget>
|
|
#include <QPushButton>
|
|
#include <QMouseEvent>
|
|
|
|
#include <limits>
|
|
#include <functional>
|
|
|
|
#include <QMessageBox>
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
|
|
#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<QWidget *>())
|
|
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<const dds::core::xtypes::StructType &>(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<RWSpinBox *>(name), data.value<char>(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<RWSpinBox *>(name), data.value<DDS_Wchar>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_8_TYPE:
|
|
setBitfieldValue(useOn->findChild<RWBitfieldWidget*>(name),data.value<uint8_t>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::INT_16_TYPE:
|
|
setSpinBoxValue(useOn->findChild<RWSpinBox *>(name), data.value<int16_t>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_16_TYPE:
|
|
setSpinBoxValue(useOn->findChild<RWSpinBox *>(name), data.value<uint16_t>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::INT_32_TYPE:
|
|
setSpinBoxValue(useOn->findChild<RWSpinBox *>(name), data.value<int32_t>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_32_TYPE:
|
|
setSpinBoxValue(useOn->findChild<RWDoubleSpinBox *>(name), data.value<uint32_t>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::INT_64_TYPE:
|
|
setSpinBoxValue(useOn->findChild<RWDoubleSpinBox *>(name), data.value<int64_t>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_64_TYPE:
|
|
setSpinBoxValue(useOn->findChild<RWDoubleSpinBox *>(name), data.value<uint64_t>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::FLOAT_32_TYPE:
|
|
setSpinBoxValue(useOn->findChild<RWDoubleSpinBox *>(name), data.value<float>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::FLOAT_64_TYPE:
|
|
setSpinBoxValue(useOn->findChild<RWDoubleSpinBox *>(name), data.value<double>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::ENUMERATION_TYPE:
|
|
setComboBoxValue(useOn->findChild<RWComboBox *>(name), data.value<int32_t>(index));
|
|
break;
|
|
case dds::core::xtypes::TypeKind::BOOLEAN_TYPE:
|
|
{
|
|
RWCheckBox *w = useOn->findChild<RWCheckBox *>(name);
|
|
if (!w)
|
|
{
|
|
WARNING_LOG(logger) << "setData: (BOOLEAN_TYPE) - can not find checkbox with name " << name;
|
|
break;
|
|
}
|
|
|
|
DDS_Boolean val = data.value<bool>(index);
|
|
w->setChecked(val);
|
|
break;
|
|
}
|
|
case dds::core::xtypes::TypeKind::STRING_TYPE:
|
|
{
|
|
RWLineEdit *w = useOn->findChild<RWLineEdit *>(name);
|
|
if (!w)
|
|
{
|
|
WARNING_LOG(logger) << "setData: (BOOLEAN_TYPE) - can not find lineedit with name " << name;
|
|
break;
|
|
}
|
|
|
|
const dds::core::string tmp = data.value<dds::core::string>(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<QWidget *>(name))
|
|
{
|
|
WARNING_LOG(logger) << "setData: (STRUCTURE_TYPE) - can not find groupbox/widget with name " << name;
|
|
break;
|
|
}
|
|
|
|
const dds::core::xtypes::DynamicData inner = data.value<dds::core::xtypes::DynamicData>(index);
|
|
const dds::core::xtypes::StructType &innerType = static_cast<const dds::core::xtypes::StructType &>(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<AbstractSequenceWidget*>(name);
|
|
if (!seq)
|
|
{
|
|
WARNING_LOG(logger) << "setData: (SEQUENCE_TYPE) - can not find primitive sequence with name " << name;
|
|
QLabel *lab = useOn->findChild<QLabel *>(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<dds::core::xtypes::DynamicData>(index).member_count()));
|
|
break;
|
|
}
|
|
|
|
const dds::core::xtypes::DynamicData inner = data.value<dds::core::xtypes::DynamicData>(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 <typename T, typename S>
|
|
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<S *>(name);
|
|
|
|
if (!w)
|
|
{
|
|
WARNING_LOG(logger) << "DetailView::getSpinBoxValue: Could not find widget with name '"
|
|
<< name << "'";
|
|
return;
|
|
}
|
|
|
|
const T val = w->value();
|
|
data.value<T>(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<RWComboBox *>(name);
|
|
|
|
if (!w)
|
|
{
|
|
WARNING_LOG(logger) << "DetailView::getComboBoxValue: Could not find widget with name '"
|
|
<< name << "'";
|
|
return;
|
|
}
|
|
|
|
int32_t val = w->currentValue();
|
|
|
|
data.value<int32_t>(member_index, val);
|
|
}
|
|
|
|
template <typename T, typename B>
|
|
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<B *>(name);
|
|
|
|
if (!w)
|
|
{
|
|
WARNING_LOG(logger) << "DetailView::getBitfieldValue: Could not find widget with name '"
|
|
<< name << "'";
|
|
return;
|
|
}
|
|
|
|
const T val = w->value();
|
|
data.value<T>(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<char, RWSpinBox>(name, data, index, useOn, logger);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_8_TYPE:
|
|
getBitfieldValue<uint8_t, RWBitfieldWidget>(name, data, index, useOn, logger);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::INT_16_TYPE:
|
|
getSpinBoxValue<int16_t, RWSpinBox>(name, data, index, useOn, logger);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_16_TYPE:
|
|
getSpinBoxValue<uint16_t, RWSpinBox>(name, data, index, useOn, logger);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::INT_32_TYPE:
|
|
getSpinBoxValue<int32_t, RWSpinBox>(name, data, index, useOn, logger);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_32_TYPE:
|
|
getSpinBoxValue<uint32_t, RWDoubleSpinBox>(name, data, index, useOn, logger);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::INT_64_TYPE:
|
|
getSpinBoxValue<int64_t, RWDoubleSpinBox>(name, data, index, useOn, logger);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_64_TYPE:
|
|
getSpinBoxValue<uint64_t, RWDoubleSpinBox>(name, data, index, useOn, logger);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::FLOAT_32_TYPE:
|
|
getSpinBoxValue<float, RWDoubleSpinBox>(name, data, index, useOn, logger);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::FLOAT_64_TYPE:
|
|
getSpinBoxValue<double, RWDoubleSpinBox>(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<RWCheckBox *>(name);
|
|
if (!w)
|
|
{
|
|
WARNING_LOG(logger) << "getData: (BOOLEAN_TYPE) - can not find checkbox with name " << name;
|
|
break;
|
|
}
|
|
|
|
data.value<bool>(index, w->isChecked());
|
|
break;
|
|
}
|
|
case dds::core::xtypes::TypeKind::STRING_TYPE:
|
|
{
|
|
RWLineEdit *w = useOn->findChild<RWLineEdit *>(name);
|
|
if (!w)
|
|
{
|
|
WARNING_LOG(logger) << "getData: (STRING_TYPE) - can not find lineedit with name " << name;
|
|
break;
|
|
}
|
|
|
|
data.value<std::string>(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<const dds::core::xtypes::StructType &>(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<AbstractSequenceWidget*>(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<dds::core::xtypes::DynamicData> DetailView::getData() const
|
|
{
|
|
QSharedPointer<dds::core::xtypes::DynamicData> data(new dds::core::xtypes::DynamicData(m_type));
|
|
|
|
// data[n] runs from 1..count()!
|
|
const dds::core::xtypes::StructType &innerType = static_cast<const dds::core::xtypes::StructType &>(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 <typename T, typename S>
|
|
void DetailView::setSpinBoxValue(S *b, const T &value)
|
|
{
|
|
Q_ASSERT(b);
|
|
if (!b)
|
|
return;
|
|
|
|
b->setMinimum(std::numeric_limits<T>::lowest());
|
|
b->setMaximum(std::numeric_limits<T>::max());
|
|
b->setValue(value);
|
|
}
|
|
|
|
|
|
void DetailView::setComboBoxValue(RWComboBox *w, int ordinal)
|
|
{
|
|
Q_ASSERT(w);
|
|
if (!w)
|
|
return;
|
|
|
|
w->setCurrentValue(ordinal);
|
|
}
|
|
|
|
template <typename T, typename B>
|
|
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<short>::lowest(), std::numeric_limits<short>::max());
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_16_TYPE:
|
|
g = createSpinBox(readOnly, parent, std::numeric_limits<unsigned short>::lowest(), std::numeric_limits<unsigned short>::max());
|
|
break;
|
|
case dds::core::xtypes::TypeKind::INT_32_TYPE:
|
|
g = createSpinBox(readOnly, parent, std::numeric_limits<int>::lowest(), std::numeric_limits<int>::max());
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_32_TYPE:
|
|
g = createDoubleSpinBox(readOnly, parent, std::numeric_limits<quint32>::lowest(), std::numeric_limits<quint32>::max(), 0);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::UINT_64_TYPE:
|
|
g = createDoubleSpinBox(readOnly, parent, std::numeric_limits<quint64>::lowest(), std::numeric_limits<quint64>::max(), 0);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::INT_64_TYPE:
|
|
g = createDoubleSpinBox(readOnly, parent, std::numeric_limits<qint64>::lowest(), std::numeric_limits<qint64>::max(), 0);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::FLOAT_32_TYPE:
|
|
g = createDoubleSpinBox(readOnly, parent, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max(), 6);
|
|
break;
|
|
case dds::core::xtypes::TypeKind::FLOAT_64_TYPE:
|
|
g = createDoubleSpinBox(readOnly, parent, std::numeric_limits<double>::lowest(), std::numeric_limits<double>::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<const dds::core::xtypes::EnumType &>(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<char>::lowest(), std::numeric_limits<char>::max());
|
|
break;
|
|
case dds::core::xtypes::TypeKind::STRING_TYPE:
|
|
{
|
|
const dds::core::xtypes::StringType &stringType = static_cast<const dds::core::xtypes::StringType &>(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<RWDoubleSpinBox *>(name + QLatin1String(".lon"));
|
|
RWDoubleSpinBox *sbLat = g->findChild<RWDoubleSpinBox *>(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<RWDoubleSpinBox *>(name + QLatin1String(".lon"));
|
|
RWDoubleSpinBox *sbLat = g->findChild<RWDoubleSpinBox *>(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<RWDoubleSpinBox *>(name + QLatin1String(".lon"));
|
|
RWDoubleSpinBox *sbLat = g->findChild<RWDoubleSpinBox *>(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<const dds::core::xtypes::SequenceType &>(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<dds::core::xtypes::TypeKind, QString> 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<RWWidget *>(g);
|
|
if (w)
|
|
connect(w, &RWWidget::writableRequested, this, &DetailView::onWritableRequested);
|
|
|
|
return g;
|
|
}
|
|
|
|
void DetailView::onWritableRequested()
|
|
{
|
|
const auto children = findChildren<QWidget *>();
|
|
for (QWidget *child : children)
|
|
{
|
|
RWWidget *w = qobject_cast<RWWidget *>(child);
|
|
if (w)
|
|
w->onSetWritable();
|
|
}
|
|
}
|