791 lines
25 KiB
C++
Executable File
791 lines
25 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* Importieren von SAAB-Dateien
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
#include "saab_import.h"
|
|
#include "ui_saab_import.h"
|
|
#include "saab_logging.h"
|
|
#include "saab_import_show.h"
|
|
|
|
#include <QFileDialog>
|
|
|
|
#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 "saab_mapping_dialog.h"
|
|
|
|
namespace saab
|
|
{
|
|
|
|
ImportSaab::ImportSaab(ParticipantManagement::ParticipantEditModel *pModel, const QModelIndex &index, QWidget *parent, LtsSession::LtsSession *pSession)
|
|
: NGLDialog(parent)
|
|
, m_xmlFile(nullptr)
|
|
, m_configFile(nullptr)
|
|
, m_indexRoot(index)
|
|
, m_pModel(pModel)
|
|
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
|
, m_pUi(new Ui_SAABImport)
|
|
, m_logger(saab::getLogger("ImportSaab"))
|
|
{
|
|
m_pUi->setupUi(this);
|
|
setWindowTitle(tr("Import SAAB Orbat"));
|
|
|
|
if (!pSession->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc) || !pSession->getFtc<ParticipantManagement::DataInterface>(m_ppmFtc))
|
|
{
|
|
ERROR_LOG(m_logger) << "Fetching m_ppmDtc or m_ppmFtc failed!";
|
|
setEnabled(false);
|
|
}
|
|
else
|
|
m_mapTypes = m_ppmDtc->types();
|
|
|
|
connect(m_pUi->m_pushbutton_SelectFile, &QToolButton::clicked,
|
|
this, &ImportSaab::slotOpenImportDialog);
|
|
connect(m_pUi->m_pushbutton_SelectConfig, &QToolButton::clicked,
|
|
this, &ImportSaab::slotOpenConfigDialog);
|
|
connect(m_pUi->m_pushButton_StartImport, &QPushButton::clicked,
|
|
this, &ImportSaab::slotStartImport);
|
|
|
|
QString strImportFile = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("SAAB"), QStringLiteral("pathSelectedImportFile"), QString()).toString();
|
|
QString strConfigFile = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("SAAB"), QStringLiteral("pathSelectedConfigFile"), QString()).toString();
|
|
|
|
m_pUi->m_lineedit_ImportFile->setText(strImportFile);
|
|
m_pUi->m_lineedit_configFile->setText(strConfigFile);
|
|
|
|
m_pUi->m_pushButton_StartImport->setEnabled(strImportFile.size() && strConfigFile.size());
|
|
}
|
|
|
|
|
|
ImportSaab::~ImportSaab()
|
|
{
|
|
delete m_pUi;
|
|
}
|
|
|
|
|
|
void ImportSaab::slotOpenImportDialog()
|
|
{
|
|
QString strPathSelectedImportFolder = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("SAAB"), QStringLiteral("pathSelectedImportFolder"), QStringLiteral("/shd/CTC/TOOLS/TDS/")).toString();
|
|
QString strPathSelectedImportFile = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("SAAB"), 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("SAAB"), QStringLiteral("pathSelectedImportFolder"), strPathSelectedImportFolder);
|
|
|
|
if (!strPathSelectedImportFile.size())
|
|
return;
|
|
|
|
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("SAAB"), QStringLiteral("pathSelectedImportFile"), strPathSelectedImportFile);
|
|
m_pUi->m_lineedit_ImportFile->setText(strPathSelectedImportFile);
|
|
m_pUi->m_pushButton_StartImport->setEnabled(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("SAAB"), QStringLiteral("pathSelectedConfigFile"), QString()).toString().size());
|
|
}
|
|
}
|
|
|
|
void ImportSaab::slotOpenConfigDialog()
|
|
{
|
|
QString strPathSelectedConfigFolder = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("SAAB"), QStringLiteral("pathSelectedConfigFolder"), QStringLiteral("/shd/CTC/TOOLS/TDS/")).toString();
|
|
QString strPathSelectedConfigFile = LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("SAAB"), QStringLiteral("pathSelectedConfigFile"), QStringLiteral("/shd/CTC/TOOLS/TDS/")).toString();
|
|
|
|
QList<QUrl> urls;
|
|
urls << QUrl::fromLocalFile(strPathSelectedConfigFile);
|
|
|
|
QFileDialog fileDialog(this, tr("Select File"), strPathSelectedConfigFolder, tr("XML files (*.xml)"));
|
|
fileDialog.setSidebarUrls(urls);
|
|
fileDialog.setOptions(QFileDialog::ReadOnly);
|
|
fileDialog.setFileMode(QFileDialog::ExistingFile);
|
|
|
|
if (fileDialog.exec()) // TODO: use show(), use signals & slots !
|
|
{
|
|
strPathSelectedConfigFile = fileDialog.selectedFiles().constFirst();
|
|
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("SAAB"), QStringLiteral("pathSelectedConfigFolder"), strPathSelectedConfigFolder);
|
|
|
|
if (!strPathSelectedConfigFile.size())
|
|
return;
|
|
|
|
LtsUtils::OperatorSettings::getInstance()->setValue(QStringLiteral("SAAB"), QStringLiteral("pathSelectedConfigFile"), strPathSelectedConfigFile);
|
|
m_pUi->m_lineedit_configFile->setText(strPathSelectedConfigFile);
|
|
m_pUi->m_pushButton_StartImport->setEnabled(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("SAAB"), QStringLiteral("pathSelectedImportFile"), QString()).toString().size());
|
|
}
|
|
}
|
|
|
|
|
|
void ImportSaab::slotStartImport()
|
|
{
|
|
if (m_xmlFile)
|
|
{
|
|
m_xmlFile->close();
|
|
delete m_xmlFile;
|
|
m_xmlFile = nullptr;
|
|
}
|
|
|
|
if (m_configFile)
|
|
{
|
|
m_configFile->close();
|
|
delete m_configFile;
|
|
m_configFile = nullptr;
|
|
}
|
|
|
|
m_pModel->resetModel();
|
|
|
|
QString fileName = m_pUi->m_lineedit_ImportFile->text();
|
|
QString configFileName = m_pUi->m_lineedit_configFile->text();
|
|
|
|
m_xmlFile = new QFile(fileName, this);
|
|
m_configFile = new QFile(configFileName, this);
|
|
|
|
if (!isValidSaabOrbatFile())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Error while reading file \"%1\".").arg(fileName));
|
|
return;
|
|
}
|
|
|
|
if (!isValidConfigFile())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Error while reading file \"%1\".").arg(configFileName));
|
|
return;
|
|
}
|
|
|
|
importExerciseScenario();
|
|
}
|
|
|
|
ParticipantManagement::ParticipantData ImportSaab::createParticipant(SaabPlayer *player)
|
|
{
|
|
ParticipantManagement::ParticipantData p;
|
|
|
|
// Note: According to Uli D., in GÜZ, TactId shall be static and
|
|
// received from SAAB and designator shall be freely changeable.
|
|
|
|
// Designator
|
|
p.tacticalIdentifier(player->designation.toStdString());
|
|
|
|
// State and Equipment
|
|
p.equipmentNumber(player->simulatorId != INT_MIN ? player->simulatorId : 0);
|
|
p.assignState() = ParticipantManagement::ParticipantAssignState::HandoutExcon;
|
|
|
|
if (player->simulatorId != INT_MIN)
|
|
p.externalId(player->simulatorId);
|
|
|
|
p.symbol(m_mapTypes[player->mappedTypeId].symbol());
|
|
p.typeId(player->mappedTypeId); // Class type is internally derived from typeid, no need (and possibility) to set it here
|
|
|
|
return p;
|
|
}
|
|
|
|
void ImportSaab::insertParticipant(SaabPlayer *player, const QModelIndex &index)
|
|
{
|
|
ParticipantManagement::ParticipantData newParticipant = createParticipant(player);
|
|
createNode(newParticipant, index, player);
|
|
}
|
|
|
|
// Parties are the root units (m_rootUnits)
|
|
void ImportSaab::insertParty(SaabUnit *party)
|
|
{
|
|
// Create "Force"-Node -> No symbol, no tact. identifier, no classtype
|
|
ParticipantManagement::ParticipantData newParty;
|
|
newParty.designator(party->designation.toStdString());
|
|
createNode(newParty, m_indexRoot, party);
|
|
}
|
|
|
|
|
|
void ImportSaab::createNode(const ParticipantManagement::ParticipantData &participant, const QModelIndex &index, SaabPlayer *parent)
|
|
{
|
|
int newRow = m_pModel->onInsertRow(index, participant);
|
|
QModelIndex newIdx = m_pModel->index(newRow, 0, index);
|
|
m_parentIndexCache[parent] = newIdx;
|
|
}
|
|
|
|
SaabPerson ImportSaab::saabPersonByGUID(const QString &guid) const
|
|
{
|
|
for (const auto ¤t : qAsConst(m_saabPersons))
|
|
{
|
|
if (current.guid == guid)
|
|
return current;
|
|
}
|
|
|
|
return SaabPerson();
|
|
}
|
|
|
|
SaabVehicle ImportSaab::saabVehicleByGUID(const QString &guid) const
|
|
{
|
|
for (const auto ¤t : qAsConst(m_saabVehicles))
|
|
{
|
|
if (current.guid == guid)
|
|
return current;
|
|
}
|
|
|
|
return SaabVehicle();
|
|
}
|
|
|
|
void ImportSaab::importOrbat()
|
|
{
|
|
if (!m_xmlFile)
|
|
{
|
|
ERROR_LOG(m_logger) << "Not possible to import ORBAT: No file selected";
|
|
return;
|
|
}
|
|
|
|
if (!m_xmlFile->open(QIODevice::ReadOnly))
|
|
{
|
|
ERROR_LOG(m_logger) << "Not possible to import ORBAT: Could not open file \""
|
|
<< m_xmlFile->fileName()
|
|
<< "\" for reading.";
|
|
return;
|
|
}
|
|
|
|
QXmlStreamReader reader(m_xmlFile);
|
|
|
|
qDeleteAll(m_rootUnits);
|
|
m_rootUnits.clear();
|
|
m_unknownTypes.clear();
|
|
|
|
while (!(reader.readNext() == QXmlStreamReader::EndElement && reader.name() == XmlStrings::SAAB_ORBAT()))
|
|
{
|
|
if (reader.atEnd())
|
|
break;
|
|
|
|
if (reader.tokenType() == QXmlStreamReader::StartElement && reader.name() == XmlStrings::SAAB_UNIT())
|
|
{
|
|
SaabUnit *unit = static_cast<SaabUnit *>(readUnit(&reader));
|
|
|
|
if (unit->isDeletedByDefault)
|
|
continue;
|
|
|
|
m_rootUnits.append(unit);
|
|
}
|
|
}
|
|
|
|
if (m_logger.isDebugEnabled())
|
|
{
|
|
for (SaabUnit *u : qAsConst(m_rootUnits))
|
|
DEBUG_LOG(m_logger) << u->toString();
|
|
}
|
|
|
|
m_xmlFile->close();
|
|
}
|
|
|
|
void ImportSaab::importConfig()
|
|
{
|
|
if (!m_mapSymbols.isEmpty() || !m_mapEchelons.isEmpty())
|
|
{
|
|
using namespace LtsWidgets;
|
|
|
|
Button b = LtsMessageDialog::showMessage(this,
|
|
tr("A config is already imported. Overwrite?"),
|
|
tr("Overwrite config?"),
|
|
Behaviour::Modal,
|
|
Button::Yes | Button::No);
|
|
if (b != Button::Yes)
|
|
return;
|
|
}
|
|
|
|
if (!m_configFile)
|
|
{
|
|
ERROR_LOG(m_logger) << "Not possible to read config: No file selected";
|
|
return;
|
|
}
|
|
|
|
if (!m_configFile->open(QIODevice::ReadOnly))
|
|
{
|
|
ERROR_LOG(m_logger) << "Not possible to read config: Could not open file \""
|
|
<< m_configFile->fileName()
|
|
<< "\" for reading.";
|
|
return;
|
|
}
|
|
|
|
m_mapSymbols.clear();
|
|
m_mapEchelons.clear();
|
|
m_mapSaabSymbolToType.clear();
|
|
|
|
QXmlStreamReader reader(m_configFile);
|
|
|
|
using namespace XmlStrings;
|
|
|
|
while (!reader.atEnd())
|
|
{
|
|
if (reader.readNextStartElement())
|
|
{
|
|
if (reader.name() == SAAB_SYMBOL())
|
|
{
|
|
SaabSymbol newSymbol = readSymbol(&reader);
|
|
m_mapSymbols.insert(newSymbol.code, newSymbol);
|
|
}
|
|
else if (reader.name() == SAAB_ECHELON())
|
|
{
|
|
SaabEchelon newEchelon = readEchelon(&reader);
|
|
m_mapEchelons.insert(newEchelon.code, newEchelon);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
m_configFile->close();
|
|
}
|
|
|
|
QVector<SaabPlayer *> ImportSaab::flattenedPlayersWithoutRootUnits() const
|
|
{
|
|
QVector<SaabPlayer *> result;
|
|
|
|
for (SaabUnit *p : qAsConst(m_rootUnits))
|
|
{
|
|
QVector<SaabPlayer *> inferiorInferiors = inferiors(p);
|
|
|
|
for (SaabPlayer *infInf : qAsConst(inferiorInferiors))
|
|
result.append(infInf);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
QVector<SaabPlayer *> ImportSaab::inferiors(SaabPlayer *player) const
|
|
{
|
|
QVector<SaabPlayer *> result;
|
|
|
|
if (typeid(*player) != typeid(SaabUnit))
|
|
{
|
|
result.append(player);
|
|
return result;
|
|
}
|
|
|
|
SaabUnit *unit = static_cast<SaabUnit *>(player);
|
|
|
|
if (!m_rootUnits.contains(unit))
|
|
result.append(player);
|
|
|
|
for (SaabPlayer *inf : qAsConst(unit->inferiors))
|
|
{
|
|
QVector<SaabPlayer *> inferiorInferiors = inferiors(inf);
|
|
for (SaabPlayer *infInf : qAsConst(inferiorInferiors))
|
|
result.append(infInf);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
SaabPlayer *ImportSaab::readUnit(QXmlStreamReader *reader) const
|
|
{
|
|
DEBUG_LOG(m_logger) << "reading unit: tokentype: " << reader->tokenString() << " | name: " << reader->name().toString();
|
|
|
|
SaabUnit *result = new SaabUnit;
|
|
|
|
using namespace XmlStrings;
|
|
|
|
QMap<QString, SaabPlayer*(ImportSaab::*)(QXmlStreamReader *)const> funcMap;
|
|
funcMap.insert(SAAB_PERSON_PLAYER(), &ImportSaab::readPersonPlayer);
|
|
funcMap.insert(SAAB_OC_PLAYER(), &ImportSaab::readOcPlayer);
|
|
funcMap.insert(SAAB_VEHICLE_PLAYER(), &ImportSaab::readVehiclePlayer);
|
|
funcMap.insert(SAAB_UNIT(), &ImportSaab::readUnit);
|
|
|
|
result->guid = reader->attributes().value(SAAB_ID()).toString();
|
|
|
|
while (!(reader->readNext() == QXmlStreamReader::EndElement && reader->name() == SAAB_UNIT()))
|
|
{
|
|
if (reader->tokenType() == QXmlStreamReader::StartElement)
|
|
{
|
|
if (reader->name() == SAAB_DESIGNATION())
|
|
result->designation = reader->readElementText();
|
|
else if (reader->name() == SAAB_FORCE())
|
|
result->force = reader->readElementText();
|
|
else if (reader->name() == SAAB_SYMBOL())
|
|
result->symbol = reader->readElementText();
|
|
else if (reader->name() == SAAB_TRASHCAN())
|
|
result->trashcan = reader->readElementText() == SAAB_TRUE();
|
|
else if (reader->name() == SAAB_POSITION_BY_PLAYER_ID())
|
|
result->positionByPlayerId = reader->readElementText();
|
|
else if (reader->name() == SAAB_UNIT_SIZE())
|
|
result->unitSize = reader->readElementText();
|
|
else if (reader->name() == SAAB_CHANGE_INFO())
|
|
result->isDeletedByDefault = reader->attributes().value(SAAB_CHANGE_TYPE()).toString() == SAAB_DELETE();
|
|
else if (reader->name() == SAAB_ORBAT_ENTITIES())
|
|
{
|
|
while (!(reader->readNext() == QXmlStreamReader::EndElement && reader->name() == SAAB_ORBAT_ENTITIES()))
|
|
{
|
|
QString tagName = reader->name().toString();
|
|
if (reader->tokenType() == QXmlStreamReader::StartElement && funcMap.contains(tagName))
|
|
{
|
|
SaabPlayer *newParticipant = (this->*funcMap.value(tagName))(reader);
|
|
|
|
if (newParticipant->isDeletedByDefault || newParticipant->isExternalPlayer)
|
|
continue;
|
|
|
|
newParticipant->superior = result;
|
|
result->inferiors.append(newParticipant);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if the unit has to take the position of a specific participant,
|
|
// take the participant to the top of the inferiors
|
|
if (!result->positionByPlayerId.isEmpty())
|
|
{
|
|
int index = playerIndexByGuid(result->guid, result->inferiors);
|
|
|
|
if (index < 0)
|
|
WARNING_LOG(m_logger) << SAAB_POSITION_BY_PLAYER_ID() << " set, but GUID " << result->positionByPlayerId << " could not be found.";
|
|
else
|
|
result->inferiors.prepend(result->inferiors.takeAt(index));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
SaabPlayer *ImportSaab::readOcPlayer(QXmlStreamReader *reader) const
|
|
{
|
|
DEBUG_LOG(m_logger) << "reading oc player: tokentype: " << reader->tokenString() << " | name: " << reader->name().toString();
|
|
|
|
return readPersonOcPlayer<SaabOcPlayer>(reader, XmlStrings::SAAB_OC_PLAYER());;
|
|
}
|
|
|
|
SaabPlayer *ImportSaab::readPersonPlayer(QXmlStreamReader *reader) const
|
|
{
|
|
DEBUG_LOG(m_logger) << "reading person player: tokentype: " << reader->tokenString() << " | name: " << reader->name().toString();
|
|
|
|
return readPersonOcPlayer<SaabPersonPlayer>(reader, XmlStrings::SAAB_PERSON_PLAYER());
|
|
}
|
|
|
|
SaabPlayer *ImportSaab::readVehiclePlayer(QXmlStreamReader *reader) const
|
|
{
|
|
DEBUG_LOG(m_logger) << "reading vehicle player: tokentype: " << reader->tokenString() << " | name: " << reader->name().toString();
|
|
|
|
using namespace XmlStrings;
|
|
|
|
SaabVehiclePlayer *result = readPlayerBaseData<SaabVehiclePlayer>(reader, SAAB_VEHICLE_PLAYER(), SAAB_VEHICLE_REF_ID());
|
|
|
|
if (!result->refId.isEmpty())
|
|
{
|
|
SaabVehicle vehicle = saabVehicleByGUID(reader->readElementText());
|
|
|
|
if (vehicle.guid.isEmpty())
|
|
WARNING_LOG(m_logger) << SAAB_VEHICLE_REF_ID() << " set, but GUID " << result->refId << " could not be found.";
|
|
else
|
|
{
|
|
result->registrationNumber = vehicle.registrationNumber;
|
|
result->description = vehicle.description;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
SaabSymbol ImportSaab::readSymbol(QXmlStreamReader *reader) const
|
|
{
|
|
SaabSymbol result;
|
|
|
|
using namespace XmlStrings;
|
|
|
|
while (reader->readNext() != QXmlStreamReader::EndElement && reader->name() != SAAB_SYMBOL())
|
|
{
|
|
if (reader->name() == SAAB_CODE())
|
|
result.code = reader->readElementText();
|
|
else if (reader->name() == SAAB_TEXT())
|
|
result.text = reader->readElementText();
|
|
else if (reader->name() == SAAB_SYMBOL_ID())
|
|
result.symbolId = reader->readElementText();
|
|
else if (reader->name() == SAAB_MODEL_ID())
|
|
result.modelId = reader->readElementText();
|
|
else if (reader->name() == SAAB_ECHELON_ID())
|
|
result.echelonId = reader->readElementText();
|
|
else if (reader->name() == SAAB_PLAYER_TYPE_ID())
|
|
result.playerTypeId = reader->readElementText();
|
|
else if (reader->name() == SAAB_COLOR())
|
|
result.color = reader->readElementText();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
SaabEchelon ImportSaab::readEchelon(QXmlStreamReader *reader) const
|
|
{
|
|
SaabEchelon result;
|
|
|
|
using namespace XmlStrings;
|
|
|
|
while (reader->readNext() != QXmlStreamReader::EndElement && reader->name() != SAAB_ECHELON())
|
|
{
|
|
if (reader->name() == SAAB_CODE())
|
|
result.code = reader->readElementText();
|
|
else if (reader->name() == SAAB_TEXT())
|
|
result.text = reader->readElementText();
|
|
else if (reader->name() == SAAB_ID())
|
|
result.id = reader->readElementText();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int ImportSaab::playerIndexByGuid(const QString &guid, const QVector<SaabPlayer *> &vec)
|
|
{
|
|
for (int i = 0; i < vec.size(); ++i)
|
|
{
|
|
if (vec.at(i)->guid == guid)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void ImportSaab::importExerciseScenario()
|
|
{
|
|
using namespace XmlStrings;
|
|
|
|
importConfig();
|
|
importRefData(m_saabPersons, SAAB_PERSONS(), SAAB_PERSON(), SAAB_PERSONAL_ID(), SAAB_NAME()); // import persons
|
|
importRefData(m_saabVehicles, SAAB_VEHICLES(), SAAB_VEHICLE(), SAAB_REGISTRATION_NUMBER(), SAAB_DESCRIPTION()); // import vehicles
|
|
importOrbat();
|
|
|
|
for (SaabUnit *party : qAsConst(m_rootUnits))
|
|
insertParty(party);
|
|
|
|
QVector<SaabPlayer *> vecUnitsWithValidDISTypes = resolveImportMapping(flattenedPlayersWithoutRootUnits());
|
|
|
|
if (!vecUnitsWithValidDISTypes.size())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("There are no units or participants which can be imported."), tr("Import Warning"));
|
|
return;
|
|
}
|
|
|
|
buildImportTreeView(vecUnitsWithValidDISTypes);
|
|
|
|
close();
|
|
}
|
|
|
|
void ImportSaab::buildImportTreeView(const QVector<SaabPlayer *> &vecUnitsWithValidDISTypes)
|
|
{
|
|
QVector<SaabPlayer *> tmp;
|
|
QVector<SaabPlayer *> current = vecUnitsWithValidDISTypes;
|
|
do
|
|
{
|
|
for (SaabPlayer *player : current)
|
|
{
|
|
auto it = m_parentIndexCache.find(player->superior);
|
|
|
|
if (it == m_parentIndexCache.end())
|
|
{
|
|
// check if the parent exists in vecUnitsWithValidDISTypes for the next approach
|
|
if (vecUnitsWithValidDISTypes.contains(player->superior))
|
|
tmp.append(player);
|
|
else
|
|
WARNING_LOG(m_logger) << "Parent missing: Could not import player " << player->designation;
|
|
|
|
continue;
|
|
}
|
|
|
|
QModelIndex &parentIdx = (*it);
|
|
insertParticipant(player, parentIdx);
|
|
}
|
|
|
|
current = tmp;
|
|
tmp.clear();
|
|
} while (!current.isEmpty());
|
|
}
|
|
|
|
bool ImportSaab::isValidSaabOrbatFile() const
|
|
{
|
|
if (!m_xmlFile)
|
|
{
|
|
ERROR_LOG(m_logger) << "Not possible to import ORBAT: No file selected";
|
|
return false;
|
|
}
|
|
|
|
if (!m_xmlFile->open(QIODevice::ReadOnly))
|
|
{
|
|
ERROR_LOG(m_logger) << "Not possible to import ORBAT: Could not open file \""
|
|
<< m_xmlFile->fileName()
|
|
<< "\" for reading.";
|
|
return false;
|
|
}
|
|
|
|
bool hasExerciseOrbatRoot = false;
|
|
bool hasExercise = false;
|
|
bool hasOrbat = false;
|
|
|
|
QXmlStreamReader reader(m_xmlFile);
|
|
|
|
using namespace XmlStrings;
|
|
|
|
while (!(hasExerciseOrbatRoot && hasExercise && hasOrbat) && !reader.atEnd())
|
|
{
|
|
if (reader.readNextStartElement())
|
|
{
|
|
if (reader.name() == SAAB_EXERCISE_ORBAT())
|
|
hasExerciseOrbatRoot = true;
|
|
else if (reader.name() == SAAB_EXERCISE())
|
|
hasExercise = true;
|
|
else if (reader.name() == SAAB_ORBAT())
|
|
hasOrbat = true;
|
|
}
|
|
}
|
|
|
|
m_xmlFile->close();
|
|
|
|
if (!hasExerciseOrbatRoot)
|
|
ERROR_LOG(m_logger) << "Could not find " << SAAB_EXERCISE_ORBAT() << " in file \"" << m_xmlFile->fileName() << '\"';
|
|
if (!hasExercise)
|
|
ERROR_LOG(m_logger) << "Could not find " << SAAB_EXERCISE() << " in file \"" << m_xmlFile->fileName() << '\"';
|
|
if (!hasOrbat)
|
|
ERROR_LOG(m_logger) << "Could not find " << SAAB_ORBAT() << " in file \"" << m_xmlFile->fileName() << '\"';
|
|
|
|
return hasExerciseOrbatRoot && hasExercise && hasOrbat;
|
|
}
|
|
|
|
bool ImportSaab::isValidConfigFile() const
|
|
{
|
|
if (!m_configFile)
|
|
{
|
|
ERROR_LOG(m_logger) << "Not possible to read config: No file selected";
|
|
return false;
|
|
}
|
|
|
|
if (!m_configFile->open(QIODevice::ReadOnly))
|
|
{
|
|
ERROR_LOG(m_logger) << "Not possible to read config: Could not open file \""
|
|
<< m_configFile->fileName()
|
|
<< "\" for reading.";
|
|
return false;
|
|
}
|
|
|
|
using namespace XmlStrings;
|
|
|
|
QXmlStreamReader reader(m_configFile);
|
|
|
|
bool hasSymbols = false;
|
|
bool hasEchelons = false;
|
|
|
|
while (!reader.atEnd() && !(hasSymbols && hasEchelons))
|
|
{
|
|
if (reader.readNextStartElement())
|
|
{
|
|
if (reader.name() == SAAB_SYMBOLS())
|
|
hasSymbols = true;
|
|
else if (reader.name() == SAAB_ECHELONS())
|
|
hasEchelons = true;
|
|
}
|
|
}
|
|
|
|
m_configFile->close();
|
|
|
|
if (!hasEchelons)
|
|
ERROR_LOG(m_logger) << "Could not find " << SAAB_ECHELONS() << " in file \"" << m_configFile->fileName() << '\"';
|
|
if (!hasSymbols)
|
|
ERROR_LOG(m_logger) << "Could not find " << SAAB_SYMBOLS() << " in file \"" << m_configFile->fileName() << '\"';
|
|
|
|
return hasEchelons && hasSymbols;
|
|
}
|
|
|
|
bool ImportSaab::hasValidType(SaabPlayer *player) const
|
|
{
|
|
return m_mapSymbols.value(player->symbol).mappedTypeId > -1;
|
|
}
|
|
|
|
QVector<SaabPlayer *> ImportSaab::resolveImportMapping(const QVector<SaabPlayer *> &playerVec)
|
|
{
|
|
QVector<SaabPlayer *> vecObjectsWithValidTypes;
|
|
QMap<QString, QVector<SaabPlayer *>> mapParticipantsWithUnknownType, mapUnitsWithUnknownType;
|
|
|
|
// first perform a mapping of saab type to rme type
|
|
for (SaabPlayer *player : playerVec)
|
|
{
|
|
if (!hasValidType(player))
|
|
{
|
|
if (typeid(*player) == typeid(SaabUnit))
|
|
{
|
|
QString text = m_mapSymbols.contains(player->symbol) ? m_mapSymbols.value(player->symbol).text : player->symbol;
|
|
QString unitSize = static_cast<SaabUnit *>(player)->unitSize;
|
|
text.append(tr(" - Size: %1").arg(m_mapEchelons.contains(unitSize) ? m_mapEchelons.value(unitSize).text : unitSize));
|
|
mapUnitsWithUnknownType[text].append(player);
|
|
}
|
|
else
|
|
mapParticipantsWithUnknownType[m_mapSymbols.contains(player->symbol) ? m_mapSymbols.value(player->symbol).text : player->symbol].append(player);
|
|
}
|
|
else
|
|
{
|
|
// A match between the imported unit (its DIS id) and one of the database types exists: Perform mapping, everything is fine.
|
|
vecObjectsWithValidTypes.append(player);
|
|
}
|
|
}
|
|
|
|
if (mapUnitsWithUnknownType.size())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("<b>Units</b> exist whose external type is unknown.<br/>You have to solve this by manually mapping<br/> the external types to existing <b>unit types</b>."), tr("Import Error"));
|
|
vecObjectsWithValidTypes.append(showMappingDialog(mapUnitsWithUnknownType, true));
|
|
}
|
|
|
|
if (mapParticipantsWithUnknownType.size())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("<b>Participants</b> exist whose external type is unknown.<br/>You have to solve this by manually mapping<br/> the external types to existing <b>participant types</b>."), tr("Import Error"));
|
|
vecObjectsWithValidTypes.append(showMappingDialog(mapParticipantsWithUnknownType, false));
|
|
}
|
|
|
|
return vecObjectsWithValidTypes;
|
|
}
|
|
|
|
|
|
QVector<SaabPlayer *> ImportSaab::showMappingDialog(const QMap<QString, QVector<SaabPlayer *>> &mapConflictMap, bool typeClassIsUnit)
|
|
{
|
|
QVector<SaabPlayer *> vecUnitsWithValidSymbols;
|
|
|
|
int32_t mappedTypeId = 0;
|
|
|
|
for (auto it = mapConflictMap.begin(); it != mapConflictMap.end(); ++it)
|
|
{
|
|
const QString &strSaabSymbol = it.key();
|
|
const QVector<SaabPlayer *> &vecData = it.value();
|
|
|
|
QString strReason;
|
|
bool offerDatabaseEntriesWithoutDISType;
|
|
|
|
if (!strSaabSymbol.size())
|
|
{
|
|
strReason = QString(tr("No 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 type \"%1\" is unknown.")).arg(strSaabSymbol);
|
|
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);
|
|
|
|
saab::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.mappingApplied())
|
|
{
|
|
m_mapSaabSymbolToType.insert(strSaabSymbol, mappedTypeId);
|
|
|
|
for (SaabPlayer *participant : qAsConst(vecData))
|
|
{
|
|
participant->mappedTypeId = mappedTypeId;
|
|
vecUnitsWithValidSymbols.push_back(participant);
|
|
}
|
|
}
|
|
}
|
|
|
|
return vecUnitsWithValidSymbols;
|
|
}
|
|
}
|