Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+103
View File
@@ -0,0 +1,103 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-05-30
#
ADD_SUBDIRECTORY(Data)
ADD_SUBDIRECTORY(Gui) #TODO: mit patric sprechen!
#
# SAAB import Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(PpmSaabImportGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_saab_import_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/..
GuiPluginInterface
)
#
# MSDL Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(PpmMSDLGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_msdl_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/..
GuiPluginInterface
)
#
# Player Info Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(PpmParticipantInfoGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_participant_info_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/..
GuiPluginInterface
)
#
# Template Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(PpmGuiTemplatesPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_templates_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
GuiPluginInterface
)
#
# Types Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(PpmGuiTypesPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_types_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
GuiPluginInterface
)
#
# Party Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(PpmGuiPartyPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_party_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
GuiPluginInterface
)
#
# Participant Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(PpmGuiParticipantsPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_participants_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
GuiPluginInterface
)
#
# Combobox Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(PpmGuiComboboxPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_gui_combobox_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
GuiPluginInterface
svcPpmCommon
)
#
# Data Plugin Interface
#
ADD_INTERFACE_LIBRARY(PpmDataPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_data_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
DataPluginInterface
svcPpmCommon
)
IF(${Qt5WebEngineWidgets_VERSION} VERSION_GREATER 5.7.9)
#
# Combat Power Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(
PpmGuiOrgChartPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ppm_org_chart_gui_plugin.h
${CMAKE_CURRENT_SOURCE_DIR}/../../
)
ENDIF()
+19
View File
@@ -0,0 +1,19 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-09-06
#
#
# Data Plugin
#
NGL_ADD_LIBRARY(WS PpmDataPlugin MODULE ppm_data_plugin.cpp ppm_data_plugin.h)
NGL_TARGET_LINK_LIBRARIES(PpmDataPlugin
Qt5::Core
PpmDataPluginInterface
svcPpmClient
NGLLogger
LtsSessionDataDds
)
NGL_INSTALL_TARGET(PpmDataPlugin)
+34
View File
@@ -0,0 +1,34 @@
/**
* @RDE_HEADER@
* Data Plugin for ParticipantManagement
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-05-30
*/
#include "ppm_data_plugin.h"
#include <ParticipantManagement/logger.h>
#include <LtsSession/lts_session_data_dds.h>
namespace ParticipantManagement
{
std::shared_ptr<DataPluginBase::Interface> DataPlugin::createDataInterface(LtsSession::LtsSessionDataDds *session)
{
std::shared_ptr<ParticipantManagement::Interface::Dtc> dtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> ftc;
if (!session->createTopicClient(dtc, ftc))
return std::shared_ptr<DataPluginBase::Interface>();
return std::make_shared<DataInterfaceImpl>(dtc, ftc);
}
DataInterfaceImpl::DataInterfaceImpl(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc)
: DataInterface()
, m_dtc(dtc)
, m_ftc(ftc)
{}
} // namespace ParticipantManagement
+53
View File
@@ -0,0 +1,53 @@
/**
* @RDE_HEADER@
* Data Plugin for ParticipantManagement
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-05-30
*/
#pragma once
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
namespace ParticipantManagement
{
class DataPlugin final : public QObject, public DataPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "data:3:ppm")
Q_INTERFACES(DataPluginBase::Plugin)
Q_OBJECT
public:
DataPlugin() = default;
~DataPlugin() = default;
QString pluginName() const override { return QStringLiteral("ParticipantManagement"); }
std::shared_ptr<DataPluginBase::Interface> createDataInterface(LtsSession::LtsSessionDataDds *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return partition == IDL::PartitionType::Exercise ||
partition == IDL::PartitionType::Replay ||
partition == IDL::PartitionType::Global;
}
};
class DataInterfaceImpl final : public DataInterface
{
public:
explicit DataInterfaceImpl(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc);
std::shared_ptr<ParticipantManagement::Interface::Dtc> getDtc() override { return m_dtc; }
std::shared_ptr<ParticipantManagement::Interface::Ftc> getFtc() override { return m_ftc; }
private:
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ftc;
};
} // namespace ParticipantManagement
+20
View File
@@ -0,0 +1,20 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-03-30
#
ADD_SUBDIRECTORY(Common)
ADD_SUBDIRECTORY(MSDL)
ADD_SUBDIRECTORY(ParticipantEdit)
ADD_SUBDIRECTORY(ParticipantInfo)
ADD_SUBDIRECTORY(OperationalPlanning)
ADD_SUBDIRECTORY(ParticipantOrgChart)
ADD_SUBDIRECTORY(ParticipantSelection)
ADD_SUBDIRECTORY(ParticipantTemplates)
ADD_SUBDIRECTORY(PartyEdit)
ADD_SUBDIRECTORY(PpmComboBox)
ADD_SUBDIRECTORY(Saab)
ADD_SUBDIRECTORY(TypeEdit)
ADD_SUBDIRECTORY(Uas)
@@ -0,0 +1,75 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-09-06
#
#
# Data Plugin
#
SET(participant_common_gui_SRCS
participant_dis_helper.cpp
participant_dis_helper.h
participant_dis_type_edit.cpp
participant_dis_type_edit.h
participant_distype_editor.cpp
participant_distype_editor.h
participant_edit_item.cpp
participant_edit_item.h
participant_edit_item_widget_base.cpp
participant_edit_item_widget_base.h
participant_edit_model.cpp
participant_edit_model.h
participant_firing_unit_validator.cpp
participant_firing_unit_validator.h
participant_icon_model_base.cpp
participant_icon_model_base.h
participant_search_modal.cpp
participant_search_modal.h
participant_time_point_model.cpp
participant_time_point_model.h
participant_template_edit_item.cpp
participant_template_edit_item.h
participant_template_edit_model.cpp
participant_template_edit_model.h
participant_tree_edit_handler.cpp
participant_tree_edit_handler.h
participant_vulnerability_types.cpp
participant_vulnerability_types.h
participant_beautify_view.h
participant_beautify_view.cpp
)
NGL_WRAP_UI(participant_common_gui_SRCS
participant_distype_editor.ui
participant_edit_item_widget_base.ui
participant_dis_type_edit.ui
participant_search_modal.ui
)
NGL_ADD_LIBRARY2(WS PpmCommon SHARED ${participant_common_gui_SRCS} )
NGL_TARGET_LINK_LIBRARIES(PpmCommon
PRIVATE
LtsSession
Qt5::Widgets
NGLLogger
AsbDataPluginInterface
ExmDataPluginInterface
advancedSymbologyGui
LtsUtilsSettings
PUBLIC
Qt5::Core
Qt5::Gui
nglwidgets
svcPpmCommon
LtsDataView
LtsUtilsGuiDds
)
NGL_TARGET_INCLUDE_DIRECTORIES(PpmCommon
PUBLIC
${CMAKE_CURRENT_BINARY_DIR}/../../..
${CMAKE_CURRENT_SOURCE_DIR}/..
)
@@ -0,0 +1,133 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#include "msdl_distype_editor.h"
#include "ui_msdl_distype_editor.h"
#include "msdl_types.h"
#include <LtsWidgets/lts_message_dialog.h>
#include <ParticipantManagement/ppm_translation.h>
#include <Common/participant_dis_helper.h>
#include <set>
namespace msdl
{
DistypeEditor::DistypeEditor(QWidget *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ppmFtc)
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_ppmDtc(ppmDtc)
, m_ppmFtc(ppmFtc)
, m_pDISTypeEdit(nullptr)
, mUi(new Ui_MSDLDistypeEditor)
{
mUi->setupUi(this);
mUi->m_pushButton_Apply->setEnabled(false);
m_pDISTypeEdit = new ParticipantManagement::DIS::DISTypeEdit(this, m_ppmDtc, m_ppmFtc);
m_pDISTypeEdit->useMinimumListWidgetHeight(250);
connect(m_pDISTypeEdit, &ParticipantManagement::DIS::DISTypeEdit::signalChangesMade, this, &DistypeEditor::slotDISTypeEditChangesMade);
mUi->m_verticalLayout->insertWidget(1, m_pDISTypeEdit);
m_mapTypes = m_ppmDtc->types();
std::set<ParticipantManagement::TypeClass> setTypeClasses;
for (const ParticipantManagement::Type &type : qAsConst(m_mapTypes))
{
const ParticipantManagement::TypeClass typeClassId = type.typeClass();
if (typeClassId == ParticipantManagement::TypeClass::SupportUnit || typeClassId == ParticipantManagement::TypeClass::SupportEntity)
continue;
setTypeClasses.insert(typeClassId);
}
for (const auto &typeClassId : setTypeClasses)
mUi->m_ltsComboBox_typeClass->addItem(ParticipantManagement::toString(typeClassId), typeClassId.underlying());
slotTypeClassChanged();
connect(mUi->m_ltsComboBox_typeClass, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged), this, &DistypeEditor::slotTypeClassChanged);
connect(mUi->m_ltsComboBox_type, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged), this, &DistypeEditor::slotTypeChanged);
connect(mUi->m_pushButton_Apply, &QPushButton::clicked, this, &DistypeEditor::slotApply);
connect(mUi->m_pushButton_Close, &QPushButton::clicked, this, &DistypeEditor::slotClose);
}
DistypeEditor::~DistypeEditor()
{
delete m_requestHelper;
delete mUi;
}
void DistypeEditor::slotDISTypeEditChangesMade()
{
mUi->m_pushButton_Apply->setEnabled(true);
}
void DistypeEditor::slotClose()
{
if (m_pDISTypeEdit->hasChanges())
{
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(this, tr("Changes to the DIS type mapping have been done. Do you want to save these changes?"), tr("Unsaved changes"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::Yes)
slotApply();
}
close();
}
void DistypeEditor::slotApply()
{
bool success = false;
while (!(success = m_pDISTypeEdit->apply()))
{
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(this, tr("Applied DIS mapping changes could not be saved to database. Do you want to retry?"), tr("Warning"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::No)
break;
}
mUi->m_pushButton_Apply->setEnabled(!success);
}
void DistypeEditor::slotTypeClassChanged()
{
mUi->m_ltsComboBox_type->clear();
int currentTypeClass = mUi->m_ltsComboBox_typeClass->currentData().toInt();
for (const ParticipantManagement::Type &type : qAsConst(m_mapTypes))
{
if (type.typeClass().underlying() != currentTypeClass)
continue;
mUi->m_ltsComboBox_type->addItem(LtsUtils::str2QString(type.name()), type.id());
}
slotTypeChanged();
}
void DistypeEditor::slotTypeChanged()
{
int currentType = mUi->m_ltsComboBox_type->currentData().toInt();
m_pDISTypeEdit->switchType(currentType);
}
}
@@ -0,0 +1,50 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <LtsWidgets/lts_frameless_dialog.h>
#include "zwmsmsdl_export.h"
#include <QMap>
#include <memory>
#include <Common/participant_dis_type_edit.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <LtsUtilsGuiDds/request_helper.h>
class Ui_MSDLDistypeEditor;
namespace msdl
{
class ZWMSMSDL_EXPORT DistypeEditor : public LtsWidgets::LtsFramelessDialog,
protected ParticipantManagement::Interface::Ftc::ModifyTypeReplyHandler
{
Q_OBJECT
public:
DistypeEditor(QWidget *parent, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc, const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ppmFtc);
~DistypeEditor();
void onModifyTypeReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
private slots:
void slotDISTypeEditChangesMade();
void slotTypeClassChanged();
void slotTypeChanged();
void slotClose();
void slotApply();
private:
QMap<int32_t, ParticipantManagement::Type> m_mapTypes;
LtsUtils::RequestHelper *m_requestHelper;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
ParticipantManagement::DIS::DISTypeEdit *m_pDISTypeEdit;
Ui_MSDLDistypeEditor *mUi;
};
}
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MSDLDistypeEditor</class>
<widget class="QWidget" name="MSDLDistypeEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>467</width>
<height>130</height>
</rect>
</property>
<property name="windowTitle">
<string>DIS Type Editor</string>
</property>
<layout class="QVBoxLayout" name="m_verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="LtsWidgets::LtsComboBox" name="m_ltsComboBox_typeClass"/>
</item>
<item row="0" column="2">
<widget class="LtsWidgets::LtsComboBox" name="m_ltsComboBox_type"/>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="2">
<widget class="QPushButton" name="m_pushButton_Close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="m_pushButton_Apply">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Note: The first element will be used for HLA instantiation.</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,36 @@
/**
* @RDE_HEADER@
* Microsoft does strange things.
* $Id: participant_edit_model.h 52287 2020-10-08 11:54:01Z biedziak_f $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/commaster/Lts/Plugins/ParticipantManagement/Gui/Common/participant_edit_model.h $
* $Author: biedziak_f $
* Created by Mike Lennart Wille, SLTE, 2023-07-14
*/
#include <Common/participant_beautify_view.h>
#include <QTreeView>
#include <QHeaderView>
#include <QModelIndex>
namespace ParticipantManagement
{
/*
* Column widths are adjusted to the displayed content. Keeps all items expanded
* after identifying the optimal column width if 'keepExpanded' is true.
*/
void beautifyTreeView(QTreeView *tv, QAbstractItemModel *pModel, bool keepExpanded)
{
tv->expandAll();
int colCount = pModel->columnCount(QModelIndex());
for (int i = 0; i < colCount; ++i)
tv->resizeColumnToContents(i);
tv->header()->resizeSection(0, tv->columnWidth(0) + tv->iconSize().width() + 10);
if (!keepExpanded)
tv->collapseAll();
}
} // namespace ParticipantManagement
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* Microsoft does strange things.
* $Id: participant_edit_model.h 52287 2020-10-08 11:54:01Z biedziak_f $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/commaster/Lts/Plugins/ParticipantManagement/Gui/Common/participant_edit_model.h $
* $Author: biedziak_f $
* Created by Mike Lennart Wille, SLTE, 2023-07-14
*/
#pragma once
#include <Common/ppmcommon_export.h>
class QTreeView;
class QAbstractItemModel;
namespace ParticipantManagement
{
PPMCOMMON_EXPORT void beautifyTreeView(QTreeView *tv, QAbstractItemModel *pModel, bool keepExpanded = true);
} // namespace ParticipantManagement
@@ -0,0 +1,128 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Last, SLSE, 2017-12-01
*/
#include "participant_dis_helper.h"
namespace ParticipantManagement
{
namespace DIS
{
const QRegularExpression gRegExValidDIS(QStringLiteral("\\b([0-9])\\." // 8 Bit: Kind Field, exact values between 0 and 9
"(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\." // 8 bit unspecified: Domain Field
"(26[0-6]|2[0-5][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\." // 16 bit but highest value is 266 which is 'Uzbekistan'
"(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}" // 4x 8 bit unspecified: Category, Subcategory, Specific, Extra
"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\b")); // Disable leading zeros
/*
* Converts a given integer to a MSDL QString which has 21 characters.
* Adds leading zeros if missing.
*
* E.g: 3001222001246001000 (integer) becomes 003001222001246001000 (QString)
*/
QString convertDISTypeInteger2MSDLString(int64_t distype)
{
QString strDisType = QString::number(distype);
// Two leading zeros might be missing if the dis entity kind is small than 10 (-> [0, 255] i spossible]
while (strDisType.size() < 21)
strDisType.insert(0, QLatin1Char('0'));
return strDisType;
}
/*
* Converts a DIS type QString to an integer.
* Adds leading zeros (if missing) to each dis attribute.
*
* Example: 3.1.222.1.246.1.0 -> 3001222001246001000
*/
int64_t convertDISTypeString2Integer(const QString &strDisType)
{
const QStringList list = strDisType.split(QLatin1Char('.'));
if (list.size() != 7)
return -1;
QString strNumber(list[0]); // Prevent leading zeros
for (int i = 1; i < list.size(); ++i)
{
QString attribute = list[i];
while (attribute.size() < 3)
attribute.insert(0, QLatin1Char('0'));
strNumber += attribute;
}
bool ok;
int64_t number = strNumber.toLongLong(&ok, 10);
if (!ok)
return -1;
return number;
}
/*
* Converts a DIS type integer to a QString which can be correct (according to the DIS standard) visualized to the user.
* E.g. 3001222001246001000 (int) becomes 3.1.222.1.246.1.0 (QString)
*/
QString convertDISTypeInteger2DISString(int64_t distype)
{
QString strMSDL = convertDISTypeInteger2MSDLString(distype);
QString strDis;
if (strMSDL.size() != 21)
return strDis;
int index = 0;
for (int i = 0; i < 7; ++i)
{
QString part = strMSDL.mid(index, 3);
part.remove(QRegularExpression(QStringLiteral("^[0]*")));
// It may be possible that a part is "000" which would be completely erased
if (!part.size())
part = QStringLiteral("0");
strDis += part;
if (i != 6)
strDis += QLatin1Char('.');
index += 3;
}
return strDis;
}
int64_t convertMSDLString2Integer(const QString &strMSDL, bool *ok)
{
int64_t number = strMSDL.toLongLong(ok, 10);
return number;
}
QString convertMSDLString2DISString(const QString &strMSDL)
{
bool ok;
int64_t number = convertMSDLString2Integer(strMSDL, &ok);
if (!ok)
return QString();
return convertDISTypeInteger2DISString(number);
}
}
}
@@ -0,0 +1,35 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Last, SLSE, 2017-12-01
*/
#pragma once
#include <Plugins/ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <QString>
#include <QRegularExpression>
namespace ParticipantManagement
{
namespace DIS
{
PPMCOMMON_EXPORT extern const QRegularExpression gRegExValidDIS;
/*
* MSDL-String: 003001222001246001000
* DIS-Integer: 3001222001246001000
* DIS-String : 3.1.222.1.246.1.0
*/
PPMCOMMON_EXPORT QString convertDISTypeInteger2MSDLString(int64_t distype);
PPMCOMMON_EXPORT QString convertDISTypeInteger2DISString(int64_t distype);
PPMCOMMON_EXPORT int64_t convertDISTypeString2Integer(const QString &strDisType);
PPMCOMMON_EXPORT int64_t convertMSDLString2Integer(const QString &strMSDL, bool *ok = nullptr);
PPMCOMMON_EXPORT QString convertMSDLString2DISString(const QString &strMSDL);
}
}
@@ -0,0 +1,259 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#include "participant_dis_type_edit.h"
#include "ui_participant_dis_type_edit.h"
#include "participant_dis_helper.h"
#include <LtsWidgets/lts_message_dialog.h>
#include <ParticipantManagement/ppm_translation.h>
#include <Common/participant_dis_helper.h>
#include <QDebug>
namespace ParticipantManagement
{
namespace DIS
{
DISTypeEdit::DISTypeEdit(QWidget *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc, int32_t typeId)
: QWidget(parent)
, m_typeId(typeId)
, m_ppmDtc(dtc)
, m_ppmFtc(ftc)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, mUi(new Ui_ParticipantDISTypeEdit)
{
mUi->setupUi(this);
connect(mUi->m_listWidget_distypes->model(), &QAbstractItemModel::rowsMoved, this, [this]()
{
m_setTouchedTypes << m_typeId;
m_DisEntitiesByType[m_typeId].clear();
for (int i=0; i< mUi->m_listWidget_distypes->count(); ++i)
m_DisEntitiesByType[m_typeId] << ParticipantManagement::DIS::convertDISTypeString2Integer(mUi->m_listWidget_distypes->item(i)->text());
emit signalChangesMade();
});
auto cbTypes = [this] (const ParticipantManagement::Type &type)
{
m_mapTypes[type.id()] = type;
const ParticipantManagement::TypeClass &typeClassId = type.typeClass();
if (typeClassId == ParticipantManagement::TypeClass::SupportUnit || typeClassId == ParticipantManagement::TypeClass::SupportEntity)
return;
// Update used DIS id map by adding all DIS ids of this type
for (const auto &disId : type.disEntities())
{
if (m_usedDisTypes.contains(disId))
continue;
m_DisEntitiesByType[type.id()] << disId;
// if (m_mapDisStr2TypeId.find(disId) != m_mapDisStr2TypeId.end())
// {
// // Warnung?
// continue;
// }
// //qWarning() << "m_mapDisStr2TypeId: disId: " << disId << ", typeId: " << type.id();
// m_mapDisStr2TypeId[disId] = type.id();
}
};
m_ppmDtc->types(cbTypes);
switchType(m_typeId);
connect(mUi->m_pushButton_AddNewDistype, &QPushButton::clicked,this, &DISTypeEdit::slotAddDistype);
connect(mUi->m_pushButton_RemoveSelectedDistypes, &QPushButton::clicked,this, &DISTypeEdit::slotRemoveSelectedDisTypes);
m_pValidator = new QRegularExpressionValidator(ParticipantManagement::DIS::gRegExValidDIS, this);
mUi->m_lineEdit_newDistype->setValidator(m_pValidator);
checkRemoveButtonStatus();
}
DISTypeEdit::~DISTypeEdit()
{
delete mUi;
}
void DISTypeEdit::useMinimumListWidgetHeight(int minHeight)
{
mUi->m_listWidget_distypes->setMinimumHeight(minHeight);
}
void DISTypeEdit::switchType(int32_t typeId)
{
setEnabled(true);
m_typeId = typeId;
if(m_typeId == 0)
{
setEnabled(false);
return;
}
mUi->m_listWidget_distypes->clear();
for (int64_t disId : qAsConst(m_DisEntitiesByType[m_typeId]))
mUi->m_listWidget_distypes->addItem(DIS::convertDISTypeInteger2DISString(disId));
// If desired: Setting text alignment is done by manipulating the actual Item object
checkRemoveButtonStatus();
}
bool DISTypeEdit::hasChanges() const
{
return m_setTouchedTypes.size();
}
bool DISTypeEdit::apply()
{
if(!hasChanges())
return true;
for(int32_t typeId : qAsConst(m_setTouchedTypes))
{
Type &touchedType = m_mapTypes[typeId];
touchedType.disEntities().clear();
for (int64_t disId : qAsConst(m_DisEntitiesByType[typeId]))
touchedType.disEntities().push_back(disId);
m_requestHelper->addRequest([this, touchedType]()
{
return m_ppmFtc->modifyTypeRequest(touchedType, this);
});
}
bool success = m_requestHelper->startRequests();
if(success)
m_setTouchedTypes.clear();
return success;
}
void DISTypeEdit::checkRemoveButtonStatus()
{
mUi->m_pushButton_RemoveSelectedDistypes->setEnabled(mUi->m_listWidget_distypes->count());
}
QVector<QString> DISTypeEdit::getDISTypes() const
{
QVector<QString> vecDISTypes;
vecDISTypes.reserve(mUi->m_listWidget_distypes->count());
for(int i = 0; i < mUi->m_listWidget_distypes->count(); ++i)
vecDISTypes.push_back(mUi->m_listWidget_distypes->item(i)->text());
return vecDISTypes;
}
void DISTypeEdit::slotAddDistype()
{
QString bgColorRed(QStringLiteral("QLineEdit { background: rgb(255, 0, 0); }"));
QString bgColorWhite(QStringLiteral("QLineEdit { background: rgb(255, 255, 255); }"));
mUi->m_lineEdit_newDistype->setStyleSheet(bgColorWhite);
int pos;
QString strDistype = mUi->m_lineEdit_newDistype->text();
if(m_pValidator->validate(strDistype, pos) != QValidator::Acceptable)
{
mUi->m_lineEdit_newDistype->setStyleSheet(bgColorRed);
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Specified DIS type is invalid. Please verify your input."), tr("DIS type invalid"));
return;
}
// Prevent adding same DIS type twice for the current type class
for(int i = 0; i < mUi->m_listWidget_distypes->count(); ++i)
{
QListWidgetItem* pItem = mUi->m_listWidget_distypes->item(i);
if(pItem->text() == strDistype)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Specified DIS type is already used."), tr("DIS type invalid"));
return;
}
}
// Check whether other type classes make usage of the desired dis type
int64_t disId = ParticipantManagement::DIS::convertDISTypeString2Integer(strDistype);
int oldTypeId = 0;
QMapIterator<int32_t, QVector<int64_t> > it(m_DisEntitiesByType);
while(it.hasNext())
{
for (int64_t mapDisId : it.next().value())
{
if (disId == mapDisId)
{
oldTypeId = it.key();
break;
}
}
if (oldTypeId != 0)
break;
}
// User specified distype already exists? Notify user and ask for remapping
if(oldTypeId > 0)
{
const ParticipantManagement::Type& type = m_mapTypes[oldTypeId];
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(this, tr("Specified DIS type is already mapped to:\nType id: %1\nName: \"%2\"\nType class: \"%3\".\nDo you want to change this mapping?").arg(QString::number(type.id()), QString::fromStdString(type.name()), ParticipantManagement::toString(type.typeClass())), tr("DIS type already in use"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::No)
return;
/*
* Two touched types in this case: 'type.id()' from which we take the existing DIS id
* and our m_typeId which receives the taken DIS id
*/
m_setTouchedTypes.insert(oldTypeId);
m_DisEntitiesByType[oldTypeId].removeOne(disId);
}
m_setTouchedTypes.insert(m_typeId);
m_DisEntitiesByType[m_typeId] << disId;
mUi->m_listWidget_distypes->addItem(strDistype);
checkRemoveButtonStatus();
emit signalChangesMade();
}
void DISTypeEdit::slotRemoveSelectedDisTypes()
{
const QList<QListWidgetItem*> selectedItems = mUi->m_listWidget_distypes->selectedItems();
if (selectedItems.isEmpty())
return;
for (const QListWidgetItem *pItem : selectedItems)
{
int64_t disId = ParticipantManagement::DIS::convertDISTypeString2Integer(pItem->text());
m_DisEntitiesByType[m_typeId].removeAll(disId);
m_setTouchedTypes.insert(m_typeId);
delete pItem;
}
checkRemoveButtonStatus();
emit signalChangesMade();
}
}
}
@@ -0,0 +1,71 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <Plugins/ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <Services/ParticipantManagement/ppm.hpp>
#include <Services/ParticipantManagement/ppm_dtc.h>
#include <Services/ParticipantManagement/ppm_ftc.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <memory>
#include <QSet>
#include <QMap>
#include <QWidget>
#include <QRegularExpressionValidator>
class Ui_ParticipantDISTypeEdit;
namespace ParticipantManagement
{
namespace DIS
{
class PPMCOMMON_EXPORT DISTypeEdit : public QWidget, protected ParticipantManagement::Interface::Ftc::ModifyTypeReplyHandler
{
Q_OBJECT
public:
DISTypeEdit(QWidget *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
int32_t typeId = 0);
~DISTypeEdit();
bool apply();
bool hasChanges() const;
void useMinimumListWidgetHeight(int minHeight);
void switchType(int32_t typeId);
QVector<QString> getDISTypes() const;
signals:
void signalChangesMade();
private slots:
void slotAddDistype();
void slotRemoveSelectedDisTypes();
private:
void onModifyTypeReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
void checkRemoveButtonStatus();
//void setData(int32_t typeId);
int32_t m_typeId;
QSet<int64_t> m_usedDisTypes;
//QMap<int64_t, int32_t> m_mapDisStr2TypeId; // not sorted, since first entry is default
// typeID DIS-Int
QMap<int32_t, QVector<int64_t> > m_DisEntitiesByType;
QMap<int32_t, ParticipantManagement::Type> m_mapTypes;
QSet<int32_t> m_setTouchedTypes;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
LtsUtils::RequestHelper *m_requestHelper;
QRegularExpressionValidator *m_pValidator;
Ui_ParticipantDISTypeEdit *mUi;
};
}
}
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParticipantDISTypeEdit</class>
<widget class="QWidget" name="ParticipantDISTypeEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>482</width>
<height>393</height>
</rect>
</property>
<property name="windowTitle">
<string>DIS Type Editor</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="m_listWidget_distypes">
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLineEdit" name="m_lineEdit_newDistype">
<property name="minimumSize">
<size>
<width>220</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="m_pushButton_AddNewDistype">
<property name="text">
<string>Add DIS type</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="m_pushButton_RemoveSelectedDistypes">
<property name="text">
<string>Remove DIS types</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,132 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#include "participant_distype_editor.h"
#include "ui_participant_distype_editor.h"
#include <LtsWidgets/lts_message_dialog.h>
#include <ParticipantManagement/ppm_translation.h>
#include <Common/participant_dis_helper.h>
#include <set>
namespace ParticipantManagement
{
DistypeEditor::DistypeEditor(QWidget *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ppmFtc)
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_ppmDtc(ppmDtc)
, m_ppmFtc(ppmFtc)
, m_pDISTypeEdit(nullptr)
, mUi(new Ui_ParticipantDistypeEditor)
{
mUi->setupUi(this);
mUi->m_pushButton_Apply->setEnabled(false);
m_pDISTypeEdit = new ParticipantManagement::DIS::DISTypeEdit(this, m_ppmDtc, m_ppmFtc);
m_pDISTypeEdit->useMinimumListWidgetHeight(250);
connect(m_pDISTypeEdit, &ParticipantManagement::DIS::DISTypeEdit::signalChangesMade, this, &DistypeEditor::slotDISTypeEditChangesMade);
mUi->m_verticalLayout->insertWidget(1, m_pDISTypeEdit);
m_mapTypes = m_ppmDtc->types();
std::set<ParticipantManagement::TypeClass> setTypeClasses;
for (const ParticipantManagement::Type &type : qAsConst(m_mapTypes))
{
const ParticipantManagement::TypeClass typeClassId = type.typeClass();
if (typeClassId == ParticipantManagement::TypeClass::SupportUnit || typeClassId == ParticipantManagement::TypeClass::SupportEntity)
continue;
setTypeClasses.insert(typeClassId);
}
for (const auto &typeClassId : setTypeClasses)
mUi->m_ltsComboBox_typeClass->addItem(ParticipantManagement::toString(typeClassId), typeClassId.underlying());
slotTypeClassChanged();
connect(mUi->m_ltsComboBox_typeClass, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged), this, &DistypeEditor::slotTypeClassChanged);
connect(mUi->m_ltsComboBox_type, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged), this, &DistypeEditor::slotTypeChanged);
connect(mUi->m_pushButton_Apply, &QPushButton::clicked, this, &DistypeEditor::slotApply);
connect(mUi->m_pushButton_Close, &QPushButton::clicked, this, &DistypeEditor::slotClose);
}
DistypeEditor::~DistypeEditor()
{
delete m_requestHelper;
delete mUi;
}
void DistypeEditor::slotDISTypeEditChangesMade()
{
mUi->m_pushButton_Apply->setEnabled(true);
}
void DistypeEditor::slotClose()
{
if (m_pDISTypeEdit->hasChanges())
{
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(this, tr("Changes to the DIS type mapping have been done. Do you want to save these changes?"), tr("Unsaved changes"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::Yes)
slotApply();
}
close();
}
void DistypeEditor::slotApply()
{
bool success = false;
while (!(success = m_pDISTypeEdit->apply()))
{
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(this, tr("Applied DIS mapping changes could not be saved to database. Do you want to retry?"), tr("Warning"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::No)
break;
}
mUi->m_pushButton_Apply->setEnabled(!success);
}
void DistypeEditor::slotTypeClassChanged()
{
mUi->m_ltsComboBox_type->clear();
int currentTypeClass = mUi->m_ltsComboBox_typeClass->currentData().toInt();
for (const ParticipantManagement::Type &type : qAsConst(m_mapTypes))
{
if (type.typeClass().underlying() != currentTypeClass)
continue;
mUi->m_ltsComboBox_type->addItem(QString::fromStdString(type.name()), type.id());
}
slotTypeChanged();
}
void DistypeEditor::slotTypeChanged()
{
int currentType = mUi->m_ltsComboBox_type->currentData().toInt();
m_pDISTypeEdit->switchType(currentType);
}
}
@@ -0,0 +1,49 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <LtsWidgets/lts_frameless_dialog.h>
#include <QMap>
#include <memory>
#include <Common/participant_dis_type_edit.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <LtsUtilsGuiDds/request_helper.h>
class Ui_ParticipantDistypeEditor;
namespace ParticipantManagement
{
class PPMCOMMON_EXPORT DistypeEditor : public LtsWidgets::LtsFramelessDialog,
protected ParticipantManagement::Interface::Ftc::ModifyTypeReplyHandler
{
Q_OBJECT
public:
DistypeEditor(QWidget *parent, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc, const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ppmFtc);
~DistypeEditor();
void onModifyTypeReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
private slots:
void slotDISTypeEditChangesMade();
void slotTypeClassChanged();
void slotTypeChanged();
void slotClose();
void slotApply();
private:
QMap<int32_t, ParticipantManagement::Type> m_mapTypes;
LtsUtils::RequestHelper *m_requestHelper;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
ParticipantManagement::DIS::DISTypeEdit *m_pDISTypeEdit;
Ui_ParticipantDistypeEditor *mUi;
};
}
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParticipantDistypeEditor</class>
<widget class="QWidget" name="ParticipantDistypeEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>467</width>
<height>385</height>
</rect>
</property>
<property name="windowTitle">
<string>DIS Type Editor</string>
</property>
<layout class="QVBoxLayout" name="m_verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="LtsWidgets::LtsComboBox" name="m_ltsComboBox_typeClass"/>
</item>
<item row="0" column="2">
<widget class="LtsWidgets::LtsComboBox" name="m_ltsComboBox_type"/>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="2">
<widget class="QPushButton" name="m_pushButton_Close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="m_pushButton_Apply">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Note: The first element will be used for HLA instantiation.</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,520 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Participant Edit Item Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#include "participant_edit_item.h"
#include "ui_participant_edit_item_widget_base.h"
#include <ParticipantManagement/ppm_translation.h>
#include <QStandardItemModel>
namespace ParticipantManagement
{
//
// ParticipantEditItemWidget
//
ParticipantEditItemWidget::ParticipantEditItemWidget(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent)
: ParticipantEditItemWidgetBase(asSupportService, session, parent)
, m_isOrgChart(false)
{
connect(m_ui->tbAssignment, &QToolButton::clicked, this, &ParticipantEditItemWidget::onTbAssignmentClicked);
connect(m_ui->cbExternal, &QCheckBox::clicked, this, &ParticipantEditItemWidget::setAssignmentButton);
connect(m_ui->sbEquipNr, QOverload<int>::of(&QSpinBox::valueChanged), this, &ParticipantEditItemWidget::onEqNoChanged);
m_ui->tbAssignment->setCheckable(false);
m_ui->tbAssignment->setAutoRaise(false);
}
bool ParticipantEditItemWidget::init(const QModelIndex &workingIndex,
int partyId,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const ParticipantManagement::ParticipantData &data,
bool isOrgChart,
const bool addItem,
const QVector<int> &usedEquipmentNumbers)
{
m_isOrgChart = isOrgChart;
m_editData = data;
m_currentAssignState = data.assignState();
m_partyId = partyId;
m_bEditMode = m_editData.typeId() > 0;
m_workingIndex = workingIndex;
m_alreadyAddedEquipmentNumbers = usedEquipmentNumbers;
return ParticipantEditItemWidgetBase::init(dtc, ppmGuiCbxIfc, asb, addItem);
}
void ParticipantEditItemWidget::setFiringUnitRestrictions(ParticipantEditModel *model, bool isEdit, const FiringUnitValidator::FiringUnitRestrictions &restrictions, FiringUnitValidator *firingUnitValidator, const int &unitGearClassType)
{
if (!firingUnitValidator || !model)
return;
if (restrictions.testFlag(FiringUnitValidator::NO_TYPE_CHANGE_ALLOWED))
{
m_ui->cbTypeClass->setDisabled(true);
m_ui->cbType->setDisabled(true);
if (isEdit) // if we are in edit mode (and not add), type and typeclass are already set where as want them to be
return;
const Type allowedType = firingUnitValidator->getAllowedType(model, m_workingIndex);
if (allowedType == Type())
return;
m_ui->cbTypeClass->setCurrentIndex(m_ui->cbTypeClass->findData(allowedType.typeClass().underlying()));
m_ui->cbType->setCurrentIndex(m_ui->cbType->findData(allowedType.id()));
return;
}
if (restrictions.testFlag(FiringUnitValidator::ONLY_SAME_GEAR_CLASS_ARTILLERY_ALLOWED))
{
if (isEdit)
return;
const QVector<Type> allowedTypes = firingUnitValidator->artilleryParticipantTypes();
m_ui->cbTypeClass->setDisabled(true);
m_ui->cbTypeClass->setCurrentIndex(m_ui->cbTypeClass->findData(allowedTypes.at(0).typeClass().underlying()));
m_ui->cbType->clear();
std::function<bool(Type)> funcIsSameGearType = [=](const Type &t)
{
if (m_isAdler)
return m_dtc->isAdlerType(t.id()) && (firingUnitValidator->getGearClassType(t.id()) == unitGearClassType);
return firingUnitValidator->getGearClassType(t.id()) == unitGearClassType;
};
QVector<Type>::ConstIterator typeIterator = std::find_if(allowedTypes.begin(), allowedTypes.end(), funcIsSameGearType);
if(typeIterator != allowedTypes.end())
{
m_ui->cbType->setDisabled(true);
m_ui->cbType->addItem(ParticipantManagement::trTypeName(typeIterator->name()), typeIterator->id());
}
else
{
for (const Type &currentType : allowedTypes)
m_ui->cbType->addItem(ParticipantManagement::trTypeName(currentType.name()), currentType.id());
m_ui->cbType->model()->sort(0);
}
m_ui->cbType->setCurrentIndex(0);
return;
}
if (isEdit && restrictions.testFlag(FiringUnitValidator::NO_FIRING_UNIT_TYPE_ALLOWED))
{
m_disabledTypeIds.unite(firingUnitValidator->firingUnitTypeIds());
QStandardItemModel *cbTypeModel = qobject_cast<QStandardItemModel *>(m_ui->cbType->model());
if (cbTypeModel == nullptr)
return;
for (int row = 0; row < m_ui->cbType->count(); ++row)
{
QStandardItem *item = cbTypeModel->item(row);
int typeId = item->data(Qt::UserRole).toInt();
if (!m_disabledTypeIds.contains(typeId))
continue;
item->setFlags(Qt::NoItemFlags);
}
}
if (restrictions.testFlag(FiringUnitValidator::NO_ARTILLERY_PARTICIPANTS_ALLOWED))
{
m_disabledTypeIds.unite(firingUnitValidator->artilleryParticipantTypeIds());
QStandardItemModel *cbTypeModel = qobject_cast<QStandardItemModel *>(m_ui->cbType->model());
if (cbTypeModel == nullptr)
return;
for (int row = 0; row < m_ui->cbType->count(); ++row)
{
QStandardItem *item = cbTypeModel->item(row);
int typeId = item->data(Qt::UserRole).toInt();
if (!m_disabledTypeIds.contains(typeId))
continue;
item->setFlags(Qt::NoItemFlags);
}
}
}
void ParticipantEditItemWidget::setData()
{
m_ui->leDesignator->setText(QString::fromStdString(m_editData.designator()));
m_ui->leTactIdent->setText(QString::fromStdString(m_editData.tacticalIdentifier()));
m_ui->leInfo->setText(QString::fromStdString(m_editData.info()));
m_ui->leSign->setText(QString::fromStdString(m_editData.identification()));
m_ui->cbExternal->setChecked(m_editData.externalId() > 0);
m_ui->leVerein->setText(QString::fromStdString(m_editData.name()));
Type type = m_dtc->type(m_editData.typeId());
m_ui->cbTypeClass->setCurrentIndex(m_ui->cbTypeClass->findData(type.typeClass().underlying()));
m_ui->cbType->setCurrentIndex(m_ui->cbType->findData(type.id()));
//set assingment first
setAssignmentButton();
if (isUnitType(m_editData.typeId()))
{
m_ui->cbTypeClass->setEnabled(false);
m_ui->sbEquipNr->setEnabled(false);
m_ui->tbAssignment->setEnabled(false); //units never get equipments and never reset
bool showVerein = m_dtc->isAdlerType(m_editData.typeId());
m_ui->lblVerein->setVisible(showVerein);
m_ui->leVerein->setVisible(showVerein);
}
else
{
const bool isEquipped = m_editData.equipmentNumber().is_set() && m_editData.equipmentNumber().get() > 0;
m_ui->cbTypeClass->setEnabled(!isEquipped);
m_ui->cbType->setEnabled(!isEquipped);
m_ui->sbEquipNr->setEnabled(m_editData.typeId() > 0);
}
if (m_editData.equipmentNumber().is_set())
m_ui->sbEquipNr->setValue(m_editData.equipmentNumber().get());
onChangeSymbol(QString::fromStdString(m_editData.symbol()));
// Saab Participants
if (m_editData.externalId() > 0)
{
m_ui->leTactIdent->setEnabled(false); // Set from OrbatImport or via HLA
m_ui->sbEquipNr->setEnabled(false); // EqNo cannot be changed on Saab Players
m_ui->tbAssignment->setEnabled(false);
// m_ui->leSign->setEnabled(); // I let it changeable at the moment...
}
}
void ParticipantEditItemWidget::setDesignatorData()
{
m_ui->leDesignator->setText(QString::fromStdString(m_editData.designator()));
m_ui->leTactIdent->setText(QString::fromStdString(m_editData.tacticalIdentifier()));
}
void ParticipantEditItemWidget::onAddItem()
{
ParticipantManagement::ParticipantData newParticipantData;
if (!collectParticipantData(newParticipantData))
return;
if (newParticipantData.equipmentNumber().is_set())
m_alreadyAddedEquipmentNumbers.append(newParticipantData.equipmentNumber().get());
DEBUG_LOG(m_logger) << "add item: " << newParticipantData;
if (m_workingIndex.isValid() || m_isOrgChart)
emit addItem(m_workingIndex, newParticipantData);
m_ui->leSign->clear();
m_ui->leInfo->clear();
}
bool ParticipantEditItemWidget::onEditItem()
{
ParticipantManagement::ParticipantData newParticipantData(m_editData);
if (!collectParticipantData(newParticipantData))
return false;
m_editData = newParticipantData;
m_currentAssignState = newParticipantData.assignState();
DEBUG_LOG(m_logger) << "edit item: " << m_editData;
if (m_workingIndex.isValid() || m_isOrgChart)
emit updateItem(m_workingIndex, m_editData);
emit readyToClose();
return true;
}
bool ParticipantEditItemWidget::collectParticipantData(ParticipantManagement::ParticipantData &data)
{
const int newEquipmentNumber = m_ui->sbEquipNr->value();
data.designator(m_ui->leDesignator->text().toStdString());
data.tacticalIdentifier(m_ui->leTactIdent->text().toStdString());
data.symbol(m_sidc.toStdString());
data.typeId(m_ui->cbType->currentData().toInt());
data.partyId(m_partyId);
data.identification(m_ui->leSign->text().toStdString());
data.info(m_ui->leInfo->text().toStdString());
data.assignState(m_currentAssignState);
// Verein is listed in name
data.name(m_ui->leVerein->text().toStdString());
if (newEquipmentNumber > 0)
{
if (newEquipmentNumber < m_typeMinimum)
{
m_ui->lbMinMaxEquipNr->setText(QStringLiteral("<span style=\"color:#aa0000;\">%1</span>").arg(m_ui->lbMinMaxEquipNr->text()));
return false;
}
if (m_editData.equipmentNumber() != newEquipmentNumber)
{
int exerciseId = 0;
if (!m_dtc->isEquipmentExerciseMappingEnabled())
{
m_dtc->enableEquipmentExerciseMapping();
m_dtc->waitForHistoricalDataEquipmentExerciseMapping(3000);
}
if (m_dtc->isEquipmentNumberInUse(newEquipmentNumber, exerciseId) || m_alreadyAddedEquipmentNumbers.contains(newEquipmentNumber))
{
if (m_session->exerciseId() == exerciseId)
{
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("The equipment number is already used by another participant"),
tr("Equipment Number already in use"));
return false;
}
if (m_session->exerciseState() != LtsWidgets::ExcState::eCreated)
{
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("The equipment number is already used by another participant in another exercise"),
tr("Equipment Number already in use"));
return false;
}
}
}
data.equipmentNumber(newEquipmentNumber);
data.externalId(m_ui->cbExternal->isChecked() ? newEquipmentNumber : 0);
m_ui->sbEquipNr->setValue(newEquipmentNumber + 1);
}
else
{
data.equipmentNumber().reset();
data.externalId(0);
}
return true;
}
void ParticipantEditItemWidget::onTbAssignmentClicked()
{
switch (m_currentAssignState.underlying())
{
case ParticipantManagement::ParticipantAssignState::AssignedWms:
m_currentAssignState = ParticipantManagement::ParticipantAssignState::HandoutExcon;
m_ui->sbEquipNr->setValue(0);
break;
case ParticipantManagement::ParticipantAssignState::HandoutWms:
m_currentAssignState = ParticipantManagement::ParticipantAssignState::ExconWmsOverruled;
m_ui->sbEquipNr->setValue(0);
break;
case ParticipantManagement::ParticipantAssignState::HandoutExcon:
case ParticipantManagement::ParticipantAssignState::ExconWmsOverruled:
m_currentAssignState = ParticipantManagement::ParticipantAssignState::NotAssigned;
m_ui->sbEquipNr->setValue(0);
break;
case ParticipantManagement::ParticipantAssignState::NotAssigned:
if (m_editData.assignState() == ParticipantManagement::ParticipantAssignState::ExconWmsOverruled ||
m_editData.assignState() == ParticipantManagement::ParticipantAssignState::HandoutWms)
m_currentAssignState = ParticipantManagement::ParticipantAssignState::ExconWmsOverruled;
else
m_currentAssignState = ParticipantManagement::ParticipantAssignState::HandoutExcon;
break;
}
setAssignmentButton();
}
void ParticipantEditItemWidget::onEqNoChanged()
{
if (m_currentAssignState == ParticipantManagement::ParticipantAssignState::NotAssigned &&
m_ui->sbEquipNr->value() != 0)
{
onTbAssignmentClicked();
return;
}
if (m_editData.assignState() == ParticipantManagement::ParticipantAssignState::AssignedWms)
{
if (m_editData.equipmentNumber().is_set() && m_editData.equipmentNumber().get() == m_ui->sbEquipNr->value())
m_currentAssignState = ParticipantManagement::ParticipantAssignState::AssignedWms;
else
m_currentAssignState = ParticipantManagement::ParticipantAssignState::HandoutExcon;
}
else if (m_editData.assignState() == ParticipantManagement::ParticipantAssignState::HandoutWms)
{
if (m_editData.equipmentNumber().is_set() && m_editData.equipmentNumber().get() == m_ui->sbEquipNr->value())
m_currentAssignState = ParticipantManagement::ParticipantAssignState::HandoutWms;
else
m_currentAssignState = ParticipantManagement::ParticipantAssignState::ExconWmsOverruled;
}
setAssignmentButton();
}
void ParticipantEditItemWidget::setAssignmentButton()
{
switch (m_currentAssignState.underlying())
{
case ParticipantManagement::ParticipantAssignState::AssignedWms:
case ParticipantManagement::ParticipantAssignState::HandoutWms:
{
if (m_editData.assignState().underlying() == ParticipantManagement::ParticipantAssignState::AssignedWms)
m_ui->tbAssignment->setText(tr("WH(A)"));
else
m_ui->tbAssignment->setText(tr("WH(H)"));
//can't override warehouse settings
break;
}
case ParticipantManagement::ParticipantAssignState::HandoutExcon:
{
m_ui->tbAssignment->setText(tr("EXC"));
break;
}
case ParticipantManagement::ParticipantAssignState::ExconWmsOverruled:
{
m_ui->tbAssignment->setText(tr("EXC(+)"));
break;
}
case ParticipantManagement::ParticipantAssignState::NotAssigned:
{
m_ui->tbAssignment->setText(QStringLiteral("-"));
break;
}
}
// Saab Participants: Can be taken down, but need to uncheck "External" first.
if (m_editData.externalId() > 0 && m_ui->cbExternal->isChecked())
{
m_ui->tbAssignment->setEnabled(false);
m_ui->sbEquipNr->setEnabled(false);
return;
}
m_ui->tbAssignment->setEnabled(true);
m_ui->sbEquipNr->setEnabled(true);
}
//
// ParticipantEditItem
//
ParticipantEditItem::ParticipantEditItem(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent)
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
, m_editItemWidget(new ParticipantEditItemWidget(asSupportService, session, parent))
, m_buttonBox(new LtsWidgets::LtsDialogButtonBox(this))
{
//HACK as close is not allowed directly
setWindowTitle(tr("Edit Participant"));
connect(m_buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this, &ParticipantEditItem::close);
connect(m_editItemWidget, &ParticipantEditItemWidget::readyToClose, this, &ParticipantEditItem::close);
//connect to other signals
connect(m_editItemWidget, &ParticipantEditItemWidget::addItem, this, &ParticipantEditItem::addItem);
connect(m_editItemWidget, &ParticipantEditItemWidget::updateItem, this, &ParticipantEditItem::updateItem);
//hide ok and aplly
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->hide();
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->hide();
}
bool ParticipantEditItem::init(const QModelIndex &workingIndex,
int partyId,
const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const ParticipantData &data,
const bool addItem,
const QVector<int> &usedEquipmentNumbers)
{
const bool isOrgChart = false;
if (!m_editItemWidget->init(workingIndex, partyId, dtc, ppmGuiCbxIfc, asb, data, isOrgChart, addItem, usedEquipmentNumbers))
return false;
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(m_editItemWidget);
layout->addWidget(m_buttonBox);
setLayout(layout);
if (data.typeId() > 0)
{
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, m_editItemWidget, &ParticipantEditItemWidget::onEditItem);
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setText(tr("Apply"));
}
else
{
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, m_editItemWidget, &ParticipantEditItemWidget::onAddItem);
}
return true;
}
void ParticipantEditItem::setFiringUnitRestrictions(ParticipantEditModel *model, bool isEdit, const FiringUnitValidator::FiringUnitRestrictions &restrictions, FiringUnitValidator *firingUnitValidator, const int unitGearClassType)
{
if (restrictions == FiringUnitValidator::NO_RESTRICTION)
return;
if (restrictions.testFlag(FiringUnitValidator::IS_AT_MAX_CAPACITY))
m_buttonBox->getButton(LtsWidgets::DialogButton::Add)->setDisabled(true);
if (m_editItemWidget)
m_editItemWidget->setFiringUnitRestrictions(model, isEdit, restrictions, firingUnitValidator, unitGearClassType);
}
//
// ParticipantEditItemTab
//
ParticipantEditItemTab::ParticipantEditItemTab(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_editItemWidget(new ParticipantEditItemWidget(asSupportService, session, this))
{
connect(m_editItemWidget, &ParticipantEditItemWidget::updateItem, this, &ParticipantEditItemTab::updateItem);
connect(m_editItemWidget, &ParticipantEditItemWidget::readyToClose, this, [this]()
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Close)->click();
});
}
void ParticipantEditItemTab::retranslate()
{
// lupdate doesn't like translate(tr("foo")) ...
const QString txt(tr("Participant Item Edit"));
translate(txt);
}
bool ParticipantEditItemTab::init(const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const ParticipantData &data,
bool isOrgChart)
{
if (!m_editItemWidget->init(QModelIndex(), data.partyId(), dtc, ppmGuiCbxIfc, asb, data, isOrgChart))
return false;
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(m_editItemWidget);
setLayout(layout);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, m_editItemWidget, &ParticipantEditItemWidget::onEditItem);
m_buttonBox->setText(LtsWidgets::DialogButton::Edit, tr("Apply"));
return true;
}
bool ParticipantEditItemTab::apply()
{
return m_editItemWidget->onEditItem();
}
} //namespace ParticipantManagement
@@ -0,0 +1,136 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Participant Edit Item Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#pragma once
#include "participant_edit_item_widget_base.h"
#include <ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <LtsWidgets/lts_dialog.h>
#include "participant_firing_unit_validator.h"
namespace LtsWidgets
{
class LtsDialogButtonBox;
}
namespace ParticipantManagement
{
class ParticipantEditItemWidget final : public ParticipantEditItemWidgetBase
{
Q_OBJECT
public:
explicit ParticipantEditItemWidget(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent = nullptr);
bool init(const QModelIndex &workingIndex,
int partyId,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const ParticipantData &data,
bool isOrgChart = false,
const bool addItem = false,
const QVector<int> &usedEquipmentNumbers = QVector<int>());
void setFiringUnitRestrictions(ParticipantEditModel *model,
bool isEdit,
const FiringUnitValidator::FiringUnitRestrictions &restrictions,
FiringUnitValidator *firingUnitValidator,
const int &unitGearClassType);
void setIsAdler(bool isAdler) { m_isAdler = isAdler; }
protected:
void setData() override;
void setDesignatorData() override;
public:
void onAddItem() override;
bool onEditItem() override;
bool collectParticipantData(ParticipantManagement::ParticipantData &data);
protected Q_SLOTS:
void onTbAssignmentClicked();
void setAssignmentButton();
void onEqNoChanged();
protected:
int editTypeId() const override { return m_editData.typeId(); }
int currentPartyId() const override { return m_editData.partyId() > 1 ? m_editData.partyId() : m_partyId; }
private:
ParticipantManagement::ParticipantAssignState getAssignmentState() const;
Q_SIGNALS:
void addItem(const QModelIndex &parent, const ParticipantData &newData);
void updateItem(const QModelIndex &parent, const ParticipantData &editData);
private:
QModelIndex m_workingIndex;
ParticipantManagement::ParticipantAssignState m_currentAssignState;
int m_partyId;
bool m_isOrgChart;
bool m_isAdler {false};
ParticipantData m_editData;
QVector<int32_t> m_alreadyAddedEquipmentNumbers;
};
class PPMCOMMON_EXPORT ParticipantEditItem final : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
ParticipantEditItem(bool asSupportService, LtsSession::LtsSession *session, QWidget *parent = nullptr);
bool init(const QModelIndex &workingIndex, int partyId,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const ParticipantData &data = ParticipantData(),
const bool addItem = false,
const QVector<int> &usedEquipmentNumbers = QVector<int>());
void setIsAdler(bool isAdler) { m_editItemWidget->setIsAdler(isAdler); }
void setFiringUnitRestrictions(ParticipantEditModel *model,
bool isEdit,
const FiringUnitValidator::FiringUnitRestrictions &restrictions,
FiringUnitValidator *firingUnitValidator,
const int unitGearClassType);
Q_SIGNALS:
void addItem(const QModelIndex &parent, const ParticipantData &newData);
void updateItem(const QModelIndex &parent, const ParticipantData &editData);
private:
ParticipantEditItemWidget *m_editItemWidget;
LtsWidgets::LtsDialogButtonBox *m_buttonBox;
};
class PPMCOMMON_EXPORT ParticipantEditItemTab final : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
ParticipantEditItemTab(bool asSupportService, LtsSession::LtsSession *session, QWidget *parent = nullptr);
bool init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const ParticipantData &data = ParticipantData(), bool isOrgChart = false);
Q_SIGNALS:
void addItem(int &row, const QModelIndex &parent, const ParticipantData &newData, bool asCopy);
void updateItem(const QModelIndex &parent, const ParticipantData &editData);
private:
void retranslate() override;
bool apply() override;
private:
ParticipantEditItemWidget *m_editItemWidget;
};
} // namespace ParticipantManagement
@@ -0,0 +1,293 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Participant Edit Item Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#include "participant_edit_item.h"
#include "ui_participant_edit_item_widget_base.h"
#include <ParticipantManagement/ppm_translation.h>
#include <Plugins/AdvancedSymbology/asb_data_plugin_interface.h>
#include <ExerciseManagement/exm_data_plugin_interface.h>
#include <Symbology/symbol_data_to_render_role.h>
#include <SymbologyGui/base_symbol_lookup_dialog.h>
#include <SymbologyGui/symbol_modification_dialog.h>
#include <Symbology/sidc_codec.h>
#include <LtsUtilsSettings/settings.h>
#include <QStandardItemModel>
namespace ParticipantManagement
{
//
// ParticipantEditItemWidgetBase
//
static int s_lastTypeClassUsed = ParticipantManagement::TypeClass_def::Human;
static int s_lastTypeUsed = -1;
ParticipantEditItemWidgetBase::ParticipantEditItemWidgetBase(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent)
: QWidget(parent)
, m_asSupportService(asSupportService)
, m_bEditMode(false)
, m_typeMinimum(0)
, m_validator(new QRegularExpressionValidator(QRegularExpression(QStringLiteral("[^,;\"'´`]*")), this))
, m_symbolConfig(nullptr)
, m_symbolWatcher(nullptr)
, m_dtc(nullptr)
, m_ppmGuiCbxIfc(nullptr)
, m_session(session)
, m_ui(new Ui::ParticipantEditItemWidgetBase)
, m_logger(getLogger("ParticipantEditItemWidgetBase"))
{
m_ui->setupUi(this);
setWindowTitle(tr("Edit Participant"));
connect(m_ui->pbIcon, &QToolButton::clicked, this, &ParticipantEditItemWidgetBase::onSymbolSelection);
connect(m_ui->pbSymbolConfig, &QToolButton::clicked, this, &ParticipantEditItemWidgetBase::onSymbolConfig);
connect(m_ui->cbTypeClass, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged),
this, &ParticipantEditItemWidget::onFillTypeCb);
connect(m_ui->cbType, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged),
this, &ParticipantEditItemWidget::onChangeMinMax);
m_ui->sbEquipNr->setEnabled(false);
m_ui->pbSymbolConfig->setEnabled(false);
m_ui->leDesignator->setValidator(m_validator);
m_ui->leTactIdent->setValidator(m_validator);
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc;
session->getDtc<ExerciseManagement::DataInterface>(exmDtc);
const bool hasHlaInterface = (LtsUtils::ProjectSettings::isFunctionEnabled(QStringLiteral("Exercises"),
QStringLiteral("HasHlaInterface"))
&& exmDtc
&& exmDtc->exercise(m_session->exerciseId()).hasHlaInterface());
if (!hasHlaInterface)
{
m_ui->cbExternal->hide();
m_ui->lblExternal->hide();
}
m_ui->lblVerein->hide();
m_ui->leVerein->hide();
}
constexpr unsigned short getUnsignedShortValue(const int value)
{
// return (value < USHRT_MAX ? value : USHRT_MAX);
return (value < 50000 ? value : 50000);
}
ParticipantEditItemWidgetBase::~ParticipantEditItemWidgetBase()
{
s_lastTypeClassUsed = m_ui->cbTypeClass->currentData().toInt();
s_lastTypeUsed = m_ui->cbType->currentData().toInt();
delete m_ui;
}
void ParticipantEditItemWidgetBase::slotRetranslate()
{
int filter = ForeignGuiComboboxInterface::eAll;
if (m_bEditMode)
{
if (isUnitType(editTypeId()))
filter = (m_asSupportService ? ForeignGuiComboboxInterface::eOcUnits : ForeignGuiComboboxInterface::eUnits);
else
filter = (m_asSupportService ? ForeignGuiComboboxInterface::eOc : ForeignGuiComboboxInterface::eParticipants);
}
else
{
filter = (m_asSupportService ? ForeignGuiComboboxInterface::eOc | ForeignGuiComboboxInterface::eOcUnits
: ForeignGuiComboboxInterface::eParticipants | ForeignGuiComboboxInterface::eUnits);
}
m_ppmGuiCbxIfc->fillTypeClassComboBox(m_ui->cbTypeClass, filter);
onFillTypeCb();
}
bool ParticipantEditItemWidgetBase::init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const bool addItem)
{
DEBUG_LOG(m_logger) << "init addItem=" << addItem
<< " m_bEditMode=" << m_bEditMode;
if (!dtc || !ppmGuiCbxIfc)
return false;
m_dtc = dtc;
m_ppmGuiCbxIfc = ppmGuiCbxIfc;
m_asbfc = asb;
m_ui->cbTypeClass->clear();
m_symbolWatcher = new AdvancedSymbology::SymbolResultWatcherQWidget<QToolButton>(m_ui->pbIcon);
slotRetranslate();
if (addItem)
{
DEBUG_LOG(m_logger) << "setDesignatorData()";
setDesignatorData();
m_ui->cbTypeClass->setCurrentIndex(m_ui->cbTypeClass->findData(s_lastTypeClassUsed));
const int idx = m_ui->cbType->findData(s_lastTypeUsed);
if (idx != -1)
m_ui->cbType->setCurrentIndex(idx);
}
else if (m_bEditMode)
{
DEBUG_LOG(m_logger) << "setData()";
setData();
}
return true;
}
void ParticipantEditItemWidgetBase::onFillTypeCb()
{
QSignalBlocker blocker(m_ui->cbType);
TypeClass currentClass(static_cast<TypeClass_def::type>(m_ui->cbTypeClass->currentData().toInt()));
m_ppmGuiCbxIfc->fillTypeComboBox(m_ui->cbType, currentClass);
if (!m_disabledTypeIds.isEmpty())
{
QStandardItemModel *cbTypeModel = qobject_cast<QStandardItemModel *>(m_ui->cbType->model());
if (cbTypeModel == nullptr)
return;
for (int row = 0; row < m_ui->cbType->count(); ++row)
{
QStandardItem *item = cbTypeModel->item(row);
int typeId = item->data(Qt::UserRole).toInt();
if (!m_disabledTypeIds.contains(typeId))
continue;
item->setFlags(Qt::NoItemFlags);
}
}
onChangeMinMax();
}
void ParticipantEditItemWidgetBase::onChangeMinMax()
{
const ParticipantManagement::Type type = m_dtc->type(m_ui->cbType->currentData().toInt());
const ParticipantManagement::EquipmentType eqType = m_dtc->equipmentType(type.equipmentTypeId());
m_ui->lbMinMaxEquipNr->setText(QString::number(getUnsignedShortValue(eqType.minEquipNo())) + QLatin1Char(':') + QString::number(getUnsignedShortValue(eqType.maxEquipNo())));
m_ui->sbEquipNr->setMaximum(getUnsignedShortValue(eqType.maxEquipNo()));
m_typeMinimum = eqType.minEquipNo();
bool isNoUnit = type.typeClass() != TypeClass::SupportUnit && type.typeClass() != TypeClass::Unit;
if (!isNoUnit)
m_ui->sbEquipNr->setValue(0);
m_ui->sbEquipNr->setEnabled(isNoUnit);
m_ui->tbAssignment->setEnabled(isNoUnit);
// Check Verein
bool showVerein = m_dtc->isAdlerType(type.id());
m_ui->lblVerein->setVisible(showVerein);
m_ui->leVerein->setVisible(showVerein);
onChangeSymbol(QString::fromStdString(type.symbol()));
}
void ParticipantEditItemWidgetBase::onSymbolSelection()
{
AdvancedSymbology::Gui::BaseSymbolLookupDialog *bslDlg =
AdvancedSymbology::Gui::BaseSymbolLookupDialog::showInstance();
connect(bslDlg, &AdvancedSymbology::Gui::BaseSymbolLookupDialog::finished, this, [this, bslDlg]() {
// qCritical() << " finished";
bslDlg->disconnect(this); // !!! disconnect my slots from bslDlg !!!
});
connect(bslDlg, &AdvancedSymbology::Gui::BaseSymbolLookupDialog::lookupAppliedCompleteSidc, this, &ParticipantEditItemWidget::onChangeSymbol);
bslDlg->setParticipantMode(true);
bslDlg->setCurrentSidc(m_sidc);
bslDlg->show();
return;
}
void ParticipantEditItemWidgetBase::onSymbolConfig()
{
if (!m_asbfc)
return;
m_symbolConfig = new AdvancedSymbology::Gui::SymbolModificationDialogFrameless(m_asbfc->getSymbolDictionary(AdvancedSymbology::SymbolDictionary::defaultSymbologyType()), false, this); //Todo Symboltype
m_symbolConfig->setSidc(m_sidc);
connect(m_symbolConfig, &AdvancedSymbology::Gui::SymbolModificationDialogFrameless::sidcOnClose, this, &ParticipantEditItemWidget::onChangeSymbol);
connect(m_symbolConfig, &AdvancedSymbology::Gui::SymbolModificationDialogFrameless::rejected, this, [this]()
{
m_symbolConfig->deleteLater();
m_symbolConfig = nullptr;
});
m_symbolConfig->show();
}
void ParticipantEditItemWidgetBase::onChangeSymbol(const QString &sidc)
{
TRACE_LOG(m_logger) << LOGFUNCTION << ", Changing symbol to " << sidc;
if (!m_asbfc || sidc == m_sidc)
return;
AdvancedSymbology::SymbolDataToRender symDataToRender(sidc);
if (currentPartyId())
{
symDataToRender.role = AdvancedSymbology::roleToRole<>((m_dtc->party(currentPartyId()).role()));
symDataToRender.fillColor = QColor::fromRgb(QRgb(m_dtc->party(currentPartyId()).color()));
symDataToRender.fillColorReplace = true;
} else {
// User-Defined Symbols (XML) need fillColor:
symDataToRender.fillColor = AdvancedSymbology::SymbolDataToRender::unknownColor();
symDataToRender.fillColorReplace = true;
}
m_symbolWatcher->setSymbolResult(m_asbfc->findImage(symDataToRender));
m_sidc = sidc;
if (AdvancedSymbology::SidcCodec::isEncoded(m_sidc))
{
const QString rawSidc = AdvancedSymbology::SidcCodec::decodeRawSidc(m_sidc);
m_ui->pbSymbolConfig->setEnabled(rawSidc.size() && (!AdvancedSymbology::SidcCodec::isCivil(m_sidc)));
}
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " sidc is not encoded, sidc = '" << sidc << "'";
m_ui->pbSymbolConfig->setEnabled(false);
}
if (m_symbolConfig)
{
m_symbolConfig->deleteLater();
m_symbolConfig = nullptr;
}
DEBUG_LOG(m_logger) << "Changing symbol to " << sidc << " is in progress";
}
ParticipantManagement::TypeClass ParticipantEditItemWidgetBase::typeClassIdFromTypeId(int typeId) const
{
auto it = m_type2TypeClass.find(typeId);
if (it != m_type2TypeClass.end())
return it.value();
auto cbTypes = [this](const ParticipantManagement::Type &type)
{
m_type2TypeClass[type.id()] = type.typeClass();
};
m_dtc->types(cbTypes);
return m_type2TypeClass.value(typeId);
}
bool ParticipantEditItemWidgetBase::isUnitType(int typeId) const
{
const ParticipantManagement::TypeClass typeClassId = typeClassIdFromTypeId(typeId);
return typeClassId == ParticipantManagement::TypeClass::Unit ||
typeClassId == ParticipantManagement::TypeClass::SupportUnit;
}
} //namespace ParticipantManagement
@@ -0,0 +1,97 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Participant Edit Item Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#pragma once
#include <ParticipantManagement/logger.h>
#include <Services/ParticipantManagement/ppm_dtc.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <LtsSession/lts_session.h>
#include <QWidget>
namespace AdvancedSymbology
{
class ForeignDataInterface;
class SymbolResultWatcherQWidgetBase;
namespace Gui
{
class SymbolModificationDialogFrameless;
class BaseSymbolModel;
class BaseSymbolProxyFilter;
}
}
namespace Ui
{
class ParticipantEditItemWidgetBase;
}
namespace ParticipantManagement
{
class ParticipantEditItemWidgetBase : public QWidget
{
Q_OBJECT
public:
explicit ParticipantEditItemWidgetBase(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent = nullptr);
~ParticipantEditItemWidgetBase();
protected:
bool init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const bool addItem);
virtual void setData() = 0;
virtual void setDesignatorData() = 0;
public Q_SLOTS:
virtual void onAddItem() = 0;
virtual bool onEditItem() = 0;
void slotRetranslate();
protected Q_SLOTS:
void onFillTypeCb();
void onChangeMinMax();
void onSymbolSelection();
void onSymbolConfig();
void onChangeSymbol(const QString &sidc);
protected:
ParticipantManagement::TypeClass typeClassIdFromTypeId(int typeId) const;
bool isUnitType(int typeId) const;
virtual int editTypeId() const = 0;
virtual int currentPartyId() const = 0;
Q_SIGNALS:
void readyToClose();
protected:
bool m_asSupportService;
bool m_bEditMode;
int m_typeMinimum;
QString m_sidc;
QValidator *m_validator;
AdvancedSymbology::Gui::SymbolModificationDialogFrameless *m_symbolConfig;
AdvancedSymbology::SymbolResultWatcherQWidgetBase *m_symbolWatcher;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asbfc;
mutable QHash<qint32, ParticipantManagement::TypeClass> m_type2TypeClass;
LtsSession::LtsSession *m_session;
QSet<int> m_disabledTypeIds;
Ui::ParticipantEditItemWidgetBase *m_ui;
LOGGER_T m_logger;
};
} // namespace ParticipantManagement
@@ -0,0 +1,352 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParticipantEditItemWidgetBase</class>
<widget class="QWidget" name="ParticipantEditItemWidgetBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>710</width>
<height>245</height>
</rect>
</property>
<property name="windowTitle">
<string>setwindowtitle in source</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="2">
<widget class="QLabel" name="lbMinMaxEquipNr">
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<property name="text">
<string notr="true">[00000,00000]:</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QLabel" name="lbInfo">
<property name="text">
<string>Info:</string>
</property>
</widget>
</item>
<item row="1" column="7" colspan="2">
<widget class="LtsWidgets::LtsComboBox" name="cbType"/>
</item>
<item row="0" column="6">
<widget class="QLabel" name="lbClass">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Class:</string>
</property>
</widget>
</item>
<item row="0" column="7" colspan="2">
<widget class="LtsWidgets::LtsComboBox" name="cbTypeClass"/>
</item>
<item row="0" column="5">
<spacer name="spacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="lbEquipNo">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Equip. No.:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="lbSign">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Sign:</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QSpinBox" name="sbEquipNr">
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QToolButton" name="tbAssignment">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Assignment</string>
</property>
<property name="statusTip">
<string>Assignment</string>
</property>
<property name="text">
<string notr="true">-</string>
</property>
</widget>
</item>
<item row="4" column="3" colspan="2">
<widget class="QLineEdit" name="leInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QLabel" name="lblSymbol">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Symbol:</string>
</property>
</widget>
</item>
<item row="2" column="9">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="3" colspan="2">
<widget class="QLineEdit" name="leSign">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="lbType">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Type:</string>
</property>
</widget>
</item>
<item row="2" column="7">
<widget class="QToolButton" name="pbIcon">
<property name="minimumSize">
<size>
<width>60</width>
<height>60</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>60</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="iconSize">
<size>
<width>60</width>
<height>60</height>
</size>
</property>
</widget>
</item>
<item row="2" column="8">
<widget class="QToolButton" name="pbSymbolConfig">
<property name="text">
<string>Configure Symbol</string>
</property>
</widget>
</item>
<item row="1" column="3" colspan="2">
<widget class="QLineEdit" name="leTactIdent">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxLength">
<number>20</number>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QLabel" name="lbTactIdent">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Tactical Identifier:</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="lbDesignator">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Designator:</string>
</property>
</widget>
</item>
<item row="0" column="3" colspan="2">
<widget class="QLineEdit" name="leDesignator">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maxLength">
<number>8</number>
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="QLabel" name="lblExternal">
<property name="text">
<string>External:</string>
</property>
</widget>
</item>
<item row="3" column="7" colspan="2">
<widget class="QCheckBox" name="cbExternal">
<property name="text">
<string>HLA</string>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="QLabel" name="lblVerein">
<property name="text">
<string>Verein:</string>
</property>
</widget>
</item>
<item row="4" column="7">
<widget class="QLineEdit" name="leVerein"/>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>17</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>leDesignator</tabstop>
<tabstop>leTactIdent</tabstop>
<tabstop>sbEquipNr</tabstop>
<tabstop>tbAssignment</tabstop>
<tabstop>leSign</tabstop>
<tabstop>leInfo</tabstop>
<tabstop>cbTypeClass</tabstop>
<tabstop>cbType</tabstop>
<tabstop>pbIcon</tabstop>
<tabstop>pbSymbolConfig</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,314 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Participant Edit Model
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-05
*/
#pragma once
#include "participant_icon_model_base.h"
#include <ParticipantManagement/logger.h>
#include <Plugins/ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <nglwidgets/ngltreeitem.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <QSet>
class QTreeView;
namespace ParticipantManagement
{
class CheckedTreeItem;
class FiringUnitValidator;
//=============================================================================================================================
// PARTICIPANTEDITMODEL
//=============================================================================================================================
class PPMCOMMON_EXPORT ParticipantEditModel : public ParticipantIconModelBase
{
Q_OBJECT
public:
enum Columns
{
ColDesignator,
ColIdentifier,
ColTypeClass,
ColType,
ColEquipmentNumber,
ColParticipantId,
ColInfo,
ColSign
};
class CheckedTreeItem final : public NGLTreeItem
{
public:
using NGLTreeItem::NGLTreeItem;
ParticipantData participant;
bool bIsChecked = false;
};
ParticipantEditModel(QObject *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc);
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
bool canDropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent) const override;
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent) override;
Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; }
Qt::DropActions supportedDragActions() const override { return Qt::MoveAction; }
virtual bool onReinitModel(int partyId, const QSet<int> &checkedParticipants = QSet<int>(), Qt::CheckState cs = Qt::Checked);
bool insertRow(int row, const QModelIndex &parent, NGLTreeItem *item);
bool removeRow(int row, const QModelIndex &parent = QModelIndex());
bool isRowRemovable(const CheckedTreeItem *parentItem) const;
bool rowsCheckable() const { return m_bRowsAreCheckable; }
bool unitsSelectable() const { return m_bUnitsSelectable; }
int partyId() const { return m_partyId; }
void dataCommitted();
void processMissingSuperiorId();
void selectItemByParticipantId(int participantId,
const std::function<void(const QModelIndex &)> &selectItem,
const QModelIndex &parent = QModelIndex());
QModelIndexList getIndexesByParticipantIds(const std::vector<int32_t> &participantIds,
const QModelIndex &parent = QModelIndex()) const;
void setRowsCheckable(bool bCheckable);
void setUnitsSelectable(bool bSelectable) { m_bUnitsSelectable = bSelectable; }
bool setCheckStateForParticipants(const QSet<int> &checkedParticipants, Qt::CheckState cs);
ParticipantManagement::ParticipantData getParticipantData(const QModelIndex &idx) const;
std::vector<ParticipantData> participantData(bool bOnlyModified = true) const;
QSet<int> participantIds() const;
QSet<int> checkStateForParticipants(Qt::CheckState cs) const;
QVector<int> usedEquipmentNumbers() const;
CheckedTreeItem *privateData(const QModelIndex &index);
const CheckedTreeItem *privateData(const QModelIndex &index) const;
QModelIndex indexFromParticipantId(int participantId) const;
QString getHierarchyFromIndex(const QModelIndex &index) const;
protected:
void gatherParticipants(QHash<int, ParticipantData> &tmap,
QHash<int, QSet<int>> &parentId2id) const;
std::vector<ParticipantData> getChildrenOf(NGLTreeItem *item,
int parentId,
int hierarchyNumber,
bool bOnlyModifed,
int &highestModId) const;
bool updateChildrenOf(int parentId,
NGLTreeItem *parent,
const QHash<int, QSet<int>> &parentId2id,
const QHash<int, ParticipantData> &tmap);
void insertChildrenOf(int parentId,
NGLTreeItem *parent,
const QModelIndex &parentIdx,
const QHash<int, QSet<int>> &parentId2id,
const QHash<int, ParticipantData> &tmap,
const QSet<int> &checkedParticipants,
Qt::CheckState cs);
bool isParentOf(const NGLTreeItem *item, int participantId) const;
QSet<int> participantIds(NGLTreeItem *parentItem) const;
QSet<int> checkState(CheckedTreeItem *parentItem, Qt::CheckState cs) const;
QVector<int> usedEquipmentNumbers(NGLTreeItem *parentItem) const;
void setCheckState(CheckedTreeItem *parentItem, const QSet<int> &checkedParticipants, Qt::CheckState cs);
QModelIndex indexFromParticipantId(int participantId, const CheckedTreeItem *cti) const;
int participantIdFromItem(NGLTreeItem *item) const;
int equipmentNumberFromItem(NGLTreeItem *item) const;
CheckedTreeItem *searchParticipant(const NGLTreeItem *parentItem, int participantId) const;
NGLTreeItem *createItem(const QVariant &data, const QIcon &icon) const override;
QVariant getItemData(const NGLTreeItem *item) const override;
public slots:
int insertParticipant(const QModelIndex &parent, ParticipantData participantData, bool bNewParticipant);
int onInsertRow(const QModelIndex &parent, const ParticipantData &participantData);
bool onUpdateRow(const QModelIndex &index, const ParticipantData &participantData);
bool onDeleteRow(const QModelIndex &idx, bool isFirstItem = true);
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
signals:
void internalDataChanged();
protected:
int m_partyId;
bool m_bRowsAreCheckable;
bool m_bUnitsSelectable;
std::vector<ParticipantManagement::ParticipantData> m_dataToDelete;
QTimer *m_missingSuperiorIdTimer;
QSet<int> m_missingSuperiorId;
QSet<int> m_usedTypeIds;
QSet<TypeClass> m_usedTypeClassIds;
FiringUnitValidator *m_firingUnitValidator;
};
//=============================================================================================================================
// PARTICIPANTTREEFILTERPROXYMODEL
//=============================================================================================================================
class PPMCOMMON_EXPORT ParticipantTreeFilterProxyModel : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setAllowedTypes(const QSet<int> &allowedTypes);
void setSourceModel(QAbstractItemModel *sourceModel) override;
int partyId() const { return m_sourceModel ? m_sourceModel->partyId() : -1; }
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
bool filterTypeRecursive(const ParticipantEditModel::CheckedTreeItem *item) const;
#endif
private:
QSet<int> m_allowedTypes;
ParticipantEditModel *m_sourceModel{nullptr};
}; // class ParticipantTreeFilterProxyModel
//=============================================================================================================================
// PARTICIPANTTABLEFILTERPROXYMODEL
//=============================================================================================================================
/**
* @brief The ParticipantTableFilterProxyModel class enables a hierarchical tree model of
* participants to be treated like a flat table model.
*
* Important connect statements that must be implemented are:
* - LtsDataView::filterChanged -> onFilter()
* - LtsDataView::sortOrderChanged -> onSort()
* - ParticipantEditModel::internalDataChanged -> init()
* In order to keep the selection after sorting, LtsDataView::sortOrderChanged can be connected to
* another function that handles that and calls onSort() instead. Otherwise, after sorting, the same
* row will be selected with most likely a different tree item than the one selected before sorting.
*
* When using this model in parallel to a standard tree model, in order to have two views that are
* consistent with each other, additional connects and workarounds are necessary. Connects include:
* - LtsDataView::filterChanged -> some function that asserts consistency
* - LtsDataView::selectionChanged -> some function that asserts consistency
* An important workaround is required when the party is changed (s.
* ParticipantEdit::onPartyChanged).
*/
class PPMCOMMON_EXPORT ParticipantTableFilterProxyModel : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
public:
struct SortData
{
bool isActive{false};
int column{-1};
Qt::SortOrder order{Qt::DescendingOrder};
bool ascending() const
{
return order == Qt::AscendingOrder;
}
bool descending() const
{
return order == Qt::DescendingOrder;
}
QString toString()
{
QString str{QStringLiteral("active=")};
str += isActive ? QStringLiteral("true") : QStringLiteral("false");
str += QStringLiteral(", column=") + QString::number(column) + QStringLiteral(", order=");
str += order == Qt::DescendingOrder ? QStringLiteral("Descending") : QStringLiteral("Ascending");
return str;
}
}; // struct SortData
explicit ParticipantTableFilterProxyModel(QObject *parent = nullptr);
void init();
void resetMapping();
void disableSorting() { m_sortData.isActive = false; }
void setSourceModel(QAbstractItemModel *sourceModel) override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
QModelIndex sibling(int row, int column, const QModelIndex &idx) const override;
bool isFilterActive() const { return m_isFilterActive; }
bool hasChildren(const QModelIndex &parent) const override;
SortData sortData() const { return m_sortData; }
protected:
bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool filterAcceptsRowInternal(int sourceRow, const QModelIndex &sourceParent) const;
private:
/**
* @brief mapTreeToTable initializes m_mapFromSource and m_mapToSource. Do NOT USE this method
* directly! Call init() instead.
* @param parent index of the parent in the source model
* @param row parent's child at rowth position
* @return current row count
*/
int mapTreeToTable(const QModelIndex &parent = QModelIndex(), int row = 0);
public slots:
void onFilter();
void onSort(int column, Qt::SortOrder order);
private:
QHash<int, QModelIndex> m_mapToSource;
QHash<QModelIndex, int> m_mapFromSource;
QHash<int, QModelIndex> m_mapToSourceInternal;
QHash<QModelIndex, int> m_mapFromSourceInternal;
QHash<int, QModelIndex> m_mapToSourceFiltered;
QHash<QModelIndex, int> m_mapFromSourceFiltered;
QVector<int> m_sortMap;
bool m_isFilterActive{false};
SortData m_sortData;
ParticipantEditModel *m_sourceModel{nullptr};
NGL::INGLLogger &m_logger;
}; // class ParticipantTableFilterProxyModel
} //namespace ParticipantManagement
Q_DECLARE_METATYPE(ParticipantManagement::ParticipantData)
@@ -0,0 +1,140 @@
/**
* @RDE_HEADER@
* The FiringUnitValidator regulates the rules for firing units
* $Id: participant_dis_helper.h 37747 2017-12-08 08:07:01Z ehrlicher $
* $HeadURL: svn://10.196.0.54/TDS/branches/product/features/24_vulcano/Lts/Plugins/ParticipantManagement/Gui/Common/participant_dis_helper.h $
* $Author: ehrlicher $
* Created by Hannes Fritsche, ESZS, 2024-03-06
*/
#include "participant_firing_unit_validator.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QVariant>
#include <LtsUtilsSettings/settings.h>
namespace ParticipantManagement
{
FiringUnitValidator::FiringUnitValidator(const std::shared_ptr<Interface::Dtc> &ppmDtc, QObject *parent)
: QObject(parent)
, m_ppmDtc(ppmDtc)
{
fetchArtilleryTypes();
}
QSet<int> FiringUnitValidator::artilleryParticipantTypeIds() const { return m_artilleryParticipantTypeIds; }
QVector<Type> FiringUnitValidator::artilleryParticipantTypes() const
{
QVector<Type> artilleryParticipantTypes;
artilleryParticipantTypes.reserve(m_artilleryParticipantTypeIds.size());
std::function<void(const Type &)> getArtilleryType = [this, &artilleryParticipantTypes](const Type &type)
{
if (!m_artilleryParticipantTypeIds.contains(type.id()))
return;
artilleryParticipantTypes.append(type);
};
m_ppmDtc->types(getArtilleryType);
return artilleryParticipantTypes;
}
QSet<int> FiringUnitValidator::firingUnitTypeIds() const { return m_firingUnitTypeIds; }
uint FiringUnitValidator::maxParticipantsPerFiringUnit()
{
LtsUtils::ProjectSettings *settings = LtsUtils::ProjectSettings::getInstance();
return settings->value(QStringLiteral("PPM"), QStringLiteral("maxParticipantsPerFiringUnit"), 8).toUInt();
}
int FiringUnitValidator::getTypeId(const ParticipantEditModel *model, const QModelIndex &index) const
{
if (!model)
return -1;
const ParticipantData data = model->getParticipantData(index);
return data.typeId();
}
int FiringUnitValidator::getTypeId(const ParticipantTemplateEditModel *model, const QModelIndex &index) const
{
if (!model)
return -1;
const TemplateData data = model->getTemplateData(index);
return data.typeId();
}
void FiringUnitValidator::fetchArtilleryTypes()
{
m_firingUnitTypeIds.clear();
m_artilleryParticipantTypeIds.clear();
std::function<void(const ParticipantManagement::Type &type)> getArtilleryTypes = [this](const ParticipantManagement::Type &type)
{
if (!isArtilleryType(type))
return;
if (type.typeClass() == ParticipantManagement::TypeClass::inner_enum::Unit)
m_firingUnitTypeIds.insert(type.id());
else
m_artilleryParticipantTypeIds.insert(type.id());
};
m_ppmDtc->types(getArtilleryTypes);
}
bool FiringUnitValidator::isArtilleryType(int typeId) const { return m_ppmDtc->isArtilleryType(typeId) && !m_ppmDtc->isAdlerVerbund(typeId); }
bool FiringUnitValidator::isArtilleryType(const Type &type) const { return isArtilleryType(type.id()); }
bool FiringUnitValidator::isArtilleryUnit(int typeId) const
{
if (!isArtilleryType(typeId))
return false;
const ParticipantManagement::Type &type = m_ppmDtc->type(typeId);
return type.typeClass() == ParticipantManagement::TypeClass::Unit;
}
bool FiringUnitValidator::isArtilleryWeaponSystem(int typeId) const
{
if (!isArtilleryType(typeId))
return false;
const ParticipantManagement::Type &type = m_ppmDtc->type(typeId);
return type.typeClass() == ParticipantManagement::TypeClass::WeaponSystem;
}
bool FiringUnitValidator::isSameGearClassArtillery(int typeIdA, int typeIdB) const
{
const ProjectDataManagement::GearClass::type gearClassA = getGearClassType(typeIdA);
if (gearClassA == ProjectDataManagement::GearClass::Unknown)
return false;
const ProjectDataManagement::GearClass::type gearClassB = getGearClassType(typeIdB);
return gearClassA == gearClassB;
}
ProjectDataManagement::GearClass::type FiringUnitValidator::getGearClassType(int typeId) const
{
const Type type = m_ppmDtc->type(typeId);
const QJsonDocument properties = QJsonDocument::fromJson(QByteArray::fromStdString(type.properties()));
const QJsonObject propertiesObject = properties.object();
const int gearClassId = propertiesObject.value(QStringLiteral("gearClassId")).toInt(ProjectDataManagement::GearClass::Unknown);
return static_cast<ProjectDataManagement::GearClass::type>(gearClassId);
}
} // namespace ParticipantManagement
@@ -0,0 +1,152 @@
/**
* @RDE_HEADER@
* The FiringUnitValidator regulates the rules for firing units
* $Id: participant_dis_helper.h 37747 2017-12-08 08:07:01Z ehrlicher $
* $HeadURL: svn://10.196.0.54/TDS/branches/product/features/24_vulcano/Lts/Plugins/ParticipantManagement/Gui/Common/participant_dis_helper.h $
* $Author: ehrlicher $
* Created by Hannes Fritsche, ESZS, 2024-03-06
*/
#pragma once
#include <QObject>
#include <memory>
#include <ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <ParticipantManagement/ppm_dtc.h>
#include "participant_edit_model.h"
#include "participant_template_edit_model.h"
namespace ParticipantManagement
{
namespace Interface
{
class Dtc;
} //namespace Interface
class Participant;
class PPMCOMMON_EXPORT FiringUnitValidator : public QObject
{
public:
enum FiringUnitRestriction: short
{
NO_RESTRICTION = 0b0000000000000000,
NO_TYPE_CHANGE_ALLOWED = 0b0000000000000001,
IS_AT_MAX_CAPACITY = 0b0000000000000010,
ONLY_SAME_GEAR_CLASS_ARTILLERY_ALLOWED = 0b0000000000000100,
NO_FIRING_UNIT_TYPE_ALLOWED = 0b0000000000001000,
NO_ARTILLERY_PARTICIPANTS_ALLOWED = 0b0000000000010000
};
Q_DECLARE_FLAGS(FiringUnitRestrictions, FiringUnitRestriction)
explicit FiringUnitValidator(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc, QObject *parent = nullptr);
template <typename T>
bool hasUnitCapacities(T *model, const QModelIndex &unitIndex) const
{
FiringUnitRestrictions restrictions = getRestrictions(model, unitIndex);
return !restrictions.testFlag(IS_AT_MAX_CAPACITY);
}
template<typename T>
ProjectDataManagement::GearClass::type getGearClassType(const T *model, const QModelIndex &participantIndex) const
{
if (!model)
return {};
const int typeId = getTypeId(model, participantIndex);
return getGearClassType(typeId);
}
template<typename T>
bool isAdler(const T *model, const QModelIndex &participantIndex) const
{
if (!model)
return {};
const int typeId = getTypeId(model, participantIndex);
return m_ppmDtc->isAdlerType(typeId);
}
template <typename T>
FiringUnitRestrictions getRestrictions(const T *model, const QModelIndex &participantIndex) const
{
if (!model)
return NO_RESTRICTION;
const int typeId = getTypeId(model, participantIndex);
if (!isArtilleryType(typeId))
{
if (!model->hasChildren(participantIndex)) // since there are only children allowed on units, we have a participant here
return NO_ARTILLERY_PARTICIPANTS_ALLOWED;
// we do not allow a unit to be a firing unit if there are non artillery children under it
// and we do not allow to add artillery participants to a non artillery unit
return {NO_FIRING_UNIT_TYPE_ALLOWED | NO_ARTILLERY_PARTICIPANTS_ALLOWED};
}
if (!m_firingUnitTypeIds.contains(typeId)) // we have an artillery participant
return NO_TYPE_CHANGE_ALLOWED;
// else we have a firing unit
if (!model->hasChildren(participantIndex))
return ONLY_SAME_GEAR_CLASS_ARTILLERY_ALLOWED;
FiringUnitRestrictions restrictions = NO_TYPE_CHANGE_ALLOWED;
uint childCount = static_cast<uint>(model->rowCount(participantIndex));
if (childCount >= maxParticipantsPerFiringUnit())
restrictions.setFlag(IS_AT_MAX_CAPACITY);
return restrictions;
}
template <typename T>
Type getAllowedType(T *model, const QModelIndex &participantIndex) const
{
if (!model)
return Type();
FiringUnitRestrictions restrictions = getRestrictions(model, participantIndex);
if (restrictions.testFlag(NO_TYPE_CHANGE_ALLOWED) && model->hasChildren(participantIndex))
{
// since we do now allow mixed types in firing units, the type of the first child is returned
const QModelIndex childIndex = model->index(0, 0, participantIndex);
const int typeId = getTypeId(model, childIndex);
return m_ppmDtc->type(typeId);
}
return Type();
}
QVector<Type> artilleryParticipantTypes() const;
QSet<int> artilleryParticipantTypeIds() const;
QSet<int> firingUnitTypeIds() const;
static uint maxParticipantsPerFiringUnit();
bool isArtilleryType(int typeId) const;
bool isArtilleryUnit(int typeId) const;
bool isArtilleryWeaponSystem(int typeId) const;
bool isSameGearClassArtillery(int typeIdA, int typeIdB) const;
ProjectDataManagement::GearClass::type getGearClassType(int typeId) const;
private: // methods
int getTypeId(const ParticipantEditModel *model, const QModelIndex &index) const;
int getTypeId(const ParticipantTemplateEditModel *model, const QModelIndex &index) const;
void fetchArtilleryTypes();
bool isArtilleryType(const ParticipantManagement::Type &type) const;
private: // attributes
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
QSet<int> m_firingUnitTypeIds;
QSet<int> m_artilleryParticipantTypeIds;
}; // namespace FiringUnitValidator
} // namespace ParticipantManagement
@@ -0,0 +1,177 @@
/**
* @RDE_HEADER@
* A small helper class to provide icon rendering capabilities for NGLTreeModels
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-10-26
*/
#include "participant_icon_model_base.h"
#include <ParticipantManagement/ppm_translation.h>
#include <Plugins/AdvancedSymbology/asb_data_plugin_interface.h>
#include <nglwidgets/ngltreeitem.h>
#include <QHash>
#include <QIcon>
#include <QPointer>
#include <QTimer>
namespace ParticipantManagement
{
ParticipantIconModelBase::ParticipantIconModelBase(const std::shared_ptr<Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc,
const QStringList &hdr,
NGLTreeItem *rootItem,
QObject *parent,
NGL::INGLLogger &logger)
: NGLTreeModel(parent, rootItem, hdr)
, m_dtc(ppmDtc)
, m_asb(asbIfc)
, m_partyRole(AdvancedSymbology::Role::Unknown)
, m_logger(logger)
{
this->setMimeDataWithIcon(false); // do not serialize icons, they are repaint on drop again (with the new party color)
connect(ppmDtc.get(), &ParticipantManagement::Interface::Dtc::typeChanged,
this, &ParticipantIconModelBase::onTypeChanged);
auto cbTypes = [this](const ParticipantManagement::Type &type)
{
onTypeChanged(type, DataModification::eAdded);
};
ppmDtc->types(cbTypes);
}
void ParticipantIconModelBase::onTypeChanged(const ParticipantManagement::Type &data, DataModification modType)
{
if (modType == DataModification::eRemoved)
{
m_types.remove(data.id());
return;
}
m_types[data.id()] = data;
}
// type handling
ParticipantManagement::TypeClass ParticipantIconModelBase::typeClassIdFromTypeId(int typeId) const
{
return m_types.value(typeId).typeClass();
}
QString ParticipantIconModelBase::typeClassStringFromTypeId(int typeId) const
{
auto it = m_types.find(typeId);
if (it == m_types.end())
return QString();
return ParticipantManagement::toString(it.value().typeClass());
}
bool ParticipantIconModelBase::isUnitType(int typeId) const
{
const ParticipantManagement::TypeClass typeClassId = typeClassIdFromTypeId(typeId);
return typeClassId == ParticipantManagement::TypeClass::Unit ||
typeClassId == ParticipantManagement::TypeClass::SupportUnit;
}
// symbol handling
void ParticipantIconModelBase::tryRenderSymbol(const QString &symbol, NGLTreeItem *item)
{
if ( (item) && (m_asb) && (!symbol.isEmpty()) )
{
AdvancedSymbology::SymbolDataToRender symDataToRender(symbol);
symDataToRender.role = m_partyRole;
DEBUG_LOG(m_logger) << "Rendering symbol '" << symbol << "' for item " << item;
if (m_partyColor.isValid())
{
symDataToRender.fillColor = m_partyColor;
symDataToRender.fillColorReplace = true;
}
else
{
// User-Defined Symbols (XML) need fillColor:
symDataToRender.fillColor = AdvancedSymbology::SymbolDataToRender::unknownColor();
symDataToRender.fillColorReplace = true;
}
QSharedPointer<AdvancedSymbology::SymbolResult> symRes = m_asb->findImage(symDataToRender);
AdvancedSymbology::SymbolResult *symResPtr = symRes.data();
if (!symResPtr)
{
WARNING_LOG(m_logger) << "Can not render symbol for sidc '" << symbol << "'";
return;
}
auto it = m_symbolResultMapping.find(symResPtr);
if (it == m_symbolResultMapping.end())
{
if (symResPtr->isResultReady())
{
item->setIcon(QIcon(QPixmap::fromImage(symRes->symbolImage().image())));
}
else
{
SymbolResultData symResData;
symResData.result = symRes;
symResData.treeItems.push_back(item);
m_symbolResultMapping.insertMulti(symResPtr, symResData);
QPointer<AdvancedSymbology::SymbolResult> qPointer(symResPtr);
// queued because the object is destroyed inside symbolRendered() due to QSharedPointer
connect(symResPtr, &AdvancedSymbology::SymbolResult::resultReadyInternal,
this, [this, qPointer]() { symbolRendered(qPointer); }, Qt::QueuedConnection);
}
}
else
{
SymbolResultData &srd = it.value();
srd.treeItems.push_back(item);
}
}
}
void ParticipantIconModelBase::symbolRendered(AdvancedSymbology::SymbolResult *symbolResult)
{
if ( (!symbolResult) || (!symbolResult->isResultReady()) )
return;
auto it = m_symbolResultMapping.constFind(symbolResult);
if (it == m_symbolResultMapping.constEnd())
return;
const SymbolResultData &symResData = it.value();
const QIcon icon(QPixmap::fromImage(symResData.result->symbolImage().image()));
for (NGLTreeItem *item : symResData.treeItems)
{
DEBUG_LOG(m_logger) << "Symbol for " << item << " ready";
// we need to search for srd.treeItem because it may be already destroyed
if (!updateIcon(QModelIndex(), item, icon))
WARNING_LOG(m_logger) << "updateIcon failed for item " << item;
}
m_symbolResultMapping.erase(it);
}
bool ParticipantIconModelBase::updateIcon(const QModelIndex &currentIndex, NGLTreeItem *itemToUpdate, const QIcon &icon)
{
const NGLTreeItem *currentItem = privateData(currentIndex);
if (currentItem == itemToUpdate)
{
itemToUpdate->setIcon(icon);
emit dataChanged(currentIndex, currentIndex, { Qt::DecorationRole });
return true;
}
const int childCount = currentItem->childCount();
for (int row = 0; row < childCount; ++row)
{
const QModelIndex childIndex = index(row, 0, currentIndex);
if (updateIcon(childIndex, itemToUpdate, icon))
return true;
}
return false;
}
} // namespace ParticipantManagement
@@ -0,0 +1,84 @@
/**
* @RDE_HEADER@
* A small helper class to provide icon rendering capabilities for NGLTreeModels
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-10-26
*/
#pragma once
#include <Plugins/ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <nglwidgets/ngltreemodel.h>
#include <QColor>
#include <QSharedPointer>
namespace LtsSession
{
class LtsSessionDataDds;
}
namespace AdvancedSymbology
{
class ForeignDataInterface;
class SymbolResult;
enum class Role;
}
namespace NGL
{
class INGLLogger;
}
namespace ParticipantManagement
{
class PPMCOMMON_EXPORT ParticipantIconModelBase : public NGLTreeModel
{
Q_OBJECT
protected:
ParticipantIconModelBase(const std::shared_ptr<Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc,
const QStringList &hdr,
NGLTreeItem *rootItem,
QObject *parent,
NGL::INGLLogger &logger);
// type handling
ParticipantManagement::TypeClass typeClassIdFromTypeId(int typeId) const;
QString typeClassStringFromTypeId(int typeId) const;
bool isUnitType(int typeId) const;
// symbol handling
void tryRenderSymbol(const QString &symbol, NGLTreeItem *item);
void symbolRendered(AdvancedSymbology::SymbolResult *symbolResult);
bool updateIcon(const QModelIndex &currentIndex, NGLTreeItem *itemToUpdate, const QIcon &icon);
protected:
void onTypeChanged(const ParticipantManagement::Type &data, DataModification modType);
protected:
// misc
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
// type handling
QHash<qint32, ParticipantManagement::Type> m_types;
// symbol handling
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asb;
struct SymbolResultData
{
QSharedPointer<AdvancedSymbology::SymbolResult> result;
QVector<NGLTreeItem *> treeItems;
};
QHash<AdvancedSymbology::SymbolResult *, SymbolResultData> m_symbolResultMapping;
AdvancedSymbology::Role m_partyRole;
QColor m_partyColor;
NGL::INGLLogger &m_logger;
};
} // namespace ParticipantManagement
@@ -0,0 +1,100 @@
/**
* @RDE_HEADER@
* OperatorManagement - Operator Change Password (Frameless) Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Malte Diers, SLSE, 2017-10-11
*/
#include "participant_search_modal.h"
#include "ui_participant_search_modal.h"
#include <LtsSession/lts_session_data_dds.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
namespace ParticipantManagement
{
ParticipantSearchModal::ParticipantSearchModal(QWidget *parent)
: LtsWidgets::LtsFramelessDialog(parent)
, m_ui(new Ui::ParticipantSearchModal)
{
m_ui->setupUi(this);
connect(m_ui->pbCancel, &QPushButton::clicked, this, &ParticipantSearchModal::reject);
connect(m_ui->pbOk, &QPushButton::clicked, this, &ParticipantSearchModal::onOkay);
}
ParticipantSearchModal::~ParticipantSearchModal()
{
delete m_ui;
}
bool ParticipantSearchModal::init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc)
{
if (!dtc)
return false;
auto cb = [this](const Participant &data)
{
if (!data.equipmentNumber().is_set())
return;
const int newEqId = data.equipmentNumber().get();
m_partId2EqId[data.id()] = newEqId;
m_eqId2PartId[newEqId] = data.id();
};
dtc->participants(cb);
connect(dtc.get(), &Interface::Dtc::participantChanged,
this, &ParticipantSearchModal::onParticipantChanged);
return true;
}
void ParticipantSearchModal::showEvent(QShowEvent *e)
{
LtsWidgets::LtsFramelessDialog::showEvent(e);
m_ui->leEquipmentNo->clear();
m_ui->leEquipmentNo->setFocus();
}
void ParticipantSearchModal::onOkay()
{
int participantId = m_eqId2PartId.value(m_ui->leEquipmentNo->text().toInt());
if (participantId > 0)
emit participantSelected(participantId);
close();
}
void ParticipantSearchModal::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
{
const int newEqId = data.equipmentNumber().is_set() ? data.equipmentNumber().get() : 0;
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
{
const int oldEqId = m_partId2EqId.value(data.id());
if (oldEqId == newEqId)
return;
if (oldEqId != 0)
m_eqId2PartId.remove(oldEqId);
if (newEqId == 0)
return;
m_partId2EqId[data.id()] = newEqId;
m_eqId2PartId[newEqId] = data.id();
break;
}
case DataModification::eRemoved:
{
const int oldEqId = m_partId2EqId.value(data.id());
m_partId2EqId.remove(data.id());
if (oldEqId != 0)
m_eqId2PartId.remove(oldEqId);
}
}
}
} // namespace
@@ -0,0 +1,55 @@
/**
* @RDE_HEADER@
* ParticipantManagement - Show ParticipantInfo by Equipment No
* $Id$
* $HeadURL$
* $Author$
* Created by Malte Diers, NLSE, 2018-04-20
*/
#pragma once
#include <Plugins/ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <QMap>
#include <memory>
enum class DataModification;
namespace Ui
{
class ParticipantSearchModal;
}
namespace ParticipantManagement
{
class Participant;
namespace Interface
{
class Dtc;
}
class PPMCOMMON_EXPORT ParticipantSearchModal : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
explicit ParticipantSearchModal(QWidget *parent = nullptr);
~ParticipantSearchModal();
bool init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc);
void showEvent(QShowEvent *e) override;
private slots:
void onOkay();
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
signals:
void participantSelected(int participantId);
private:
QMap<int,int> m_eqId2PartId;
QMap<int,int> m_partId2EqId;
Ui::ParticipantSearchModal *m_ui;
};
} // namespace
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParticipantSearchModal</class>
<widget class="LtsWidgets::LtsFramelessDialog" name="ParticipantSearchModal">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>188</width>
<height>79</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pbOk">
<property name="text">
<string>OK</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbCancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="leEquipmentNo">
<property name="maxLength">
<number>5</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblEquipmentNo">
<property name="text">
<string>Equipment No.:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsFramelessDialog</class>
<extends>QDialog</extends>
<header>LtsWidgets/lts_frameless_dialog.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,359 @@
/**
* @RDE_HEADER@
* HMI Plugin for MeteoDataManagement - Meteo Data Overview Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-05
*/
#include "participant_template_edit_item.h"
#include "ui_participant_edit_item_widget_base.h"
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <ParticipantManagement/ppm_translation.h>
#include <QStandardItemModel>
#include <LtsSession/lts_session_manager.h>
namespace ParticipantManagement
{
//
// ParticipantTemplateEditItemWidget
//
ParticipantTemplateEditItemWidget::ParticipantTemplateEditItemWidget(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent)
: ParticipantEditItemWidgetBase(asSupportService, session, parent)
{
m_ui->lbInfo->hide();
m_ui->leInfo->hide();
m_ui->lbSign->hide();
m_ui->leSign->hide();
m_ui->tbAssignment->hide();
}
bool ParticipantTemplateEditItemWidget::init(const QModelIndex &workingIndex,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const ParticipantManagement::TemplateData &data,
const bool addItem)
{
m_workingIndex = workingIndex;
m_editData = data;
m_bEditMode = m_editData.typeId() > 0;
return ParticipantEditItemWidgetBase::init(dtc, ppmGuiCbxIfc, asb, addItem);
}
void ParticipantTemplateEditItemWidget::setFiringUnitRestrictions(ParticipantTemplateEditModel *model, bool isEdit, const FiringUnitValidator::FiringUnitRestrictions &restrictions, FiringUnitValidator *firingUnitValidator, const int &unitGearClassType)
{
if (!firingUnitValidator || !model)
return;
if (restrictions.testFlag(FiringUnitValidator::NO_TYPE_CHANGE_ALLOWED))
{
m_ui->cbTypeClass->setDisabled(true);
m_ui->cbType->setDisabled(true);
if (isEdit) // if we are in edit mode (and not add), type and typeclass are already set where as want them to be
return;
const Type allowedType = firingUnitValidator->getAllowedType(model, m_workingIndex);
if (allowedType == Type())
return;
m_ui->cbTypeClass->setCurrentIndex(m_ui->cbTypeClass->findData(allowedType.typeClass().underlying()));
m_ui->cbType->setCurrentIndex(m_ui->cbType->findData(allowedType.id()));
return;
}
if (restrictions.testFlag(FiringUnitValidator::ONLY_SAME_GEAR_CLASS_ARTILLERY_ALLOWED))
{
if (isEdit)
return;
const QVector<Type> allowedTypes = firingUnitValidator->artilleryParticipantTypes();
m_ui->cbTypeClass->setDisabled(true);
m_ui->cbTypeClass->setCurrentIndex(m_ui->cbTypeClass->findData(allowedTypes.at(0).typeClass().underlying()));
QSignalBlocker typeSignalBlocker(m_ui->cbType);
m_ui->cbType->clear();
std::function<bool(Type)> funcIsSameGearType = [=](const Type &t)
{
if (m_isAdler)
return m_dtc->isAdlerType(t.id()) && (firingUnitValidator->getGearClassType(t.id()) == unitGearClassType);
return firingUnitValidator->getGearClassType(t.id()) == unitGearClassType;
};
QVector<Type>::ConstIterator typeIterator = std::find_if(allowedTypes.begin(), allowedTypes.end(), funcIsSameGearType);
if(typeIterator != allowedTypes.end())
{
m_ui->cbType->setDisabled(true);
m_ui->cbType->addItem(ParticipantManagement::trTypeName(typeIterator->name()), typeIterator->id());
}
else
{
for (const Type &currentType : allowedTypes)
m_ui->cbType->addItem(ParticipantManagement::trTypeName(currentType.name()), currentType.id());
m_ui->cbType->model()->sort(0);
}
m_ui->cbType->setCurrentIndex(0);
return;
}
if (isEdit && restrictions.testFlag(FiringUnitValidator::NO_FIRING_UNIT_TYPE_ALLOWED))
{
m_disabledTypeIds.unite(firingUnitValidator->firingUnitTypeIds());
QStandardItemModel *cbTypeModel = qobject_cast<QStandardItemModel *>(m_ui->cbType->model());
if (cbTypeModel == nullptr)
return;
for (int row = 0; row < m_ui->cbType->count(); ++row)
{
QStandardItem *item = cbTypeModel->item(row);
int typeId = item->data(Qt::UserRole).toInt();
if (!m_disabledTypeIds.contains(typeId))
continue;
item->setFlags(Qt::NoItemFlags);
}
}
if (restrictions.testFlag(FiringUnitValidator::NO_ARTILLERY_PARTICIPANTS_ALLOWED))
{
m_disabledTypeIds.unite(firingUnitValidator->artilleryParticipantTypeIds());
QStandardItemModel *cbTypeModel = qobject_cast<QStandardItemModel *>(m_ui->cbType->model());
if (cbTypeModel == nullptr)
return;
for (int row = 0; row < m_ui->cbType->count(); ++row)
{
QStandardItem *item = cbTypeModel->item(row);
int typeId = item->data(Qt::UserRole).toInt();
if (!m_disabledTypeIds.contains(typeId))
continue;
item->setFlags(Qt::NoItemFlags);
}
}
}
void ParticipantTemplateEditItemWidget::setData()
{
m_ui->leDesignator->setText(QString::fromStdString(m_editData.designator()));
m_ui->leTactIdent->setText(QString::fromStdString(m_editData.tacticalIdentifier()));
Type type = m_dtc->type(m_editData.typeId());
m_ui->cbTypeClass->setCurrentIndex(m_ui->cbTypeClass->findData(type.typeClass().underlying()));
m_ui->cbType->setCurrentIndex(m_ui->cbType->findData(type.id()));
// set EqNr after all cbx change
m_ui->sbEquipNr->setValue(m_editData.equipmentNumber());
// Not templates for Externals.
m_ui->cbExternal->hide();
m_ui->cbExternal->setChecked(false);
m_ui->lblExternal->hide();
// nach den Setzen des Typs, sonst wird Default Typ-Symbol benutzt...
onChangeSymbol(QString::fromStdString(m_editData.symbol()));
}
void ParticipantTemplateEditItemWidget::setDesignatorData()
{
m_ui->leDesignator->setText(QString::fromStdString(m_editData.designator()));
m_ui->leTactIdent->setText(QString::fromStdString(m_editData.tacticalIdentifier()));
}
void ParticipantTemplateEditItemWidget::onAddItem()
{
ParticipantManagement::TemplateData newTemplateParticipant;
newTemplateParticipant.designator() = m_ui->leDesignator->text().toStdString();
newTemplateParticipant.tacticalIdentifier() = m_ui->leTactIdent->text().toStdString();
newTemplateParticipant.symbol(m_sidc.toStdString());
newTemplateParticipant.typeId(m_ui->cbType->currentData().toInt());
const int equipNo = m_ui->sbEquipNr->value();
if (!checkEquipNo(equipNo))
return;
newTemplateParticipant.equipmentNumber(equipNo);
DEBUG_LOG(m_logger) << "adding item: " << newTemplateParticipant;
emit addItem(m_workingIndex, newTemplateParticipant);
if (equipNo > 0)
m_ui->sbEquipNr->setValue(equipNo + 1);
}
bool ParticipantTemplateEditItemWidget::onEditItem()
{
m_editData.designator() = m_ui->leDesignator->text().toStdString();
m_editData.tacticalIdentifier() = m_ui->leTactIdent->text().toStdString();
m_editData.symbol(m_sidc.toStdString());
m_editData.typeId(m_ui->cbType->currentData().toInt());
//eqNr is set
const int equipNo = m_ui->sbEquipNr->value();
if (!checkEquipNo(equipNo))
return false;
m_editData.equipmentNumber(equipNo);
DEBUG_LOG(m_logger) << "edit item: " << m_editData;
emit updateItem(m_workingIndex, m_editData);
emit readyToClose();
return true;
}
bool ParticipantTemplateEditItemWidget::checkEquipNo(int equipNo)
{
if (equipNo > 0)
{
if (equipNo < m_typeMinimum)
{
//eqNr is below minimum!
m_ui->lbMinMaxEquipNr->setText(QStringLiteral("<span style=\"color:#aa0000;\">%1</span>").arg(equipNo));
return false;
}
if (m_editData.equipmentNumber() != equipNo)
{
//eqNr is in range (max is set in sp directly)
if (m_usedEquipmentNumbers.contains(equipNo))
{
const QString msg = tr("The equipment number is already used by another participant in this template");
LtsWidgets::LtsMessageDialog::showMessage(this,
msg,
tr("Equipment Number already in use"));
return false;
}
}
}
return true;
}
//
// ParticipantTemplateEditItem
//
ParticipantTemplateEditItem::ParticipantTemplateEditItem(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent)
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
, m_editItemWidget(new ParticipantTemplateEditItemWidget(asSupportService, session, parent))
, m_buttonBox(new LtsWidgets::LtsDialogButtonBox(this))
{
//HACK as close is not allowed directly
connect(m_buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this, &ParticipantTemplateEditItem::close);
connect(m_editItemWidget, &ParticipantTemplateEditItemWidget::readyToClose, this, &ParticipantTemplateEditItem::close);
//connect to other signals
connect(m_editItemWidget, &ParticipantTemplateEditItemWidget::addItem, this, &ParticipantTemplateEditItem::addItem);
connect(m_editItemWidget, &ParticipantTemplateEditItemWidget::updateItem, this, &ParticipantTemplateEditItem::updateItem);
//hide ok and aplly
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->hide();
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->hide();
}
bool ParticipantTemplateEditItem::init(const QModelIndex &workingIndex,
const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const TemplateData &data,
const bool addItem)
{
if (!m_editItemWidget->init(workingIndex, dtc, ppmGuiCbxIfc, asb, data, addItem))
return false;
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(m_editItemWidget);
layout->addWidget(m_buttonBox);
setLayout(layout);
if (data.typeId() > 0)
{
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, m_editItemWidget, &ParticipantTemplateEditItemWidget::onEditItem);
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setText(tr("Apply"));
}
else
{
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, m_editItemWidget, &ParticipantTemplateEditItemWidget::onAddItem);
}
return true;
}
void ParticipantTemplateEditItem::setFiringUnitRestrictions(ParticipantTemplateEditModel *model, bool isEdit, const FiringUnitValidator::FiringUnitRestrictions &restrictions, FiringUnitValidator *firingUnitValidator, const int unitGearClassType)
{
if (restrictions == FiringUnitValidator::NO_RESTRICTION)
return;
if (restrictions.testFlag(FiringUnitValidator::IS_AT_MAX_CAPACITY))
m_buttonBox->getButton(LtsWidgets::DialogButton::Add)->setDisabled(true);
if (m_editItemWidget)
m_editItemWidget->setFiringUnitRestrictions(model, isEdit, restrictions, firingUnitValidator, unitGearClassType);
}
//
// ParticipantTemplateEditItemTab
//
ParticipantTemplateEditItemTab::ParticipantTemplateEditItemTab(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_editItemWidget(new ParticipantTemplateEditItemWidget(asSupportService, session, this))
{
connect(m_editItemWidget, &ParticipantTemplateEditItemWidget::updateItem, this, &ParticipantTemplateEditItemTab::updateItem);
connect(m_editItemWidget, &ParticipantTemplateEditItemWidget::readyToClose, this, [this]()
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Close)->click();
});
}
bool ParticipantTemplateEditItemTab::init(const QModelIndex &workingIndex,
const std::shared_ptr<Interface::Dtc> &dtc,
const std::shared_ptr<ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const TemplateData &data)
{
if (!m_editItemWidget->init(workingIndex, dtc, ppmGuiCbxIfc, asb, data))
return false;
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(m_editItemWidget);
setLayout(layout);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, m_editItemWidget, &ParticipantTemplateEditItemWidget::onEditItem);
return true;
}
void ParticipantTemplateEditItemTab::retranslate()
{
// lupdate doesn't like translate(tr("foo")) ...
const QString txt(tr("Participant Item Edit"));
translate(txt);
}
bool ParticipantTemplateEditItemTab::apply()
{
return m_editItemWidget->onEditItem();
}
} //namespace ParticipantManagement
@@ -0,0 +1,118 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Template Edit Item Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-05
*/
#pragma once
#include "participant_edit_item_widget_base.h"
#include <ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include "participant_firing_unit_validator.h"
#include <LtsWidgets/lts_frameless_dialog.h>
#include <LtsWidgets/lts_dialog.h>
#include <LtsWidgets/lts_dialog_button_box.h>
#include <QModelIndex>
namespace ParticipantManagement
{
class ParticipantTemplateEditItemWidget final : public ParticipantEditItemWidgetBase
{
Q_OBJECT
public:
explicit ParticipantTemplateEditItemWidget(bool asSupportService,
LtsSession::LtsSession *session,
QWidget *parent = nullptr);
bool init(const QModelIndex &workingIndex,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const TemplateData &data,
const bool addItem = false);
void setUsedEquipmentNumbers(const QSet<int> &usedEquipmentNumbers) { m_usedEquipmentNumbers = usedEquipmentNumbers; }
void setFiringUnitRestrictions(ParticipantTemplateEditModel *model, bool isEdit, const FiringUnitValidator::FiringUnitRestrictions &restrictions, FiringUnitValidator *firingUnitValidator, const int &unitGearClassTyp);
void setIsAdler(bool isAdler) {m_isAdler = isAdler;}
protected:
void setData() override;
void setDesignatorData() override;
public:
void onAddItem() override;
bool onEditItem() override;
protected:
int editTypeId() const override { return m_editData.typeId(); }
int currentPartyId() const override { return 0; }
bool checkEquipNo(int equipNo);
Q_SIGNALS:
void addItem(const QModelIndex &parent, const TemplateData &newData);
void updateItem(const QModelIndex &index, const TemplateData &editData);
private:
QSet<int> m_usedEquipmentNumbers;
TemplateData m_editData;
QModelIndex m_workingIndex;
bool m_isAdler;
};
class PPMCOMMON_EXPORT ParticipantTemplateEditItem final : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
ParticipantTemplateEditItem(bool asSupportService, LtsSession::LtsSession *session, QWidget *parent = nullptr);
bool init(const QModelIndex &workingIndex,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const TemplateData &data = TemplateData(),
const bool addItem = false);
void setFiringUnitRestrictions(ParticipantTemplateEditModel *model, bool isEdit, const FiringUnitValidator::FiringUnitRestrictions &restrictions,
FiringUnitValidator *firingUnitValidator,
const int unitGearClassType);
void setIsAdler(bool isAdler) {m_editItemWidget->setIsAdler(isAdler);}
public Q_SLOTS:
void setUsedEquipmentNumbers(const QSet<int> &usedEquipmentNumbers) { m_editItemWidget->setUsedEquipmentNumbers(usedEquipmentNumbers); }
Q_SIGNALS:
void addItem(const QModelIndex &parent, const TemplateData &newData);
void updateItem(const QModelIndex &index, const TemplateData &editData);
private:
ParticipantTemplateEditItemWidget *m_editItemWidget;
LtsWidgets::LtsDialogButtonBox *m_buttonBox;
};
class PPMCOMMON_EXPORT ParticipantTemplateEditItemTab final : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
ParticipantTemplateEditItemTab(bool asSupportService, LtsSession::LtsSession *session, QWidget *parent = nullptr);
bool init(const QModelIndex &workingIndex,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asb,
const TemplateData &data = TemplateData());
Q_SIGNALS:
void addItem(int &row, const QModelIndex &parent, const TemplateData &newData, bool asCopy);
void updateItem(const QModelIndex &index, const TemplateData &editData);
private:
void retranslate() override;
bool apply() override;
private:
ParticipantTemplateEditItemWidget *m_editItemWidget;
};
} // namespace ParticipantManagement
@@ -0,0 +1,468 @@
/**
* @RDE_HEADER@
* This Model is used by the Force-Tree-Editors
* $Id: participant_template_edit_model.cpp 50265 2020-03-05 15:48:19Z ehrlicher $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Plugins/ParticipantManagement/Gui/ParticipantTemplates/participant_template_edit_model.cpp $
* $Author: ehrlicher $
*/
#include "participant_template_edit_model.h"
#include <ParticipantManagement/ppm_translation.h>
#include "participant_firing_unit_validator.h"
#include <nglwidgets/ngltreeitem.h>
#include <QSet>
namespace ParticipantManagement
{
QDataStream &operator<<(QDataStream &ds, const TemplateData &td)
{
ds << td.templateId()
<< td.hierarchyNumber()
<< td.equipmentNumber()
<< td.typeId()
<< QString::fromStdString(td.symbol())
<< QString::fromStdString(td.name())
<< QString::fromStdString(td.designator())
<< QString::fromStdString(td.tacticalIdentifier())
<< QString::fromStdString(td.info())
<< td.modId()
<< td.superiorModId()
<< td.isDeleted();
return ds;
}
QDataStream &operator>>(QDataStream &ds, TemplateData &td)
{
int templateId, hierarchyNumber, equipmentNumber, typeId, modId, superiorModId;
QString symbol, name, designator, tacticalIdentifier, info;
bool isDeleted;
ds >> templateId
>> hierarchyNumber
>> equipmentNumber
>> typeId
>> symbol
>> name
>> designator
>> tacticalIdentifier
>> info
>> modId
>> superiorModId
>> isDeleted;
td.templateId(templateId);
td.equipmentNumber(equipmentNumber);
td.typeId(typeId);
td.symbol(symbol.toStdString());
td.name(name.toStdString());
td.designator(designator.toStdString());
td.tacticalIdentifier(tacticalIdentifier.toStdString());
td.info(info.toStdString());
td.modId(modId);
td.superiorModId(superiorModId);
td.isDeleted(isDeleted);
return ds;
}
//----------------------------------------------------------------------------
ParticipantTemplateEditModel::ParticipantTemplateEditModel(QObject *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc,
int rootId)
: ParticipantIconModelBase(ppmDtc,
asbIfc,
{ tr("Designator"), tr("Tact. Identifier"), tr("Class"), tr("Type"), tr("Equip. No."), QStringLiteral("TemplateId") },
new NGLTreeItem(QVariant()),
parent,
getLogger("ParticipantTemplateEditModel"))
, m_rootTemplateId(rootId)
, m_firingUnitValidator(new FiringUnitValidator(ppmDtc, this))
{
connect(this, &ParticipantTemplateEditModel::signalDataDropped,
this, &ParticipantTemplateEditModel::internalDataChanged);
qRegisterMetaTypeStreamOperators<ParticipantManagement::TemplateData>();
setMimeType(QStringLiteral("ParticipantTemplateEditModel_%1").arg(qlonglong(this)));
init();
}
QVariant ParticipantTemplateEditModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || role != Qt::DisplayRole)
return NGLTreeModel::data(index, role);
NGLTreeItem *item = privateData(index);
if (item->data().canConvert<ParticipantManagement::TemplateData>())
{
ParticipantManagement::TemplateData templateData = item->data().value<ParticipantManagement::TemplateData>();
switch (index.column())
{
case ColDesignator:
return QString::fromStdString(templateData.designator());
case ColIdentifier:
return QString::fromStdString(templateData.tacticalIdentifier());
case ColTypeClass:
return typeClassStringFromTypeId(templateData.typeId());
case ColType:
return ParticipantManagement::trTypeName(m_types.value(templateData.typeId()).name());
case ColEquipmentNumber:
if (templateData.equipmentNumber() != 0)
return templateData.equipmentNumber();
return QVariant();
case ColTemplateId:
return templateData.templateId();
}
}
return NGLTreeModel::data(index, role);
}
int ParticipantTemplateEditModel::columnCount(const QModelIndex &parent) const
{
int cc = NGLTreeModel::columnCount(parent);
#ifndef LTS_DEBUG
// template id only in dev mode
cc -= 1;
#endif
return cc;
}
void ParticipantTemplateEditModel::init()
{
NGLTreeModel::resetModel();
m_dataToDelete.clear();
onInsertTemplate(m_rootTemplateId, QModelIndex(), false);
}
std::vector<TemplateData> ParticipantTemplateEditModel::getChildrenOf(NGLTreeItem *item,
int parentId,
int hierarchyNumber,
bool bOnlyModified,
int &highestModId) const
{
if (!item)
return {};
std::vector<TemplateData> ret;
ParticipantManagement::TemplateData templateData = item->data().value<ParticipantManagement::TemplateData>();
templateData.superiorModId(parentId);
templateData.hierarchyNumber(hierarchyNumber);
if (templateData.modId() == 0)
templateData.modId(++highestModId);
// check for children of this item
for (int i = 0; i < item->childCount(); i++)
{
const auto c = getChildrenOf(item->child(i), templateData.modId(), i + 1, bOnlyModified, highestModId);
ret.insert(ret.end(), c.begin(), c.end());
}
if (!bOnlyModified || item->modified() || !ret.empty())
ret.push_back(std::move(templateData));
return ret;
}
//slots
bool ParticipantTemplateEditModel::onInsertRow(const QModelIndex &parent, ParticipantManagement::TemplateData templateData)
{
templateData.templateId(0); //reset templateId is new!
templateData.modId(0); //need new modId
QVariant data;
data.setValue(templateData);
NGLTreeItem *item = createItem(data, QIcon());
item->setModified(true);
emit internalDataChanged();
return NGLTreeModel::insertRow(rowCount(parent), parent, item);
}
bool ParticipantTemplateEditModel::onUpdateRow(const QModelIndex &index, const ParticipantManagement::TemplateData &templateData)
{
if (!index.isValid())
return false;
QVariant data;
data.setValue(templateData);
NGLTreeItem *item = privateData(index);
item->setIcon(QIcon());
tryRenderSymbol(QString::fromStdString(templateData.symbol()), item);
emit internalDataChanged();
return setItemData(index, data, item->icon());
}
bool ParticipantTemplateEditModel::onDeleteRow(const QModelIndex &idx, bool isFirstItem)
{
while (rowCount(idx) > 0)
onDeleteRow(NGLTreeModel::index(0, 0, idx), false);
if (m_rootTemplateId > 0 && isFirstItem) //edit mode
{
NGLTreeItem *item = privateData(idx);
ParticipantManagement::TemplateData data = item->data().value<ParticipantManagement::TemplateData>();
if (data.modId() != 0) //only append old items to remove list
{
data.isDeleted(true);
m_dataToDelete.append(data);
}
}
removeRow(idx.row(), idx.parent());
emit internalDataChanged();
return true;
}
std::vector<ParticipantManagement::TemplateData> ParticipantTemplateEditModel::templateData(bool bOnlyModified) const
{
return templateData(QModelIndex(), false, bOnlyModified);
}
std::vector<ParticipantManagement::TemplateData> ParticipantTemplateEditModel::templateDataAsCopy(const QModelIndex &idx) const
{
return templateData(idx, true, false);
}
std::vector<ParticipantManagement::TemplateData> ParticipantTemplateEditModel::templateData(const QModelIndex &idx, bool bAsNewTemplate, bool bOnlyModified) const
{
if (m_rootItem->childCount() == 0)
return {};
NGLTreeItem *root = idx.isValid() ? privateData(idx) : m_rootItem->child(0);
// gehen wir mal davon aus, dass man nie mehr als 1mrd template - Einträge angelegt hat...
int modId = 1000000000;
auto templateDatas(getChildrenOf(root, 0, 1, bOnlyModified, modId));
if (bAsNewTemplate)
{
// reset templateId
for (auto &templ : templateDatas)
templ.templateId(0);
}
else
{
templateDatas.insert(templateDatas.end(), m_dataToDelete.begin(), m_dataToDelete.end());
}
return templateDatas;
}
void ParticipantTemplateEditModel::dataCommitted()
{
m_dataToDelete.clear();
resetModifedFlag(m_rootItem);
}
QSet<int> ParticipantTemplateEditModel::usedEquipmentNumbers() const
{
return usedEquipmentNumbers(m_rootItem);
}
TemplateData ParticipantTemplateEditModel::getTemplateData(const QModelIndex &index) const
{
return privateData(index)->data().value<ParticipantManagement::TemplateData>();
}
QSet<int> ParticipantTemplateEditModel::usedEquipmentNumbers(NGLTreeItem *item) const
{
QSet<int> ret;
const TemplateData data = item->data().value<ParticipantManagement::TemplateData>();
if (data.equipmentNumber() != 0)
ret += data.equipmentNumber();
for (int i = 0; i < item->childCount(); ++i)
ret += usedEquipmentNumbers(item->child(i));
return ret;
}
Qt::ItemFlags ParticipantTemplateEditModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags f = NGLTreeModel::flags(index);
// can not drag the whole tree, also we allow only dragging the first column
if (index.column() != 0 || !index.parent().isValid())
f &= ~Qt::ItemIsDragEnabled;
// drop also only on first column
if (index.column() != 0)
f &= ~Qt::ItemIsDropEnabled;
return f;
}
bool ParticipantTemplateEditModel::canDropMimeData(const QMimeData *data,
Qt::DropAction action,
int row,
int column,
const QModelIndex &parent) const
{
if (!ParticipantIconModelBase::canDropMimeData(data, action, row, column, parent))
return false;
// only drop on first column allowed
if (column > 0)
return false;
// we do not allow creating a new root knot
if (!parent.isValid() && m_rootItem->childCount() > 0)
return false;
const TemplateData &parentItem = getTemplateData(parent);
if (!isUnitType(parentItem.typeId()))
return false;
DEBUG_LOG(m_logger) << "can drop on " << row << ", " << column << ", parent: "
<< parent.row() << "," << parent.column() << ", " << parent.isValid()
<< ", action: " << action;
// make sure to not drop a parent on a child of this parent
// QAbstractItemModel takes care for this within internal drops,
// but can not do this for external drops (e.g. tactical organisation)
const QVector<NGLTreeItem *> tiSources = getMimeDataItems(data, m_mimeType);
if (tiSources.isEmpty())
return false;
// copy due to qDeleteAll!
const TemplateData pdSource = tiSources.first()->data().value<ParticipantManagement::TemplateData>();
qDeleteAll(tiSources);
if (m_firingUnitValidator)
{
FiringUnitValidator::FiringUnitRestrictions restrictions = m_firingUnitValidator->getRestrictions(this, parent);
if (restrictions != FiringUnitValidator::NO_RESTRICTION)
{
if (restrictions.testFlag(FiringUnitValidator::IS_AT_MAX_CAPACITY))
return false;
if (restrictions.testFlag(FiringUnitValidator::ONLY_SAME_GEAR_CLASS_ARTILLERY_ALLOWED))
{
if (!m_firingUnitValidator->isSameGearClassArtillery(parentItem.typeId(), pdSource.typeId()))
return false;
if (m_firingUnitValidator->isArtilleryUnit(parentItem.typeId()) && m_firingUnitValidator->isArtilleryUnit(pdSource.typeId()))
return false;
}
if (restrictions.testFlag(FiringUnitValidator::NO_ARTILLERY_PARTICIPANTS_ALLOWED))
{
if (m_firingUnitValidator->isArtilleryWeaponSystem(pdSource.typeId()))
return false;
}
if (restrictions.testFlag(FiringUnitValidator::NO_TYPE_CHANGE_ALLOWED))
{
const Type allowedType = m_firingUnitValidator->getAllowedType(this, parent);
if (pdSource.typeId() != allowedType.id())
return false;
if (m_dtc->isAdlerVerbund(pdSource.typeId()))
return false;
}
}
}
return true;
}
bool ParticipantTemplateEditModel::onInsertTemplate(int rootId,
const QModelIndex &parentIndex,
bool asCopy)
{
if (rootId <= 0)
return false;
QHash<int, TemplateData> tmap;
QHash<int, QSet<int>> parentId2id;
const QSet<int> usedEquipNo(usedEquipmentNumbers());
QVector<ParticipantManagement::TemplateParticipant> templateMap;
m_dtc->templateParticipantsFromTemplateId(rootId, templateMap);
for (const ParticipantManagement::TemplateParticipant &tmpl : qAsConst(templateMap))
{
//should be there
if (!tmpl.templateId())
continue;
// parentId -> id for lookup
parentId2id[tmpl.superiorTemplateId()] += tmpl.templateId();
auto data = m_dtc->convertFromParticipantTemplateToTemplateData(tmpl);
if (asCopy)
{
data.templateId(0);
data.modId(0);
}
if (usedEquipNo.contains(data.equipmentNumber()))
data.equipmentNumber(0);
tmap.insert(tmpl.templateId(), data);
}
NGLTreeItem *root = parentIndex.isValid() ? privateData(parentIndex) : m_rootItem;
// insert recursivly
insertChildrenOf(0, root, parentIndex, parentId2id, tmap);
if (asCopy)
emit internalDataChanged();
return true;
}
//----------------------------------------------------------------------------
void ParticipantTemplateEditModel::insertChildrenOf(int parentId,
NGLTreeItem *parent,
const QModelIndex &parentIdx,
const QHash<int, QSet<int>> &parentId2id,
const QHash<int, TemplateData> &tmap)
{
const QSet<int> childIds = parentId2id.value(parentId);
QMap<int, int> currentHierachyNumbers; // no QSet, must be sorted!
for (int childId : childIds)
{
auto it = tmap.constFind(childId);
if (it == tmap.constEnd())
{
WARNING_LOG(m_logger) << "Can not find template with id " << childId << " - ignoring";
continue;
}
const int templateId = it.key(); // it.value().templateId() is optional and maybe not set
const TemplateData &data = it.value();
if (data.hierarchyNumber() <= 0)
{
WARNING_LOG(m_logger) << "Invalid / no hierarchy number set for participant " << data.templateId() << " - ignoring";
continue;
}
auto hierIt = currentHierachyNumbers.insert(data.hierarchyNumber(), data.hierarchyNumber());
const int insertPos = std::distance(currentHierachyNumbers.begin(), hierIt);
NGLTreeItem *childItem = createItem(QVariant::fromValue(data), QIcon());
DEBUG_LOG(m_logger) << "insert Child " << childItem << "(" << data.templateId() << ", " << data.hierarchyNumber()
<< ") to parent " << parent << " at pos " << insertPos;
insertRow(insertPos, parentIdx, childItem);
const QModelIndex childIdx = index(insertPos, 0, parentIdx);
insertChildrenOf(templateId, childItem, childIdx, parentId2id, tmap);
}
}
//----------------------------------------------------------------------------
NGLTreeItem *ParticipantTemplateEditModel::createItem(const QVariant &data, const QIcon &icon) const
{
auto ret = NGLTreeModel::createItem(data, icon);
const TemplateData templateData = data.value<TemplateData>();
if (templateData.symbol().size() != 0)
{
ParticipantTemplateEditModel *that = const_cast<ParticipantTemplateEditModel*>(this);
// mutable
that->tryRenderSymbol(QString::fromStdString(templateData.symbol()), ret);
}
return ret;
}
} //namespace ParticipantManagement
@@ -0,0 +1,105 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Template Edit Model
* $Id: participant_template_edit_model.h 49756 2020-02-04 08:46:35Z ehrlicher $
* $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Plugins/ParticipantManagement/Gui/ParticipantTemplates/participant_template_edit_model.h $
* $Author: ehrlicher $
* Created by Patric Karwat, SLSE, 2016-10-05
*/
#pragma once
#include <ParticipantManagement/logger.h>
#include <Services/ParticipantManagement/ppm_dtc.h>
#include <Common/participant_icon_model_base.h>
namespace AdvancedSymbology
{
class ForeignDataInterface;
class SymbolResult;
}
namespace LtsSession
{
class LtsSessionDataDds;
}
namespace ParticipantManagement
{
class FiringUnitValidator;
//----------------------------------------------------------------------------
class PPMCOMMON_EXPORT ParticipantTemplateEditModel final : public ParticipantIconModelBase
{
Q_OBJECT
public:
enum Columns
{
ColDesignator,
ColIdentifier,
ColTypeClass,
ColType,
ColEquipmentNumber,
ColTemplateId
};
ParticipantTemplateEditModel(QObject *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc,
int rootId);
QVariant data(const QModelIndex &index, int role) const override;
int columnCount(const QModelIndex &parent) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool canDropMimeData(const QMimeData *data,
Qt::DropAction action,
int row,
int column,
const QModelIndex &parent) const override;
Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; }
Qt::DropActions supportedDragActions() const override { return Qt::MoveAction; }
std::vector<TemplateData> templateData(bool bOnlyModified = true) const;
std::vector<TemplateData> templateDataAsCopy(const QModelIndex &idx = QModelIndex()) const;
void dataCommitted(); // the modified data returned by getTemplateData() was successfully commited into db
QSet<int> usedEquipmentNumbers() const;
TemplateData getTemplateData(const QModelIndex &index) const;
public slots:
bool onInsertRow(const QModelIndex &parent, TemplateData templateData);
bool onUpdateRow(const QModelIndex &index, const TemplateData &templateData);
bool onDeleteRow(const QModelIndex &idx, bool isFirstItem = true);
bool onInsertTemplate(int rootId, const QModelIndex &parentIndex,
bool asCopy);
signals:
void internalDataChanged();
private:
std::vector<TemplateData> templateData(const QModelIndex &idx, bool bAsNewTemplate, bool bOnlyModified) const;
void init();
std::vector<TemplateData> getChildrenOf(NGLTreeItem *item,
int parentId,
int hierarchyNumber,
bool bOnlyModified,
int &highestModId) const;
void insertChildrenOf(int parentId,
NGLTreeItem *parent,
const QModelIndex &parentIdx,
const QHash<int, QSet<int>> &parentId2id,
const QHash<int, TemplateData> &tmap);
NGLTreeItem *createItem(const QVariant &data, const QIcon &icon) const override;
QSet<int> usedEquipmentNumbers(NGLTreeItem *item) const;
private:
int m_rootTemplateId;
QVector<ParticipantManagement::TemplateData> m_dataToDelete;
FiringUnitValidator *m_firingUnitValidator;
};
} //namespace ParticipantManagement
Q_DECLARE_METATYPE(ParticipantManagement::TemplateData)
@@ -0,0 +1,101 @@
/**
* @RDE_HEADER@
* Enhanced Participant Edit Model - show participant structure at specific time point
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2018-02-15
*/
#include "participant_time_point_model.h"
#include <QDateTime>
#include <QTimer>
namespace ParticipantManagement
{
//----------------------------------------------------------------------------
ParticipantTimePointModel::ParticipantTimePointModel(QObject *parent,
const std::shared_ptr<Interface::Dtc> &ppmDtc,
const std::shared_ptr<Interface::Ftc> &ppmFtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc)
: ParticipantEditModel(parent, ppmDtc, asbIfc)
, m_requestTimer(new QTimer(this))
, m_currentTimePoint(0)
, m_csTimePointModel(Qt::Unchecked)
, m_ppmFtc(ppmFtc)
{
m_requestTimer->setSingleShot(true);
m_requestTimer->setInterval(50);
connect(m_requestTimer, &QTimer::timeout, this, &ParticipantTimePointModel::startRequest);
m_requestHelper.setQuiet(true);
}
void ParticipantTimePointModel::setTimePoint(qint64 tp)
{
if (m_currentTimePoint == tp)
return;
m_currentTimePoint = tp;
m_requestTimer->start();
}
bool ParticipantTimePointModel::onReinitModel(int partyId, const QSet<int> &checkedParticipants, Qt::CheckState cs)
{
if (m_partyId == partyId)
return true;
m_partyId = partyId;
m_partyColor = QColor::fromRgb(QRgb(m_dtc->party(m_partyId).color()));
m_checkedParticipantsTimepointModel = checkedParticipants;
m_csTimePointModel = cs;
m_requestTimer->start();
return true;
}
void ParticipantTimePointModel::startRequest()
{
ParticipantManagement::GetParticipantsRequest req;
req.partyId(partyId());
req.timeStamp(m_currentTimePoint);
m_requestHelper.startSingleRequest([this, req]() { return m_ppmFtc->getParticipantsRequest(req, this); });
}
void ParticipantTimePointModel::onGetParticipantsReply(const GetParticipantsReply &reply)
{
m_requestHelper.requestReply(reply);
NGLTreeModel::resetModel();
QHash<int, ParticipantData> tmap;
QHash<int, QSet<int>> parentId2id;
tmap.reserve(reply.participants().size());
parentId2id.reserve(reply.participants().size());
for (const auto &part : reply.participants())
{
if (part.isDeleted())
continue;
if (part.partyId() != m_partyId)
continue;
// parentId -> id for lookup
parentId2id[part.superiorId()] += part.id();
tmap.insert(part.id(), m_dtc->convertParticipantToParticipantData(part));
};
// insert recursivly
insertChildrenOf(0, m_rootItem, QModelIndex(), parentId2id, tmap, m_checkedParticipantsTimepointModel, m_csTimePointModel);
// unset modifed flag
resetModifedFlag(m_rootItem);
emit participantDataChanged();
}
} //namespace ParticipantManagement
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* Enhanced Participant Edit Model - show participant structure at specific time point
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2018-02-15
*/
#pragma once
#include "participant_edit_model.h"
#include <ParticipantManagement/ppm_ftc.h>
#include <LtsUtilsGuiDds/request_helper.h>
class QTimer;
namespace ParticipantManagement
{
//----------------------------------------------------------------------------
class PPMCOMMON_EXPORT ParticipantTimePointModel : public ParticipantEditModel,
protected ParticipantManagement::Interface::Ftc::GetParticipantsReplyHandler
{
Q_OBJECT
public:
ParticipantTimePointModel(QObject *parent,
const std::shared_ptr<Interface::Dtc> &ppmDtc,
const std::shared_ptr<Interface::Ftc> &ppmFtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc);
void setTimePoint(qint64 tp);
bool onReinitModel(int partyId, const QSet<int> &checkedParticipants = QSet<int>(), Qt::CheckState cs = Qt::Checked) override;
qint64 timePoint() const { return m_currentTimePoint; }
Q_SIGNALS:
void participantDataChanged();
protected:
void startRequest();
void onGetParticipantsReply(const GetParticipantsReply &reply) override final;
private:
QTimer *m_requestTimer;
qint64 m_currentTimePoint;
LtsUtils::RequestHelper m_requestHelper;
QSet<int> m_checkedParticipantsTimepointModel;
Qt::CheckState m_csTimePointModel;
std::shared_ptr<Interface::Ftc> m_ppmFtc;
};
} // namespace ParticipantManagement
@@ -0,0 +1,229 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Last, SLSE, 2017-11-10
*/
#include "participant_tree_edit_handler.h"
#include "participant_edit_model.h"
#include <QAction>
#include <QMenu>
#include <QTreeView>
#include <QDebug>
namespace ParticipantManagement
{
ParticipantTreeEditHandler::ParticipantTreeEditHandler(LtsDataView::LtsDataView *dataView,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
bool asSupportService,
QObject *parent)
: QObject(parent)
, m_dataView(dataView)
, m_model(qobject_cast<ParticipantEditModel *>(m_dataView->sourceModel()))
, m_asSupportService(asSupportService)
, m_editParticipantsAllowed(false)
, m_dtc(dtc)
, m_ftc(ftc)
, m_requestHelper(nullptr)
{
Q_ASSERT(m_model);
m_dataView->setRootIsDecorated(true);
auto treeView = m_dataView->treeView();
connect(treeView, &QTreeView::customContextMenuRequested,
this, &ParticipantTreeEditHandler::showContextMenu);
QItemSelectionModel *selectionModel = treeView->selectionModel();
connect(selectionModel, &QItemSelectionModel::selectionChanged,
this, &ParticipantTreeEditHandler::signalSelectionChanged);
selectionModel->clearSelection();
connect(treeView, &QTreeView::doubleClicked,
this, &ParticipantTreeEditHandler::signalDoubleClicked);
}
//private
QModelIndex ParticipantTreeEditHandler::selectedIndexView() const
{
const QModelIndexList indexL = m_dataView->selectedRows();
return indexL.isEmpty() ? QModelIndex() : indexL.at(0);
}
bool ParticipantTreeEditHandler::isContainer() const
{
const QModelIndex idx = selectedIndexView();
if (!idx.isValid())
return false;
const int typeId = m_model->privateData(idx)->participant.typeId();
if (typeId <= 0)
return false;
if (m_asSupportService)
return m_dtc->type(typeId).typeClass() == ParticipantManagement::TypeClass_def::SupportUnit;
return m_dtc->type(typeId).typeClass() == ParticipantManagement::TypeClass_def::Unit;
}
QVector<int> ParticipantTreeEditHandler::usedEquipmentNumbers() const
{
return m_model->usedEquipmentNumbers();
}
bool ParticipantTreeEditHandler::isSelectedIndexValid() const
{
return selectedIndexView().isValid();
}
// is selected Index is equiped, it can't be removed
bool ParticipantTreeEditHandler::isSelectedIndexRemovable() const
{
const QModelIndex idx = selectedIndexView();
if (!idx.isValid() || !idx.parent().isValid())
return false;
return m_model->isRowRemovable(m_model->privateData(idx));
}
ParticipantManagement::ParticipantData ParticipantTreeEditHandler::getSelectedData() const
{
const QModelIndex idx = selectedIndexView();
return idx.isValid() ? m_model->privateData(idx)->participant : ParticipantData();
}
void ParticipantTreeEditHandler::removeCurrentRow()
{
const QModelIndex idx = selectedIndexView();
if (!idx.isValid())
return;
m_model->onDeleteRow(idx, true);
}
void ParticipantTreeEditHandler::onRemoveItem()
{
removeCurrentRow();
}
void ParticipantTreeEditHandler::beautifyTreeView(bool keepExpanded)
{
m_dataView->expandAll();
m_dataView->resizeHeadersByContent();
/*
m_dataView->resizeSection(0, m_dataView->treeView()->columnWidth(0) +
m_dataView->treeView()->iconSize().width() + 10);
*/
if (!keepExpanded)
m_dataView->collapseAll();
}
void ParticipantTreeEditHandler::partyHasChanged(int newPartyId, bool keepExpanded)
{
if (m_model->partyId() == newPartyId)
return;
if (m_model->onReinitModel(newPartyId))
beautifyTreeView(keepExpanded);
}
bool ParticipantTreeEditHandler::onApplyChanges()
{
ModifyParticipantDataRequest req;
req.data(m_model->participantData());
if (req.data().size() == 0)
return true;
if (!m_requestHelper)
m_requestHelper = new LtsUtils::RequestHelper(this);
m_requestHelper->addRequest([this, req]()
{
return m_ftc->modifyParticipantDataRequest(req, this);
});
return m_requestHelper->startRequests();
}
/*
* If 'expand' is true all subnodes of the currently selected node will be expanded.
* If 'expand' is false all subnodes of the currently selected node will be collapsed.
*/
void ParticipantTreeEditHandler::expandNodeChildren(QTreeView *pTreeView, const QModelIndex &index, bool expand)
{
if (!index.isValid())
return;
int childCount = index.model()->rowCount(index);
for (int i = 0; i < childCount; i++) {
const QModelIndex &child = index.model()->index(i,0, index);
// Recursively call the function for each child node.
expandNodeChildren(pTreeView, child, expand);
}
if(expand)
pTreeView->expand(index);
else
pTreeView->collapse(index);
}
void ParticipantTreeEditHandler::showContextMenu(const QPoint &position)
{
QTreeView *tv = qobject_cast<QTreeView*>(sender());
if (!tv)
return;
const QModelIndex curIdx = tv->currentIndex();
const QModelIndex idx = curIdx.column() == 0 ? curIdx : tv->model()->index(curIdx.row(), 0, curIdx.parent());
if (!idx.isValid())
return;
QMenu menu;
if (m_editParticipantsAllowed)
{
QAction *editParticipantAction = new QAction(tr("Edit"), &menu);
connect(editParticipantAction, &QAction::triggered, this, [this]() { emit signalEditParticipant(); });
menu.addAction(editParticipantAction);
}
if (tv->model()->rowCount(idx) != 0)
{
if (tv->isExpanded(idx))
{
QAction *collapseAction = new QAction(tr("Collapse"), &menu);
connect(collapseAction, &QAction::triggered, this, [tv, idx]() { tv->collapse(idx);});
menu.addAction(collapseAction);
QAction *collapseAllAction = new QAction(tr("Collapse all"), &menu);
connect(collapseAllAction, &QAction::triggered, this, [this, tv, idx]() { expandNodeChildren(tv, idx, false); });
menu.addAction(collapseAllAction);
}
else
{
QAction *expandAction = new QAction(tr("Expand"), &menu);
connect(expandAction, &QAction::triggered, this, [tv, idx]() { tv->expand(idx);});
menu.addAction(expandAction);
}
QAction *expandAllAction = new QAction(tr("Expand all"), &menu);
connect(expandAllAction, &QAction::triggered, this, [this, tv, idx]() { expandNodeChildren(tv, idx, true); });
menu.addAction(expandAllAction);
}
if (!menu.actions().isEmpty())
menu.exec(tv->viewport()->mapToGlobal(position));
}
void ParticipantTreeEditHandler::onModifyParticipantDataReply(const Core::FunctionReplyObject &replyObject)
{
if (!m_requestHelper)
return;
if (!replyObject.error())
m_model->dataCommitted();
emit signalChangesMade();
m_requestHelper->requestReply(replyObject);
}
}
@@ -0,0 +1,75 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Last, SLSE, 2017-11-10
*/
#pragma once
#include <memory>
#include <LtsDataView/lts_data_view.h>
#include <Plugins/ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <LtsUtilsGuiDds/request_helper.h>
namespace ParticipantManagement
{
class ParticipantEditModel;
class ParticipantTreeFilterProxyModel;
class PPMCOMMON_EXPORT ParticipantTreeEditHandler : public QObject, protected ParticipantManagement::Interface::Ftc::ModifyParticipantDataReplyHandler
{
Q_OBJECT
public:
ParticipantTreeEditHandler(LtsDataView::LtsDataView *dataView,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
bool asSupportService,
QObject *parent = nullptr);
void setEditParticipantsAllowed(bool bAllow) { m_editParticipantsAllowed = bAllow; }
QModelIndex selectedIndexView() const;
bool isSelectedIndexValid() const;
bool isSelectedIndexRemovable() const;
bool isContainer() const;
QVector<int> usedEquipmentNumbers() const;
ParticipantManagement::ParticipantData getSelectedData() const;
void beautifyTreeView(bool keepExpanded);
void partyHasChanged(int newPartyId, bool keepExpanded = true);
signals:
void signalChangesMade();
void signalDoubleClicked();
void signalSelectionChanged();
void signalEditParticipant(); // use getSelectedData() to retrieve the current participant data
public slots:
bool onApplyChanges();
void onRemoveItem();
void showContextMenu(const QPoint &position);
private:
void expandNodeChildren(QTreeView *pTreeView, const QModelIndex &index, bool expand);
void removeCurrentRow();
void onModifyParticipantDataReply(const Core::FunctionReplyObject &replyObject) override final;
LtsDataView::LtsDataView *m_dataView;
ParticipantEditModel *m_model;
bool m_asSupportService;
bool m_editParticipantsAllowed;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ftc;
LtsUtils::RequestHelper *m_requestHelper;
};
}
@@ -0,0 +1,181 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, NLE, 2020-02-10
*/
#include "participant_vulnerability_types.h"
#include <ProjectDataManagement/pdm_to_string.h>
#include <LtsUtilsSettings/settings.h>
#include <QComboBox>
#include <QDebug>
namespace ParticipantManagement
{
static ProjectDataManagement::VulnerabilityClass vulnerabilityClassFromTypeClass(TypeClass tc)
{
switch (tc.underlying())
{
case TypeClass::Human:
return ProjectDataManagement::VulnerabilityClass::SoldierInjuries;
case TypeClass::GroundVehicle:
case TypeClass::Vessel:
case TypeClass::VehicleWithGear:
case TypeClass::WeaponSystem:
return ProjectDataManagement::VulnerabilityClass::VehicleDamages;
case TypeClass::SupportEntity:
case TypeClass::SupportUnit:
case TypeClass::Unit:
case TypeClass::Unknown:
case TypeClass::Aircraft:
return ProjectDataManagement::VulnerabilityClass::Unknown;
}
Q_ASSERT(false);
return ProjectDataManagement::VulnerabilityClass::Unknown;
}
QVector<ProjectDataManagement::VulnerabilityState> vulnerabilityStatesForTypeClass(TypeClass tc)
{
using namespace ProjectDataManagement;
const LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
const bool hasVulnerabilityStateLightDamage = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasVulnerabilityStateLightDamage")).toBool();
const bool hasVulnerabilityStateMediumDamage = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasVulnerabilityStateMediumDamage")).toBool();
const bool hasVulnerabilityStateHeavyDamage = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasVulnerabilityStateHeavyDamage")).toBool();
const bool hasVulnerabilityStateMobilityKill = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasVulnerabilityStateMobilityKill")).toBool();
const bool hasVulnerabilityStateVisibleMobilityKill = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasVulnerabilityStateVisibleMobilityKill")).toBool();
const bool hasVulnerabilityStateWeaponSystemDamage = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasVulnerabilityStateWeaponSystemDamage")).toBool();
const bool hasVulnerabilityStateVisibleWeaponSystemDamage = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasVulnerabilityStateVisibleWeaponSystemDamage")).toBool();
const bool hasVulnerabilityStateTemporarySeverance = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasVulnerabilityStateTemporarySeverance")).toBool();
switch (tc.underlying())
{
case TypeClass::Human:
{
QVector<ProjectDataManagement::VulnerabilityState> ret;
ret += VulnerabilityState::CombatReady;
if (hasVulnerabilityStateLightDamage)
ret += VulnerabilityState::LightDamage;
if (hasVulnerabilityStateMediumDamage)
ret += VulnerabilityState::MediumDamage;
if (hasVulnerabilityStateHeavyDamage)
ret += VulnerabilityState::HeavyDamage;
if (hasVulnerabilityStateWeaponSystemDamage)
ret += VulnerabilityState::WeaponSystemDamage;
if (hasVulnerabilityStateVisibleWeaponSystemDamage)
ret += VulnerabilityState::VisibleWeaponSystemDamage;
if (hasVulnerabilityStateTemporarySeverance)
ret += VulnerabilityState::TemporarySeverance;
ret += VulnerabilityState::CatastrophicKill;
return ret;
}
case TypeClass::GroundVehicle:
case TypeClass::Vessel:
case TypeClass::VehicleWithGear:
case TypeClass::WeaponSystem:
{
// ets nur CombatReady, LightDamage, HeavyDamage, MobilityKill, CatastrophicKill
QVector<ProjectDataManagement::VulnerabilityState> ret;
ret += VulnerabilityState::CombatReady;
if (hasVulnerabilityStateLightDamage)
ret += VulnerabilityState::LightDamage;
if (hasVulnerabilityStateMediumDamage)
ret += VulnerabilityState::MediumDamage;
if (hasVulnerabilityStateHeavyDamage)
ret += VulnerabilityState::HeavyDamage;
if (hasVulnerabilityStateMobilityKill)
ret += VulnerabilityState::MobilityKill;
if (hasVulnerabilityStateVisibleMobilityKill)
ret += VulnerabilityState::VisibleMobilityKill;
if (hasVulnerabilityStateWeaponSystemDamage)
ret += VulnerabilityState::WeaponSystemDamage;
if (hasVulnerabilityStateVisibleWeaponSystemDamage)
ret += VulnerabilityState::VisibleWeaponSystemDamage;
if (hasVulnerabilityStateTemporarySeverance)
ret += VulnerabilityState::TemporarySeverance;
ret += VulnerabilityState::CatastrophicKill;
return ret;
}
case TypeClass::SupportEntity:
case TypeClass::SupportUnit:
case TypeClass::Unit:
return {};
case TypeClass::Unknown:
case TypeClass::Aircraft:
return { VulnerabilityState::CombatReady, VulnerabilityState::CatastrophicKill };
}
Q_ASSERT(false);
return {};
}
QVector<ProjectDataManagement::OcCode> ocCodeForTypeClass(TypeClass tc)
{
using namespace ProjectDataManagement;
const LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
const bool hasOcCodeWoundingPaused = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasOcCodeWoundingPaused")).toBool();
const bool hasOcCodeWoundingContinue = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasOcCodeWoundingContinue")).toBool();
const bool hasOcCodeOptimalTreatment = ps->value(QStringLiteral("ppm"),
QStringLiteral("hasOcCodeOptimalTreatment")).toBool();
switch (tc.underlying())
{
case TypeClass::Human:
{
QVector<ProjectDataManagement::OcCode> ret;
ret.reserve(3);
if (hasOcCodeWoundingPaused)
ret += OcCode::WoundingPaused;
if (hasOcCodeWoundingContinue)
ret += OcCode::WoundingContinue;
if (hasOcCodeOptimalTreatment)
ret += OcCode::OptimalTreatment;
ret.squeeze();
return ret;
}
case TypeClass::GroundVehicle:
case TypeClass::Vessel:
case TypeClass::VehicleWithGear:
case TypeClass::WeaponSystem:
case TypeClass::SupportEntity:
case TypeClass::SupportUnit:
case TypeClass::Unit:
case TypeClass::Unknown:
case TypeClass::Aircraft:
return {};
}
Q_ASSERT(false);
return {};
}
void insertVulnerabilityStates(QComboBox *cbx, TypeClass tc)
{
using namespace ProjectDataManagement;
VulnerabilityClass cls = vulnerabilityClassFromTypeClass(tc);
const auto vec = vulnerabilityStatesForTypeClass(tc);
for (const auto vs : vec)
cbx->addItem(toString(vs, cls), vs.underlying());
// OcCodes
const auto ocVec = ocCodeForTypeClass(tc);
for (const auto vs : ocVec)
cbx->addItem(toString(vs), vs.underlying()+100);
}
}
@@ -0,0 +1,23 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, NLE, 2020-02-10
*/
#pragma once
#include <ProjectDataManagement/pdm_enums.hpp>
#include <ParticipantManagement/ppm_enums.hpp>
#include <ParticipantManagement/Gui/Common/ppmcommon_export.h>
#include <QVector>
class QComboBox;
namespace ParticipantManagement
{
PPMCOMMON_EXPORT QVector<ProjectDataManagement::VulnerabilityState> vulnerabilityStatesForTypeClass(TypeClass tc);
PPMCOMMON_EXPORT QVector<ProjectDataManagement::OcCode> ocCodeForTypeClass(TypeClass tc);
PPMCOMMON_EXPORT void insertVulnerabilityStates(QComboBox *cbx, TypeClass tc);
}
+39
View File
@@ -0,0 +1,39 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Philipp Last, SLSE, 2017-10-26
#
ADD_SUBDIRECTORY(msdl)
SET(ppm_msdl_SRCS
ppm_msdl_gui_plugin.cpp
ppm_msdl_gui_plugin.h
ppm_msdl_edit.cpp
ppm_msdl_edit.h
)
NGL_WRAP_UI(ppm_msdl_SRCS
ppm_msdl_edit.ui
)
NGL_ADD_LIBRARY(WS PpmMSDLGuiPlugin MODULE ${ppm_msdl_SRCS})
NGL_TARGET_LINK_LIBRARIES(PpmMSDLGuiPlugin
AsbDataPluginInterface
NGLLogger
LtsSession
PpmGuiPartyPluginInterface
PpmDataPluginInterface
PpmGuiComboboxPluginInterface
Qt5::Widgets
LtsWidgets
LtsDataView
LtsUtilsGuiDds
PpmCommon
zwmsmsdl
LtsUtilsSettings
)
NGL_INSTALL_TARGET(PpmMSDLGuiPlugin)
@@ -0,0 +1,104 @@
#
# @RDE_HEADER@
# $Id$
# $HeadURL$
# $Author$
#
FIND_PACKAGE(XercesC REQUIRED)
FIND_PACKAGE(XSD REQUIRED)
SET(zwmsmsdl_SRCS
msdl_export.cpp
msdl_export.h
msdl_export_scenario_data.cpp
msdl_export_scenario_data.h
msdl_import.cpp
msdl_import.h
msdl_import_show.cpp
msdl_import_show.h
msdl_logging.cpp
msdl_logging.h
msdl_mapping_dialog.cpp
msdl_mapping_dialog.h
msdl_types.cpp
msdl_types.h
zwmsmsdl_export.h
)
SET(zwmsmsdl_UICS
ui/msdl_import_show.ui
ui/msdl_import.ui
ui/msdl_export.ui
ui/msdl_export_scenario_data.ui
ui/msdl_mapping_dialog.ui
)
SET(zwmsmsdl_XSDS
xsd/MilitaryScenario_1.0.0.xsd
xsd/MsdlCodes_1.0.0.xsd
xsd/MsdlComplexTypes_1.0.0.xsd
xsd/MsdlSimpleTypes_1.0.0.xsd
)
SET(zwmsmsdl_XSDS_EXT
xsd/extern/JC3IEDM-3.1-Codes-20061208.xsd
xsd/extern/JC3IEDMMeteorological.xsd
xsd/extern/ModelID_v2006_FINAL.xsd
)
SET(zwmsmsdl_XSDS_install MilitaryScenario_1.0.0.xsd)
FOREACH(xsd ${zwmsmsdl_XSDS} ${zwmsmsdl_XSDS_EXT})
XSD_GENERATE_TREE(zwmsmsdl_IDLS ${xsd})
ENDFOREACH(xsd ${zwmsmsdl_XSDS} ${zwmsmsdl_XSDS_EXT})
# Copy all required msdl *.xml and *.xsd files to shared folder
INSTALL_SHARED_FILES(zwmsmsdl_SRCS
FILES ${zwmsmsdl_XSDS}
DESTINATION "msdl/"
WS
)
INSTALL_SHARED_FILES(zwmsmsdl_SRCS
FILES ${zwmsmsdl_XSDS_EXT}
DESTINATION "msdl/extern"
WS
)
NGL_WRAP_UI(zwmsmsdl_SRCS ${zwmsmsdl_UICS})
NGL_ADD_LIBRARY(WS zwmsmsdl SHARED ${zwmsmsdl_SRCS} ${zwmsmsdl_UICS} ${zwmsmsdl_IDLS})
NGL_TARGET_INCLUDE_DIRECTORIES(zwmsmsdl
PRIVATE
${XSD_INCLUDE_DIR}
PUBLIC
${CMAKE_CURRENT_BINARY_DIR}
)
NGL_TARGET_LINK_LIBRARIES(zwmsmsdl
PRIVATE
Qt5::Gui
Qt5::Xml
Qt5::XmlPatterns
XercesC::XercesC
PUBLIC
svcPpmCommon
LtsUtilsSettings
LtsUtilsGuiDds
LtsSession
PpmDataPluginInterface
PpmCommon
ExmDataPluginInterface
OpmDataPluginInterface
LtsSessionData
ngltools
NGLLogger
LtsWidgets
Qt5::Core
)
IF (WIN32)
NGL_SET_TARGET_PROPERTIES(zwmsmsdl PROPERTIES UNITY_BUILD FALSE)
ENDIF()
NGL_INSTALL_TARGET(zwmsmsdl)
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,578 @@
/**
* @RDE_HEADER@
* Exportieren einer Uebung in eine MSDL-Datei
* $Id$
* $HeadURL$
* $Author$
*/
// at first to avoid compiler errors on windows
#include <xsd/MilitaryScenario_1.0.0.hxx>
#include "msdl_export.h"
#include "ui_msdl_export.h"
#include "msdl_export_scenario_data.h"
#include <Common/participant_dis_helper.h>
#include <ngltools/ngltools_filesystem.h>
#include <QFileDialog>
#include <QFileInfo>
#include <QUrl>
#include <QDate>
#include <QUuid>
#include <fstream>
#include <LtsWidgets/lts_message_dialog.h>
#include <LtsUtilsSettings/settings.h>
#include <LtsSession/lts_session.h>
#include <ParticipantManagement/ppm_data_plugin_interface.h>
namespace msdl
{
using organizationsType = msdl_1::MilitaryScenarioType::Organizations_type;
using equipType = organizationsType::Equipment_type;
using equipItemType = equipType::EquipmentItem_type;
using coordChoiceType = equipItemType::Disposition_type::Location_type::CoordinateChoice_type;
using coordDataType = equipItemType::Disposition_type::Location_type::CoordinateData_type;
using descriptionType = schemas::modelID::modelIdentificationType::description_type;
using equipOptional = organizationsType::Equipment_optional;
using equipRelationsType = equipItemType::Relations_type;
using unitsType = organizationsType::Units_type;
using unitType = unitsType::Unit_type;
using relationsType = unitType::Relations_type;
using forceRelationChoiceType = relationsType::ForceRelation_type::ForceRelationChoice_type;
using forceRelationDataType = relationsType::ForceRelation_type::ForceRelationData_type;
using forceSidesType = msdl_1::MilitaryScenarioType::ForceSides_type;
using forceSideType = forceSidesType::ForceSide_type;
using ownerChoiceType = equipRelationsType::HoldingOrganization_type::OwnerChoice_type;
using ownerDataType = equipRelationsType::HoldingOrganization_type::OwnerData_type;
namespace Private
{
static msdl_1::MilitaryScenarioType::ScenarioID_type createTagScenarioID(const msdl::ScenarioDataDialog &dlgData);
static msdl_1::MilitaryScenarioType::ForceSides_type createTagForceSides(const QMap<qint32, ParticipantManagement::Party> &mapForces,
QMap<qint32, QString> &mapForceHandles);
static msdl_1::MilitaryScenarioType::Options_type createTagOptions();
static msdl_1::MilitaryScenarioType::Environment_type createTagEnvironment();
static msdl_1::MilitaryScenarioType::Organizations_type::Units_type createTagUnits(const QMap<qint32, ParticipantManagement::Participant> &mapParticipants,
const QMap<qint32, QString> &mapForceHandles,
QMap<qint32, std::string> &mapParticipantsUUIDs);
static msdl_1::MilitaryScenarioType::Organizations_type::Equipment_type createTagEquipment(const QMap<qint32, ParticipantManagement::Participant> &mapParticipants,
const QMap<qint32, std::string> &mapParticipantsUUIDs,
const QMap<int32_t, ParticipantManagement::ParticipantPosition> &mapParticipantPositions,
const QMap<qint32, ParticipantManagement::Type> &mapTypes,
const QMap<int32_t, ParticipantManagement::EquipmentType> &mapEquipment,
const QMap<qint32, QString> &mapForceHandles, NGL::INGLLogger &logger);
static void writeMilitaryScenario(const msdl_1::MilitaryScenarioType &miType,
const std::string &filename);
}
ExportMsdl::ExportMsdl(LtsSession::LtsSession *pSession, QWidget *parent)
: NGLDialog(parent)
, mLogger(msdl::getLogger("ExportMsdl"))
, mUi(new Ui_MSDLExport)
, m_pSession(pSession)
{
mUi->setupUi(this);
setWindowTitle(tr("Export Exercise Scenario"));
connect(mUi->tbExportFile, &QToolButton::clicked, this, &ExportMsdl::onTbExportFileClicked);
connect(mUi->m_pushButton_StartExport, &QPushButton::clicked, this, &ExportMsdl::onApply);
QString strExportFile = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pathSelectedExportFile"), QString()).toString();
if (strExportFile.size())
{
mUi->leExportFile->setText(strExportFile);
mUi->m_pushButton_StartExport->setEnabled(true);
}
if (!m_pSession->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc) ||
!m_pSession->getDtc<ExerciseManagement::DataInterface>(m_exmDtc) ||
!m_pSession->getDtc<OperatorManagement::DataInterface>(m_opmDtc))
{
ERROR_LOG(mLogger) << "Fetching m_ppmDtc or m_exmDtc or m_opmDtc failed!";
setEnabled(false);
}
}
ExportMsdl::~ExportMsdl()
{
delete mUi;
}
void ExportMsdl::onTbExportFileClicked()
{
QString strExportPath = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pathSelectedExportFile"), QStringLiteral("/tmp/msdl.xml")).toString();
QString caption(tr("Select File"));
QFileDialog fileDialog(this, caption, strExportPath, tr("XML files (*.xml)"));
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
QList<QUrl> urls;
urls << QUrl::fromLocalFile(strExportPath);
fileDialog.setSidebarUrls(urls);
if (fileDialog.exec()) // TODO: use show(), use signals & slots !
{
strExportPath = fileDialog.selectedFiles().constFirst();
mUi->leExportFile->setText(strExportPath);
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("pathSelectedExportFile"), strExportPath);
}
mUi->m_pushButton_StartExport->setEnabled(!mUi->leExportFile->text().isEmpty());
}
msdl_1::MilitaryScenarioType::ScenarioID_type Private::createTagScenarioID(const msdl::ScenarioDataDialog &dlgData)
{
QDate cuDa = QDate::currentDate();
xml_schema::date da(cuDa.year(), cuDa.month(), cuDa.day());
// Block ScenarioID: General information
msdl_1::MilitaryScenarioType::ScenarioID_type::name_type nameType(dlgData.exerciseName().toStdString());
msdl_1::MilitaryScenarioType::ScenarioID_type::type_type typeType("BOM");
msdl_1::MilitaryScenarioType::ScenarioID_type::version_type versionType(dlgData.exerciseVersion().toStdString());
msdl_1::MilitaryScenarioType::ScenarioID_type::modificationDate_type modDateType(da);
msdl_1::MilitaryScenarioType::ScenarioID_type::securityClassification_type secClassType("Unclassified");
msdl_1::MilitaryScenarioType::ScenarioID_type::description_type desType(dlgData.exerciseDescription().toStdString());
msdl_1::MilitaryScenarioType::ScenarioID_type scIDType(nameType,
typeType,
versionType,
modDateType,
secClassType,
desType);
msdl_1::MilitaryScenarioType::ScenarioID_type::applicationDomain_type domainType(dlgData.exerciseDomain().toStdString());
scIDType.applicationDomain(domainType);
// ScenarioID: poc information as part of the general information (Mandatory!)
msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type pocType(dlgData.pocType().toStdString());
pocType.pocName(dlgData.pocAuthor().toStdString());
msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocEmail_sequence pocSeqMail;
pocSeqMail.push_back(msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocEmail_type(dlgData.pocEmail().toStdString()));
pocType.pocEmail(pocSeqMail);
msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocTelephone_sequence pocSeqTelephone;
pocSeqTelephone.push_back(msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocTelephone_type(dlgData.pocTelephone().toStdString()));
// pocSeqTelephone.push_back(msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocTelephone_type("+421-1080-4288")); // Example for adding further telephone numbers
pocType.pocTelephone(pocSeqTelephone);
msdl_1::MilitaryScenarioType::ScenarioID_type::poc_type::pocOrg_type pocOrgType(dlgData.pocOrganization().toStdString());
pocType.pocOrg(pocOrgType);
msdl_1::MilitaryScenarioType::ScenarioID_type::poc_sequence pocSequence;
pocSequence.push_back(pocType);
scIDType.poc(pocSequence);
scIDType.purpose(dlgData.exercisePurpose().toStdString());
scIDType.modificationDate(da);
return scIDType;
}
msdl_1::MilitaryScenarioType::ForceSides_type Private::createTagForceSides(const QMap<qint32, ParticipantManagement::Party> &mapForces,
QMap<qint32, QString> &mapForceHandles)
{
msdl_1::MilitaryScenarioType::ForceSides_type foType;
msdl_1::MilitaryScenarioType::ForceSides_type::ForceSide_sequence &foSiSe(foType.ForceSide());
// We have to create all UUIDs first
QMap<QString, ParticipantManagement::Party> mapUUID2Force;
for (const ParticipantManagement::Party &party : mapForces)
{
// Skip Pool and O/C Service
if (party.id() == 0 || party.id() == 1)
continue;
QString obHaStr = QUuid::createUuid().toString();
obHaStr = obHaStr.mid(1, obHaStr.size() - 2);
mapUUID2Force[obHaStr] = party;
}
// Create ForceSide for each party
QMapIterator<QString, ParticipantManagement::Party> itForce(mapUUID2Force);
while (itForce.hasNext())
{
itForce.next();
const QString &strUUID = itForce.key();
const ParticipantManagement::Party &party = itForce.value();
msdl_1::ForceSideType::ObjectHandle_type obHaTy(strUUID.toStdString().c_str());
msdl_1::ForceSideType::ForceSideName_type foSiNaTy(party.name().c_str());
msdl_1::ForceSideType foSiTy(obHaTy, foSiNaTy);
// Connect all parties among each other by using their relationship status (Hostile, Friend, ...)
msdl_1::ForceSideType::Associations_type::Association_sequence asSequence;
QMapIterator<QString, ParticipantManagement::Party> itRelationship(mapUUID2Force);
while (itRelationship.hasNext())
{
itRelationship.next();
if (itRelationship.key() == strUUID)
continue;
/*
* Identify relationship. Only FR / HO / NEUTR / UNK are used
*/
ParticipantManagement::Role role = itRelationship.value().role();
msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type relType = msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type::UNK;
if (role == ParticipantManagement::Role_def::Enemy)
relType = msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type::HO;
else if (role == ParticipantManagement::Role_def::Friend)
relType = msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type::FR;
else if (role == ParticipantManagement::Role_def::Neutral)
relType = msdl_1::ForceSideType::Associations_type::Association_type::Relationship_type::NEUTRL;
msdl_1::ForceSideType::Associations_type::Association_type aType(itRelationship.key().toStdString().c_str(), relType);
asSequence.push_back(aType);
}
msdl_1::ForceSideType::Associations_type asType;
asType.Association(asSequence);
foSiTy.Associations(asType);
foSiSe.push_back(foSiTy);
mapForceHandles[party.id()] = strUUID;
}
return foType;
}
msdl_1::MilitaryScenarioType::Options_type Private::createTagOptions()
{
msdl_1::MilitaryScenarioType::Options_type opType("");
opType.MSDLVersion("1.0.0");
msdl_1::boolean aggrBased = false;
msdl_1::OrganizationDetailType orType(aggrBased);
msdl_1::OrganizationDetailType::AggregateEchelon_type aggrEchelon(msdl_1::OrganizationDetailType::AggregateEchelon_type::enumEchelon::BATTALION);
orType.AggregateEchelon(aggrEchelon);
opType.OrganizationDetail(orType);
return opType;
}
msdl_1::MilitaryScenarioType::Environment_type Private::createTagEnvironment()
{
msdl_1::MilitaryScenarioType::Environment_type enType;
// Time
msdl_1::MilitaryScenarioType::Environment_type::ScenarioTime_type timeType("2013-05-28T17:37:24Z");
enType.ScenarioTime(timeType);
// Upper Right
msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::UpperRight_type::CoordinateChoice_type choiceType_ur(msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::UpperRight_type::CoordinateChoice_type::GCC);
coordDataType::GCC_type::X_type x_ur(123);
coordDataType::GCC_type::X_type y_ur(456);
coordDataType::GCC_type::Z_type z_ur(789);
coordDataType::GCC_type utTy_ur(x_ur, y_ur, z_ur);
coordDataType coDaTy_ur;
coDaTy_ur.GCC(utTy_ur);
msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::UpperRight_type urType(choiceType_ur, coDaTy_ur);
// Lower Left
msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::LowerLeft_type::CoordinateChoice_type choiceType(msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::UpperRight_type::CoordinateChoice_type::GCC);
coordDataType::GCC_type::X_type x_ll(987);
coordDataType::GCC_type::X_type y_ll(654);
coordDataType::GCC_type::Z_type z_ll(321);
coordDataType::GCC_type utTy_ll(x_ll, y_ll, z_ll);
coordDataType coDaTy_ll;
coDaTy_ll.GCC(utTy_ll);
msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type::LowerLeft_type llType(choiceType, coDaTy_ll);
// AreaOfInterest
msdl_1::MilitaryScenarioType::Environment_type::AreaOfInterest_type areaType(urType, llType);
enType.AreaOfInterest(areaType);
return enType;
}
msdl_1::MilitaryScenarioType::Organizations_type::Units_type Private::createTagUnits(const QMap<qint32, ParticipantManagement::Participant> &mapParticipants,
const QMap<qint32, QString> &mapForceHandles,
QMap<qint32, std::string> &mapParticipantsUUIDs)
{
mapParticipantsUUIDs.clear();
// Create unique identifier for all participants
for (const ParticipantManagement::Participant &participant : mapParticipants)
{
QString obHaStr = QUuid::createUuid().toString();
obHaStr = obHaStr.mid(1, obHaStr.size() - 2);
mapParticipantsUUIDs[participant.id()] = obHaStr.toStdString();
}
unitsType unitsTy;
unitsType::Unit_sequence &unSe(unitsTy.Unit());
for (auto it = mapForceHandles.begin(); it != mapForceHandles.end(); ++it)
{
for (const ParticipantManagement::Participant &participant : mapParticipants)
{
// Does participant belong to currently exported party?
if (participant.partyId() != it.key())
continue;
if (participant.isDeleted())
continue;
forceRelationDataType foReDaTy;
forceRelationChoiceType foReChTy = forceRelationChoiceType::FORCE_SIDE;
if (participant.superiorId() == 0) // Vorgesetzter ist die Truppe
{
foReChTy = forceRelationChoiceType::FORCE_SIDE;
const QString &obHaStr = it.value();
foReDaTy.ForceSideHandle(obHaStr.toStdString().c_str());
}
else
{
foReChTy = forceRelationChoiceType::UNIT;
msdl_1::CommandRelationType::CommandingSuperiorHandle_type handle(mapParticipantsUUIDs.value(participant.superiorId()));
forceRelationDataType::CommandRelation_type cmdRelation(handle, msdl_1::CommandRelationType::CommandRelationshipType_type::TACON); // No idea about the enumeration values (ADCON, None, etc.)
foReDaTy.CommandRelation(cmdRelation);
}
unitType::ObjectHandle_type unObHaTy(mapParticipantsUUIDs.value(participant.id()));
unitType::SymbolIdentifier_type syIdTy = "S--------------";
relationsType::ForceRelation_type foReTy(foReChTy, foReDaTy);
unitType::Relations_type reTy(foReTy);
unitType unitTy(unObHaTy, syIdTy, reTy);
unitTy.SymbolIdentifier(syIdTy);
unitType::Name_type naTy(participant.designator().c_str());
unitTy.Name(naTy);
unSe.push_back(unitTy);
}
}
return unitsTy;
}
msdl_1::MilitaryScenarioType::Organizations_type::Equipment_type Private::createTagEquipment(const QMap<qint32, ParticipantManagement::Participant> &mapParticipants,
const QMap<qint32, std::string> &mapParticipantsUUIDs,
const QMap<int32_t, ParticipantManagement::ParticipantPosition> &mapParticipantPositions,
const QMap<qint32, ParticipantManagement::Type> &mapTypes,
const QMap<int32_t, ParticipantManagement::EquipmentType> &mapEquipment,
const QMap<qint32, QString> &mapForceHandles,
NGL::INGLLogger &logger)
{
equipType eqTy;
equipType::EquipmentItem_sequence &eqItSeq(eqTy.EquipmentItem());
for (auto it = mapForceHandles.begin(); it != mapForceHandles.end(); ++it)
{
const int32_t partyId = it.key();
for (const ParticipantManagement::Participant &participant : mapParticipants)
{
// Does participant belong to current party?
if (participant.partyId() != partyId)
continue;
if (participant.isDeleted())
continue;
/*
* Identify equipment owner handle (UUID)
* According to ICD is 'ownerChoise' always unit
*/
ownerDataType::UnitOwnerHandle_type foOwHaTy;
foOwHaTy = mapParticipantsUUIDs.value(participant.id()).c_str();
ownerDataType owDaTy;
owDaTy.UnitOwnerHandle(foOwHaTy);
ownerChoiceType owChTy(ownerChoiceType::UNIT);
equipRelationsType::HoldingOrganization_type hoOrTy(owChTy, owDaTy);
equipItemType::Relations_type reTy(hoOrTy);
// Equipment modifiers
auto vecDISEntities = mapTypes.value(participant.typeId()).disEntities();
if (!vecDISEntities.size())
{
WARNING_LOG(logger) << "Participant id " << participant.id()
<< " belongs to a type id " << participant.typeId() << " which has no DIS id! Skipping export of participant!";
continue;
}
// DIS entity id: Does not matter if this type has more than 1 DIS id. Simply pick first one
equipItemType::EquipmentSymbolModifiers_type eqModifiers(ParticipantManagement::DIS::convertDISTypeInteger2MSDLString(vecDISEntities[0]).toStdString().c_str());
eqModifiers.Quantity(1);
eqModifiers.EquipmentType("S--------------");
// Coordinates and Elevation
// Unclear: Are participant coordinates correctly specified converted?
coordDataType::GCC_type::X_type x(mapParticipantPositions[participant.id()].pos().lon());
coordDataType::GCC_type::X_type y(mapParticipantPositions[participant.id()].pos().lat());
coordDataType::GCC_type::Z_type z(mapParticipantPositions[participant.id()].pos().z());
coordDataType::GCC_type utTy(x, y, z);
coordDataType coDaTy;
coDaTy.GCC(utTy);
coordChoiceType coChTy(coordChoiceType::enumCoordinateSystemType::GCC);
/*
// UTM Version
coordDataType::UTM_type::UTMGridZone_type utmGriZoTy("UTM");
coordDataType::UTM_type::UTMEasting_type utmEaTy(mapParticipantPositions[participant.id()].pos().lon());
coordDataType::UTM_type::UTMNorthing_type utmNoTy(mapParticipantPositions[participant.id()].pos().lat());
coordDataType::UTM_type utTy(utmGriZoTy, utmEaTy, utmNoTy);
coordDataType::UTM_type::ElevationAGL_type elType(mapParticipantPositions[participant.id()].pos().z());
utTy.ElevationAGL(elType);
coordDataType coDaTy;
coDaTy.UTM(utTy);
coordChoiceType coChTy(coordChoiceType::enumCoordinateSystemType::UTM);
*/
equipItemType::Disposition_type::Location_type loTy(coChTy, coDaTy);
equipItemType::Disposition_type diTy(loTy);
// Direction of Movement
equipItemType::Disposition_type::DirectionOfMovement_type loDir(0.0);
diTy.DirectionOfMovement(loDir);
// SIDC
equipItemType::SymbolIdentifier_type syIdTy("S--------------");
// Finally create equipment
equipItemType eqItTy(foOwHaTy, syIdTy, diTy, reTy);
eqItTy.EquipmentSymbolModifiers(eqModifiers);
// Create UUID for equipment
QString obHaStr = QUuid::createUuid().toString();
obHaStr = obHaStr.mid(1, obHaStr.size() - 2);
equipItemType::ObjectHandle_type eqObHaTy = obHaStr.toStdString().c_str();
eqItTy.ObjectHandle(eqObHaTy);
// Participant -> TypeId -> EquipmentId -> Equipment name (Easy workflow, right?)
equipItemType::Name_type naTy(mapEquipment.value(mapTypes.value(participant.typeId()).equipmentTypeId()).name());
eqItTy.Name(naTy);
eqItTy.SymbolIdentifier(syIdTy);
eqItSeq.push_back(eqItTy);
}
}
return eqTy;
}
void Private::writeMilitaryScenario(const msdl_1::MilitaryScenarioType &miType,
const std::string &filename)
{
xml_schema::namespace_infomap map;
map["msdl"].name = "urn:sisostds:scenario:military:data:draft:msdl:1";
map["msdl"].schema = NGL::findFile(NGL::FileType::ConfigFile, QStringLiteral("MilitaryScenario_1.0.0.xsd")).toStdString();
map["modelID"].name = "http://www.sisostds.org/schemas/modelID";
std::ofstream ofs(filename);
msdl_1::MilitaryScenario(ofs, miType, map);
}
void ExportMsdl::onApply()
{
ScenarioDataDialog dlg(this, m_pSession, m_opmDtc, m_exmDtc);
int retCode = dlg.exec();
if (retCode == QDialog::Rejected)
{
close();
return;
}
try
{
const auto participants = m_ppmDtc->participants();
QMap<qint32, QString> mapForceHandles;
QMap<qint32, std::string> mapParticipantsUUIDs;
msdl_1::MilitaryScenarioType::ScenarioID_type scIDType = Private::createTagScenarioID(dlg);
msdl_1::MilitaryScenarioType::ForceSides_type foType = Private::createTagForceSides(m_ppmDtc->partys(), mapForceHandles);
msdl_1::MilitaryScenarioType::Options_type opType = Private::createTagOptions();
msdl_1::MilitaryScenarioType miType(scIDType, opType, foType);
msdl_1::MilitaryScenarioType::Environment_type enType = Private::createTagEnvironment();
unitsType unitsTy = Private::createTagUnits(participants, mapForceHandles, mapParticipantsUUIDs);
equipType equipmentTy = Private::createTagEquipment(participants,
mapParticipantsUUIDs,
m_ppmDtc->participantPositions(),
m_ppmDtc->types(),
m_ppmDtc->equipmentTypes(),
mapForceHandles,
mLogger);
equipType::EquipmentItem_sequence &eqItSeq(equipmentTy.EquipmentItem());
organizationsType orTy(unitsTy);
miType.Environment(enType);
if ( eqItSeq.size() > 0)
{
INFO_LOG(mLogger) << "orTy.Equipment(equipmentTy)";
orTy.Equipment(equipmentTy);
}
miType.Organizations(orTy);
QString fileName = mUi->leExportFile->text();
QFileInfo fileInfo(fileName);
if ( !fileInfo.exists(fileName))
{
QFile file(fileName);
file.open(QIODevice::WriteOnly);
file.close();
}
if (!fileInfo.isWritable())
LtsWidgets::LtsMessageDialog::showMessage(this, tr("MSDL export file \"%1\" can not be written").arg(fileName));
else
{
Private::writeMilitaryScenario(miType, fileName.toStdString());
LtsWidgets::LtsMessageDialog::showMessage(this, tr("MSDL export file has successfully been created"));
}
}
catch (const std::exception &e)
{
// There is so much that could be wrong when importing or exporting MSDL files (missing tags, optional tags, ...)
LtsWidgets::LtsMessageDialog::showMessage(this, tr("MSDL export failed!"));
ERROR_LOG(mLogger) << "MSDL export failed with an exception, e.what(): " << e.what();
}
close();
}
}
@@ -0,0 +1,51 @@
/**
* @RDE_HEADER@
* Klasse fuer das Exportieren von einer Uebung in eine MSDL-Datei
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <nglwidgets/ngldialog.h>
#include "msdl_logging.h"
#include "zwmsmsdl_export.h"
#include <memory>
#include <OperatorManagement/opm_data_plugin_interface.h>
#include <ExerciseManagement/exm_data_plugin_interface.h>
#include <ParticipantManagement/ppm_dtc.h>
class Ui_MSDLExport;
namespace LtsSession
{
class LtsSession;
}
namespace msdl
{
class ZWMSMSDL_EXPORT ExportMsdl : public NGLDialog
{
Q_OBJECT
public:
ExportMsdl(LtsSession::LtsSession *pSession, QWidget *parent);
virtual ~ExportMsdl();
protected slots:
void onTbExportFileClicked();
void onApply();
private:
msdl::LOGGER_T mLogger;
Ui_MSDLExport *mUi;
LtsSession::LtsSession *m_pSession;
std::shared_ptr<OperatorManagement::Interface::Dtc> m_opmDtc; // Operator name
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc; // Exercise name, description
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc; // Organisation structure, participants, equipment ...
};
}
@@ -0,0 +1,136 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#include "msdl_export_scenario_data.h"
#include <LtsUtilsSettings/settings.h>
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_data.h>
#include <LtsWidgets/lts_message_dialog.h>
namespace msdl
{
ScenarioDataDialog::ScenarioDataDialog(QWidget *parent,
LtsSession::LtsSession *pSession,
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc)
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
, mUi(new Ui_ExportScenarioData)
{
mUi->setupUi(this);
connect(mUi->m_pushButton_Ok, &QPushButton::clicked, this, &ScenarioDataDialog::onButtonOk);
connect(mUi->m_pushButton_Cancel, &QPushButton::clicked, this, &ScenarioDataDialog::onButtonCancel);
ExerciseManagement::Exercise exercise = exmDtc->exercise(pSession->exerciseId());
mUi->m_lineEdit_ExerciseDescription->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("exerciseDescription"), QString::fromStdString(exercise.description())).toString());
// Must be a single word according to msdl standard. "-" is not allowed!
QString strName(QString::fromStdString(exercise.name()));
strName.remove(QLatin1Char(' '));
mUi->m_lineEdit_ExerciseName->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("exerciseName"), strName).toString());
mUi->m_lineEdit_Domain->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("exerciseDomain"), QString::fromStdString(exercise.partitionName())).toString());
mUi->m_lineEdit_Version->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("exerciseVersion"), QString()).toString());
mUi->m_lineEdit_Purpose->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("exercisePurpose"), QString()).toString());
OperatorManagement::User user = opmDtc->user(LtsSessionData::LtsSessionData::getInstance()->getOperatorId());
mUi->m_lineEdit_Type->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pocType"), QString::fromStdString(user.description())).toString());
mUi->m_lineEdit_AuthorName->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pocAuthor"), QString::fromStdString(user.name())).toString());
mUi->m_lineEdit_Organization->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pocOrganization"), QString()).toString());
mUi->m_lineEdit_Email->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pocEmail"), QString()).toString());
mUi->m_lineEdit_Telephone->setText(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pocTelephone"), QString()).toString());
highlightInvalidInput();
}
ScenarioDataDialog::~ScenarioDataDialog()
{
delete mUi;
}
void ScenarioDataDialog::highlightInvalidInput()
{
QString bgColorRed(QStringLiteral("QLineEdit { background: rgb(255, 0, 0); }"));
QString bgColorWhite(QStringLiteral("QLineEdit { background: rgb(255, 255, 255); }"));
mUi->m_lineEdit_ExerciseDescription->setStyleSheet((mUi->m_lineEdit_ExerciseDescription->text().size() < 2) ? bgColorRed : bgColorWhite);
// Must be a single word according to msdl standard. "-" is not allowed!
QStringList strWords = mUi->m_lineEdit_ExerciseName->text().split(QStringLiteral(" "));
mUi->m_lineEdit_ExerciseName->setStyleSheet(bgColorWhite);
if (strWords.size() != 1)
{
mUi->m_lineEdit_ExerciseName->setStyleSheet(bgColorRed);
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Exercise name must be one word!"));
}
else if (strWords[0] == QStringLiteral("-"))
{
mUi->m_lineEdit_ExerciseName->setStyleSheet(bgColorRed);
LtsWidgets::LtsMessageDialog::showMessage(this, tr("\"-\" is no valid exercise name!"));
}
mUi->m_lineEdit_Version->setStyleSheet(mUi->m_lineEdit_Version->text().isEmpty() ? bgColorRed : bgColorWhite);
mUi->m_lineEdit_Purpose->setStyleSheet(mUi->m_lineEdit_Purpose->text().isEmpty() ? bgColorRed : bgColorWhite);
mUi->m_lineEdit_Domain->setStyleSheet(mUi->m_lineEdit_Domain->text().isEmpty() ? bgColorRed : bgColorWhite);
mUi->m_lineEdit_Type->setStyleSheet(mUi->m_lineEdit_Type->text().isEmpty() ? bgColorRed : bgColorWhite);
mUi->m_lineEdit_AuthorName->setStyleSheet(mUi->m_lineEdit_AuthorName->text().isEmpty() ? bgColorRed : bgColorWhite);
mUi->m_lineEdit_Organization->setStyleSheet(mUi->m_lineEdit_Organization->text().isEmpty() ? bgColorRed : bgColorWhite);
mUi->m_lineEdit_Telephone->setStyleSheet(mUi->m_lineEdit_Telephone->text().isEmpty() ? bgColorRed : bgColorWhite);
mUi->m_lineEdit_Email->setStyleSheet(mUi->m_lineEdit_Email->text().isEmpty() ? bgColorRed : bgColorWhite);
}
bool ScenarioDataDialog::inputValid() const
{
QStringList strWords = mUi->m_lineEdit_ExerciseName->text().split(QStringLiteral(" "));
return (!mUi->m_lineEdit_ExerciseDescription->text().isEmpty() &&
(strWords.size() == 1 && strWords[0] != QStringLiteral("-")) &&
!mUi->m_lineEdit_Version->text().isEmpty() &&
!mUi->m_lineEdit_Purpose->text().isEmpty() &&
!mUi->m_lineEdit_Domain->text().isEmpty() &&
!mUi->m_lineEdit_Type->text().isEmpty() &&
!mUi->m_lineEdit_AuthorName->text().isEmpty() &&
!mUi->m_lineEdit_Organization->text().isEmpty() &&
!mUi->m_lineEdit_Telephone->text().isEmpty() &&
!mUi->m_lineEdit_Email->text().isEmpty());
}
void ScenarioDataDialog::onButtonOk()
{
highlightInvalidInput();
if (inputValid())
{
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("exerciseDescription"), mUi->m_lineEdit_ExerciseDescription->text());
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("exerciseName"), mUi->m_lineEdit_ExerciseName->text());
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("exerciseDomain"), mUi->m_lineEdit_Domain->text());
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("exerciseVersion"), mUi->m_lineEdit_Version->text());
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("exercisePurpose"), mUi->m_lineEdit_Purpose->text());
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("pocType"), mUi->m_lineEdit_Type->text());
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("pocAuthor"), mUi->m_lineEdit_AuthorName->text());
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("pocOrganization"), mUi->m_lineEdit_Organization->text());
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("pocEmail"), mUi->m_lineEdit_Email->text());
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("pocTelephone"), mUi->m_lineEdit_Telephone->text());
QDialog::accept();
}
else
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Please verify your input!"));
}
void ScenarioDataDialog::onButtonCancel()
{
QDialog::reject();
}
}
@@ -0,0 +1,54 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <memory>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <OperatorManagement/opm_dtc.h>
#include <ExerciseManagement/exm_dtc.h>
#include "ui_msdl_export_scenario_data.h"
namespace LtsSession
{
class LtsSession;
}
namespace msdl
{
class ScenarioDataDialog : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
ScenarioDataDialog(QWidget *parent,
LtsSession::LtsSession *pSession,
const std::shared_ptr<OperatorManagement::Interface::Dtc> &opmDtc,
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc);
~ScenarioDataDialog();
QString exerciseDescription() const { return mUi->m_lineEdit_ExerciseDescription->text(); }
QString exerciseName() const { return mUi->m_lineEdit_ExerciseName->text(); }
QString exerciseVersion() const { return mUi->m_lineEdit_Version->text(); }
QString exerciseDomain() const { return mUi->m_lineEdit_Domain->text(); }
QString exercisePurpose() const { return mUi->m_lineEdit_Purpose->text(); }
QString pocType() const { return mUi->m_lineEdit_Type->text(); }
QString pocAuthor() const { return mUi->m_lineEdit_AuthorName->text(); }
QString pocOrganization() const { return mUi->m_lineEdit_Organization->text(); }
QString pocEmail() const { return mUi->m_lineEdit_Email->text(); }
QString pocTelephone() const { return mUi->m_lineEdit_Telephone->text(); }
private slots:
void onButtonOk();
void onButtonCancel();
private:
void highlightInvalidInput();
bool inputValid() const;
Ui_ExportScenarioData *mUi;
};
}
@@ -0,0 +1,917 @@
/**
* @RDE_HEADER@
* Importieren von MSDL-Dateien
* $Id$
* $HeadURL$
* $Author$
*/
// at first to avoid compiler errors on windows (CONST as enum value)
#include <xsd/MilitaryScenario_1.0.0.hxx>
#include <xsd/MsdlComplexTypes_1.0.0.hxx>
#include "msdl_import.h"
#include "ui_msdl_import.h"
#include "msdl_logging.h"
#include "msdl_import_show.h"
#include "msdl_mapping_dialog.h"
#include <QFileDialog>
#include <QFile>
#include <QUuid>
#include <QTextStream>
#include <QUrl>
#include <QAbstractMessageHandler>
#include <QDomDocument>
#include <QMimeData>
#include <QProcess>
#include <QtXmlPatterns/QXmlSchema>
#include <QtXmlPatterns/QXmlSchemaValidator>
#include <ngltools/ngltools_filesystem.h>
#include <Common/participant_dis_helper.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <LtsSession/lts_session.h>
#include <LtsUtilsSettings/settings.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <QDir>
namespace msdl
{
static QString gStrMSDLWorkingFolderPath()
{
return QDir::tempPath() + QLatin1String("/excon_msdl/");
}
static QString gStrMSDLWorkingFile()
{
return gStrMSDLWorkingFolderPath() + QStringLiteral("msdl_user_input.xml");
}
using descriptionType = schemas::modelID::modelIdentificationType::description_type;
using organizationsType = msdl_1::MilitaryScenarioType::Organizations_type;
using equipType = organizationsType::Equipment_type;
using equipItemType = equipType::EquipmentItem_type;
using equipOptional = organizationsType::Equipment_optional;
using equipRelationsType = equipItemType::Relations_type;
using unitsType = organizationsType::Units_type;
using unitType = unitsType::Unit_type;
using relationsType = unitType::Relations_type;
using forceRelationDataType = relationsType::ForceRelation_type::ForceRelationData_type;
using forceSidesType = msdl_1::MilitaryScenarioType::ForceSides_type;
using forceSideType = forceSidesType::ForceSide_type;
using ownerChoiceType = equipRelationsType::HoldingOrganization_type::OwnerChoice_type;
using ownerDataType = equipRelationsType::HoldingOrganization_type::OwnerData_type;
using purposeOptional = schemas::modelID::modelIdentificationType::purpose_optional;
ImportMsdl::ImportMsdl(ParticipantManagement::ParticipantEditModel *pModel, const QModelIndex &index, QWidget *parent, LtsSession::LtsSession *pSession)
: NGLDialog(parent)
, m_indexRoot(index)
, m_pModel(pModel)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_pMsdlImportShow(nullptr)
, m_pUi(new Ui_MSDLImport)
, mLogger(msdl::getLogger("ImportMsdl"))
{
m_pUi->setupUi(this);
setWindowTitle(tr("Import Exercise Scenario"));
if (!pSession->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc) || !pSession->getFtc<ParticipantManagement::DataInterface>(m_ppmFtc))
{
ERROR_LOG(mLogger) << "Fetching m_ppmDtc or m_ppmFtc failed!";
setEnabled(false);
}
else
{
m_mapTypes = m_ppmDtc->types();
/*
* Store all DIS ids of each type in 'm_mapDisStr2TypeId' to allow a mapping between
* DIS ids and types when importing units.
*
* Note: A type may have more than one DIS id.
* Note: Each type should have an assigned DIS id! Otherwise it will not be available for mapping!
*/
for (const ParticipantManagement::Type &type : qAsConst(m_mapTypes))
{
for (const auto &disId : type.disEntities())
{
QString strMSDL_DISId = ParticipantManagement::DIS::convertDISTypeInteger2MSDLString(disId);
if (m_mapMSDL_DIS_2TypeId.find(strMSDL_DISId) != m_mapMSDL_DIS_2TypeId.end())
{
WARNING_LOG(mLogger) << "DIS id \"" << strMSDL_DISId << "\" which is assigned to type id \"" << type.id() << "\" is already assigned to type id \"" << m_mapMSDL_DIS_2TypeId[strMSDL_DISId] << "\"";
continue;
}
m_mapMSDL_DIS_2TypeId[strMSDL_DISId] = type.id();
}
}
}
QDir dir(gStrMSDLWorkingFolderPath());
dir.removeRecursively();
if (!dir.mkpath(QStringLiteral(".")))
{
ERROR_LOG(mLogger) << "Could not create path \"" << gStrMSDLWorkingFolderPath() << "\" which is required to parse MSDL data";
setEnabled(false);
}
if (!NGL::copyDirContentsToDir(QStringLiteral("msdl"), gStrMSDLWorkingFolderPath(), true))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Not possible to start MSDL import. Could not copy validation files."));
ERROR_LOG(mLogger) << "Could not copy xsd files to " << gStrMSDLWorkingFolderPath();
return;
}
connect(m_pUi->m_pushbutton_SelectFile, &QPushButton::clicked,
this, &ImportMsdl::slotOpenImportDialog);
connect(m_pUi->m_pushButton_StartImport, &QPushButton::clicked,
this, &ImportMsdl::slotStartImport);
QString strImportFile = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pathSelectedImportFile"), QString()).toString();
m_pUi->m_lineedit_ImportFile->setText(strImportFile);
m_pUi->m_pushButton_StartImport->setEnabled(strImportFile.size());
}
ImportMsdl::~ImportMsdl()
{
delete m_pUi;
}
void ImportMsdl::slotOpenImportDialog()
{
QString strPathSelectedImportFolder = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pathSelectedImportFolder"), QStringLiteral("/shd/CTC/TOOLS/TDS/")).toString();
QString strPathSelectedImportFile = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("MSDL"), QStringLiteral("pathSelectedImportFile"), QStringLiteral("/shd/CTC/TOOLS/TDS/")).toString();
QList<QUrl> urls;
urls << QUrl::fromLocalFile(strPathSelectedImportFile);
QFileDialog fileDialog(this, tr("Select File"), strPathSelectedImportFolder, tr("XML files (*.xml)"));
fileDialog.setSidebarUrls(urls);
fileDialog.setOptions(QFileDialog::ReadOnly);
fileDialog.setFileMode(QFileDialog::ExistingFile);
if (fileDialog.exec()) // TODO: use show(), use signals & slots !
{
strPathSelectedImportFile = fileDialog.selectedFiles().constFirst();
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("pathSelectedImportFolder"), strPathSelectedImportFolder);
if (!strPathSelectedImportFile.size())
return;
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("MSDL"), QStringLiteral("pathSelectedImportFile"), strPathSelectedImportFile);
m_pUi->m_lineedit_ImportFile->setText(strPathSelectedImportFile);
m_pUi->m_pushButton_StartImport->setEnabled(true);
}
}
void ImportMsdl::slotStartImport()
{
QString strPathSelectedImportFile = m_pUi->m_lineedit_ImportFile->text();
createWorkingCopy(strPathSelectedImportFile);
if (!schemaValidation())
return;
#ifdef LTS_DEBUG
delete m_pMsdlImportShow;
m_pMsdlImportShow = new msdl::ImportMsdlShow(nullptr, gStrMSDLWorkingFile());
m_pMsdlImportShow->show();
#endif
QFile file(gStrMSDLWorkingFile());
if (!file.open(QIODevice::ReadOnly))
{
ERROR_LOG(mLogger) << "Could not open msdl working copy: " << gStrMSDLWorkingFile();
return;
}
QDomDocument doc(QStringLiteral("mydocument"));
if (!doc.setContent(&file))
{
file.close();
return;
}
try
{
importExerciseScenario();
}
catch (std::exception &e)
{
// There is so much that could be wrong when importing or exporting MSDL files (missing tags, optional tags, ...)
LtsWidgets::LtsMessageDialog::showMessage(this, tr("MSDL import failed!"));
ERROR_LOG(mLogger) << "MSDL import failed with an exception, e.what(): " << e.what();
}
close();
}
void ImportMsdl::createWorkingCopy(const QString &strImportFile)
{
// Input File
QFile file(strImportFile);
if (!file.open(QIODevice::ReadOnly))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Selected input file doesn't exist on filesystem. Has it been deleted?"), tr("Error"));
return;
}
// Output File
QFile fileWithNamespace(gStrMSDLWorkingFile());
if (!fileWithNamespace.open(QIODevice::WriteOnly | QIODevice::Text))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Cannot create working copy of input file on filesystem:") + QLatin1Char('\n') + gStrMSDLWorkingFile(), tr("Error"));
return;
}
QTextStream inputTextStream(&file);
QTextStream outputTextStream(&fileWithNamespace);
QString line;
bool kommentar = false;
do
{
line = inputTextStream.readLine();
if (kommentar && !line.contains(QStringLiteral("-->")))
continue;
if (line.contains(QStringLiteral("-->")))
{
kommentar = false;
continue;
}
if (line.contains(QStringLiteral("<!--")))
{
kommentar = true;
continue;
}
if ((!line.contains(QStringLiteral("msdl:"))) &&
(!line.contains(QStringLiteral("?xml"))) &&
(!line.contains(QStringLiteral("<!"))) &&
(!line.contains(QStringLiteral("<modelID"))) &&
(!line.contains(QStringLiteral("</modelID"))) &&
(!line.contains(QStringLiteral("<?xml"))))
{
line.replace(QStringLiteral("<"), QStringLiteral("<msdl:"));
line.replace(QStringLiteral("<msdl:/"), QStringLiteral("</msdl:"));
}
if (line.contains(QStringLiteral("<msdl:MilitaryScenario")))
line = QStringLiteral("<msdl:MilitaryScenario xmlns:msdl=\"urn:sisostds:scenario:military:data:draft:msdl:1\" xmlns:modelID=\"http://www.sisostds.org/schemas/modelID\" xmlns:jc3=\"urn:int:nato:standard:mip:jc3iedm:3.1:oo:2.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:sisostds:scenario:military:data:draft:msdl:1 ./MilitaryScenario_1.0.0.xsd\">");
outputTextStream << line << "\n";
}
while (!line.isNull());
}
bool ImportMsdl::schemaValidation()
{
QString strPathToSchemaFile = NGL::findFile(NGL::FileType::ConfigFile, QStringLiteral("MilitaryScenario_1.0.0.xsd"));
QFile schemaFile(strPathToSchemaFile);
if (!schemaFile.open(QIODevice::ReadOnly))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("MilitaryScenario_1.0.0.xsd doesn't exist on filesystem"), tr("Validation Error"));
return false;
}
QXmlSchema schema;
msdl::SchemaMessageHandler smh;
schema.setMessageHandler(&smh);
schema.load(&schemaFile, QUrl::fromLocalFile(schemaFile.fileName()));
// Erst einmal das Schema (*.xsd) ueberpruefen
if (!schema.isValid())
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Schema is invalid"));
return false;
}
QProcess xmllint_cmd;
xmllint_cmd.setProcessChannelMode(QProcess::MergedChannels);
xmllint_cmd.start(QStringLiteral("xmllint"), QStringList()
<< QStringLiteral("--noout")
<< QStringLiteral("--schema")
<< schemaFile.fileName()
<< gStrMSDLWorkingFile());
if (!xmllint_cmd.waitForFinished())
{
ERROR_LOG(mLogger) << "Validation Fault cmd";
return false;
}
#ifdef LTS_DEBUG
QByteArray validation = xmllint_cmd.readAllStandardOutput();
LtsWidgets::LtsMessageDialog::showMessage(this, QString::fromLatin1(validation), tr("Info"));
if (!validation.contains("validates"))
return false;
#endif
// Nun das Schema (*.xsd) gegen das zu importierende MilitaryScenario (*.xml) validieren
QXmlSchemaValidator validator(schema);
if (false /*|| validator.validate(QUrl::fromLocalFile(mImportFile))*/)
{
#ifdef LTS_DEBUG
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Instance document is invalid"));
#endif
return false;
}
return true;
}
ParticipantManagement::ParticipantData ImportMsdl::createParticipant(const MSDLParticipant &unit)
{
ParticipantManagement::ParticipantData p;
// Designator
p.designator(unit.m_designator.toStdString());
p.tacticalIdentifier(unit.m_tacticalIdentifier.toStdString());
// State and Equipment
p.equipmentNumber() = 0;
p.assignState() = ParticipantManagement::ParticipantAssignState::HandoutExcon;
/* Symbol respectively sidc
* We are not using the imported 2525c symbol (that would be: p.symbol(unit.m_symbolIdentifier.toStdString());)
* Instead, we use the symbol of the mapped type!
*/
p.symbol(m_mapTypes[unit.m_mappedTypeId].symbol());
p.typeId(unit.m_mappedTypeId); // Class type is internally derived from typeid, no need (and possibility) to set it here
return p;
}
void ImportMsdl::insertParticipant(const MSDLParticipant &unit, const QModelIndex &index)
{
ParticipantManagement::ParticipantData newParticipant = createParticipant(unit);
createNode(newParticipant, index, unit.m_ownHandle);
}
/*
* All parties respectively forces are display in one treewidget. Hence, they represent root nodes which means
* they are directly appended to the QModelIndex 'm_indexRoot'.
*/
void ImportMsdl::insertParty(const MSDLParty &party)
{
// Create "Force"-Node -> No symbol, no tact. identifier, no classtype
ParticipantManagement::ParticipantData newParty;
newParty.designator(party.m_forceSideName.toStdString());
createNode(newParty, m_indexRoot, party.m_ownHandle);
}
void ImportMsdl::createNode(const ParticipantManagement::ParticipantData &participant, const QModelIndex &index, const QString &handle)
{
int newRow = m_pModel->onInsertRow(index, participant);
QModelIndex newIdx = m_pModel->index(newRow, 0, index);
m_parentIndexCache[handle] = newIdx;
}
/*
* Should be called after each 'insertParticipant' since the newly added participant
* might be the parent of one of the so far parentless units.
*/
void ImportMsdl::checkParentlessUnits()
{
// Check all Units which have not been added so far because their parent is missing
bool parentFound = false;
do
{
parentFound = false;
for (auto itParentless = m_parentlessItems.begin(); itParentless != m_parentlessItems.end();)
{
const MSDLParticipant &parentlessUnit = (*itParentless);
auto itParent = m_parentIndexCache.find(parentlessUnit.m_parentHandle);
// Parent now available in tree?
if (itParent != m_parentIndexCache.end())
{
parentFound = true;
insertParticipant(parentlessUnit, (*itParent));
itParentless = m_parentlessItems.erase(itParentless);
}
else
++itParentless;
}
}
while (parentFound);
}
void ImportMsdl::importExerciseScenario()
{
importPurpose();
QVector<MSDLParty> vecParties = importParties();
for (auto &party : vecParties)
insertParty(party);
QMap<QString, MSDLParticipant> mapUnits = importParticipants();
importEquipment(mapUnits);
QVector<MSDLParticipant> vecUnitsWithValidDISTypes = resolveImportMapping(mapUnits);
if (!vecUnitsWithValidDISTypes.size())
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("There are no units or participants which can be imported."), tr("Import Warning"));
return;
}
buildImportTreeView(vecUnitsWithValidDISTypes);
if (m_setTouchedTypes.size())
{
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(this, tr("You have applied manual DIS mappings between imported units/participants and available database types.<br/>Do you want to save this mapping to database?<br/><br/> If you choose \"No\" you will have to perform the DIS mapping again when importing the same input file at a later timepoint."), tr("Import Information"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::Yes)
{
while (!applyDISMappingChangesToDatabase())
{
LtsWidgets::Button button = LtsWidgets::LtsMessageDialog::showMessage(this, tr("Applied DIS mapping changes could not be saved to database.<br/>Do you want to retry?"), tr("Import Warning"),
LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::No);
if (button == LtsWidgets::Button::No)
break;
}
}
}
}
void ImportMsdl::importPurpose()
{
try
{
std::unique_ptr<msdl_1::MilitaryScenarioType> p(msdl_1::MilitaryScenario(gStrMSDLWorkingFile().toStdString()));
msdl_1::MilitaryScenarioType::ScenarioID_type scIDType = p->ScenarioID();
// Purpose
QString strPurpose;
QString strDescription;
purposeOptional pO = scIDType.purpose();
if (!pO)
{
#ifdef LTS_DEBUG
LtsWidgets::LtsMessageDialog::showMessage(this, tr("No purpose in xml-file"), windowTitle());
#endif
}
else
strPurpose = QString::fromStdString(pO.get());
// Description
descriptionType dT = scIDType.description();
if (dT.empty())
{
#ifdef LTS_DEBUG
LtsWidgets::LtsMessageDialog::showMessage(this, tr("No description in xml-file"), windowTitle());
#endif
}
else
strDescription = QString::fromStdString(dT);
WARNING_LOG(mLogger) << "importPurpose: ToDo: Unused imported data (purpose: \"" << strPurpose << "\", description: \"" << strDescription << "\")";
}
catch (std::exception &e)
{
WARNING_LOG(mLogger) << "importPurpose: exception occurred: " << e.what();
}
}
QVector<MSDLParty> ImportMsdl::importParties()
{
std::unique_ptr<msdl_1::MilitaryScenarioType> p(msdl_1::MilitaryScenario(gStrMSDLWorkingFile().toStdString()));
forceSidesType foSides = p->ForceSides();
forceSidesType::ForceSide_sequence foSiSeq = foSides.ForceSide();
QVector<MSDLParty> vecForces;
vecForces.reserve(foSiSeq.size());
for (const auto &foSiTy : foSiSeq)
{
MSDLParty party; // Destination
party.m_ownHandle = QString::fromStdString(foSiTy.ObjectHandle());
party.m_forceSideName = QString::fromStdString(foSiTy.ForceSideName());
vecForces.push_back(std::move(party));
}
return vecForces;
}
QMap<QString, MSDLParticipant> ImportMsdl::importParticipants()
{
QMap<QString, MSDLParticipant> mapParticipants; // Handle to Participant
std::unique_ptr<msdl_1::MilitaryScenarioType> p(msdl_1::MilitaryScenario(gStrMSDLWorkingFile().toStdString()));
msdl_1::MilitaryScenarioType::Organizations_optional orgOpt = p->Organizations();
if (!orgOpt)
{
WARNING_LOG(mLogger) << "Optional msdl xml tag \"Organizations\" missing. There are not participants to import!";
return mapParticipants;
}
organizationsType orgType = orgOpt.get();
unitsType units = orgType.Units();
unitsType::Unit_sequence unitSeq = units.Unit();
QSet<QString> setParents; // All parents are of type class "Unit"
for (const auto &uTy : unitSeq)
{
try
{
MSDLParticipant tUnit; // Destination
// Designator
QString designator(QStringLiteral("Unknown"));
unitType::Name_optional nameOpt = uTy.Name();
if (nameOpt)
designator = QString::fromStdString(nameOpt.get());
tUnit.m_designator = designator.left(9);
tUnit.m_tacticalIdentifier = designator;
// Symbol respectively sidc
unitType::SymbolIdentifier_type symIdTy = uTy.SymbolIdentifier();
tUnit.m_symbolIdentifier = QString::fromStdString(symIdTy);
// Currently ignoring "hierarchy"
// Element 'ForceSideHandle' stellt den Bezug zur Truppe her
// Element 'CommandingSuperiorHandle' stellt den Bezug zu einer uebergeordneten Einheit her
relationsType reTyps = uTy.Relations();
relationsType::ForceRelation_type reTyp = reTyps.ForceRelation();
relationsType::ForceRelation_type::ForceRelationChoice_type foRelChTy = reTyp.ForceRelationChoice();
unitType::ObjectHandle_type obHaTy = uTy.ObjectHandle();
tUnit.m_ownHandle = QString::fromStdString(obHaTy);
// Einheit ist direkt unter der Truppe
if (foRelChTy == relationsType::ForceRelation_type::ForceRelationChoice_type::FORCE_SIDE)
{
// obHaTy ist eigener Object-Handle. "0", weil Vorgesetzter die Pooltruppe
forceRelationDataType::ForceSideHandle_optional foSiHaOp = uTy.Relations().ForceRelation().ForceRelationData().ForceSideHandle();
tUnit.m_parentForce = QString::fromStdString(foSiHaOp.get());
tUnit.m_parentHandle = QStringLiteral("0"); // 0 for "FORCE_SIDE" types since forces are always on top without parent
setParents.insert(tUnit.m_ownHandle);
DEBUG_LOG(mLogger) << "Party: handle: " << tUnit.m_ownHandle << ", parentHandle: " << tUnit.m_parentHandle << ", parent force: " << tUnit.m_parentForce;
}
else if (foRelChTy == relationsType::ForceRelation_type::ForceRelationChoice_type::UNIT)
{
// Einheit ist unter einer anderen Einheit
// Vorgesetzte Einheit ermitteln
forceRelationDataType::CommandRelation_optional cmdRelOpt = uTy.Relations().ForceRelation().ForceRelationData().CommandRelation();
forceRelationDataType::CommandRelation_type cmdRelTyp = cmdRelOpt.get();
tUnit.m_parentHandle = QString::fromStdString(cmdRelTyp.CommandingSuperiorHandle());
WARNING_LOG(mLogger) << "Participant: handle: " << tUnit.m_ownHandle.toStdString() << ", parentHandle: " << tUnit.m_parentHandle;
setParents.insert(tUnit.m_parentHandle);
}
mapParticipants[tUnit.m_ownHandle] = tUnit;
}
catch (std::exception &e)
{
ERROR_LOG(mLogger) << "Exception occured when importing unit, skipping unit! " << e.what();
}
}
// Each parent is of type class 'Unit' or 'SupportUnit'
for (auto &e : setParents)
mapParticipants[e].m_typeClassIsUnit = true;
return mapParticipants;
}
void ImportMsdl::importEquipment(QMap<QString, MSDLParticipant> &mapUnits)
{
std::unique_ptr<msdl_1::MilitaryScenarioType> p(msdl_1::MilitaryScenario(gStrMSDLWorkingFile().toStdString()));
msdl_1::MilitaryScenarioType::Organizations_optional orgOpt = p->Organizations();
if (!orgOpt)
{
WARNING_LOG(mLogger) << "Optional msdl xml tag \"Organizations\" missing. There is no equipment to import!";
return;
}
organizationsType orgType = orgOpt.get();
equipOptional equipOpt = orgType.Equipment();
if (!equipOpt)
{
WARNING_LOG(mLogger) << "Optional msdl xml tag \"Equipment\" missing: There is no equipment to import!";
return;
}
equipType eqTy = equipOpt.get();
equipType::EquipmentItem_sequence eqItSeq = eqTy.EquipmentItem();
for (const auto &eqItType : eqItSeq)
{
// Equipment handle
equipItemType::ObjectHandle_type obHaTy = eqItType.ObjectHandle();
QString equipmentHandle = QString::fromStdString(obHaTy);
// Owner (unit) handle
equipRelationsType reTyps = eqItType.Relations();
ownerDataType::UnitOwnerHandle_optional unOwHa = reTyps.HoldingOrganization().OwnerData().UnitOwnerHandle();
if (!unOwHa)
{
WARNING_LOG(mLogger) << "No owner handle found for equipment handle " << equipmentHandle << ", ignoring equipment";
continue;
}
QString ownerHandle = QString::fromStdString(unOwHa.get());
if (mapUnits.find(ownerHandle) == mapUnits.end())
{
WARNING_LOG(mLogger) << "Equipment owner handle " << ownerHandle << " for equipment handle " << equipmentHandle << " does not exist, ignoring equipment";
continue;
}
equipItemType::EquipmentSymbolModifiers_optional eqSymModifiers = eqItType.EquipmentSymbolModifiers();
if (!eqSymModifiers)
{
WARNING_LOG(mLogger) << "No EquipmentSymbolModifier found for equipment handle " << equipmentHandle << ", not importing equipment and therefore skipping associated unit";
continue;
}
// prüfen ob vorhanden bzw. 21 zeichen?
QString strDisType = QString::fromStdString(eqSymModifiers.get().UniqueDesignation());
if (strDisType.size() != 21)
{
WARNING_LOG(mLogger) << "IGNORING Equipment handle " << equipmentHandle << ": MSDL DIS string length does not equal 21 characters: " << strDisType << " (ownerHandle: " << ownerHandle << ")";
continue;
}
WARNING_LOG(mLogger) << "Equipment: Handle " << equipmentHandle << ". DIS string " << strDisType << " ownerHandle: " << ownerHandle;
mapUnits[ownerHandle].m_DISTypeMSDL = strDisType;
// Equipment name
// equipItemType::Name_optional nameOpt = eqItType.Name();
// if(nameOpt)
// QString::fromStdString(nameOpt.get());
// Equipment Symbolidentifier
// equipItemType::SymbolIdentifier_type symIdTy = eqItType.SymbolIdentifier();
// symbolIdentifier = QString::fromStdString(symIdTy);
}
}
void ImportMsdl::buildImportTreeView(QVector<MSDLParticipant> &vecUnitsWithValidDISTypes)
{
// Sort units by their designator which allows to create a treeview that has ordered elements
std::sort(vecUnitsWithValidDISTypes.begin(), vecUnitsWithValidDISTypes.end(), [](const MSDLParticipant & unit1, const MSDLParticipant & unit2)
{
return QString::localeAwareCompare(unit1.m_designator, unit2.m_designator) < 0;
});
for (const MSDLParticipant &p : vecUnitsWithValidDISTypes)
{
/*
* At this point we have to distinguish between 'UNIT' and 'FORCE_SIDE'.
* Force sides do not have a 'm_parentHandle' (they are a root node within the xml-file).
* Hence, we have to append them to a actual force which is stored in 'm_parentForce'.
* A 'UNIT' however as always a parent.
*/
auto it = (p.m_parentHandle != QStringLiteral("0")) ? m_parentIndexCache.find(p.m_parentHandle) : m_parentIndexCache.find(p.m_parentForce);
if (it == m_parentIndexCache.end())
{
m_parentlessItems[p.m_ownHandle] = p;
continue;
}
QModelIndex &parentIdx = (*it);
insertParticipant(p, parentIdx);
checkParentlessUnits();
}
for (auto &unit : m_parentlessItems)
WARNING_LOG(mLogger) << "Parent missing: Could not import unit with handle " << unit.m_ownHandle << ", missing parent: " << unit.m_parentHandle;
}
bool ImportMsdl::applyDISMappingChangesToDatabase()
{
// Apply changes (=user mapped imported unknown DIS ids to database type ids) to database
for (int32_t typeId : qAsConst(m_setTouchedTypes))
{
const ParticipantManagement::Type &touchedType = m_mapTypes.value(typeId);
m_requestHelper->addRequest([this, touchedType]()
{
return m_ppmFtc->modifyTypeRequest(touchedType, this);
});
}
return m_requestHelper->startRequests();
}
void ImportMsdl::mapParticipant2Type(MSDLParticipant &participant, qint32 mappedTypeId)
{
participant.m_mappedTypeId = mappedTypeId;
/*
* We can map non existing DIS id (=empty QString) to type ids.
* However, we cannot extend the type disEntities()-vector within the database since in this case since there is
* simply no DIS id which could be appended to the vector.
* Hence, mapping units/participants with no DIS id to a type id is only temporary and needs to be done each time
* a MSDL file is used for import.
*/
if (!participant.hasDISType())
return;
/*
* It may be possible that several participants have the same unknown DIS id.
* Prevent adding the same DIS id again and again to the same type.
*/
if (!m_mapMSDL_DIS_2TypeId.contains(participant.m_DISTypeMSDL))
{
m_mapMSDL_DIS_2TypeId[participant.m_DISTypeMSDL] = mappedTypeId;
m_mapTypes[mappedTypeId].disEntities().push_back(ParticipantManagement::DIS::convertMSDLString2Integer(participant.m_DISTypeMSDL));
m_setTouchedTypes.insert(mappedTypeId);
}
}
QVector<MSDLParticipant> ImportMsdl::resolveImportMapping(const QMap<QString, MSDLParticipant> &mapUnits)
{
QVector<MSDLParticipant> vecObjectsWithValidDISTypes;
/*
* Identify possible conflicts. Each conflict needs to be solved or ignored by the user.
*
* Note: We have to distinguish between actual participants (which will be later leaves in the treemodel) and units such as "Platoon".
* A MSDLParticipant can be both. If a MSDLUnit has no childs it is a participant otherwise an actual unit.
*
* - Participants can only be edited and appended to units.
* - Units can additionally be extended adding new participants.
*
* Hence, if the user needs to manually specify the type only the classes "Unit" and "SupportUnit" should be available for units
* to create a valid treemodel.
*/
QMap<QString, QVector<MSDLParticipant>> mapParticipantsWithUnknownDisType, mapUnitsWithUnknownDisType;
for (const MSDLParticipant &unit : mapUnits)
{
/*
* No DIS type: User has to perform a manual mapping
* DIS type available but there is no type in our database that matches: User has to perform a manual mapping
*/
if (!unit.hasDISType() || !m_mapMSDL_DIS_2TypeId.contains(unit.m_DISTypeMSDL))
{
if (unit.m_typeClassIsUnit)
mapUnitsWithUnknownDisType[unit.m_DISTypeMSDL].push_back(unit);
else
mapParticipantsWithUnknownDisType[unit.m_DISTypeMSDL].push_back(unit);
}
else
{
// A match between the imported unit (its DIS id) and one of the database types exists: Perform mapping, everything is fine.
vecObjectsWithValidDISTypes.push_back(unit);
vecObjectsWithValidDISTypes.back().m_mappedTypeId = m_mapMSDL_DIS_2TypeId[unit.m_DISTypeMSDL];
}
}
if (mapUnitsWithUnknownDisType.size())
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("<b>Units</b> exist whose DIS type is unknown.<br/>You have to solve this by manually mapping<br/> the appropriate DIS types to existing <b>unit types</b>."), tr("Import Error"));
vecObjectsWithValidDISTypes.append(showMappingDialog(mapUnitsWithUnknownDisType, true));
}
if (mapParticipantsWithUnknownDisType.size())
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("<b>Participants</b> exist whose DIS type is unknown.<br/>You have to solve this by manually mapping<br/> the appropriate DIS types to existing <b>participant types</b>."), tr("Import Error"));
vecObjectsWithValidDISTypes.append(showMappingDialog(mapParticipantsWithUnknownDisType, false));
}
return vecObjectsWithValidDISTypes;
}
QVector<MSDLParticipant> ImportMsdl::showMappingDialog(const QMap<QString, QVector<MSDLParticipant>> &mapConflictMap, bool typeClassIsUnit)
{
QVector<MSDLParticipant> vecUnitsWithValidSymbols;
// Let user solve conflicts
bool userWantsAutoSolve = false;
int32_t mappedTypeId = 0;
auto it = mapConflictMap.begin();
for (; it != mapConflictMap.end(); ++it)
{
const QString &strDisType = it.key();
const QVector<MSDLParticipant> &vecData = it.value();
QString strReason;
bool offerDatabaseEntriesWithoutDISType;
if (!strDisType.size())
{
strReason = QString(tr("No DIS type specified."));
// Imported unit/participant has no DIS type. Mapping "no DIS type" to database elements without a DIS type does not make sense
offerDatabaseEntriesWithoutDISType = false;
}
else
{
strReason = QString(tr("Specified DIS type \"%1\" is unknown.<br/>Affected %2:\nDesignator: %3\nTact. Identifier: %4")).arg(ParticipantManagement::DIS::convertMSDLString2DISString(strDisType), typeClassIsUnit ? QStringLiteral("unit") : QStringLiteral("participant"), vecData[0].m_designator, vecData[0].m_tacticalIdentifier);
offerDatabaseEntriesWithoutDISType = true;
}
QString strType = typeClassIsUnit ? tr("unit(s)") : tr("participant(s)");
strReason += tr("<br/>This applies for %1 %2. Please choose an option:").arg(QString::number(vecData.size()), strType);
msdl::MappingDialog dialog(this, typeClassIsUnit, strReason, m_ppmDtc, offerDatabaseEntriesWithoutDISType);
dialog.exec(); // TODO: use show(), use signals & slots !
if (dialog.skipAllUnmappedElements())
break;
mappedTypeId = dialog.getMappedTypeId();
if (dialog.autoMapAllUnmappedElements())
{
userWantsAutoSolve = true;
break;
}
if (dialog.mappingApplied())
{
for (auto participant : vecData)
{
mapParticipant2Type(participant, mappedTypeId);
vecUnitsWithValidSymbols.push_back(participant);
}
}
}
if (userWantsAutoSolve)
{
// Use selected symbol for all remaining conflicts
for (; it != mapConflictMap.end(); ++it)
{
const QVector<MSDLParticipant> &vecData = it.value();
for (auto participant : vecData)
{
mapParticipant2Type(participant, mappedTypeId);
vecUnitsWithValidSymbols.push_back(participant);
}
}
}
return vecUnitsWithValidSymbols;
}
}
@@ -0,0 +1,106 @@
/**
* @RDE_HEADER@
* Klasse fuer das Importieren von MSDL-Dateien
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <nglwidgets/ngldialog.h>
#include "msdl_logging.h"
#include "msdl_types.h"
#include "zwmsmsdl_export.h"
#include <QModelIndex>
#include <Plugins/ParticipantManagement/Gui/Common/participant_edit_model.h>
#include <memory>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_participants_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_templates_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
namespace LtsSession
{
class LtsSession;
}
class Ui_MSDLImport;
namespace msdl
{
class ImportMsdlShow;
class ZWMSMSDL_EXPORT ImportMsdl : public NGLDialog, protected ParticipantManagement::Interface::Ftc::ModifyTypeReplyHandler
{
Q_OBJECT
public:
ImportMsdl(ParticipantManagement::ParticipantEditModel *pModel, const QModelIndex &index, QWidget *parent, LtsSession::LtsSession *pSession);
virtual ~ImportMsdl();
private slots:
void slotOpenImportDialog();
void slotStartImport();
private:
void onModifyTypeReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
void createWorkingCopy(const QString &strImportFile);
bool schemaValidation();
ParticipantManagement::ParticipantData createParticipant(const MSDLParticipant &unit);
void insertParticipant(const MSDLParticipant &unit, const QModelIndex &index);
void insertParty(const MSDLParty &party);
void createNode(const ParticipantManagement::ParticipantData &participant, const QModelIndex &index, const QString &handle);
void checkParentlessUnits();
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
// Exercise importing has the following call order
void importExerciseScenario();
void importPurpose();
QVector<MSDLParty> importParties();
void importOrganization();
QMap<QString, MSDLParticipant> importParticipants();
void importEquipment(QMap<QString, MSDLParticipant> &mapUnits);
QVector<MSDLParticipant> resolveImportMapping(const QMap<QString, MSDLParticipant> &mapUnits);
QVector<MSDLParticipant> showMappingDialog(const QMap<QString, QVector<MSDLParticipant> > &mapConflictMap, bool typeClassIsUnit);
void buildImportTreeView(QVector<MSDLParticipant> &vecUnitsWithValidDISTypes);
bool applyDISMappingChangesToDatabase();
QMap<QString, int32_t> m_mapMSDL_DIS_2TypeId; // E.g. "003001222001246001000" to "47"
QMap<qint32, ParticipantManagement::Type> m_mapTypes; // E.g. participant id "47" to type id
void mapParticipant2Type(MSDLParticipant &participant, qint32 mappedTypeId);
QSet<int32_t> m_setTouchedTypes;
// Used to create the treeview with the imported participants
QMap<QString, QModelIndex> m_parentIndexCache;
QMap<QString, MSDLParticipant> m_parentlessItems;
QModelIndex m_indexRoot; // Used to append parties/forces to the tree
ParticipantManagement::ParticipantEditModel *m_pModel;
LtsUtils::RequestHelper *m_requestHelper;
msdl::ImportMsdlShow *m_pMsdlImportShow; // Import debug view. Not visible for the actual user when compiling in release mode
Ui_MSDLImport *m_pUi;
msdl::LOGGER_T mLogger;
};
}
@@ -0,0 +1,204 @@
/**
* @RDE_HEADER@
* Den Inhalt von MSDL-Dateien anzeigen
* $Id$
* $HeadURL$
* $Author$
*/
#include "msdl_import_show.h"
#include "ui_msdl_import_show.h"
#include <QMenu>
#include <QFile>
#include <LtsWidgets/lts_message_dialog.h>
#include <nglwidgets/nglstandardbutton.h>
using namespace msdl;
ImportMsdlShow::ImportMsdlShow(QWidget *parent, const QString &xmlFile)
: NGLDialog(parent)
, mImportFile(xmlFile)
, mCollapsedAll(true)
, mExpandedAll(false)
, mLogger(getLogger("ImportMsdlShow"))
{
mUi.setupUi(this);
setWindowTitle(tr("Exercise Scenario"));
move(50, 50);
// ButtonBox
connect(mUi.buttonBox, &NGLDialogButtonBox::onClose,
this, &ImportMsdlShow::onClose);
mUi.treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(mUi.treeWidget, &QTreeWidget::customContextMenuRequested,
this, &ImportMsdlShow::slotCustomContextMenuRequested);
// buttons
buttonClose = mUi.buttonBox->button(NGLStandardButton::Close);
buttonClose->setEnabled(true);
QTreeWidgetItem *header = mUi.treeWidget->headerItem();
mUi.treeWidget->setColumnCount(2);
mUi.treeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
header->setText(0, tr("Element"));
header->setText(1, tr("Content"));
// xsd-Schema gegen xml-Datei ueberpruefen
initTree();
}
void ImportMsdlShow::initTree()
{
QFile file(mImportFile);
if (!file.open(QIODevice::ReadOnly))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("File doesn't exist on filesystem"));
return;
}
QDomDocument doc(QStringLiteral("mydocument"));
if (!doc.setContent(&file))
{
file.close();
return;
}
QDomElement docElem = doc.documentElement();
QDomNodeList qdlist = docElem.childNodes();
for (int i = 0; i < qdlist.size(); i++)
{
QDomNode qdn = qdlist.item(i);
QDomElement e = qdn.toElement();
QTreeWidgetItem *qtWI = new QTreeWidgetItem((QTreeWidget *)nullptr, QStringList(e.tagName()));
mItems.append(qtWI);
showTree(qdn, qtWI);
}
mUi.treeWidget->insertTopLevelItems(0, mItems);
file.close();
}
void ImportMsdlShow::addChild(const QDomElement &scenarioIdElement, QTreeWidgetItem *qtWI)
{
QDomNode domNode = scenarioIdElement.firstChildElement();
while (!domNode.isNull())
{
QDomElement domElement = domNode.toElement();
if (!domElement.isNull())
{
QStringList itemList;
itemList << domElement.tagName() << domElement.text();
QTreeWidgetItem *qtWINew = new QTreeWidgetItem((QTreeWidget *)nullptr, itemList);
qtWI->addChild(qtWINew);
}
domNode = domNode.nextSibling();
}
}
void ImportMsdlShow::showTree(const QDomNode &n, QTreeWidgetItem *qtwi)
{
QDomNodeList qdlist = n.childNodes();
QTreeWidgetItem *dummyParent = nullptr;
for (int i = 0; i < qdlist.size(); i++)
{
QDomNode qdn = qdlist.item(i);
QDomElement qde = qdn.toElement();
if (qde.tagName().size() == 0)
continue;
QStringList itemList;
if (qde.firstChild().toElement().tagName().size())
itemList << qde.tagName();
else
itemList << qde.tagName() << qde.text();
QTreeWidgetItem *qtWI1 = new QTreeWidgetItem(dummyParent, itemList);
qtwi->addChild(qtWI1);
showTree(qdn, qtWI1);
}
}
void ImportMsdlShow::onClose()
{
INFO_LOG(mLogger) << "ON close() ";
accept();
emit signalDialogClose(this);
}
void ImportMsdlShow::slotCustomContextMenuRequested(QPoint p)
{
INFO_LOG(mLogger) << "slotCustomContextMenuRequested";
QMenu *menu = new QMenu(this);
QAction *ac = new QAction(tr("Expand all"), this);
ac->setCheckable(true);
if (mExpandedAll)
ac->setChecked(true);
else
ac->setChecked(false);
ac->setData(QVariant(QStringLiteral("E"))); // expand all
menu->addAction(ac);
ac = new QAction(tr("Collapse all"), this);
ac->setCheckable(true);
ac->setData(QVariant(QStringLiteral("C"))); // collapse all
if (mCollapsedAll)
ac->setChecked(true);
else
ac->setChecked(false);
menu->addAction(ac);
connect(menu, &QMenu::triggered,
this, &ImportMsdlShow::slotCustomContextMenuActionTriggered);
menu->exec(mUi.treeWidget->mapToGlobal(p));
delete menu;
}
void ImportMsdlShow::slotCustomContextMenuActionTriggered(QAction *ac)
{
if (!ac)
return;
if (ac->data().toString() == QStringLiteral("E"))
{
mUi.treeWidget->expandAll();
mCollapsedAll = false;
mExpandedAll = true;
return;
}
if (ac->data().toString() == QStringLiteral("C"))
{
mUi.treeWidget->collapseAll();
mCollapsedAll = true;
mExpandedAll = false;
return;
}
}
void SchemaMessageHandler::handleMessage(QtMsgType type,
const QString &description,
const QUrl &identifier,
const QSourceLocation &sourceLocation)
{
ERROR_LOG(mLogger) << "type: " << type << " desc: " << description;
if (identifier.isValid())
ERROR_LOG(mLogger) << "identifier: " << identifier.toString();
if (!sourceLocation.isNull())
ERROR_LOG(mLogger) << "sourceLocation: "
<< sourceLocation.uri().toString()
<< " line: " << sourceLocation.line()
<< " column: " << sourceLocation.column()
;
}
@@ -0,0 +1,65 @@
/**
* @RDE_HEADER@
* Klasse zum Anzeigen von MSDL-Dateien
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtXml/QDomDocument>
#include <QtXmlPatterns/QAbstractMessageHandler>
#include <nglwidgets/ngldialog.h>
#include "msdl_logging.h"
#include "ui_msdl_import_show.h"
namespace msdl
{
class SchemaMessageHandler : public QAbstractMessageHandler
{
Q_OBJECT
public:
explicit SchemaMessageHandler(QObject *parent = nullptr)
: QAbstractMessageHandler(parent)
, mLogger(getLogger("SchemaMessageHandler"))
{}
protected:
void handleMessage(QtMsgType type,
const QString &description,
const QUrl &identifier = QUrl(),
const QSourceLocation &sourceLocation = QSourceLocation()) override;
private:
LOGGER_T mLogger;
};
class ImportMsdlShow : public NGLDialog
{
Q_OBJECT
public:
ImportMsdlShow(QWidget *parent, const QString &xmlFile);
signals:
void signalDialogClose(NGLDialog *ngld);
private slots:
void onClose();
void slotCustomContextMenuRequested(QPoint p);
void slotCustomContextMenuActionTriggered(QAction *ac);
private:
void initTree();
void addChild(const QDomElement &scenarioIdElement, QTreeWidgetItem *qtWI);
void showTree(const QDomNode &n, QTreeWidgetItem *qtwi);
QList<QTreeWidgetItem *> mItems;
NGLStandardButton *buttonClose;
Ui_MSDLImportShow mUi;
QString mImportFile;
bool mCollapsedAll;
bool mExpandedAll;
LOGGER_T &mLogger;
};
} // namespace ZWMSMSDL
@@ -0,0 +1,29 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#include <NGLLogger/NGLLoggerBootstrap.h>
#include "msdl_logging.h"
namespace msdl
{
LOGGER_T getLogger(const char *name)
{
static const QLatin1String zwmsmsdl("NGL.ZWMSMSDL.");
std::string loggerName;
const size_t len = strlen(name);
loggerName.reserve(zwmsmsdl.size() + len);
loggerName.append(zwmsmsdl.data(), zwmsmsdl.size());
loggerName.append(name, len);
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
getNGLLogger(loggerName);
}
} // namespace ZWMSMSDL
@@ -0,0 +1,20 @@
/**
* @RDE_HEADER@
* WiSi - logging facility
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
namespace msdl
{
using LOGGER_T = NGL::INGLLogger&;
LOGGER_T getLogger(const char *name);
} // namespace ZWMSWI
@@ -0,0 +1,132 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#include "msdl_mapping_dialog.h"
#include "ui_msdl_mapping_dialog.h"
#include <ParticipantManagement/ppm_translation.h>
#include <set>
namespace msdl
{
MappingDialog::MappingDialog(QWidget *parent, bool typeClassIsUnit, const QString &strReason, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc, bool offerDatabaseEntriesWithoutDISType) : LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
, m_offerDatabaseEntriesWithoutDISType(offerDatabaseEntriesWithoutDISType)
, mLogger(msdl::getLogger("MSDLMappingDialog"))
, m_ppmDtc(ppmDtc)
, mUi(new Ui_MSDLMappingDialog)
{
mUi->setupUi(this);
mUi->m_label_ConflictReason->setText(strReason);
m_mapTypes = m_ppmDtc->types();
std::set<ParticipantManagement::TypeClass> setTypeClasses; // unordered set?
/*
* Show only type classes that include types with DIS ids. This should normally the case for all
* type classes!
*/
for (const ParticipantManagement::Type &type : qAsConst(m_mapTypes))
{
if (!m_offerDatabaseEntriesWithoutDISType && (type.disEntities().size() == 0))
{
WARNING_LOG(mLogger) << "Type id " << type.id() << " does not have assigned DIS types! Type cannot be used when importing MSDL data!";
continue;
}
const ParticipantManagement::TypeClass typeClassId = type.typeClass();
if (typeClassIsUnit)
{
if (typeClassId != ParticipantManagement::TypeClass::Unit)
continue;
}
else
{
if (typeClassId == ParticipantManagement::TypeClass::Unit || typeClassId == ParticipantManagement::TypeClass::SupportUnit || typeClassId == ParticipantManagement::TypeClass::SupportEntity)
continue;
}
setTypeClasses.insert(typeClassId);
}
for (const auto &typeclass : setTypeClasses)
mUi->m_ltsComboBox_typeClass->addItem(ParticipantManagement::toString(typeclass), typeclass.underlying());
slotClassTypeChanged();
connect(mUi->m_ltsComboBox_typeClass, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged), this, &MappingDialog::slotClassTypeChanged);
connect(mUi->m_PushButton_Skip, &QPushButton::clicked, this, &MappingDialog::close);
connect(mUi->m_pushButton_Apply, &QPushButton::clicked, this, &MappingDialog::slotApplyMapping);
connect(mUi->m_pushButton_SkipAllConflicts, &QPushButton::clicked, this, &MappingDialog::slotSkipAllElements);
}
MappingDialog::~MappingDialog()
{
delete mUi;
}
void MappingDialog::slotClassTypeChanged()
{
mUi->m_ltsComboBox_type->clear();
int currentClass = mUi->m_ltsComboBox_typeClass->currentData().toInt();
for (const ParticipantManagement::Type &type : qAsConst(m_mapTypes))
{
if (type.typeClass().underlying() != currentClass)
continue;
if (!m_offerDatabaseEntriesWithoutDISType && (type.disEntities().size() == 0))
{
// Should never happen -> Database broken?!
WARNING_LOG(mLogger) << "Type id " << type.id() << " does not have assigned DIS types! Type cannot be used when importing MSDL data!";
continue;
}
mUi->m_ltsComboBox_type->addItem(QString::fromStdString(type.name()), type.id());
}
}
void MappingDialog::slotApplyMapping()
{
m_mappingPerformed = true;
close();
}
void MappingDialog::slotSkipAllElements()
{
m_skipAllUnmappedElements = true;
close();
}
bool MappingDialog::mappingApplied() const
{
return m_mappingPerformed;
}
bool MappingDialog::skipAllUnmappedElements() const
{
return m_skipAllUnmappedElements;
}
bool MappingDialog::autoMapAllUnmappedElements() const
{
return mUi->m_checkBox_UseTypeForAllConflicts->isChecked();
}
int32_t MappingDialog::getMappedTypeId() const
{
int index = mUi->m_ltsComboBox_type->currentData().toInt();
return m_mapTypes[index].id();
}
}
@@ -0,0 +1,53 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "msdl_logging.h"
#include <memory>
#include <ParticipantManagement/ppm_dtc.h>
#include <LtsWidgets/lts_frameless_dialog.h>
class Ui_MSDLMappingDialog;
namespace msdl
{
class MappingDialog : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
MappingDialog(QWidget *parent,
bool typeClassIsUnit,
const QString &strReason,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
bool offerDatabaseEntriesWithoutDISType);
~MappingDialog();
bool mappingApplied() const;
bool skipAllUnmappedElements() const;
bool autoMapAllUnmappedElements() const;
int32_t getMappedTypeId() const;
private slots:
void slotClassTypeChanged();
void slotApplyMapping();
void slotSkipAllElements();
private:
bool m_offerDatabaseEntriesWithoutDISType = false;
bool m_mappingPerformed = false;
bool m_skipAllUnmappedElements = false;
QMap<qint32, ParticipantManagement::Type> m_mapTypes;
msdl::LOGGER_T mLogger;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
Ui_MSDLMappingDialog *mUi;
};
}
@@ -0,0 +1,15 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#include "msdl_types.h"
#include <QRegularExpression>
#include <QStringList>
namespace msdl
{
}
@@ -0,0 +1,51 @@
/**
* @RDE_HEADER@
* Typen fuer das Importieren von MSDL-Dateien
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QString>
namespace msdl
{
struct MSDLParty
{
QString m_ownHandle;
QString m_forceSideName;
};
class MSDLParticipant
{
public:
int32_t m_mappedTypeId = 0;
QString m_parentForce;
QString m_ownHandle;
QString m_parentHandle;
QString m_designator;
QString m_tacticalIdentifier;
QString m_symbolIdentifier;
bool hasDISType() const { return m_DISTypeMSDL.size(); }
/*
* Mapping of imported units is NOT done by using the symbolIdentifier (sidc).
* Instead, the Equipment::UniqueDesignation field which stores a
* dis entity type information is used to perform the mapping.
*/
QString m_DISTypeMSDL;
/*
* If true, the type class is: Bt, Co, Plt, Sec
* This means the created nodes within the treewidget will differ.
* E.g., appending soldiers is only allowed to units.
*/
bool m_typeClassIsUnit = false;
};
}
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MSDLExport</class>
<widget class="NGLDialog" name="MSDLExport">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>422</width>
<height>48</height>
</rect>
</property>
<property name="maximumSize">
<size>
<width>800</width>
<height>600</height>
</size>
</property>
<property name="windowTitle">
<string>Import Exercise Scenario</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Export exercise to file:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="leExportFile">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="tbExportFile">
<property name="text">
<string notr="true">...</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="m_pushButton_StartExport">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Ok</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>NGLDialog</class>
<extends>QDialog</extends>
<header>nglwidgets/ngldialog.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>leExportFile</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,236 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExportScenarioData</class>
<widget class="QDialog" name="ExportScenarioData">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>521</width>
<height>527</height>
</rect>
</property>
<property name="windowTitle">
<string>Enter Export Information</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Scenario Information:</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Exercise name:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="m_lineEdit_ExerciseName">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Description:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="m_lineEdit_ExerciseDescription">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Purpose:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="m_lineEdit_Purpose">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Version:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="m_lineEdit_Version">
<property name="text">
<string>1.0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Domain:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="m_lineEdit_Domain">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Point of Contact:</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Type:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="m_lineEdit_Type">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Author:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="m_lineEdit_AuthorName">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Organization:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="m_lineEdit_Organization">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Telephone:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="m_lineEdit_Telephone">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Email:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="m_lineEdit_Email">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="1">
<widget class="QPushButton" name="m_pushButton_Ok">
<property name="text">
<string>Start Export</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="m_pushButton_Cancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MSDLImport</class>
<widget class="NGLDialog" name="MSDLImport">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>433</width>
<height>49</height>
</rect>
</property>
<property name="maximumSize">
<size>
<width>800</width>
<height>600</height>
</size>
</property>
<property name="windowTitle">
<string>Import Exercise Scenario</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="m_label_Import">
<property name="text">
<string>Selected MSDL File:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="m_lineedit_ImportFile">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="m_pushbutton_SelectFile">
<property name="text">
<string notr="true">...</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="m_pushButton_StartImport">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Start Import</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>NGLDialog</class>
<extends>QDialog</extends>
<header>nglwidgets/ngldialog.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>m_lineedit_ImportFile</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MSDLImportShow</class>
<widget class="NGLDialog" name="MSDLImportShow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>735</width>
<height>514</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">defined in source</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTreeWidget" name="treeWidget">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item row="1" column="0">
<widget class="NGLDialogButtonBox" name="buttonBox" native="true">
<property name="focusPolicy">
<enum>Qt::TabFocus</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>NGLDialog</class>
<extends>QDialog</extends>
<header>nglwidgets/ngldialog.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>NGLDialogButtonBox</class>
<extends>QWidget</extends>
<header>nglwidgets/ngldialogbuttonbox.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MSDLMappingDialog</class>
<widget class="QDialog" name="MSDLMappingDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>645</width>
<height>194</height>
</rect>
</property>
<property name="windowTitle">
<string>Import Conflict Occurred</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="m_label_ConflictReason">
<property name="text">
<string notr="true">TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Skip mapping:</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="m_label_ConflictReason_2">
<property name="text">
<string>Note: Skipped types will not be imported</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="m_pushButton_SkipAllConflicts">
<property name="text">
<string>Skip all remaining types</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="m_PushButton_Skip">
<property name="text">
<string>Skip only this type</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Apply mapping:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="2">
<widget class="LtsWidgets::LtsComboBox" name="m_ltsComboBox_typeClass"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="LtsWidgets::LtsComboBox" name="m_ltsComboBox_type"/>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="m_checkBox_UseTypeForAllConflicts">
<property name="text">
<string>Use type for all remaining types</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="m_pushButton_Apply">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<?purpose description="This schema defines the Military Scenario" ?>
<?version number="1.0" date="March 25, 2007"?>
<?copyright statement="Copyright © 2007 by the Simulation Interoperability Standards Organization, Inc.
P.O. Box 781238
Orlando, FL 32878-1238, USA
All rights reserved.
Permission is hereby granted for SISO developing committee participants to reproduce this document only for purposes of SISO product development activities. Prior to submitting this document to another standards development organization for standardization activities, permission must first be obtained from the SISO Standards Activity Committee (SAC). Other entities seeking permission to reproduce this document, in whole or in part, must obtain permission from the SISO Executive Committee (EXCOM).
SISO EXCOM
P.O. Box 781238
Orlando, FL 32878-1238, USA"?>
<xs:schema targetNamespace="urn:sisostds:scenario:military:data:draft:msdl:1" xmlns:msdl="urn:sisostds:scenario:military:data:draft:msdl:1"
xmlns:modelID="http://www.sisostds.org/schemas/modelID" xmlns:jc3iedm="urn:int:nato:standard:mip:jc3iedm:3.1:oo:2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="1.0.0" id="MSDL">
<xs:include schemaLocation="MsdlComplexTypes_1.0.0.xsd"/>
<xs:element name="MilitaryScenario" type="msdl:MilitaryScenarioType">
<xs:annotation>
<xs:documentation>The Military Scenario for the exercise.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:schema>
@@ -0,0 +1,456 @@
<?xml version="1.0" encoding="UTF-8"?>
<?purpose description="This schema defines the Military Scenario" ?>
<?version number="1.0" date="March 25, 2007"?>
<?copyright statement="Copyright © 2007 by the Simulation Interoperability Standards Organization, Inc.
P.O. Box 781238
Orlando, FL 32878-1238, USA
All rights reserved.
Permission is hereby granted for SISO developing committee participants to reproduce this documentfor purposes of SISO product development activities only. Prior to submitting this document to another standards development organization for standardization activities, permission must first be obtained from the SISO Standards Activity Committee (SAC). Other entities seeking permission to reproduce this document, in whole or in part, must obtain permission from the SISO Executive Committee (EXCOM).
SISO EXCOM
P.O. Box 781238
Orlando, FL 32878-1238, USA"?>
<xs:schema targetNamespace="urn:sisostds:scenario:military:data:draft:msdl:1" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdl="urn:sisostds:scenario:military:data:draft:msdl:1" elementFormDefault="qualified" version="1.0.0" id="MSDL">
<xs:simpleType name="enumAnchorPointType">
<xs:annotation>
<xs:documentation>Enumerated choice of an absolute Coordinate or point graphic as a location reference</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="COORDINATE"/>
<xs:enumeration value="POINT_TACTICAL_GRAPHIC"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumAirFormationType">
<xs:annotation>
<xs:documentation>The formation of air (aviation) elements</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="NOT_SPECIFIED"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumBaseAffiliation">
<xs:annotation>
<xs:documentation>Enumerated values for the base affiliation of FRIEND, HOSTILE, NEUTRAL, and UNKNOWN.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="HOSTILE"/>
<xs:enumeration value="FRIEND"/>
<xs:enumeration value="NEUTRAL"/>
<xs:enumeration value="UNKNOWN"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumCombatEffectivenessType">
<xs:annotation>
<xs:documentation>The text modifier for units and installations that indicates unit effectiveness or installation capability.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="GREEN">
<xs:annotation>
<xs:documentation>85 percent or greater strength (combat capable)</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="AMBER">
<xs:annotation>
<xs:documentation>70 to 84 percent strength (combat capable with minor deficiencies)</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="RED">
<xs:annotation>
<xs:documentation>50 to 69 percent strength (combat ineffective, unit has major losses or deficiencies)</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="BLACK">
<xs:annotation>
<xs:documentation>Less than 50 percent strength (requires reconstitution before next mission)</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="WHITE">
<xs:annotation>
<xs:documentation>Not applicable or no information available</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumCommandRelationshipType">
<xs:annotation>
<xs:documentation>Enumerated choice for the type of command under which the unit has been task organized as taken from FM 100-7 'The Army In Theater Operations'</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="ORGANIC"/>
<xs:enumeration value="ATTACHED"/>
<xs:enumeration value="OPCON"/>
<xs:enumeration value="TACON"/>
<xs:enumeration value="ADCON"/>
<xs:enumeration value="NONE"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumCommunicationNetType">
<xs:annotation>
<xs:documentation>The typical list of Communications Net Types for Army Units.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="OTHER"/>
<xs:enumeration value="COMMAND_NET"/>
<xs:enumeration value="OPERATIONS_INTELLIGENCE_NET"/>
<xs:enumeration value="ADMIN_LOGISTICS_NET"/>
<xs:enumeration value="FIRE_SUPPORT_NET"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumCommunicationServiceType">
<xs:annotation>
<xs:documentation>The typical list of Communications Net Types for Army Units.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="DATTRF">
<xs:annotation>
<xs:documentation>Data Transfer.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="FAX">
<xs:annotation>
<xs:documentation>Facsimile.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="IIF">
<xs:annotation>
<xs:documentation>Identify Friend or Foe.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="IMAGE">
<xs:annotation>
<xs:documentation>Image.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="MCI">
<xs:annotation>
<xs:documentation>MCI.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="MHS">
<xs:annotation>
<xs:documentation>Message Handling Service.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="TDL">
<xs:annotation>
<xs:documentation>Tactical Data Link.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="VIDSVC">
<xs:annotation>
<xs:documentation>Video Service.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="VOCSVC">
<xs:annotation>
<xs:documentation>Voice Service.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NOS">
<xs:annotation>
<xs:documentation>Not Otherwise Specified</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumCoordinateSystemType">
<xs:annotation>
<xs:documentation>Enumerated choice for the type of coordinate as MGRS, UTM, GCC, and GCS.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="MGRS"/>
<xs:enumeration value="GDC"/>
<xs:enumeration value="UTM"/>
<xs:enumeration value="GCC"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumEchelon">
<xs:annotation>
<xs:documentation>Graphic modifier that identifies Command level.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="NONE"/>
<xs:enumeration value="TEAM"/>
<xs:enumeration value="CREW"/>
<xs:enumeration value="SQUAD"/>
<xs:enumeration value="SECTION"/>
<xs:enumeration value="PLATOON"/>
<xs:enumeration value="DETACHMENT"/>
<xs:enumeration value="COMPANY"/>
<xs:enumeration value="BATTERY"/>
<xs:enumeration value="TROOP"/>
<xs:enumeration value="BATTALION"/>
<xs:enumeration value="SQUADRON"/>
<xs:enumeration value="REGIMENT"/>
<xs:enumeration value="GROUP"/>
<xs:enumeration value="BRIGADE"/>
<xs:enumeration value="DIVISION"/>
<xs:enumeration value="CORPS"/>
<xs:enumeration value="ARMY"/>
<xs:enumeration value="ARMYGROUP"/>
<xs:enumeration value="FRONT"/>
<xs:enumeration value="REGION"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumForceOwnerType">
<xs:annotation>
<xs:documentation>Enumerated choice for the type of owning organization as a force or unit.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="UNIT"/>
<xs:enumeration value="FORCE_SIDE"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumFormationLocationType">
<xs:annotation>
<xs:documentation>Enumerated choice for the method used to correlate formation to location as cetner of mass or lead element.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="LEAD_ELEMENT">
<xs:annotation>
<xs:documentation>The unit location represents the location of the formation's lead element, identified by a formation order of 1.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="CENTER_OF_MASS">
<xs:annotation>
<xs:documentation>The unit location represents the location of the geographical center.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumFormationType">
<xs:annotation>
<xs:documentation>Enumerated choice for The type of formation being Ground, Air, Surface or Subsurface</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="GROUND"/>
<xs:enumeration value="AIR"/>
<xs:enumeration value="SURFACE"/>
<xs:enumeration value="SUBSURFACE"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumGroundFormationType">
<xs:annotation>
<xs:documentation>This is the ground formation from which subordinate elements are placed in formation.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="COLUMN"/>
<xs:enumeration value="STAGGERED_COLUMN"/>
<xs:enumeration value="ECHELON_LEFT"/>
<xs:enumeration value="ECHELON_RIGHT"/>
<xs:enumeration value="LINE"/>
<xs:enumeration value="WEDGE"/>
<xs:enumeration value="VEE"/>
<xs:enumeration value="ASSAULT_VEE"/>
<xs:enumeration value="FSE_COLUMN"/>
<xs:enumeration value="STACK"/>
<xs:enumeration value="NONE"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumMilitaryDomainType">
<xs:annotation>
<xs:documentation>Military domain for the scenario of ACR, RDA, and TEMO.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="ACR"/>
<xs:enumeration value="RDA"/>
<xs:enumeration value="TEMO"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumModelResolutionType">
<xs:annotation>
<xs:documentation>Enumeration indicating the level of fidelity appropriate for instancing the unit or equipment in the simulation</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="NONE">
<xs:annotation>
<xs:documentation>No resolution/representation of the unit or equipment is neccesary to achieve scenario objectives.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="MINIMAL">
<xs:annotation>
<xs:documentation>Minimal resolution representation (graphical display only, no behaviors) of the unit or equipment is necessary to achieve scenario objectives. This resolution typically applies to elements that are displayed as part of the common operating picture, but have not direct impact on scenario objectives.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="STANDARD">
<xs:annotation>
<xs:documentation>Standard (low) resolution representation of the unit or equipment necessary to achieve scenario objectives. This resolution typically applies to elements that are two or more echelons above, below or adjacient to the principle planning unit.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="ENHANCED">
<xs:annotation>
<xs:documentation>Enhanced (medium) resolution representation of the unit or equipment necessary to achieve scenario objectives. This resolution typically applies to elements that are within two echelons of the principle planning unit.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HIGH">
<xs:annotation>
<xs:documentation>High resolution representation of the unit or equipment necessary to achieve scenario objectives. This resolution typically applies to elements that are within one echelon of the principle planning unit.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NOT_SPECIFIED">
<xs:annotation>
<xs:documentation>No resolution has been specified for the unit or equipment.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumMOPPLevelType">
<xs:annotation>
<xs:documentation>Unit specific status of Mission Oriented Protective Posture</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="LEVEL_0">
<xs:annotation>
<xs:documentation>None of the protective clothing and equipment is worn, but it is readily available. </xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="LEVEL_1">
<xs:annotation>
<xs:documentation>The overgarment and helmet cover are worn. </xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="LEVEL_2">
<xs:annotation>
<xs:documentation>TBD. </xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="LEVEL_3">
<xs:annotation>
<xs:documentation>Chemical protective mask and hood are added. At this point personnel are completely encapsulated. </xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="LEVEL_4">
<xs:annotation>
<xs:documentation>Butyl rubber gloves are added.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumOrientationType">
<xs:annotation>
<xs:documentation>Orientation of the graphic to the right or left as defined in the symbology standard</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="ORIENT_RIGHT">
<xs:annotation>
<xs:documentation>Orientation of the point graphic is 90 degress to the right.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="ORIENT_LEFT">
<xs:annotation>
<xs:documentation>Orientation of the point graphic is 90 degress to the left.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumOverlayType">
<xs:annotation>
<xs:documentation>A specific overlay used in the scenario, that is then referenced by the control measures that are to be included on the overlay</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="OPERATIONS"/>
<xs:enumeration value="FIRE_SUPPORT"/>
<xs:enumeration value="MODIFIED_COMBINED_OBSTACLES"/>
<xs:enumeration value="INTEL"/>
<xs:enumeration value="RECON_SURVEILLANCE"/>
<xs:enumeration value="OBSTACLE"/>
<xs:enumeration value="AIR_DEFENSE"/>
<xs:enumeration value="LOGISTICS"/>
<xs:enumeration value="A2C2"/>
<xs:enumeration value="USER_DEFINED"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumReinforcedReducedType">
<xs:annotation>
<xs:documentation>The graphic modifier in a unit symbol that displays (+) for reinforced, (-) for reduced, (±) for reinforced and reduced.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="R"/>
<xs:enumeration value="D"/>
<xs:enumeration value="RD"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumSubsurfaceFormationType">
<xs:annotation>
<xs:documentation>This is the subsurface formation from which subordinate elements are placed in formation</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="NOT_SPECIFIED"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumSupportRelationType">
<xs:annotation>
<xs:documentation>The support relationship of this unit with respect to the unit being supported</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="GS"/>
<xs:enumeration value="DS"/>
<xs:enumeration value="R"/>
<xs:enumeration value="GSR"/>
<xs:enumeration value="NONE"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumSupportRoleType">
<xs:annotation>
<xs:documentation>The support role taken from classes of Priority of Effort being Chemical, Engineer, Fires, and Intelligence</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="FIRES"/>
<xs:enumeration value="INTELLIGENCE"/>
<xs:enumeration value="ENGINEER"/>
<xs:enumeration value="CHEMICAL"/>
<xs:enumeration value="NOT_SPECIFIED"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumSurfaceFormationType">
<xs:annotation>
<xs:documentation>This is the surface formation from which subordinate elements are placed in formation</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="NOT_SPECIFIED"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumSymbolClassType">
<xs:annotation>
<xs:documentation>Enumerated choice for the class of symbology modifiers.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="POINT"/>
<xs:enumeration value="LINE"/>
<xs:enumeration value="AREA"/>
<xs:enumeration value="BOUNDARY"/>
<xs:enumeration value="NBC_EVENT"/>
<xs:enumeration value="TASK"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumSymbologyStandardType">
<xs:annotation>
<xs:documentation>Enumerated choice for the type of symbology standandard.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="MILSTD_2525B"/>
<xs:enumeration value="NATO_APP-6"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="enumWeaponControlStatusType">
<xs:annotation>
<xs:documentation>Degree of fire control, values include free, tight, and hold.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="WEAPONS_FREE">
<xs:annotation>
<xs:documentation>Weapons systems may be fired at any target not positively recognized as friendly.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="WEAPONS_TIGHT">
<xs:annotation>
<xs:documentation>Weapons systems may only be fired in self-defense or in response to a formal order.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="WEAPONS_HOLD">
<xs:annotation>
<xs:documentation>Weapons systems may be fired only at targets recognized as hostile.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:schema>
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,344 @@
<?xml version="1.0" encoding="UTF-8"?>
<?purpose description="This schema defines simple types used in the Military Scenario Definition Language." ?>
<?version number="1.0" date="March 25, 2007"?>
<?copyright statement="Copyright © 2007 by the Simulation Interoperability Standards Organization, Inc.
P.O. Box 781238
Orlando, FL 32878-1238, USA
All rights reserved.
Permission is hereby granted for SISO developing committee participants to reproduce this document only for purposes of SISO product development activities. Prior to submitting this document to another standards development organization for standardization activities, permission must first be obtained from the SISO Standards Activity Committee (SAC). Other entities seeking permission to reproduce this document, in whole or in part, must obtain permission from the SISO Executive Committee (EXCOM).
SISO EXCOM
P.O. Box 781238
Orlando, FL 32878-1238, USA"?>
<xs:schema targetNamespace="urn:sisostds:scenario:military:data:draft:msdl:1" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jc3iedm="urn:int:nato:standard:mip:jc3iedm:3.1:oo:2.0" xmlns:modelID="http://www.sisostds.org/schemas/modelID" xmlns:msdl="urn:sisostds:scenario:military:data:draft:msdl:1" elementFormDefault="qualified" version="1.0.0" id="MSDL">
<xs:simpleType name="boolean">
<xs:annotation>
<xs:documentation>The MSDL base type for boolean values.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:boolean"/>
</xs:simpleType>
<xs:simpleType name="floatCartesianValue9_3">
<xs:annotation>
<xs:documentation>The double precision X component of the Geocentric coordinate.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:double"/>
</xs:simpleType>
<xs:simpleType name="floatCompassDegrees3_3">
<xs:annotation>
<xs:documentation>Compass degrees.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:float">
<xs:minInclusive value="0.00"/>
<xs:maxInclusive value="360.00"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="floatElevationAGL6_2">
<xs:annotation>
<xs:documentation>Altitude or height relative to ground level in metres.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:float">
<xs:minInclusive value="-999999.0"/>
<xs:maxInclusive value="999999.0"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="floatLatitudeLongitude3_3">
<xs:annotation>
<xs:documentation>Fractional degrees of longitude/latitude.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:float">
<xs:maxInclusive value="180.0"/>
<xs:minInclusive value="-180.0"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="floatSpacing4_3">
<xs:annotation>
<xs:documentation>The default spacing in metres between subordinate elements one echelon below.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:float">
<xs:minInclusive value="1."/>
<xs:maxExclusive value="9999.999"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="floatSpeed6_2">
<xs:annotation>
<xs:documentation>The field for unit or equipment speed (for display only). Kilometres per Hour for ground elements; Nautical miles per Hour for air and marine elements.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:float">
<xs:minInclusive value="0.0"/>
<xs:maxInclusive value="999999.0"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="floatUTMEasting9_2">
<xs:annotation>
<xs:documentation>The easting component of the UTM coordinate to the precision value of the MGRS precision element.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:float">
<xs:minInclusive value="0.0"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="floatUTMNorthing9_2">
<xs:annotation>
<xs:documentation>The northing component of the UTM coordinate to the precision value of the MGRS precision element.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:float">
<xs:minInclusive value="0.0"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="integerMajorVersion1">
<xs:annotation>
<xs:documentation>The major version of a product or standard (Major.Minor).</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:int">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="9"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="integerMGRSEasting5">
<xs:annotation>
<xs:documentation>The easting component of the MGRS coordinate to the precision value of the MGRS precision element. </xs:documentation>
</xs:annotation>
<xs:restriction base="xs:long">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="99999"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="integerMGRSNorthing5">
<xs:annotation>
<xs:documentation>The northing component of the MGRS coordinate to the precision value of the MGRS precision element.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:long">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="99999"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="integerMGRSPrecision1">
<xs:annotation>
<xs:documentation>The precision, 2 (km) to 5 (metres), used for each MGRS coordinate.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:int">
<xs:minInclusive value="2"/>
<xs:maxInclusive value="5"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="integerMinorVersion2">
<xs:annotation>
<xs:documentation>The minor version of a product or standard (Major.Minor).</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:int">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="99"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="integerPriorityToSupport1">
<xs:annotation>
<xs:documentation> The Supporting Unit's priority to support another unit from 1 to 9 where 1 is the top priority. </xs:documentation>
</xs:annotation>
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="9"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="integerQuantity9">
<xs:annotation>
<xs:documentation>The text modifier of an equipment symbol that identifies the number of items present.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:int">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="999999999"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="integerSequence6">
<xs:annotation>
<xs:documentation>The sequence or order of elements.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="999999"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternForceSymbolID15">
<xs:annotation>
<xs:documentation>The 15 character Symbol identifier with fields that shall not be interpreted restricted using dashes. These fields would be redundant to other explicit elements in the standard. Affiliation, Status, and Country Code are restricted in this manner. Affiliation and Country Code values are provided in the ForceStructure data. Status is to be interpreted as 'Present' until such time as a separate element is created to distinguish truth values from perceived values.The coding scheme, position 1, must be ‘S’ for unit and equipment symbol identification.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:length value="15"/>
<xs:pattern value="[S]{1}[\-]{1}[PAGMOSTUFVXLIZ\-]{1}[\-]{1}[A-Z\-]{6}[A-Z\-\*]{1}[A-Z\-\*]{1}[\-]{2}[AECGNSX\-\*]{1}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternInstallationSymbolID15">
<xs:annotation>
<xs:documentation>The 15 character Symbol identifier with fields that shall not be interpreted restricted using dashes. These fields would be redundant to other explicit elements in the standard. Affiliation, Status, and Country Code are restricted in this manner. Affiliation and Country Code values are provided in the ForceStructure data. Status is to be interpreted as 'Present' until such time as a separate element is created to distinguish truth values from perceived values. The coding scheme, position 1, must be ‘S’ for unit and equipment symbol identification.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:length value="15"/>
<xs:pattern value="[S]{1}[\-]{1}[G]{1}[AP\-]{1}[I]{1}[A-Z\-]{5}[A-Z\-\*]{1}[A-Z\-\*]{1}[\-]{2}[AECGNSX\-\*]{1}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternMETOCSymbolID15">
<xs:annotation>
<xs:documentation>The 15 character Symbol identifier with fields that shall not be interpreted restricted using dashes. These fields would be redundant to other explicit elements in the standard. Affiliation, Status, and Country Code are restricted in this manner. Affiliation and Country Code values are provided in the ForceStructure data. Status is to be interpreted as 'Present' until such time as a separate element is created to distinguish truth values from perceived values. The coding scheme, position 1, must be ‘W’ for METOC symbol identification.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:length value="15"/>
<xs:pattern value="[W]{1}[AOS]{1}\-\-[BCGHILMOPTW\-]{1}[ABCDEFHIJLMNOPRSTX\-]{1}[ABCDFGHILMNOPQRSTUVW\-]{1}[ABCDEFGHIKLMOPQRSTUVWZ\-]{1}[ABCDEFGHILMNOPRSTVW\-]{1}[ABCEFGHILMOPQSTUVWYZ\-]{1}\-\-\-\-\-"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternMGRSGridSquare2">
<xs:annotation>
<xs:documentation>The MGRS one hundred thousand meter grid square designator, as defined by NIMA TM 8358.1.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:length value="2"/>
<xs:pattern value="[ABCDEFGHJKLMNPQRSTUVWXYZ]{2}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternMOOTWSymbolID15">
<xs:annotation>
<xs:documentation>The 15 character Symbol identifier with fields that shall not be interpreted restricted using dashes. These fields would be redundant to other explicit elements in the standard. Affiliation, Status, and Country Code are restricted in this manner. Affiliation and Country Code values are provided in the ForceStructure data. Status is to be interpreted as 'Present' until such time as a separate element is created to distinguish truth values from perceived values. The coding scheme, position 1, must be ‘O’ for METOC symbol identification.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:length value="15"/>
<xs:pattern value="[O]{1}[\-]{1}[VXLIZ\-]{1}[AP\-]{1}[A-Z\-]{6}[A-Z\-\*]{1}[A-Z\-\*]{1}[\-]{2}[AECGNSX\-\*]{1}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternTacticalGraphicSymbolID15">
<xs:annotation>
<xs:documentation>The 15 character Symbol identifier with fields that shall not be interpreted restricted using dashes. These fields would be redundant to other explicit elements in the standard. Affiliation, Status, and Country Code are restricted in this manner. Affiliation and Country Code values are provided in the ForceStructure data. Status is to be interpreted as 'Present' until such time as a separate element is created to distinguish truth values from perceived values.The coding scheme, position 1, must be ‘G’ for METOC symbol identification.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:length value="15"/>
<xs:pattern value="[G]{1}[\-]{1}[PAGMOSTUFVXLIZ\-]{1}[AP\-]{1}[A-Z\-]{6}[A-Z\-\*]{1}[A-Z\-\*]{1}[\-]{2}[AECGNSX\-\*]{1}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternTimeDTG20">
<xs:annotation>
<xs:documentation>The ISO 8601:2000 DateTime Group format yyyy-mm-ddThh:mm:ssZ e.g. 1998-05-12T14:15:00Z. </xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]{4}-[0-9]{2}-[0-9]{2}[T]{1}[0-9]{2}:[0-9]{2}:[0-9]{2}[Z]{1}"/>
<xs:length value="20"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternTimeDTGRelative20">
<xs:annotation>
<xs:documentation>The ISO 8601:2000 time interval by duration format PnYnMnDTnHnMnS e.g. P00Y00M00DT00H00M00S relative to ScenarioTime when n is a two digit number padded with 0.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:pattern value="[P]{1}[0-9]{2}[Y]{1}[M]{1}[0-9]{2}[D]{1}[0-9]{2}[H]{1}[0-9]{2}[M]{1}[0-9]{2}[S]{1}"/>
<xs:length value="20"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternUTMGridZone3">
<xs:annotation>
<xs:documentation>The UTM Grid Zone designator, to include the number and letter as defined by NIMA TM 8358.1.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:length value="3"/>
<xs:pattern value="[0-9]{2}[ABCDEFGHJKLMNPQRSTUVWXYZ]{1}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternUUID32">
<xs:annotation>
<xs:documentation>The Universal Unique Identifier (UUID) of an object as defined in ISO/IEC 11578:1996 Information technology - Open Systems Interconnection - Remote Procedure Call (RPC).</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:pattern value="[0-9a-z]{8}\-[0-9a-z]{4}\-[0-9a-z]{4}\-[0-9a-z]{4}\-[0-9a-z]{12}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="patternUUIDRef32">
<xs:annotation>
<xs:documentation>Reference to a Universal Unique Identifier (UUID) of an object as defined in ISO/IEC 11578:1996 Information technology - Open Systems Interconnection - Remote Procedure Call (RPC).</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:pattern value="[0-9a-z]{8}\-[0-9a-z]{4}\-[0-9a-z]{4}\-[0-9a-z]{4}\-[0-9a-z]{12}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="text20">
<xs:annotation>
<xs:documentation>General text of length 20 characters.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="20"/>
<xs:pattern value="([ -z]{1})*"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="text21">
<xs:annotation>
<xs:documentation>General text of length 21 characters.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="21"/>
<xs:pattern value="([ -z]{1})*"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="textDatum8">
<xs:annotation>
<xs:documentation>The Datum used to calculate cooridinates.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="8"/>
<xs:pattern value="([ -z]{1})*"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="textEquipmentType24">
<xs:annotation>
<xs:documentation>The text modifier that indicates type of equipment.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="24"/>
<xs:pattern value="([ -z]{1})*"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="textFrameShapeModifier1">
<xs:annotation>
<xs:documentation>The affiliation modifier from the base friend, hostile, neutral, and unknown applied to overlay graphics.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:length value="1"/>
<xs:pattern value="[UJK?_]{1}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="textIdentifier64">
<xs:annotation>
<xs:documentation>The general text identifier.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="64"/>
<xs:pattern value="([ -z]{1})*"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="textIFF5">
<xs:annotation>
<xs:documentation>Text modifier for identification friend or foe (IFF).</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:maxLength value="5"/>
<xs:minLength value="0"/>
<xs:pattern value="([ -z]{1})*"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="textName255">
<xs:annotation>
<xs:documentation xml:lang="en">A character string (i.e. a finite set of characters) generally in the form of words of a language.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="255"/>
<xs:pattern value="([ -z\w]{1})*"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="textSpecialC2HQ9">
<xs:annotation>
<xs:documentation>The name of the special C2 headquarters.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="9"/>
<xs:pattern value="([ -z]{1})*"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,299 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:jc3iedm="urn:int:nato:standard:mip:jc3iedm:3.1:oo:2.0" targetNamespace="urn:int:nato:standard:mip:jc3iedm:3.1:oo:2.0" elementFormDefault="qualified" attributeFormDefault="unqualified">
<annotation>
<documentation xml:lang="en">XML schema defined by the Multilateral Interoperability Programme (MIP) - Editor: Dr. Michael Gerz, gerz@fgan.de, FGAN FKIE, Germany</documentation>
</annotation>
<include schemaLocation="JC3IEDM-3.1-Codes-20061208.xsd" />
<simpleType name="AngleOptionalTypeRangeAngle7_4">
<annotation>
<documentation xml:lang="en">The rotational measurement between two lines and/or planes diverging from a common point and/or line. This measurement will be expressed in units of degrees.</documentation>
</annotation>
<restriction base="decimal">
<totalDigits value="7" />
<fractionDigits value="4" />
<minInclusive value="0.0000" />
<maxInclusive value="360.0000" />
</restriction>
</simpleType>
<simpleType name="DatetimeOptionalTypeFix18">
<annotation>
<documentation xml:lang="en">A designation of a specified chronological point measured using Coordinated Universal Time (UTC) ISO 8601:2000 as a standard of reference, constrained to "zero meridian" i.e. Zulu time zone only. This is expressed as a composite field using a compacted ISO notation YYYYMMDDHHMMSS.SSS where YYYY represents a year, MM represents a month in values from 00 to 12, and DD represents a day in values from 00 to 31, HH represents an hour, MM represents a minute, and SS.SSS represents the number of seconds and milliseconds. (Optional)</documentation>
</annotation>
<restriction base="string">
<minLength value="18" />
<maxLength value="18" />
</restriction>
</simpleType>
<simpleType name="DimensionOptionalType12_3">
<annotation>
<documentation xml:lang="en">A non-negative one-dimensional linear distance measure. This will be expressed in metres. (Optional)</documentation>
</annotation>
<restriction base="decimal">
<totalDigits value="12" />
<fractionDigits value="3" />
<minInclusive value="-999999999.999" />
<maxInclusive value="999999999.999" />
</restriction>
</simpleType>
<simpleType name="DimensionMandatoryType12_3">
<annotation>
<documentation xml:lang="en">A non-negative one-dimensional linear distance measure. This will be expressed in metres. (Mandatory)</documentation>
</annotation>
<restriction base="decimal">
<totalDigits value="12" />
<fractionDigits value="3" />
<minInclusive value="-999999999.999" />
<maxInclusive value="999999999.999" />
</restriction>
</simpleType>
<simpleType name="QuantityOptionalType8_4">
<annotation>
<documentation xml:lang="en">A numeric value that denotes a measure of the physical property of an object. Class word quantity has a fixed unit of measure that must be specified on an attribute-by-attribute basis. Class word quantity is not to be used where class words angle, coordinate, count, dimension, and rate apply. (Optional)</documentation>
</annotation>
<restriction base="decimal">
<totalDigits value="8" />
<fractionDigits value="4" />
<minInclusive value="-9999.9999" />
<maxInclusive value="9999.9999" />
</restriction>
</simpleType>
<simpleType name="RateOptionalType4_1">
<annotation>
<documentation xml:lang="en">A numeric value that denotes a physical property of an object expressed as a proportion of a physical property with respect to a unit of time.The unit of measure for class word rate must be specified on an attribute-by-attribute basis. (Optional)</documentation>
</annotation>
<restriction base="decimal">
<totalDigits value="4" />
<fractionDigits value="1" />
<minInclusive value="-999.9" />
<maxInclusive value="999.9" />
</restriction>
</simpleType>
<simpleType name="RateOptionalType8_4">
<annotation>
<documentation xml:lang="en">A numeric value that denotes a physical property of an object expressed as a proportion of a physical property with respect to a unit of time.The unit of measure for class word rate must be specified on an attribute-by-attribute basis. (Optional)</documentation>
</annotation>
<restriction base="decimal">
<totalDigits value="8" />
<fractionDigits value="4" />
<minInclusive value="-9999.9999" />
<maxInclusive value="9999.9999" />
</restriction>
</simpleType>
<simpleType name="RatioOptionalTypeRangeRatio6_5">
<annotation>
<documentation xml:lang="en">A numeric value representing the quotient of two values that have the same unit of measurement, i.e., ratio has no units of measure. May be used to express a percentage. The allowable range must be specified on an attribute-by-attribute basis. (Optional)</documentation>
</annotation>
<restriction base="decimal">
<totalDigits value="6" />
<fractionDigits value="5" />
<minInclusive value="0.00000" />
<maxInclusive value="1.00000" />
</restriction>
</simpleType>
<simpleType name="RatioOptionalTypeRangeRatio7_6">
<annotation>
<documentation xml:lang="en">A numeric value representing the quotient of two values that have the same unit of measurement, i.e., ratio has no units of measure. May be used to express a percentage. The allowable range must be specified on an attribute-by-attribute basis. (Optional)</documentation>
</annotation>
<restriction base="decimal">
<totalDigits value="7" />
<fractionDigits value="6" />
<minInclusive value="0.000000" />
<maxInclusive value="1.000000" />
</restriction>
</simpleType>
<simpleType name="TemperatureTypeRangeTemperature5_1">
<annotation>
<documentation xml:lang="en">A measure of degree of hotness or coldness in an object or in space. This will be expressed in degrees Celsius.</documentation>
</annotation>
<restriction base="decimal">
<totalDigits value="5" />
<fractionDigits value="1" />
<minInclusive value="-273.2" />
<maxInclusive value="9999.9" />
</restriction>
</simpleType>
<complexType name="Atmosphere">
<annotation>
<documentation xml:lang="en">A METEOROLOGIC-FEATURE that specifies humidity, pressure, and temperature characteristics of Earth's atmosphere.</documentation>
</annotation>
<sequence>
<element name="HumidityRatio" type="jc3iedm:RatioOptionalTypeRangeRatio6_5" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The numeric quotient value that represents the proportion of water present in the air to the maximum amount of water (saturation point) possible at a given temperature and pressure. The value must be in the range from 0 to 1.</documentation>
</annotation>
</element>
<element name="InversionLayerCode" type="jc3iedm:AtmosphereInversionLayerCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the height of the inversion layer in the atmosphere. The stability class describes the degree of mixing of released material in the atmosphere.</documentation>
</annotation>
</element>
<element name="PressureQuantity" type="jc3iedm:QuantityOptionalType8_4" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The numeric value that denotes the ambient air in terms of force per unit area. The unit of measure is newtons per square metre.</documentation>
</annotation>
</element>
<element name="Temperature" type="jc3iedm:TemperatureTypeRangeTemperature5_1" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The numeric value that indicates the heat of the ambient air for a specific ATMOSPHERE.</documentation>
</annotation>
</element>
<element name="TemperatureGradientCode" type="jc3iedm:AtmosphereTemperatureGradientCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents heat change with respect to the ground and 100 m in elevation in a certain area. Acts as an indication of vertical air movement between the ground and higher elevations.</documentation>
</annotation>
</element>
</sequence>
</complexType>
<complexType name="CloudCover">
<annotation>
<documentation xml:lang="en">A METEOROLOGIC-FEATURE that specifies the characteristics of clouds above Earth's surface.</documentation>
</annotation>
<sequence>
<element name="CategoryCode" type="jc3iedm:CloudCoverCategoryCode" minOccurs="1" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the prevailing class of a specific CLOUD-COVER.</documentation>
</annotation>
</element>
<element name="BaseDimension" type="jc3iedm:DimensionOptionalType12_3" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The one-dimensional linear distance representing the elevation of the lowest cloud base for a specific CLOUD-COVER.</documentation>
</annotation>
</element>
<element name="TopDimension" type="jc3iedm:DimensionOptionalType12_3" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The one-dimensional linear distance representing the elevation of the highest cloud ceiling for a specific CLOUD-COVER.</documentation>
</annotation>
</element>
<element name="AverageCoverageCode" type="jc3iedm:CloudCoverAverageCoverageCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the average density of a specific CLOUD-COVER as fractional coverage.</documentation>
</annotation>
</element>
<element name="LightRefractionRatio" type="jc3iedm:RatioOptionalTypeRangeRatio7_6" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The numeric quotient value that represents the velocity of light in a specific CLOUD-COVER as a fraction of the velocity of light in a vacuum, based on cloud height. This represents the inverse of the index of refraction. The value must be in the range from 0 to 1.</documentation>
</annotation>
</element>
</sequence>
</complexType>
<complexType name="Icing">
<annotation>
<documentation xml:lang="en">A METEOROLOGIC-FEATURE that specifies the accumulation of frozen water on stationary or moving surfaces.</documentation>
</annotation>
<sequence>
<element name="CategoryCode" type="jc3iedm:IcingCategoryCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the class of a particular ICING.</documentation>
</annotation>
</element>
<element name="SeverityQualifierCode" type="jc3iedm:IcingSeverityQualifierCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the severity of a particular ICING.</documentation>
</annotation>
</element>
</sequence>
</complexType>
<complexType name="Light">
<annotation>
<documentation xml:lang="en">A METEOROLOGIC-FEATURE that specifies the availability of natural illumination by type and time.</documentation>
</annotation>
<sequence>
<element name="CategoryCode" type="jc3iedm:LightCategoryCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the class of LIGHT.</documentation>
</annotation>
</element>
<element name="UpDatetime" type="jc3iedm:DatetimeOptionalTypeFix18" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The character string representing a point in time that designates the time of day that marks the beginning of the period of effectiveness of the specified type of LIGHT.</documentation>
</annotation>
</element>
<element name="DownDatetime" type="jc3iedm:DatetimeOptionalTypeFix18" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The character string representing a point in time that designates the time of day that marks the end of the period of effectiveness of the specified type of LIGHT.</documentation>
</annotation>
</element>
<element name="MoonPhaseCode" type="jc3iedm:LightMoonPhaseCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the phase of the moon for a specific LIGHT.</documentation>
</annotation>
</element>
</sequence>
</complexType>
<complexType name="Precipitation">
<annotation>
<documentation xml:lang="en">A METEOROLOGIC-FEATURE that specifies the type of particulate matter in the Earth's atmosphere and the rate of its descent onto the Earth's surface.</documentation>
</annotation>
<sequence>
<element name="CategoryCode" type="jc3iedm:PrecipitationCategoryCode" minOccurs="1" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the prevailing class of a specific PRECIPITATION.</documentation>
</annotation>
</element>
<element name="Rate" type="jc3iedm:RateOptionalType4_1" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The numeric value that denotes the amount of PRECIPITATION deposited per unit time. The unit of measure is millimetres per hour.</documentation>
</annotation>
</element>
</sequence>
</complexType>
<complexType name="Visibility">
<annotation>
<documentation xml:lang="en">A METEOROLOGIC-FEATURE that specifies the distance at which an object illuminated by light in the visual spectrum can be detected.</documentation>
</annotation>
<sequence>
<element name="CategoryCode" type="jc3iedm:VisibilityCategoryCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the class of obscurant that governs a particular VISIBILITY.</documentation>
</annotation>
</element>
<element name="RangeDimension" type="jc3iedm:DimensionMandatoryType12_3" minOccurs="1" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The one-dimensional linear distance representing the distance which can be surveyed using visual observation for a specific VISIBILITY.</documentation>
</annotation>
</element>
</sequence>
</complexType>
<complexType name="Wind">
<annotation>
<documentation xml:lang="en">A METEOROLOGIC-FEATURE that specifies the velocity and directional characteristics of atmospheric movement.</documentation>
</annotation>
<sequence>
<element name="CategoryCode" type="jc3iedm:WindCategoryCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value that represents the class of WIND.</documentation>
</annotation>
</element>
<element name="AirStabilityCategoryCode" type="jc3iedm:WindAirStabilityCategoryCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value used to indicate the class of air stability.</documentation>
</annotation>
</element>
<element name="AltitudeLayerCode" type="jc3iedm:WindAltitudeLayerCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value used to indicate the class of the altitude for a specific set of reported wind data.</documentation>
</annotation>
</element>
<element name="DirectionAngle" type="jc3iedm:AngleOptionalTypeRangeAngle7_4" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The rotational measurement clockwise between the line of true North and the direction from which a specific WIND originates.</documentation>
</annotation>
</element>
<element name="EffectiveDownwindDirectionAngle" type="jc3iedm:AngleOptionalTypeRangeAngle7_4" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The rotational measurement of the mean downwind direction at ground level in the hazard area towards which the cloud travels.</documentation>
</annotation>
</element>
<element name="SpeedRate" type="jc3iedm:RateOptionalType8_4" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The numeric value that denotes the distance per unit time of a specific WIND. The unit of measure is kilometres per hour.</documentation>
</annotation>
</element>
<element name="NuclearYieldQualifierCode" type="jc3iedm:NuclearYieldGroupCode" minOccurs="0" maxOccurs="1">
<annotation>
<documentation xml:lang="en">The specific value used to identify predicted wind values associated with nuclear fallout prediction for a specific Nuclear yield group.</documentation>
</annotation>
</element>
</sequence>
</complexType>
</schema>
@@ -0,0 +1,301 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- edited with XMLSpy v2006 sp1 U (http://www.altova.com) by Paul Gustavson (SimVentions, Inc.) -->
<!-- created with XMLSpy v2006 U (http://www.altova.com) by Tram Chase (SimVentions) -->
<!--W3C Schema developed by the SISO BOM Product Develop Group (PDG) - version 2006 - copyright 2006 -->
<!--Schema for BOM DIF
Version 0.12 - Sep 8, 2005
Version 2006 - March 25, 2005
Version 2006a - April 2, 2007 // Reflects and complies to the approved standard SISO-STD-003-2006 submitted March 31, 2006
-->
<xs:schema xmlns="http://www.sisostds.org/schemas/modelID" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.sisostds.org/schemas/modelID" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="String">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="IdentifierType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="NonEmptyString">
<xs:simpleContent>
<xs:extension base="nonEmptyString">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="OMTypeEnumerations">
<xs:restriction base="xs:string">
<xs:enumeration value="FOM"/>
<xs:enumeration value="SOM"/>
<xs:enumeration value="BOM"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="OMTypeUnion">
<xs:union memberTypes="OMTypeEnumerations nonEmptyString"/>
<!--this allows enumerations to be used plus any user defined content -->
</xs:simpleType>
<xs:simpleType name="glyphTypeEnumerations">
<xs:restriction base="xs:string">
<xs:enumeration value="BITMAP"/>
<xs:enumeration value="JPG"/>
<xs:enumeration value="GIF"/>
<xs:enumeration value="PNG"/>
<xs:enumeration value="TIFF"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="glyphTypeUnion">
<xs:union memberTypes="glyphTypeEnumerations xs:string"/>
<!--this allows enumerations to be used plus any user defined content -->
</xs:simpleType>
<xs:complexType name="glyphType">
<xs:simpleContent>
<xs:extension base="xs:base64Binary">
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="type" type="glyphTypeUnion" use="required"/>
<xs:attribute name="height" type="xs:short"/>
<xs:attribute name="width" type="xs:short"/>
<xs:attribute name="alt" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="pocType">
<xs:sequence>
<xs:element name="pocType" type="pocTypeType">
<xs:annotation>
<xs:documentation>specifies the role that the POC has with
respect to the model</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="pocName" type="String" minOccurs="0"/>
<xs:element name="pocOrg" type="String" minOccurs="0"/>
<xs:element name="pocTelephone" type="String" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="pocEmail" type="String" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:attributeGroup name="commonAttributes">
<!--this is the common attributes for any element -->
<xs:attribute name="notes" type="xs:IDREFS" use="optional"/>
<xs:attribute name="idtag" type="xs:ID" use="optional"/>
<xs:anyAttribute namespace="##other"/>
</xs:attributeGroup>
<xs:simpleType name="nonEmptyString">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="SecurityClassificationEnumeration">
<xs:restriction base="xs:string">
<xs:enumeration value="Unclassified"/>
<xs:enumeration value="Confidential"/>
<xs:enumeration value="Secret"/>
<xs:enumeration value="Top Secret"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="SecurityClassificationUnion">
<xs:union memberTypes="SecurityClassificationEnumeration nonEmptyString"/>
</xs:simpleType>
<xs:complexType name="modelType">
<xs:simpleContent>
<xs:extension base="OMTypeUnion">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="securityClassificationType">
<xs:simpleContent>
<xs:extension base="SecurityClassificationUnion">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="ApplicationDomainEnumerations">
<xs:restriction base="xs:string">
<xs:enumeration value="Analysis"/>
<xs:enumeration value="Training"/>
<xs:enumeration value="Test and Evaluation"/>
<xs:enumeration value="Engineering"/>
<xs:enumeration value="Acquisition"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ApplicationDomainUnion">
<xs:union memberTypes="ApplicationDomainEnumerations xs:string"/>
</xs:simpleType>
<xs:complexType name="applicationDomainType">
<xs:simpleContent>
<xs:extension base="ApplicationDomainUnion">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="POCTypeEnumeration">
<xs:restriction base="xs:string">
<xs:enumeration value="Primary author"/>
<xs:enumeration value="Contributor"/>
<xs:enumeration value="Proponent"/>
<xs:enumeration value="Sponsor"/>
<xs:enumeration value="Release authority"/>
<xs:enumeration value="Technical POC"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="POCTypeUnion">
<xs:union memberTypes="POCTypeEnumeration nonEmptyString"/>
</xs:simpleType>
<xs:complexType name="pocTypeType">
<xs:simpleContent>
<xs:extension base="POCTypeUnion">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="referenceTypeEnumerations">
<xs:restriction base="xs:string">
<xs:enumeration value="Source Material"/>
<xs:enumeration value="Conceptual Model"/>
<xs:enumeration value="Related BOM"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="referenceTypeUnion">
<xs:union memberTypes="referenceTypeEnumerations xs:string"/>
<!--this allows enumerations to be used plus any user defined content -->
</xs:simpleType>
<xs:complexType name="referenceType">
<xs:sequence>
<xs:element name="type">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="referenceTypeUnion">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="identification">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:anyURI">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
<xs:complexType name="keywordType">
<xs:sequence>
<xs:element name="taxonomy" type="String" minOccurs="0"/>
<xs:element name="keywordValue" type="NonEmptyString"/>
</xs:sequence>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
<xs:complexType name="modelIdentificationType">
<xs:sequence>
<xs:element name="name" type="IdentifierType">
<xs:annotation>
<xs:documentation>specifies the name assigned to the object model</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="type" type="modelType">
<xs:annotation>
<xs:documentation>specify the type of model that is represented</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="version" type="NonEmptyString">
<xs:annotation>
<xs:documentation>specifies the version identification assigned to the object model</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="modificationDate" nillable="false">
<xs:annotation>
<xs:documentation>specifies the latest date on which this version of the object model was created or modified. The modification date shall be specified in the format "YYYY-MM-DD"</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:date">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="securityClassification" type="securityClassificationType">
<xs:annotation>
<xs:documentation>specifies the security classification of the
object model</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="releaseRestriction" type="String" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>specifies any restrictions on the release of the object models to specific organizations or individuals</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="purpose" type="String" minOccurs="0">
<xs:annotation>
<xs:documentation>specifies the purpose for which the federate or federation was developed</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="applicationDomain" type="applicationDomainType" minOccurs="0">
<xs:annotation>
<xs:documentation>specifies the type or class of application to which the federate or federation applies</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="description" type="NonEmptyString"/>
<xs:element name="useLimitation" type="String" minOccurs="0">
<xs:annotation>
<xs:documentation>specifies any known applications for which this model has been found not to be appropriate</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="useHistory" type="String" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>specifies a description of where this model has been used</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="keyword" type="keywordType" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>specifies keywords that characterize the model</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="poc" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>specify an organization or a
person who has a particular role with respect to the model</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:complexContent>
<xs:extension base="pocType">
<xs:attributeGroup ref="commonAttributes"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="reference" type="referenceType" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>specifies a pointer to additional sources of information</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="other" type="String" minOccurs="0">
<xs:annotation>
<xs:documentation>specifies other data deemed relevant by the author of the object model</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="glyph" minOccurs="0">
<xs:annotation>
<xs:documentation>specifies a glyph to visually represent the model</xs:documentation>
</xs:annotation>
<xs:complexType mixed="true">
<xs:simpleContent>
<xs:extension base="glyphType"/>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,17 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/qglobal.h>
#ifndef ZWMSMSDL_EXPORT
# ifdef MAKE_ZWMSMSDL_LIB
# define ZWMSMSDL_EXPORT Q_DECL_EXPORT
# else
# define ZWMSMSDL_EXPORT Q_DECL_IMPORT
# endif
#endif
@@ -0,0 +1,272 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Last, SLSE, 2017-10-26
*/
#include "ppm_msdl_edit.h"
#include "ui_ppm_msdl_edit.h"
#include "msdl/msdl_import.h"
#include "msdl/msdl_export.h"
#include <QAction>
#include <AdvancedSymbology/asb_data_plugin_interface.h>
#include <Common/participant_edit_model.h>
#include <Common/participant_edit_item.h>
#include <Common/participant_tree_edit_handler.h>
#include <Common/participant_distype_editor.h>
#include <QTreeView>
namespace ParticipantManagement
{
MSDLEdit::MSDLEdit(LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_actionRemove(nullptr)
, m_actionEdit(nullptr)
, m_ppmDtc(nullptr)
, m_ppmFtc(nullptr)
, m_ppmGuiCbxIfc(nullptr)
, m_session(session)
, m_pTreehandlerSystem(nullptr)
, m_pTreehandlerImport(nullptr)
, m_pModelSystem(nullptr)
, m_pModelImport(nullptr)
, m_ui(new Ui::MSDLDialog)
, m_logger(getLogger("MSDLEdit"))
{
m_ui->setupUi(this);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &MSDLEdit::onAddItem);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &MSDLEdit::onEditItem);
connect(m_ui->m_pushButton_Import, &QPushButton::clicked, this, &MSDLEdit::onImport);
connect(m_ui->m_pushButton_Export, &QPushButton::clicked, this, &MSDLEdit::onExport);
connect(m_ui->m_pushButton_distypeEditor, &QPushButton::clicked, this, &MSDLEdit::onDistypeEditor);
setOnlineHelpFilename(QStringLiteral("Situation-Import-Export_MSDL"));
m_ui->m_treeViewEdit_Right->treeView()->setDragDropMode(QAbstractItemView::DragOnly);
m_ui->m_treeViewEdit_Right->treeView()->setSelectionMode(QAbstractItemView::SingleSelection);
m_ui->m_treeViewEdit_Right->treeView()->setDragEnabled(true);
m_ui->m_treeViewEdit_Left->treeView()->setDragDropMode(QAbstractItemView::DropOnly);
m_ui->m_treeViewEdit_Left->treeView()->setAcceptDrops(true);
m_ui->m_treeViewEdit_Left->treeView()->setDropIndicatorShown(true);
}
MSDLEdit::~MSDLEdit()
{
delete m_pTreehandlerImport;
delete m_pTreehandlerSystem;
delete m_ui;
}
void MSDLEdit::retranslate()
{
translate(m_ui, tr("MSDL Import/Export"));
m_ppmGuiCbxIfc->fillPartyComboBox(m_ui->cbParty, ForeignGuiComboboxInterface::CbxPartyFilter::Normal);
}
void MSDLEdit::onDistypeEditor()
{
ParticipantManagement::DistypeEditor dialog(this, m_ppmDtc, m_ppmFtc);
dialog.exec();
}
void MSDLEdit::onImport()
{
m_pModelImport->resetModel();
m_pModelImport->setMimeType(QStringLiteral("MSDLDialog"));
m_pModelSystem->setMimeType(QStringLiteral("MSDLDialog"));
msdl::ImportMsdl dialog(m_pModelImport, QModelIndex(), this, m_session);
dialog.exec(); // TODO: use show(), use signals & slots !
m_pTreehandlerImport->beautifyTreeView(false);
}
void MSDLEdit::onExport()
{
msdl::ExportMsdl dialog(m_session, this);
dialog.exec(); // TODO: use show(), use signals & slots !
}
bool MSDLEdit::init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
const std::shared_ptr<ForeignGuiComboboxInterface> &ppmGuiCbxIfc)
{
if (!dtc || !ftc || !ppmGuiCbxIfc)
{
m_ui->m_pushButton_Import->setEnabled(false);
m_ui->m_pushButton_Export->setEnabled(false);
m_ui->m_pushButton_distypeEditor->setEnabled(false);
return false;
}
m_ppmDtc = dtc;
m_ppmFtc = ftc;
m_ppmGuiCbxIfc = ppmGuiCbxIfc;
m_session->getForeignDataInterface<AdvancedSymbology::DataInterface>(m_asb);
m_pModelImport = new ParticipantEditModel(this, m_ppmDtc, m_asb);
m_ui->m_treeViewEdit_Right->setModel(m_pModelImport);
m_pModelSystem = new ParticipantEditModel(this, m_ppmDtc, m_asb);
connect(m_pModelSystem, &ParticipantEditModel::internalDataChanged, this, &MSDLEdit::slotChangesMade);
m_ui->m_treeViewEdit_Left->setModel(m_pModelSystem);
m_ui->m_treeViewEdit_Left->setContextMenuPolicy(Qt::CustomContextMenu);
m_actionRemove = new QAction(QIcon(QLatin1String("icon:remove.svg")), tr("Remove"), this);
m_actionEdit = new QAction(QIcon(QLatin1String("icon:edit.svg")), tr("Edit"), this);
connect(m_ui->cbParty, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged),
this, &MSDLEdit::onPartyChanged);
m_ppmGuiCbxIfc->fillPartyComboBox(m_ui->cbParty, ForeignGuiComboboxInterface::CbxPartyFilter::Normal);
m_pTreehandlerSystem = new ParticipantTreeEditHandler(m_ui->m_treeViewEdit_Left, m_ppmDtc, m_ppmFtc, false);
connect(m_actionRemove, &QAction::triggered, m_pTreehandlerSystem, &ParticipantTreeEditHandler::onRemoveItem);
connect(m_actionEdit, &QAction::triggered, this, &MSDLEdit::onEditItem);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, m_pTreehandlerSystem, &ParticipantTreeEditHandler::onRemoveItem);
connect(m_pTreehandlerSystem, &ParticipantTreeEditHandler::signalDoubleClicked, this, &MSDLEdit::onEditItem);
connect(m_pTreehandlerSystem, &ParticipantTreeEditHandler::signalSelectionChanged, this, &MSDLEdit::onEnaDisa);
connect(m_pTreehandlerSystem, &ParticipantTreeEditHandler::signalChangesMade, this, &MSDLEdit::onEnaDisa);
// Editing not allowed, just enable context menu (Collapse/Expand item)
m_pTreehandlerImport = new ParticipantTreeEditHandler(m_ui->m_treeViewEdit_Right, m_ppmDtc, m_ppmFtc, false);
onPartyChanged();
onEnaDisa();
return true;
}
void MSDLEdit::onPartyChanged()
{
const int newPartyId = m_ui->cbParty->currentData().toInt();
if (hasUnsavedChanges())
{
switch (askApplyDiscardCancel())
{
case LtsWidgets::Button::Apply:
if (!apply())
return;
break;
case LtsWidgets::Button::Cancel:
m_ui->cbParty->setCurrentIndex(m_ui->cbParty->findData(m_pModelSystem->partyId(), Qt::UserRole));
return;
case LtsWidgets::Button::Discard:
__unchange__(); // can't call resetChanges() by myself :(
break;
default:
break;
}
}
// DEBUG_LOG(m_logger) << LOGFUNCTION << " onPartyChanged !!! -> newPartyId=" << newPartyId;
// m_ui->cbParty->setEnabled(false); // will be re-enabled with reply (::lock, ::unlock)
// tryLockTopicNew(QStringLiteral("LockParty"), newPartyId);
m_pTreehandlerSystem->partyHasChanged(newPartyId, false);
}
bool MSDLEdit::apply()
{
return m_pTreehandlerSystem->onApplyChanges();
}
void MSDLEdit::lock()
{
m_ui->cbParty->setEnabled(true); // true!!
}
void MSDLEdit::unlock()
{
m_ui->cbParty->setEnabled(true);
}
void MSDLEdit::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->m_treeViewEdit_Left->setColumnsOrganiserEnabled(identifier(), true);
m_ui->m_treeViewEdit_Right->setColumnsOrganiserEnabled(identifier(), true);
}
void MSDLEdit::onEnaDisa()
{
bool enableAdd = false;
bool enableEdit = false;
bool enableRemove = false;
if (m_pTreehandlerSystem->isSelectedIndexValid())
{
if (m_pTreehandlerSystem->isContainer()) //only add to units
enableAdd = true;
if (m_pTreehandlerSystem->isSelectedIndexRemovable())
enableRemove = true;
enableEdit = true;
}
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, enableAdd);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, enableEdit);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, enableRemove);
m_actionRemove->setEnabled(enableRemove);
m_actionEdit->setEnabled(enableEdit);
}
void MSDLEdit::onAddItem()
{
ParticipantEditItem *newItemDlg = new ParticipantEditItem(false, m_session, this);
newItemDlg->setAttribute(Qt::WA_DeleteOnClose);
if (!newItemDlg->init(m_pTreehandlerSystem->selectedIndexView(),
m_ui->cbParty->currentData().toInt(),
m_ppmDtc, m_ppmGuiCbxIfc, m_asb))
{
newItemDlg->deleteLater();
return;
}
connect(newItemDlg, &ParticipantEditItem::addItem, m_pModelSystem, &ParticipantEditModel::onInsertRow);
newItemDlg->show();
onEnaDisa();
}
void MSDLEdit::onEditItem()
{
if (!m_pTreehandlerSystem->isSelectedIndexValid())
return;
ParticipantManagement::ParticipantData data = m_pTreehandlerSystem->getSelectedData();
ParticipantEditItem *newItemDlg = new ParticipantEditItem(false, m_session, this);
if (!newItemDlg->init(m_pTreehandlerSystem->selectedIndexView(),
m_ui->cbParty->currentData().toInt(),
m_ppmDtc, m_ppmGuiCbxIfc, m_asb, data))
{
newItemDlg->deleteLater();
return;
}
connect(newItemDlg, &ParticipantEditItem::updateItem, m_pModelSystem, &ParticipantEditModel::onUpdateRow);
newItemDlg->exec();
onEnaDisa();
}
} //namespace ParticipantManagement
+86
View File
@@ -0,0 +1,86 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Last, SLSE, 2017-10-26
*/
#pragma once
#include <ParticipantManagement/logger.h>
#include <Services/ParticipantManagement/ppm_dtc.h>
#include <Services/ParticipantManagement/ppm_ftc.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <LtsWidgets/lts_dialog.h>
#include <LtsSession/lts_session.h>
#include <LtsUtilsGuiDds/request_helper.h>
class QSortFilterProxyModel;
namespace AdvancedSymbology
{
class ForeignDataInterface;
}
namespace Ui
{
class MSDLDialog;
}
namespace ParticipantManagement
{
class ParticipantEditModel;
class ParticipantTreeEditHandler;
class MSDLEdit : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
MSDLEdit(LtsSession::LtsSession *session, QWidget *parent = nullptr);
~MSDLEdit();
bool init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc);
private:
void retranslate() override;
bool apply() override;
void lock() override;
void unlock() override;
void tableColumnOrganiserSetting() override;
protected slots:
void onEnaDisa(); // enable/disable the widgets
void onAddItem();
void onEditItem();
void onPartyChanged();
void onImport();
void onExport();
void onDistypeEditor();
private:
QAction *m_actionRemove;
QAction *m_actionEdit;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asb;
LtsSession::LtsSession *m_session;
ParticipantTreeEditHandler *m_pTreehandlerSystem;
ParticipantTreeEditHandler *m_pTreehandlerImport;
ParticipantEditModel *m_pModelSystem;
ParticipantEditModel *m_pModelImport;
Ui::MSDLDialog *m_ui;
NGL::INGLLogger &m_logger;
};
} //ParticipantManagement
+109
View File
@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MSDLDialog</class>
<widget class="QWidget" name="MSDLDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1179</width>
<height>433</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true">setwindowtitle in source</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="LtsWidgets::LtsComboBox" name="cbParty">
<property name="const" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>346</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="5">
<widget class="QPushButton" name="m_pushButton_Import">
<property name="text">
<string>Import</string>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QPushButton" name="m_pushButton_Export">
<property name="text">
<string>Export</string>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>346</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="m_pushButton_distypeEditor">
<property name="text">
<string>Edit DIS type mapping</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblParty">
<property name="text">
<string>Party:</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="8">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="LtsDataView::LtsDataView" name="m_treeViewEdit_Left" native="true"/>
<widget class="LtsDataView::LtsDataView" name="m_treeViewEdit_Right" native="true"/>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,100 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Last, SLSE, 2017-10-26
*/
#include "ppm_msdl_gui_plugin.h"
#include "ppm_msdl_edit.h"
#include <LtsSession/lts_session.h>
#include <Services/ParticipantManagement/ppm_operator_rights.h>
#include <LtsUtilsSettings/settings.h>
namespace ParticipantManagement
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Ppm.msdl"))
, m_pSession(session)
, m_dtc(nullptr)
, m_ftc(nullptr)
, m_ppmGuiCbxIfc(nullptr)
{}
bool InterfaceImpl::fetchInterfaces()
{
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_dtc))
return false;
if (!m_session->getFtc<ParticipantManagement::DataInterface>(m_ftc))
return false;
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmGuiCbxIfc))
return false;
return true;
}
void InterfaceImpl::clearInterfaces()
{
m_dtc = nullptr;
m_ftc = nullptr;
m_ppmGuiCbxIfc = nullptr;
}
QString InterfaceImpl::menuGroup() const
{
return tr("Participants");
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
/*
* Importing exercise data is only possible if
* the operator is actually operating within an exercise
*/
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
const bool enableMSDL_ImExport = ps->value(QStringLiteral("ppm"),
QStringLiteral("enableMSDL_ImExport")).toBool();
if ( (m_pSession->exerciseId() != 0) && enableMSDL_ImExport)
{
LtsWidgets::PluginData plData;
plData.menuGroup = menuGroup();
plData.menuText = tr("MSDL Import/Export");
plData.identifier = QLatin1String("ppmmsdlview");
plData.menuIcon = QIcon(QLatin1String("icon:import_msdl.svg"));
plData.operatorRight = OperatorRights::Msdl::MsdlImportExport; // OperatorRights::PartyEdit::PartiesShow
plData.exercisePart = LtsWidgets::ExercisePart::ePlanning;
plData.createWidgetFunc = [this](QWidget * parent)
{
return onShowMSDLEdit(parent);
};
ret.append(plData);
}
return ret;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowMSDLEdit(QWidget *parent)
{
return LtsWidgets::initDialog(new ParticipantManagement::MSDLEdit(m_session, parent),
m_dtc, m_ftc, m_ppmGuiCbxIfc);
}
} // namespace ParticipantManagement
@@ -0,0 +1,66 @@
/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Last, SLSE, 2017-10-26
*/
#pragma once
#include <ParticipantManagement/logger.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_msdl_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
namespace ParticipantManagement
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:ppm.msdl")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QStringLiteral("ParticipantManagement.GuiPlugin.msdl"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Global ||
partition == IDL::PartitionType::Exercise);
}
};
class InterfaceImpl final : public QObject, public ForeignMSDLGuiInterface, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
bool fetchInterfaces() override;
void clearInterfaces() override;
QString menuGroup() const override;
QVector<LtsWidgets::PluginData> getActions() override;
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Global || partition == IDL::PartitionType::Exercise; }
private:
LtsWidgets::LtsDialog *onShowMSDLEdit(QWidget *parent);
LtsSession::LtsSession *m_pSession;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ftc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
};
} // namespace ParticipantManagement
@@ -0,0 +1,57 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Patric Karwat, SLSE, 2016-10-05
#
SET(ppm_operational_planing_gui_SRCS
ppm_party_edit_gui_plugin.cpp
ppm_party_edit_gui_plugin.h
ppm_party_view.cpp
ppm_party_view.h
ppm_party_model.cpp
ppm_party_model.h
participant_show.cpp
participant_show.h
ppm_planning_model.cpp
ppm_planning_model.h
)
NGL_WRAP_UI(ppm_operational_planing_gui_SRCS
ppm_party_view.ui
participant_show.ui
)
NGL_ADD_LIBRARY(WS PpmOperationalPlaningGuiPlugin MODULE ${ppm_operational_planing_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(PpmOperationalPlaningGuiPlugin
AsbDataPluginInterface
NGLLogger
LtsPrinting
LtsSession
PpmGuiPartyPluginInterface
PpmDataPluginInterface
PpmGuiComboboxPluginInterface
Qt5::Widgets
LtsWidgets
LtsDataView
LtsUtilsGuiDds
AsbDataPluginInterface
AsbHelper
nglwidgets
NGLLogger
LtsPrinting
PpmCommon
PpmGuiParticipantsPluginInterface
PpmGuiComboboxPluginInterface
PpmGuiTemplatesPluginInterface
PpmDataPluginInterface
Qt5::Widgets
LtsWidgets
LtsSession
LtsUtilsGuiDds
)
NGL_INSTALL_TARGET(PpmOperationalPlaningGuiPlugin)
@@ -0,0 +1,111 @@
/**
* @RDE_HEADER@
* GUI Plugin for ParticipantManagement - Participant Edit
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#include "participant_show.h"
#include "ui_participant_show.h"
#include <../Common/participant_edit_model.h>
#include <../Common/participant_edit_item.h>
#include <../Common/participant_tree_edit_handler.h>
#include <LtsPrinting/printing.h>
#include <QTreeView>
namespace ParticipantManagement
{
ParticipantShow::ParticipantShow(LtsSession::LtsSession *session,
bool asSupportService,
QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_asSupportService(asSupportService)
, m_pTreehandler(nullptr)
, m_dtc(nullptr)
, m_ftc(nullptr)
, m_session(session)
, m_model(nullptr)
, m_ui(new Ui::ParticipantShow)
, m_logger(getLogger("ParticipantShow"))
{
m_ui->setupUi(this);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &ParticipantShow::onPrint);
setOnlineHelpFilename(QStringLiteral("Situation-Operational_Planing"));
}
ParticipantShow::~ParticipantShow()
{
delete m_pTreehandler;
delete m_ui;
}
void ParticipantShow::retranslate()
{
translate(m_ui, tr("Operational Planning - Party: %1").arg(m_nameParty));
}
bool ParticipantShow::init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc,
const int partyId,
const QString &nameParty)
{
if (!dtc || !ftc)
return false;
m_dtc = dtc;
m_ftc = ftc;
m_partyId = partyId;
m_nameParty = nameParty;
m_model = new ParticipantPlanningModel(this, m_dtc, asbIfc);
connect(m_model, &ParticipantPlanningModel::internalDataChanged, this, &ParticipantShow::slotChangesMade);
m_ui->treeViewEdit->setModel(m_model);
m_ui->treeViewEdit->expandAll();
m_ui->treeViewEdit->setContextMenuPolicy(Qt::CustomContextMenu);
m_ui->treeViewEdit->moveSection(8, 1);
m_pTreehandler = new ParticipantTreeEditHandler(m_ui->treeViewEdit, m_dtc, m_ftc, m_asSupportService);
onPartyChanged();
return true;
}
void ParticipantShow::onPartyChanged()
{
if (hasUnsavedChanges())
{
switch (askApplyDiscardCancel())
{
case LtsWidgets::Button::Cancel:
{
return;
}
case LtsWidgets::Button::Discard:
__unchange__(); // can't call resetChanges() by myself :(
break;
default:
break;
}
}
m_pTreehandler->partyHasChanged(m_partyId);
}
void ParticipantShow::onPrint()
{
LtsPrinting::printView(m_session, this, m_ui->treeViewEdit->treeView() );
}
} //namespace ParticipantManagement
@@ -0,0 +1,76 @@
/**
* @RDE_HEADER@
* GUI Plugin for ParticipantManagement - Participant Edit
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#pragma once
#include <ParticipantManagement/logger.h>
#include <Services/ParticipantManagement/ppm_dtc.h>
#include <Services/ParticipantManagement/ppm_ftc.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <LtsWidgets/lts_dialog.h>
#include <LtsSession/lts_session.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include "ppm_planning_model.h"
namespace AdvancedSymbology
{
class ForeignDataInterface;
}
namespace Ui
{
class ParticipantShow;
}
namespace ParticipantManagement
{
class ParticipantPlanningModel;
class ParticipantTreeEditHandler;
class ParticipantShow : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
ParticipantShow(LtsSession::LtsSession *session,
bool asSupportService,
QWidget *parent = nullptr);
virtual ~ParticipantShow();
bool init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc,
const int partyId,
const QString &nameParty);
private:
void retranslate() override;
protected slots:
void onPartyChanged();
void onPrint();
private:
bool m_asSupportService;
ParticipantTreeEditHandler* m_pTreehandler;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ftc;
int m_partyId;
QString m_nameParty;
LtsSession::LtsSession *m_session;
ParticipantPlanningModel *m_model;
Ui::ParticipantShow *m_ui;
NGL::INGLLogger &m_logger;
};
} //ParticipantManagement
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParticipantShow</class>
<widget class="QWidget" name="ParticipantShow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>423</width>
<height>438</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true">setwindowtitle in source</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="LtsDataView::LtsDataView" name="treeViewEdit"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,91 @@
/**
* @RDE_HEADER@
* Gui Plugin for ParticipantManagement - Party
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-11-11
*/
#include "ppm_party_edit_gui_plugin.h"
#include "ppm_party_view.h"
#include <LtsSession/lts_session.h>
#include <Plugins/AdvancedSymbology/asb_data_plugin_interface.h>
#include <Services/ParticipantManagement/ppm_operator_rights.h>
namespace ParticipantManagement
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Ppm.OperationalPlanning"))
, m_dtc(nullptr)
, m_ftc(nullptr)
, m_ppmGuiCbxIfc(nullptr)
{}
bool InterfaceImpl::fetchInterfaces()
{
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_dtc))
return false;
if (!m_session->getFtc<ParticipantManagement::DataInterface>(m_ftc))
return false;
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmGuiCbxIfc))
return false;
m_session->getForeignDataInterface<AdvancedSymbology::DataInterface>(m_asb);
return true;
}
void InterfaceImpl::clearInterfaces()
{
m_dtc = nullptr;
m_ftc = nullptr;
m_ppmGuiCbxIfc = nullptr;
m_asb = nullptr;
}
QString InterfaceImpl::menuGroup() const
{
return tr("Participants");
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
if (m_session->isExercisePartition())
{
LtsWidgets::PluginData plData;
plData.menuGroup = tr("Exercise Documents");
plData.menuText = tr("Operational Planning");
plData.identifier = QLatin1String("ppmOperationalPlanningView");
plData.menuIcon = QIcon(QLatin1String("icon:operational_planning.svg"));
plData.operatorRight = OperatorRights::OperationalPlanning::OperationalPlanningView; // Todo
plData.exercisePart = LtsWidgets::ExercisePart::ePlanning;
plData.createWidgetFunc = [this](QWidget *parent)
{
return onShowParties(parent);
};
ret.append(plData);
}
return ret;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowParties(QWidget *parent)
{
return LtsWidgets::initDialog(new PartyView(menuGroup(), m_session, parent),
m_dtc, m_ftc, m_ppmGuiCbxIfc, m_asb);
}
} // namespace ParticipantManagement
@@ -0,0 +1,71 @@
/**
* @RDE_HEADER@
* Gui Plugin for ParticipantManagement - Party
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-11-11
*/
#pragma once
#include <ParticipantManagement/logger.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_party_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
namespace AdvancedSymbology
{
class ForeignDataInterface;
}
namespace ParticipantManagement
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:ppm.operationalplaning")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QStringLiteral("ParticipantManagement.GuiPlugin.OperationalPlanning"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Global ||
partition == IDL::PartitionType::Exercise);
}
};
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
bool fetchInterfaces() override;
void clearInterfaces() override;
QString menuGroup() const override;
QVector<LtsWidgets::PluginData> getActions() override;
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Global || partition == IDL::PartitionType::Exercise; }
private:
LtsWidgets::LtsDialog *onShowParties(QWidget *parent);
LtsWidgets::LtsDialog *onShowAddParty(QWidget *parent);
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ftc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asb;
};
} // namespace ParticipantManagement
@@ -0,0 +1,64 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Party Overview Model
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-11-11
*/
#include "ppm_party_model.h"
namespace ParticipantManagement
{
//---------------------------------
// PartyModel
//---------------------------------
PartyModel::PartyModel(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<PartyData>({tr("Id"),
tr("Name")}, parent)
, m_dtc(nullptr)
, m_logger(getLogger("PartyModel"))
{}
bool PartyModel::initModel(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc)
{
if (!dtc)
return false;
m_dtc = dtc;
// Insert Operator
PartyData partyData;
partyData.id = -1;
partyData.name = tr("Operator");
insertRow(partyData);
// Insert Parties
auto cb = [this](const ParticipantManagement::Party &p)
{
insertRow(PartyData(p));
};
m_dtc->partys(cb);
return true;
}
QVariant PartyModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole || !indexIsValid(index))
return QVariant();
const PartyData &party = m_vecData.at(index.row());
switch (index.column())
{
case Id:
return party.id;
case Name:
return party.name;
}
return QVariant();
}
} // namespace ParticipantManagement
@@ -0,0 +1,55 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Party Overview Model
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-11-11
*/
#pragma once
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/logger.h>
#include <ParticipantManagement/ppm_translation.h>
#include <LtsWidgets/lts_abstract_table_model.h>
namespace ParticipantManagement
{
struct PartyData
{
int id = 0;
QString name;
PartyData() = default;
explicit PartyData(const ParticipantManagement::Party &p)
: id(p.id())
, name(ParticipantManagement::trPartyName(p.name()))
{}
};
// --------------------------------------------------------
// PartyModel
// --------------------------------------------------------
class PartyModel final : public LtsWidgets::LtsAbstractTableModel<PartyData>
{
Q_OBJECT
public:
enum Columns
{
Id,
Name
};
explicit PartyModel(QObject *parent = nullptr);
bool initModel(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc);
QVariant data(const QModelIndex &, int) const override;
protected:
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
LOGGER_T m_logger;
};
} //namespace ParticipantManagement
@@ -0,0 +1,153 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Party View
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-11-11
*/
#include "ppm_party_view.h"
#include "ui_ppm_party_view.h"
#include "participant_show.h"
#include <LtsSession/lts_session_manager.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <LtsPrinting/printing.h>
#include <QTreeView>
namespace ParticipantManagement
{
PartyView::PartyView(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_menuGroup(menuGroup)
, m_model(nullptr)
, m_dtc(nullptr)
, m_ftc(nullptr)
, m_session(session)
, m_ui(new Ui::PartyView)
, m_logger(getLogger("PartyView"))
{
m_ui->setupUi(this);
m_ui->widget->setSelectionMode(QAbstractItemView::SingleSelection);
connect(m_ui->widget, &LtsDataView::LtsDataView::signalSelectionChanged,
this, &PartyView::onSelectionChanged);
connect(m_ui->widget, &LtsDataView::LtsDataView::signalDoubleClicked,
this, &PartyView::onShowParty);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Show, this, &PartyView::onShowParty);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &PartyView::onPrint);
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Load, false);
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Print, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Show, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
setOnlineHelpFilename(QStringLiteral("Situation-Operational_Planing"));
}
PartyView::~PartyView()
{
delete m_ui;
}
void PartyView::retranslate()
{
translate(m_ui, tr("Operational Planing"));
}
bool PartyView::init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
const std::shared_ptr<ForeignGuiComboboxInterface> &ppmGuiCbxIfc, const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc)
{
if (!dtc || !ftc || !ppmGuiCbxIfc)
return false;
m_dtc = dtc;
m_ftc = ftc;
m_ppmGuiCbxIfc = ppmGuiCbxIfc;
m_asbIfc = asbIfc;
m_model = new PartyModel(this);
m_model->initModel(m_dtc);
m_ui->widget->setModel(m_model);
#ifndef LTS_DEBUG
m_ui->widget->hideColumn(PartyModel::Id);
#endif
m_ui->widget->setSortingEnabled(false);
m_ui->widget->setSortIndicator(-1, Qt::AscendingOrder);
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Show, true);
return true;
}
void PartyView::onSelectionChanged()
{
const QModelIndex idx = m_ui->widget->currentIndex();
int row = idx.row();
if (m_ui->widget->selectedRows().size() == 0
|| row < 0)
{
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Show, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
return;
}
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Show, true);
}
void PartyView::onShowParty()
{
const QModelIndex idx = m_ui->widget->currentIndex();
int row = idx.row();
if (row < 0)
return;
PartyData party = m_model->getRowData(row);
if (party.id < 0)
{
// Show Operator-List
std::shared_ptr<OperatorManagement::OverviewForeignGuiInterface> opmOverviewIfc;
if (m_session->getForeignGuiInterface(opmOverviewIfc))
{
opmOverviewIfc->showOperators(tr("Operational Planning - Operators"));
}
}
else
{
bool asSupportService = false;
ParticipantShow *diag = new ParticipantShow(m_session, asSupportService, this);
if (diag->init(m_dtc, m_ftc, m_asbIfc, party.id , party.name))
addDialog(diag, m_menuGroup, QStringLiteral("Participants") + QString::number(party.id), LtsWidgets::LayoutArea::eDialogTab);
else
delete diag;
}
}
void PartyView::onPrint()
{
LtsPrinting::printView(m_session, this, m_ui->widget->treeView() );
}
void PartyView::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->widget->setColumnsOrganiserEnabled(identifier(), true);
}
} // namespace ParticipantManagement
@@ -0,0 +1,71 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Party View
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-11-11
*/
#pragma once
#include "ppm_party_model.h"
#include <Services/ParticipantManagement/ppm_dtc.h>
#include <Services/ParticipantManagement/ppm_ftc.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Plugins/OperatorManagement/opm_overview_gui_plugin_interface.h>
#include <LtsWidgets/lts_dialog.h>
#include <LtsSession/lts_session.h>
namespace AdvancedSymbology
{
class ForeignDataInterface;
}
namespace Ui
{
class PartyView;
}
namespace ParticipantManagement
{
class PartyView : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit PartyView(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent = nullptr);
~PartyView();
bool init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc);
private:
void retranslate() override;
void onSelectionChanged();
void onShowParty();
void onPrint();
void tableColumnOrganiserSetting() override;
private:
QString m_menuGroup;
PartyModel *m_model;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ftc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asbIfc;
LtsSession::LtsSession *m_session;
Ui::PartyView *m_ui;
LOGGER_T m_logger;
};
} // namespace ParticipantManagement
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PartyView</class>
<widget class="QWidget" name="PartyView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>455</width>
<height>341</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="LtsDataView::LtsDataView" name="widget">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,40 @@
/**
* @RDE_HEADER@
* Model for ParticipantsMoveDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2018-01-02
*/
#include "ppm_planning_model.h"
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
namespace ParticipantManagement
{
//----------------------------------------------------------------------------
ParticipantPlanningModel::ParticipantPlanningModel(QObject *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc)
: ParticipantManagement::ParticipantEditModel(parent, ppmDtc, asbIfc)
, m_logger(getLogger("ParticipantPlanningModel"))
{
m_titles += tr("Hierarchy");
DEBUG_LOG(m_logger) << "ParticipantPlanningModel::ParticipantPlanningModel";
}
QVariant ParticipantPlanningModel::data(const QModelIndex &index, int role) const
{
const CheckedTreeItem *item = privateData(index);
const ParticipantManagement::ParticipantData &participantData = item->participant;
if (role == Qt::DisplayRole && index.column() == columnCount() - 1)
return m_dtc->hierarchyFromParticipant(participantData.id());
return ParticipantManagement::ParticipantEditModel::data(index, role);
}
} // namespace ParticipantManagement
@@ -0,0 +1,41 @@
/**
* @RDE_HEADER@
* Model for ParticipantsMoveDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2018-01-02
*/
#pragma once
#include <QObject>
#include <nglwidgets/ngltreeitem.h>
#include <Services/ParticipantManagement/ppm_dtc.h>
#include <QStringList>
//ParticipantManagement
#include <Plugins/ParticipantManagement/Gui/Common/participant_edit_model.h>
#include <ParticipantManagement/logger.h>
namespace ParticipantManagement
{
class ParticipantPlanningModel final : public ParticipantManagement::ParticipantEditModel
{
Q_OBJECT
public:
ParticipantPlanningModel(QObject *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals:
void newData();
private:
//void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
NGL::INGLLogger &m_logger;
};
} // namespace ParticipantManagement
@@ -0,0 +1,52 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-05-05
#
SET(participant_edit_gui_SRCS
participant_edit_gui_plugin.cpp
participant_edit_gui_plugin.h
participant_edit.cpp
participant_edit.h
participant_orga_model.cpp
participant_orga_model.h
participant_organisation.cpp
participant_organisation.h
participant_pool_model.cpp
participant_pool_model.h
participant_unit_namer.cpp
participant_unit_namer.h
tactical_organisation.cpp
tactical_organisation.h
)
NGL_WRAP_UI(participant_edit_gui_SRCS
participant_edit.ui
participant_organisation.ui
participant_unit_namer.ui
tactical_organisation.ui
)
NGL_ADD_LIBRARY2(WS PpmParticipantEditGuiPlugin MODULE ${participant_edit_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(PpmParticipantEditGuiPlugin
AsbDataPluginInterface
AsbHelper
nglwidgets
NGLLogger
LtsPrinting
PpmCommon
PpmGuiParticipantsPluginInterface
PpmGuiComboboxPluginInterface
PpmGuiTemplatesPluginInterface
PpmDataPluginInterface
LtsDataView
LtsWidgets
LtsSession
LtsSessionData
LtsUtilsGuiDds
LtsUtilsSettings
svcCoreClient # Core Ftc - for TLH
)
@@ -0,0 +1,593 @@
/**
* @RDE_HEADER@
* GUI Plugin for ParticipantManagement - Participant Edit
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#include "participant_edit.h"
#include "ui_participant_edit.h"
#include <Common/participant_beautify_view.h>
#include <Common/participant_edit_item.h>
#include <Common/participant_edit_model.h>
#include <Common/participant_firing_unit_validator.h>
#include <Common/participant_tree_edit_handler.h>
#include <LtsDataView/search_model.h>
#include <LtsPrinting/printing.h>
#include <LtsSession/lts_session.h>
#include <ParticipantManagement/logger.h>
#include <QAction>
#include <QHeaderView>
#include <QJsonDocument>
#include <QTableView>
#include <QTimer>
#include <QTreeView>
namespace ParticipantManagement
{
int ParticipantEdit::s_preselectedParty = -1;
ParticipantEdit::ParticipantEdit(LtsSession::LtsSession *session, bool asSupportService, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_asSupportService(asSupportService)
, m_actionRemove(nullptr)
, m_actionEdit(nullptr)
, m_dtc(nullptr)
, m_ftc(nullptr)
, m_ppmGuiCbxIfc(nullptr)
, m_session(session)
, m_pbTreeView(new QPushButton(tr("Tree View")))
, m_pbTableView(new QPushButton(tr("Table View")))
, m_pbTreeViewDummy(new QPushButton(m_pbTreeView->text()))
, m_pbTableViewDummy(new QPushButton(m_pbTableView->text()))
, m_ui(new Ui::ParticipantEdit)
, m_logger(getLogger("ParticipantEdit"))
{
m_ui->setupUi(this);
m_ui->cbParty->setVisible(!m_asSupportService); // hide when SupportService
m_ui->lblParty->setVisible(!m_asSupportService);
m_ui->treeViewEdit->treeView()->setDragEnabled(true);
m_ui->treeViewEdit->treeView()->setDragDropMode(QAbstractItemView::DragDrop);
m_ui->treeViewEdit->treeView()->setDefaultDropAction(Qt::MoveAction);
// this will make the tree view look like a table
m_ui->tableViewEdit->treeView()->setIndentation(0);
m_ui->tableViewEdit->treeView()->setItemsExpandable(false);
// add buttons to switch between a tree view and a table view
m_pbTreeViewDummy->setEnabled(false);
m_pbTableViewDummy->setEnabled(false);
QHBoxLayout *hboxTree = new QHBoxLayout;
hboxTree->addWidget(m_pbTreeViewDummy);
hboxTree->addWidget(m_pbTableView);
QWidget *widgetTree = new QWidget;
widgetTree->setLayout(hboxTree);
m_ui->treeViewEdit->setCustomWidget(widgetTree);
m_pbTreeViewDummy->setEnabled(false);
m_pbTableViewDummy->setEnabled(false);
QHBoxLayout *hboxTable = new QHBoxLayout;
hboxTable->addWidget(m_pbTreeView);
hboxTable->addWidget(m_pbTableViewDummy);
QWidget *widgetTable = new QWidget;
widgetTable->setLayout(hboxTable);
m_ui->tableViewEdit->setCustomWidget(widgetTable);
connect(m_pbTreeView, &QPushButton::clicked, this, &ParticipantEdit::onSwitchToTreeView);
connect(m_pbTableView, &QPushButton::clicked, this, &ParticipantEdit::onSwitchToTableView);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &ParticipantEdit::onAddItem);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &ParticipantEdit::onEditItem);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &ParticipantEdit::onPrint);
if (m_asSupportService)
setOnlineHelpFilename(QStringLiteral("Situation-Edit_Support_Participants"));
else
setOnlineHelpFilename(QStringLiteral("Situation-Edit_Participants"));
m_ui->treeViewEdit->treeView()->setContextMenuPolicy(Qt::CustomContextMenu);
m_ui->tableViewEdit->treeView()->setContextMenuPolicy(Qt::CustomContextMenu);
setStyleSheet(QStringLiteral("QToolTip { background-color: #ffffff; }"));
}
ParticipantEdit::~ParticipantEdit() { delete m_ui; }
bool ParticipantEdit::init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
const std::shared_ptr<ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc)
{
// interfaces ...............................................................................................................
if (!dtc || !ftc || !ppmGuiCbxIfc)
return false;
if (m_dtc)
return false;
m_dtc = dtc;
m_ftc = ftc;
m_ppmGuiCbxIfc = ppmGuiCbxIfc;
m_asb = asbIfc;
// tree model ...............................................................................................................
m_model = new ParticipantEditModel(this, m_dtc, m_asb);
connect(m_model, &ParticipantEditModel::internalDataChanged, this, &ParticipantEdit::slotChangesMade);
// proxy model for the tree view ............................................................................................
m_proxyTree = new ParticipantTreeFilterProxyModel(this);
m_proxyTree->setSourceModel(m_model);
// firing unit validator ....................................................................................................
if (m_firingUnitValidator)
delete m_firingUnitValidator;
m_firingUnitValidator = new FiringUnitValidator(m_dtc, this);
m_ui->treeViewEdit->setModel(m_proxyTree);
m_ui->treeViewEdit->setContextMenuPolicy(Qt::CustomContextMenu);
#ifndef LTS_DEBUG
m_ui->treeViewEdit->setColumnHidden(ParticipantEditModel::ColParticipantId, true);
#endif
// proxy model for the table view ...........................................................................................
m_proxyTable = new ParticipantTableFilterProxyModel(this);
m_proxyTable->setSourceModel(m_model);
connect(m_ui->tableViewEdit, &LtsDataView::LtsDataView::filterChanged, m_proxyTable, &ParticipantTableFilterProxyModel::onFilter);
connect(m_ui->tableViewEdit, &LtsDataView::LtsDataView::sortOrderChanged, this, &ParticipantEdit::onSortTableView);
connect(m_model, &ParticipantEditModel::internalDataChanged, m_proxyTable, &ParticipantTableFilterProxyModel::init);
m_ui->tableViewEdit->setModel(m_proxyTable);
m_ui->tableViewEdit->setContextMenuPolicy(Qt::CustomContextMenu);
#ifndef LTS_DEBUG
m_ui->tableViewEdit->setColumnHidden(ParticipantEditModel::ColParticipantId, true);
#endif
// actions ..................................................................................................................
m_actionRemove = new QAction(QIcon(QLatin1String("icon:remove.svg")), tr("Remove"), this);
m_actionEdit = new QAction(QIcon(QLatin1String("icon:edit.svg")), tr("Edit"), this);
// party combo box ..........................................................................................................
connect(m_ui->cbParty, static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged), this, &ParticipantEdit::onPartyChanged);
m_ppmGuiCbxIfc->fillPartyComboBox(m_ui->cbParty,
m_asSupportService ? ForeignGuiComboboxInterface::CbxPartyFilter::Oc : ForeignGuiComboboxInterface::CbxPartyFilter::NormalPool);
// tree handler .............................................................................................................
m_pTreehandler = new ParticipantTreeEditHandler(m_ui->treeViewEdit, m_dtc, m_ftc, m_asSupportService, this);
m_pTreehandler->setEditParticipantsAllowed(true);
connect(m_pTreehandler, &ParticipantTreeEditHandler::signalEditParticipant, this, &ParticipantEdit::onEditItem);
connect(m_pTreehandler, &ParticipantTreeEditHandler::signalDoubleClicked, this, &ParticipantEdit::onEditItem);
connect(m_pTreehandler, &ParticipantTreeEditHandler::signalSelectionChanged, this, &ParticipantEdit::onEnaDisa);
connect(m_pTreehandler, &ParticipantTreeEditHandler::signalChangesMade, this, &ParticipantEdit::onChangesMade);
connect(m_actionRemove, &QAction::triggered, m_pTreehandler, &ParticipantTreeEditHandler::onRemoveItem);
connect(m_actionEdit, &QAction::triggered, this, &ParticipantEdit::onEditItem);
connect(m_ui->tableViewEdit->treeView(), &QTreeView::customContextMenuRequested, m_pTreehandler, &ParticipantTreeEditHandler::showContextMenu);
connect(m_ui->tableViewEdit->treeView(), &QTreeView::doubleClicked, this, &ParticipantEdit::onEditItem);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, m_pTreehandler, &ParticipantTreeEditHandler::onRemoveItem);
// ..........................................................................................................................
const int idx = m_ui->cbParty->findData(s_preselectedParty);
if (idx >= 0)
m_ui->cbParty->setCurrentIndex(idx);
// synchronize tree view and table view .....................................................................................
// filtering
connect(m_ui->treeViewEdit,
&LtsDataView::LtsDataView::filterChanged,
this,
[this]() { onFilterChanged(m_ui->treeViewEdit->searchModel(), m_ui->tableViewEdit->searchModel()); });
connect(m_ui->tableViewEdit,
&LtsDataView::LtsDataView::filterChanged,
this,
[this]() { onFilterChanged(m_ui->tableViewEdit->searchModel(), m_ui->treeViewEdit->searchModel()); });
// selection
connect(m_ui->treeViewEdit, &LtsDataView::LtsDataView::selectionChanged, this, &ParticipantEdit::onSelectionChangedInTree);
connect(m_ui->tableViewEdit, &LtsDataView::LtsDataView::selectionChanged, this, &ParticipantEdit::onSelectionChangedInTable);
// column width
connect(m_ui->treeViewEdit->searchView()->header(),
&QHeaderView::sectionResized,
this,
[this](int column, int oldWidth, int newWidth)
{
Q_UNUSED(oldWidth);
onColumnWidthChanged(m_ui->tableViewEdit->searchView(), column, newWidth);
});
connect(m_ui->tableViewEdit->searchView()->header(),
&QHeaderView::sectionResized,
this,
[this](int column, int oldWidth, int newWidth)
{
Q_UNUSED(oldWidth);
onColumnWidthChanged(m_ui->treeViewEdit->searchView(), column, newWidth);
});
// ..........................................................................................................................
onSwitchToTreeView();
onPartyChanged();
onEnaDisa();
return true;
}
void ParticipantEdit::retranslate() { translate(m_ui, m_asSupportService ? tr("Edit Support Participants") : tr("Edit Participants")); }
bool ParticipantEdit::apply()
{
m_proxyTable->resetMapping();
bool ret = m_pTreehandler->onApplyChanges();
m_proxyTable->init();
return ret;
}
void ParticipantEdit::showIsSimulated()
{
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Participant is simulated"), windowTitle(), LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes, texts);
}
void ParticipantEdit::lock()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
m_ui->cbParty->setEnabled(true); // true!!
// avoid BaseClass::lock to be called. partyEdit stays enabled
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
void ParticipantEdit::unlock()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
m_ui->cbParty->setEnabled(true);
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
void ParticipantEdit::onPartyChanged()
{
const int newPartyId = m_ui->cbParty->currentData().toInt();
s_preselectedParty = newPartyId;
if (hasUnsavedChanges())
{
switch (askApplyDiscardCancel())
{
case LtsWidgets::Button::Apply:
if (!apply())
return;
__unchange__();
break;
case LtsWidgets::Button::Cancel:
{
QSignalBlocker block(m_ui->cbParty);
m_ui->cbParty->setCurrentIndex(m_ui->cbParty->findData(m_model->partyId(), Qt::UserRole)); // reset position
s_preselectedParty = m_ui->cbParty->currentData().toInt();
return;
}
case LtsWidgets::Button::Discard:
__unchange__(); // can't call resetChanges() by myself :(
break;
default:
break;
}
}
// DEBUG_LOG(m_logger) << LOGFUNCTION << " ParticipantEdit::onPartyChanged !!! -> newPartyId=" << newPartyId;
// m_ui->cbParty->setEnabled(false); // will be re-enabled with reply (::lock, ::unlock)
// tryLockTopicNew(QStringLiteral("LockParty"), newPartyId);
m_proxyTable->resetMapping();
m_proxyTable->disableSorting();
m_pTreehandler->partyHasChanged(newPartyId);
m_proxyTable->init();
// Some icons in the table view won't update automatically after initialization (maybe a timing issue?).
// Workaround: emit dataChanged on the first items (up to 50 rows, since more will not be visible after reinit)
// with a slight delay of 100 msecs to force an update.
QTimer *timer = new QTimer(this);
timer->singleShot(100,
this,
[this, timer]()
{
m_ui->tableViewEdit->treeView()->dataChanged(m_proxyTable->index(0, 0),
m_proxyTable->index(std::min(50, m_proxyTable->rowCount()), 0),
{Qt::DecorationRole});
timer->deleteLater();
});
}
void ParticipantEdit::onPrint() { LtsPrinting::printView(m_session, this, m_ui->treeViewEdit->treeView()); }
void ParticipantEdit::onChangesMade()
{
onEnaDisa();
if (m_model->onReinitModel(s_preselectedParty))
beautifyTreeView(m_ui->treeViewEdit->treeView(), m_model, true);
}
void ParticipantEdit::onBeautifyTreeView() { beautifyTreeView(m_ui->treeViewEdit->treeView(), m_model, true); }
void ParticipantEdit::onEnaDisa()
{
bool enableAdd = false;
bool enableEdit = false;
bool enableRemove = false;
if (m_pTreehandler->isSelectedIndexValid())
{
if (m_dtc->isAdlerVerbund(m_pTreehandler->getSelectedData().typeId()))
{
DEBUG_LOG(m_logger) << "Can't Edit Adler SAA Participants";
enableEdit = true;
}
else
{
enableAdd = m_pTreehandler->isContainer();
if (m_firingUnitValidator)
enableAdd &= m_firingUnitValidator->hasUnitCapacities(m_model, m_pTreehandler->selectedIndexView());
if (m_pTreehandler->isSelectedIndexRemovable())
enableRemove = true;
enableEdit = true;
}
}
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, enableAdd && m_ui->treeViewEdit->isVisible());
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, enableEdit);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, enableRemove && m_ui->treeViewEdit->isVisible());
m_actionRemove->setEnabled(enableRemove);
m_actionEdit->setEnabled(enableEdit);
}
void ParticipantEdit::onAddItem()
{
ParticipantEditItem *newItemDlg = new ParticipantEditItem(m_asSupportService, m_session, this);
ParticipantManagement::ParticipantData dataAll = m_pTreehandler->getSelectedData();
ParticipantData data = ParticipantData();
data.designator(dataAll.designator());
data.tacticalIdentifier(dataAll.tacticalIdentifier());
const bool addItem = true;
newItemDlg->setAttribute(Qt::WA_DeleteOnClose);
QModelIndex workingIndex = m_pTreehandler->selectedIndexView();
if (!newItemDlg->init(workingIndex,
m_ui->cbParty->currentData().toInt(),
m_dtc,
m_ppmGuiCbxIfc,
m_asb,
static_cast<const ParticipantData>(data),
addItem,
m_pTreehandler->usedEquipmentNumbers()))
{
delete newItemDlg;
return;
}
connect(newItemDlg, &ParticipantEditItem::addItem, m_model, &ParticipantEditModel::onInsertRow);
connect(newItemDlg, &ParticipantEditItem::addItem, this, &ParticipantEdit::onBeautifyTreeView);
connect(newItemDlg, &ParticipantEditItem::addItem, m_proxyTable, &ParticipantTableFilterProxyModel::init);
if (m_firingUnitValidator)
{
newItemDlg->setIsAdler(m_firingUnitValidator->isAdler(m_model, workingIndex));
const int unitGearClassType = m_firingUnitValidator->getGearClassType(m_model, workingIndex);
newItemDlg->setFiringUnitRestrictions(m_model, false, m_firingUnitValidator->getRestrictions(m_model, workingIndex), m_firingUnitValidator, unitGearClassType);
connect(newItemDlg,
&ParticipantEditItem::addItem,
this,
[this, newItemDlg, unitGearClassType](const QModelIndex &parent, const ParticipantData &newData)
{
Q_UNUSED(newData)
if (!newItemDlg || !m_firingUnitValidator)
return;
newItemDlg->setFiringUnitRestrictions(m_model, false, m_firingUnitValidator->getRestrictions(m_model, parent), m_firingUnitValidator, unitGearClassType);
});
}
newItemDlg->show();
}
void ParticipantEdit::onEditItem()
{
if (!m_pTreehandler->isSelectedIndexValid() || m_newItemDlg)
return;
ParticipantManagement::ParticipantData data = m_pTreehandler->getSelectedData();
if (data.isSimulated())
showIsSimulated();
m_newItemDlg = new ParticipantEditItem(m_asSupportService, m_session, this);
m_newItemDlg->setAttribute(Qt::WA_DeleteOnClose);
QModelIndex workingIndex = m_pTreehandler->selectedIndexView();
if (!m_newItemDlg->init(workingIndex, m_ui->cbParty->currentData().toInt(), m_dtc, m_ppmGuiCbxIfc, m_asb, data, false, m_pTreehandler->usedEquipmentNumbers()))
{
delete m_newItemDlg;
return;
}
QObject::connect(m_newItemDlg,
&ParticipantEditItem::destroyed,
this,
[this]
{
m_newItemDlg = nullptr;
onEnaDisa();
});
QObject::connect(m_newItemDlg, &ParticipantEditItem::updateItem, m_model, &ParticipantEditModel::onUpdateRow);
if (m_firingUnitValidator)
{
const int unitGearClassType = m_firingUnitValidator->getGearClassType(m_model, workingIndex);
m_newItemDlg->setFiringUnitRestrictions(m_model, true, m_firingUnitValidator->getRestrictions(m_model, workingIndex), m_firingUnitValidator, unitGearClassType);
}
m_newItemDlg->show();
}
void ParticipantEdit::onSwitchToTreeView()
{
m_ui->tableViewEdit->hide();
m_ui->treeViewEdit->show();
m_ui->treeViewEdit->expandAll();
if (!m_ui->treeViewEdit->selectionModel()->selectedIndexes().isEmpty()) // scroll to selection
{
const QModelIndex &proxyIndex = m_ui->treeViewEdit->selectionModel()->selectedIndexes().first();
m_ui->treeViewEdit->scrollTo(proxyIndex);
} // if
onEnaDisa();
}
void ParticipantEdit::onSwitchToTableView()
{
m_ui->treeViewEdit->hide();
m_ui->tableViewEdit->show();
if (!m_ui->tableViewEdit->selectionModel()->selectedIndexes().isEmpty()) // scroll to selection
{
const QModelIndex &proxyIndex = m_ui->tableViewEdit->selectionModel()->selectedIndexes().first();
m_ui->tableViewEdit->scrollTo(proxyIndex);
} // if
onEnaDisa();
}
void ParticipantEdit::onSelectionChangedInTree(const QItemSelection &selected, const QItemSelection &deselected)
{
m_ui->tableViewEdit->blockSignals(true);
QModelIndexList indexes = deselected.indexes();
for (const QModelIndex &sourceIndex : qAsConst(indexes))
{
QModelIndex proxyIndex = m_proxyTable->mapFromSource(sourceIndex);
if (m_ui->tableViewEdit->selectionModel()->selectedIndexes().contains(proxyIndex))
m_ui->tableViewEdit->selectionModel()->select(proxyIndex, {QItemSelectionModel::Deselect, QItemSelectionModel::Rows});
} // for
indexes = selected.indexes();
for (const QModelIndex &sourceIndex : qAsConst(indexes))
{
QModelIndex proxyIndex = m_proxyTable->mapFromSource(sourceIndex);
if (!m_ui->tableViewEdit->selectionModel()->selectedIndexes().contains(proxyIndex))
m_ui->tableViewEdit->selectionModel()->select(proxyIndex, {QItemSelectionModel::Select, QItemSelectionModel::Rows});
} // for
m_ui->tableViewEdit->blockSignals(false);
}
void ParticipantEdit::onSelectionChangedInTable(const QItemSelection &selected, const QItemSelection &deselected)
{
m_ui->treeViewEdit->blockSignals(true);
QModelIndexList indexes = deselected.indexes();
for (const QModelIndex &sourceIndex : qAsConst(indexes))
{
QModelIndex proxyIndex = m_proxyTree->mapFromSource(sourceIndex);
if (m_ui->treeViewEdit->selectionModel()->selectedIndexes().contains(proxyIndex))
m_ui->treeViewEdit->selectionModel()->select(proxyIndex, {QItemSelectionModel::Deselect, QItemSelectionModel::Rows});
} // for
indexes = selected.indexes();
for (const QModelIndex &sourceIndex : qAsConst(indexes))
{
QModelIndex proxyIndex = m_proxyTree->mapFromSource(sourceIndex);
if (!m_ui->treeViewEdit->selectionModel()->selectedIndexes().contains(proxyIndex))
m_ui->treeViewEdit->selectionModel()->select(proxyIndex, {QItemSelectionModel::Select, QItemSelectionModel::Rows});
} // for
m_ui->treeViewEdit->blockSignals(false);
}
void ParticipantEdit::onFilterChanged(LtsDataView::SearchModel *from, LtsDataView::SearchModel *to)
{
for (int column = 0; column < to->columnCount(); ++column)
{
QModelIndex fromIndex = from->index(0, column, QModelIndex());
QModelIndex toIndex = to->index(0, column, QModelIndex());
QVariant columnFilter = from->data(fromIndex, Qt::EditRole);
QVariant comboBoxData = from->data(fromIndex, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
if (columnFilter != to->data(toIndex, Qt::EditRole))
{
to->setData(toIndex, columnFilter, Qt::EditRole);
to->setData(toIndex, from->data(fromIndex, Qt::DisplayRole).toString(), Qt::DisplayRole);
} // if
else if (comboBoxData != to->data(toIndex, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole))
{
to->setData(toIndex, comboBoxData, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
LtsWidgets::ComboboxFilterContent comboFilterContent
= LtsWidgets::ComboboxFilterContent::fromVariant(m_model->headerData(column, Qt::Horizontal, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole));
if (comboBoxData.toInt() == 0)
{
to->setData(toIndex, tr("<no filter>"), Qt::DisplayRole);
} // if
else
{
for (const LtsWidgets::ComboboxFilterData &data : qAsConst(comboFilterContent.data))
if (data.data == comboBoxData)
{
to->setData(toIndex, data.text, Qt::DisplayRole);
break;
} // if
} // else
} // else if
} // for
// undo selection
m_ui->tableViewEdit->blockSignals(true);
m_ui->tableViewEdit->selectionModel()->clearSelection();
m_ui->tableViewEdit->blockSignals(false);
m_ui->treeViewEdit->blockSignals(true);
m_ui->treeViewEdit->selectionModel()->clearSelection();
m_ui->treeViewEdit->blockSignals(false);
}
void ParticipantEdit::onSortTableView(int column, Qt::SortOrder order)
{
QModelIndex sourceIndex;
if (!m_ui->treeViewEdit->selectionModel()->selectedIndexes().isEmpty()) // store selected item
{
QModelIndex proxyIndex = m_ui->tableViewEdit->selectionModel()->selectedIndexes().first();
sourceIndex = m_proxyTable->mapToSource(proxyIndex);
m_ui->tableViewEdit->blockSignals(true);
m_ui->tableViewEdit->selectionModel()->select(proxyIndex, {QItemSelectionModel::Deselect, QItemSelectionModel::Rows});
m_ui->tableViewEdit->blockSignals(false);
} // if
m_proxyTable->onSort(column, order);
if (sourceIndex != QModelIndex()) // reselect item with new index
{
QModelIndex proxyIndex = m_proxyTable->mapFromSource(sourceIndex);
m_ui->tableViewEdit->blockSignals(true);
m_ui->tableViewEdit->selectionModel()->select(proxyIndex, {QItemSelectionModel::Select, QItemSelectionModel::Rows});
m_ui->tableViewEdit->blockSignals(false);
m_ui->tableViewEdit->scrollTo(proxyIndex);
} // if
}
void ParticipantEdit::onColumnWidthChanged(QTreeView *to, const int &column, const int &width)
{
if (to->columnWidth(column) != width)
to->setColumnWidth(column, width);
}
void ParticipantEdit::tableColumnOrganiserSetting()
{
// LtsColumnOrganiser
m_ui->tableViewEdit->setColumnsOrganiserEnabled(identifier(), true);
m_ui->treeViewEdit->setColumnsOrganiserEnabled(identifier(), true);
}
} // namespace ParticipantManagement
@@ -0,0 +1,130 @@
/**
* @RDE_HEADER@
* GUI Plugin for ParticipantManagement - Participant Edit
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#pragma once
#include <Services/ParticipantManagement/ppm_dtc.h>
#include <Services/ParticipantManagement/ppm_ftc.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <LtsWidgets/lts_dialog.h>
#include <LtsSession/lts_session.h>
#include <LtsUtilsGuiDds/request_helper.h>
class QTreeView;
namespace AdvancedSymbology
{
class ForeignDataInterface;
}
namespace Ui
{
class ParticipantEdit;
}
namespace NGL
{
class INGLLogger;
}
namespace LtsDataView
{
class SearchModel;
}
namespace ParticipantManagement
{
class FiringUnitValidator;
class ParticipantEditModel;
class ParticipantEditItem;
class ParticipantTreeEditHandler;
class ParticipantTreeFilterProxyModel;
class ParticipantTableFilterProxyModel;
class ParticipantEdit : public LtsWidgets::LtsDialog
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsDialog;
public:
ParticipantEdit(LtsSession::LtsSession *session, bool asSupportService, QWidget *parent = nullptr);
~ParticipantEdit();
bool init(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ftc,
const std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> &ppmGuiCbxIfc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc);
private:
void retranslate() override;
bool apply() override;
void showIsSimulated();
void lock() override;
void unlock() override;
protected slots:
void onEnaDisa(); // enable/disable the widgets
void onAddItem();
void onEditItem();
void onPartyChanged();
void onPrint();
void onChangesMade();
void onBeautifyTreeView();
private slots:
void onSwitchToTreeView();
void onSwitchToTableView();
void onFilterChanged(LtsDataView::SearchModel *from, LtsDataView::SearchModel *to);
void onSortTableView(int column, Qt::SortOrder order);
void onSelectionChangedInTree(const QItemSelection &selected, const QItemSelection &deselected);
void onSelectionChangedInTable(const QItemSelection &selected, const QItemSelection &deselected);
void onColumnWidthChanged(QTreeView *to, const int &column, const int &width);
private:
void tableColumnOrganiserSetting() override;
bool m_asSupportService;
QAction *m_actionRemove;
QAction *m_actionEdit;
ParticipantTreeEditHandler *m_pTreehandler{nullptr};
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ftc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asb;
ParticipantEditItem *m_newItemDlg{nullptr};
LtsSession::LtsSession *m_session{nullptr};
static int s_preselectedParty;
ParticipantEditModel *m_model{nullptr};
ParticipantTreeFilterProxyModel *m_proxyTree{nullptr};
ParticipantTableFilterProxyModel *m_proxyTable{nullptr};
QPushButton *m_pbTreeView{nullptr};
QPushButton *m_pbTableView{nullptr};
QPushButton *m_pbTreeViewDummy{nullptr};
QPushButton *m_pbTableViewDummy{nullptr};
FiringUnitValidator *m_firingUnitValidator{nullptr};
Ui::ParticipantEdit *m_ui;
NGL::INGLLogger &m_logger;
};
} //ParticipantManagement
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParticipantEdit</class>
<widget class="QWidget" name="ParticipantEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>655</width>
<height>472</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">setwindowtitle in source</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblParty">
<property name="text">
<string>Party:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LtsWidgets::LtsComboBox" name="cbParty">
<property name="const" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="LtsDataView::LtsDataView" name="treeViewEdit">
<property name="showColumnCount" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="LtsDataView::LtsDataView" name="tableViewEdit">
<property name="showColumnCount" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,156 @@
/**
* @RDE_HEADER@
* GUI Plugin for ParticipantManagement - ParticipantEdit
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#include "participant_edit_gui_plugin.h"
#include "participant_organisation.h"
#include "participant_edit.h"
#include "tactical_organisation.h"
#include <ParticipantManagement/ppm_operator_rights.h>
#include <Plugins/AdvancedSymbology/asb_data_plugin_interface.h>
#include <LtsUtilsSettings/settings.h>
namespace ParticipantManagement
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Ppm.ParticipantTemplates"))
, m_dtc(nullptr)
, m_ftc(nullptr)
, m_ppmGuiTemplateIfc(nullptr)
, m_ppmGuiCbxIfc(nullptr)
{}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
QVector<LtsWidgets::PluginData> ret;
//were are in Exercise so only use exercise participants
LtsWidgets::PluginData pd;
pd.menuGroup = menuGroup();
pd.layoutArea = LtsWidgets::LayoutArea::eDialogTab;
pd.menuText = tr("Organise Participants");
pd.identifier = QStringLiteral("organiseParticipants");
pd.menuIcon = QIcon(QLatin1String("icon:force_organization.svg"));
pd.createWidgetFunc = [this](QWidget *parent) { return onParticipantOrganisation(parent, false); };
pd.operatorRight = OperatorRights::ParticipantEdit::ParticipantsOrganise;
pd.exercisePart = LtsWidgets::ExercisePart::ePlanning;
ret.append(pd);
pd.menuText = tr("Edit Participants");
pd.identifier = QStringLiteral("editParticipants");
pd.menuIcon = QIcon(QLatin1String("icon:force_player_configuration.svg"));
pd.createWidgetFunc = [this](QWidget *parent) { return onParticipantEdit(parent, false); };
pd.operatorRight = OperatorRights::ParticipantEdit::ParticipantsEdit;
pd.exercisePart = LtsWidgets::ExercisePart::ePlanning;
pd.exerciseStates = LtsWidgets::ExcState::eCreated | LtsWidgets::ExcState::eStarted | LtsWidgets::ExcState::ePaused;
ret.append(pd);
pd.menuText = tr("Tactical Organisation");
pd.identifier = QStringLiteral("tacticalParticipantOrganisation");
pd.menuIcon = QIcon(QLatin1String("icon:tactical_organization.svg"));
pd.createWidgetFunc = [this](QWidget *parent) { return onTacticalParticipantOrganisation(parent); };
pd.operatorRight = OperatorRights::ParticipantEdit::TacticalParticipantOrganisation;
pd.exercisePart = LtsWidgets::ExercisePart::eExecution;
ret.append(pd);
if (ps->value(QStringLiteral("ppm"),
QStringLiteral("enableSupportParticipantsOrganise")).toBool())
{
pd.menuText = tr("Organise Support Participants");
pd.identifier = QStringLiteral("organiseSupParticipants");
pd.menuIcon = QIcon(QLatin1String("icon:oc_composition.svg"));
pd.createWidgetFunc = [this](QWidget *parent) { return onParticipantOrganisation(parent, true); };
pd.operatorRight = OperatorRights::ParticipantEdit::SupportParticipantsOrganise;
pd.exercisePart = LtsWidgets::ExercisePart::ePlanning;
ret.append(pd);
}
if (ps->value(QStringLiteral("ppm"),
QStringLiteral("enableSupportParticipantsEdit")).toBool())
{
pd.menuText = tr("Edit Support Participants");
pd.identifier = QStringLiteral("editSupportParticipants");
pd.menuIcon = QIcon(QLatin1String("icon:oc_player_configuration.svg"));
pd.createWidgetFunc = [this](QWidget *parent) { return onParticipantEdit(parent, true); };
pd.operatorRight = OperatorRights::ParticipantEdit::SupportParticipantsEdit;
pd.exercisePart = LtsWidgets::ExercisePart::ePlanning;
pd.exerciseStates = LtsWidgets::ExcState::eCreated | LtsWidgets::ExcState::eStarted | LtsWidgets::ExcState::ePaused;
ret.append(pd);
}
return ret;
}
QString InterfaceImpl::menuGroup() const
{
return tr("Participants");
}
QString InterfaceImpl::menuGroupSup() const // TODO: UNUSED!
{
return tr("Support");
}
bool InterfaceImpl::fetchInterfaces()
{
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_dtc))
return false;
if (!m_session->getFtc<ParticipantManagement::DataInterface>(m_ftc))
return false;
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiTemplatesInterface>(m_ppmGuiTemplateIfc))
return false;
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmGuiCbxIfc))
return false;
m_session->getForeignDataInterface<AdvancedSymbology::DataInterface>(m_asb);
return true;
}
void InterfaceImpl::clearInterfaces()
{
m_ppmGuiTemplateIfc = nullptr;
m_ppmGuiCbxIfc = nullptr;
m_dtc = nullptr;
m_ftc = nullptr;
m_asb = nullptr;
}
LtsWidgets::LtsDialog *InterfaceImpl::onParticipantEdit(QWidget *parent, bool asSupportService)
{
return LtsWidgets::initDialog(new ParticipantEdit(m_session, asSupportService, parent),
m_dtc, m_ftc, m_ppmGuiCbxIfc, m_asb);
}
LtsWidgets::LtsDialog *InterfaceImpl::onParticipantOrganisation(QWidget *parent, bool asSupportService)
{
return LtsWidgets::initDialog(new ParticipantOrganisationDialog(m_session, asSupportService, parent),
m_dtc, m_ftc, m_ppmGuiTemplateIfc, m_ppmGuiCbxIfc, m_asb);
}
LtsWidgets::LtsDialog *InterfaceImpl::onTacticalParticipantOrganisation(QWidget *parent)
{
return LtsWidgets::initDialog(new TacticalOrganisation(m_session, parent),
m_dtc, m_ftc, m_ppmGuiCbxIfc, m_asb);
}
} // namespace ParticipantManagement
@@ -0,0 +1,74 @@
/**
* @RDE_HEADER@
* GUI Plugin for ParticipantManagement - Participant Edit
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#pragma once
#include <ParticipantManagement/logger.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_participants_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_templates_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
namespace AdvancedSymbology
{
class ForeignDataInterface;
}
namespace ParticipantManagement
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:ppm.participant")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QStringLiteral("ParticipantManagement.GuiPlugin.ParticipantEdit"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Exercise);
}
};
class InterfaceImpl final : public QObject, public ForeignGuiParticipantsInterface, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
QVector<LtsWidgets::PluginData> getActions() override;
bool fetchInterfaces() override;
void clearInterfaces() override;
QString menuGroup() const override;
QString menuGroupSup() const;
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Exercise; }
private:
LtsWidgets::LtsDialog *onParticipantEdit(QWidget *parent, bool asSupportService);
LtsWidgets::LtsDialog *onParticipantOrganisation(QWidget *parent, bool asSupportService);
LtsWidgets::LtsDialog *onTacticalParticipantOrganisation(QWidget *parent);
private:
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ftc;
std::shared_ptr<ParticipantManagement::ForeignGuiTemplatesInterface> m_ppmGuiTemplateIfc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmGuiCbxIfc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asb;
};
} // namespace ParticipantManagement
@@ -0,0 +1,513 @@
/**
* @RDE_HEADER@
* HMI Plugin for ParticipantManagement - Participant Organisation Model
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-17
*/
#include "participant_orga_model.h"
#include <Plugins/ParticipantManagement/ppm_mime_datas.h>
#include <Common/participant_edit_model.h>
#include <ParticipantManagement/ppm_translation.h>
#include <Symbology/symbol_data_to_render_role.h>
#include <QMimeData>
#include <nglwidgets/ngltreeitem.h>
namespace ParticipantManagement
{
//----------------------------------------------------------------------------
ParticipantOrgaModel::ParticipantOrgaModel(PartyOrganisationType orgType,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc,
QObject *parent)
: ParticipantIconModelBase(ppmDtc,
asbIfc,
{ headerFromOrganisationType(orgType), tr("Participant Id") },
new NGLTreeItem(QVariant()),
parent,
getLogger(QStringLiteral("ParticipantOrgaModel.") + headerFromOrganisationType(orgType)))
, m_partyId(-1)
, m_orgType(orgType)
{
connect(m_dtc.get(), &ParticipantManagement::Interface::Dtc::participantOrganisationChanged,
this, &ParticipantOrgaModel::onParticipantOrganisationChanged);
m_dtc->participantOrganisations([this](const ParticipantOrganisation &org) { m_participantOrganization[org.participantId()] = org;});
}
QVariant ParticipantOrgaModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || role != Qt::DisplayRole)
return NGLTreeModel::data(index, role);
NGLTreeItem *item = privateData(index);
if (item->data().canConvert<ParticipantManagement::ParticipantData>())
{
const ParticipantManagement::ParticipantData participantData = item->data().value<ParticipantManagement::ParticipantData>();
switch (index.column())
{
case ColDescription:
return QVariant(QString::fromStdString(participantData.designator()) + QLatin1Char('/') +
QString::fromStdString(participantData.tacticalIdentifier()));
case ColParticipantId:
return participantData.id();
}
}
return NGLTreeModel::data(index, role);
}
int ParticipantOrgaModel::columnCount(const QModelIndex &parent) const
{
int cc = NGLTreeModel::columnCount(parent);
#ifndef LTS_DEBUG
// participant id only in dev mode
cc -= 1;
#endif
return cc;
}
Qt::ItemFlags ParticipantOrgaModel::flags(const QModelIndex &index) const
{
return NGLTreeModel::flags(index) | Qt::ItemIsDropEnabled;
}
QStringList ParticipantOrgaModel::mimeTypes() const
{
switch (m_orgType)
{
case PartyOrganisationType::Party:
return { ParticipantPoolRoot, ParticipantPartyDetached };
case PartyOrganisationType::Attached:
case PartyOrganisationType::Cooperate:
return { ParticipantPoolRoot, ParticipantPoolDetached };
case PartyOrganisationType::Detached:
return { ParticipantPartyChild };
}
return QStringList();
}
QMimeData *ParticipantOrgaModel::mimeData(const QModelIndexList &indexes) const
{
if (indexes.size() < 1)
return nullptr;
const QModelIndex &idx = indexes.first();
if (!idx.isValid())
return nullptr;
// we only allow to move the complete tree here
if (m_orgType == PartyOrganisationType::Detached ||
m_orgType == PartyOrganisationType::Attached ||
m_orgType == PartyOrganisationType::Cooperate)
{
if (idx.parent().isValid())
return nullptr;
}
const ParticipantData data = privateData(idx)->data().value<ParticipantManagement::ParticipantData>();
if (data.id() == 0)
return nullptr;
if (m_orgType == PartyOrganisationType::Detached)
{
// if attached to another party, do not allow to move it back to origin party ...
auto it = m_participantOrganization.find(data.id());
if (it != m_participantOrganization.end() && it.value().currentPartyId() != 0)
return nullptr;
}
const QByteArray encodedData(QByteArray::number(data.id()));
QMimeData *mimeData = new QMimeData;
switch (m_orgType)
{
case PartyOrganisationType::Party:
mimeData->setData(idx.parent().isValid() ? ParticipantPartyChild : ParticipantPartyRoot, encodedData);
break;
case PartyOrganisationType::Detached:
mimeData->setData(ParticipantPartyDetached, encodedData);
break;
case PartyOrganisationType::Attached:
case PartyOrganisationType::Cooperate:
mimeData->setData(ParticipantPartyAttached, encodedData);
break;
}
return mimeData;
}
bool ParticipantOrgaModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{
if (!NGLTreeModel::canDropMimeData(data, action, row, column, parent))
return false;
// in Party - Mode we don't accept a new pool template since only one tree is allowed
if (m_orgType == PartyOrganisationType::Party)
{
if (data->hasFormat(ParticipantPoolRoot) && m_rootItem->childCount() > 0)
return false;
if (data->hasFormat(ParticipantPartyDetached) && !parent.isValid())
return false;
}
if (m_orgType == PartyOrganisationType::Attached ||
m_orgType == PartyOrganisationType::Cooperate)
{
if (data->hasFormat(ParticipantPoolRoot))
return true;
// don't allow attach/cooperate of own subunits
bool bOk;
const int participantId = data->data(ParticipantPoolDetached).toInt(&bOk);
if (bOk)
{
auto it = m_participantOrganization.find(participantId);
if (it != m_participantOrganization.end() &&
it.value().originPartyId() == m_partyId)
return false;
}
}
return true;
}
bool ParticipantOrgaModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent)
{
Q_UNUSED(row)
Q_UNUSED(column)
Q_UNUSED(parent)
// only in PartyOrganisationType::Party mode
if (action != Qt::MoveAction)
{
ERROR_LOG(m_logger) << "Drop: action is not move action: " << action;
return false;
}
// all data we accept here is packaged the same, the different mime type
// is only used to (dis)allow the moves to the different models
// since we can only move one item, the data is a simple integer (=participantId)
int participantId = -1;
for (const auto &mt : { ParticipantPoolRoot, ParticipantPartyChild, ParticipantPartyDetached, ParticipantPoolDetached })
{
if (data->hasFormat(mt))
{
bool bOk;
participantId = data->data(mt).toInt(&bOk);
if (bOk)
break;
}
}
DEBUG_LOG(m_logger) << "Drop: participantId: " << participantId;
if (participantId <= 0)
{
WARNING_LOG(m_logger) << "Can not decode mime data - ignoring";
return false;
}
// since inferiorParticipants is walking recursivly the tree, the vector is sorted
QVector<Participant> movedParticipants = inferiorParticipants(participantId);
if (movedParticipants.isEmpty())
{
WARNING_LOG(m_logger) << "Can not find valid data for participant " << participantId;
return false;
}
// when we are attached/detached/cooperate then the participant is a new leader -> superiorId = 0, hierarchyNumber = 1
movedParticipants[0].superiorId(0);
movedParticipants[0].hierarchyNumber(1);
int rootParticipantId = 0;
NGLTreeItem *rootItem = m_rootItem;
QModelIndex rootModelIndex;
if (m_orgType == PartyOrganisationType::Party && data->hasFormat(ParticipantPartyDetached))
{
if (!parent.isValid())
return false;
NGLTreeItem *item = privateData(parent);
if (!item)
return false;
if (!item->data().canConvert<ParticipantManagement::ParticipantData>())
return false;
const ParticipantManagement::ParticipantData participantData = item->data().value<ParticipantManagement::ParticipantData>();
if (participantData.id() == 0)
return false;
rootParticipantId = participantData.id();
rootItem = item;
rootModelIndex = parent;
movedParticipants[0].superiorId(rootParticipantId);
movedParticipants[0].hierarchyNumber(-1);
}
DEBUG_LOG(m_logger) << "Drop: #movedParticipants: " << movedParticipants.size();
QHash<int, ParticipantManagement::ParticipantData> tmap;
tmap.reserve(movedParticipants.size());
QHash<int, QSet<int>> parentId2id;
parentId2id.reserve(movedParticipants.size());
for (const Participant &part : qAsConst(movedParticipants))
{
if (part.isDeleted())
continue;
// parentId -> id for lookup
parentId2id[part.superiorId()] += part.id();
tmap.insert(part.id(), m_dtc->convertParticipantToParticipantData(part));
}
// insert recursivly
insertChildrenOf(rootParticipantId, rootItem, rootModelIndex, parentId2id, tmap);
// save current party config
emit participantDataChanged(movedParticipants.at(0).id());
return true;
}
bool ParticipantOrgaModel::isParticipantType(int source_row, const QModelIndex &source_parent) const
{
NGLTreeItem *parentItem = privateData(source_parent);
if (!parentItem)
return false;
const NGLTreeItem *childItem = parentItem->child(source_row);
if (!childItem)
return false;
if (!childItem->data().canConvert<ParticipantManagement::ParticipantData>())
return false;
const ParticipantManagement::ParticipantData participantData = childItem->data().value<ParticipantManagement::ParticipantData>();
return !isUnitType(participantData.typeId());
}
QVector<Participant> ParticipantOrgaModel::inferiorParticipants(int partId) const
{
QVector<Participant> retVector;
const Participant participant = m_dtc->participant(partId);
retVector.reserve(participant.inferiorIds().size() + retVector.size() + 1);
retVector.append(participant);
for (int inferiorId : participant.inferiorIds())
retVector.append(inferiorParticipants(inferiorId));
return retVector;
}
QVector<ParticipantData> ParticipantOrgaModel::getChildrenOf(NGLTreeItem *parentItem, int parentId, int hierarchyNumber, int &highestModId) const
{
QVector<ParticipantData> ret;
if (!parentItem)
return ret;
ParticipantManagement::ParticipantData participantData = parentItem->data().value<ParticipantManagement::ParticipantData>();
participantData.superiorModId(parentId);
participantData.hierarchyNumber(hierarchyNumber);
if (participantData.modId() == 0)
participantData.modId(++highestModId);
ret += participantData;
for (int i = 0; i < parentItem->childCount(); i++)
ret.append(getChildrenOf(parentItem->child(i), participantData.modId(), i + 1, highestModId));
return ret;
}
QVector<ParticipantData> ParticipantOrgaModel::participantData(int partyId) const
{
QVector<ParticipantData> ret;
// gehen wir mal davon aus, dass man nie mehr als 1mrd template - Einträge angelegt hat...
int modId = 1000000000;
for (int i = 0; i < m_rootItem->childCount(); ++i)
{
NGLTreeItem *rootKnot = m_rootItem->child(0);
ret += getChildrenOf(rootKnot, 0, 1, modId);
}
for (int i = 0; i < ret.size(); ++i)
ret[i].partyId(partyId);
return ret;
}
QVector<int> ParticipantOrgaModel::rootParticipantIds() const
{
QVector<int> ret;
for (int i = 0; i < m_rootItem->childCount(); ++i)
{
const NGLTreeItem *rootKnot = m_rootItem->child(i);
const ParticipantManagement::ParticipantData participantData = rootKnot->data().value<ParticipantManagement::ParticipantData>();
// should not happen but who knows...
if (participantData.id() == 0)
continue;
ret += participantData.id();
}
return ret;
}
void ParticipantOrgaModel::onReinitModel(int partyId)
{
m_partyId = partyId;
const ParticipantManagement::Party &party = m_dtc->party(m_partyId);
m_partyRole = AdvancedSymbology::roleToRole<>(party.role());
m_partyColor = QColor::fromRgb(QRgb(party.color()));
m_symbolResultMapping.clear();
NGLTreeModel::resetModel();
QHash<int, ParticipantData> tmap;
QHash<int, QSet<int>> parentId2id;
auto cb = [this, &tmap, &parentId2id](const Participant & part)
{
if (part.isDeleted())
return;
if (m_orgType != PartyOrganisationType::Detached && part.partyId() != m_partyId)
return;
if (m_orgType == PartyOrganisationType::Detached && part.partyId() == m_partyId)
return;
if (part.superiorId() == 0 && !isRootParticipantRelevant(part, m_partyId))
return;
// parentId -> id for lookup
parentId2id[part.superiorId()] += part.id();
tmap.insert(part.id(), m_dtc->convertParticipantToParticipantData(part));
};
m_dtc->participants(cb);
// insert recursivly
insertChildrenOf(0, m_rootItem, QModelIndex(), parentId2id, tmap);
}
void ParticipantOrgaModel::onParticipantOrganisationChanged(const ParticipantOrganisation &data, DataModification modType)
{
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
m_participantOrganization[data.participantId()] = data;
break;
case DataModification::eRemoved:
m_participantOrganization.remove(data.participantId());
break;
}
}
void ParticipantOrgaModel::insertChildrenOf(int parentId,
NGLTreeItem *parent,
const QModelIndex &parentIdx,
const QHash<int, QSet<int>> &parentId2id,
const QHash<int, ParticipantData> &tmap)
{
const QSet<int> childIds = parentId2id.value(parentId);
QMap<int, int> currentHierachyNumbers; // no QSet, must be sorted!
for (int childId : childIds)
{
auto it = tmap.constFind(childId);
if (it == tmap.constEnd())
{
WARNING_LOG(m_logger) << "Can not find participant with id " << childId << " - ignoring";
continue;
}
const ParticipantData &data = it.value();
int insertPos = 0;
if (data.hierarchyNumber() > 0)
{
auto hierIt = currentHierachyNumbers.insert(data.hierarchyNumber(), data.hierarchyNumber());
insertPos = std::distance(currentHierachyNumbers.begin(), hierIt);
}
else
{
// append if no valid hierarchy number is set
const NGLTreeItem *treeItemParent = privateData(parentIdx);
if (treeItemParent)
insertPos = treeItemParent->childCount();
}
NGLTreeItem *childItem = createItem(QVariant::fromValue(data), QIcon());
DEBUG_LOG(m_logger) << "insert Child " << childItem << "(" << data.id() << ", " << data.hierarchyNumber()
<< ") to parent " << parent << " at pos " << insertPos;
insertRow(insertPos, parentIdx, childItem);
const QModelIndex childIdx = index(insertPos, 0, parentIdx);
insertChildrenOf(data.id(), childItem, childIdx, parentId2id, tmap);
}
}
QString ParticipantOrgaModel::headerFromOrganisationType(PartyOrganisationType orgType)
{
switch (orgType)
{
case PartyOrganisationType::Party:
return tr("Party");
case PartyOrganisationType::Attached:
return tr("Attached");
case PartyOrganisationType::Detached:
return tr("Detached");
case PartyOrganisationType::Cooperate:
return tr("Directed to Cooperate");
}
return QString();
}
bool ParticipantOrgaModel::isRootParticipantRelevant(const Participant &participant, int partyId) const
{
// this function assumes, that the participant is in the correct party
const int participantId = participant.id();
const int participantPartyId = participant.partyId();
const ParticipantOrganisation org = m_participantOrganization.value(participantId);
switch (m_orgType)
{
case PartyOrganisationType::Party:
return participantPartyId == partyId && org.participantId() == 0; // is 0 when not in m_participantOrganization
case PartyOrganisationType::Attached:
return participantPartyId == partyId && org.participantId() == participantId && org.isAttached();
case PartyOrganisationType::Detached:
return org.participantId() == participantId && org.originPartyId() == partyId;
case PartyOrganisationType::Cooperate:
return participantPartyId == partyId && org.participantId() == participantId && org.isCooperate();
}
return false;
}
NGLTreeItem *ParticipantOrgaModel::createItem(const QVariant &data, const QIcon &icon) const
{
auto ret = NGLTreeModel::createItem(data, icon);
const ParticipantData participantData = data.value<ParticipantData>();
if (participantData.symbol().size() != 0)
{
ParticipantOrgaModel *that = const_cast<ParticipantOrgaModel*>(this);
// mutable
that->tryRenderSymbol(QString::fromStdString(participantData.symbol()), ret);
}
return ret;
}
//----------------------------------------------------------------------------
void ParticipantOrgaProxyModel::onReinitModel(int partyId)
{
if (m_sourceModel)
m_sourceModel->onReinitModel(partyId);
}
//----------------------------------------------------------------------------
void ParticipantOrgaProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<ParticipantOrgaModel*>(sourceModel);
QSortFilterProxyModel::setSourceModel(sourceModel);
}
//----------------------------------------------------------------------------
bool ParticipantOrgaProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!m_sourceModel || m_sourceModel->isParticipantType(source_row, source_parent))
return false;
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
} //namespace ParticipantManagement
Loaded 100 of 16245 files, more files were not shown because too many files have changed in this diff. Show more