440 lines
16 KiB
C++
Executable File
440 lines
16 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* HMI Plugin for OperatorManangement - Operator Overview Dialog Model
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
|
*/
|
|
|
|
|
|
#include "charge_table_model.h"
|
|
|
|
#include <QIcon>
|
|
#include <QJsonObject>
|
|
#include <QJsonDocument>
|
|
|
|
namespace ProjectDataManagement
|
|
{
|
|
|
|
|
|
const QVector<int> ChargeTableDialogModel::ALL_ULEIS = {ChargeTableDialogModel::DirectImpactGrandparent,
|
|
ChargeTableDialogModel::DirectImpactChild,
|
|
ChargeTableDialogModel::BurstOfFireParent,
|
|
ChargeTableDialogModel::BurstOfFireChild,
|
|
ChargeTableDialogModel::AirBurstParent,
|
|
ChargeTableDialogModel::AirBurstChild,
|
|
ChargeTableDialogModel::UnarmedParent,
|
|
ChargeTableDialogModel::UnarmedChild,
|
|
ChargeTableDialogModel::FireAndForgetParent,
|
|
ChargeTableDialogModel::FireAndForgetChild,
|
|
ChargeTableDialogModel::ShortTimeScanningParent,
|
|
ChargeTableDialogModel::ShortTimeScanningChild };
|
|
const QVector<int> ChargeTableDialogModel::ALL_TAS = {ChargeTableDialogModel::ShortTimeChild1,
|
|
ChargeTableDialogModel::ShortTimeChild2,
|
|
ChargeTableDialogModel::ShortTimeChild3,
|
|
ChargeTableDialogModel::ShortTimeChild4,
|
|
ChargeTableDialogModel::ShortTimeChild5 };
|
|
|
|
//---------------------------------
|
|
// ChargeTableDialogModel
|
|
//---------------------------------
|
|
ChargeTableDialogModel::ChargeTableDialogModel(bool isOrganiser, QObject *parent )
|
|
: LtsWidgets::LtsAbstractTableModel<ProjectDataManagement::ChargeType>({tr("Id"),
|
|
tr("Is Visible"),
|
|
tr("Predefined Name"),
|
|
tr("Short Name"),
|
|
tr("Long Name"),
|
|
tr("Direct Impact"),
|
|
tr("Top Attack"),
|
|
tr("Burst of Fire"),
|
|
tr("Air Burst"),
|
|
tr("Unarmed"),
|
|
tr("Short Time"),
|
|
tr("Fire-and-Forget"),
|
|
tr("Short-Time Scanning"),
|
|
tr("DIS Entity")},
|
|
parent)
|
|
, m_dtc(nullptr)
|
|
, m_isOrganiser(isOrganiser)
|
|
, m_logger(getLogger("ChargeTableDialogModel"))
|
|
{}
|
|
|
|
ChargeTableDialogModel::~ChargeTableDialogModel()
|
|
{}
|
|
|
|
bool ChargeTableDialogModel::initModel(const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &dtc, const QSet<GearClass> &gearClasses)
|
|
{
|
|
m_dtc = dtc;
|
|
m_gearClasses = gearClasses;
|
|
connect(m_dtc.get(), &ProjectDataManagement::Interface::Dtc::chargeTypeChanged,
|
|
this, &ChargeTableDialogModel::onDataChanged);
|
|
m_dtc->chargeTypes([this](const ProjectDataManagement::ChargeType &ct)
|
|
{
|
|
if (!m_isOrganiser && !m_dtc->isVisible(ct.id()))
|
|
return;
|
|
insertRow(ct);
|
|
if (m_isOrganiser && m_dtc->isVisible(ct.id()))
|
|
m_visibleCharges.insert(ct.id());
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
QVariant ChargeTableDialogModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!indexIsValid(index))
|
|
return QVariant();
|
|
|
|
const ProjectDataManagement::ChargeType &ct = m_vecData.at(index.row());
|
|
|
|
// if (role == Qt::DecorationRole && index.column() == PredefinedName)
|
|
// return QIcon(QLatin1String(":/style/mortar_ammunition_administration.svg"));
|
|
|
|
if (role == Qt::CheckStateRole)
|
|
{
|
|
// CheckBoxes only for columns that are actually checkable
|
|
if (!flags(index).testFlag(Qt::ItemIsUserCheckable))
|
|
return QVariant();
|
|
|
|
// Organiser:
|
|
if (m_isOrganiser)
|
|
{
|
|
if (index.column() == IsVisible)
|
|
return (m_visibleCharges.contains(ct.id()) ? Qt::Checked : Qt::Unchecked);
|
|
return QVariant();
|
|
}
|
|
|
|
|
|
// Non Organiser:
|
|
qint32 tasCode = ct.id();
|
|
|
|
// TAS Codes < 2000 -> One Column fits all
|
|
if (tasCode < 2000)
|
|
{
|
|
if (index.column() == IsVisible)
|
|
return m_visibleCharges.contains(ct.id()) ? Qt::Checked : Qt::Unchecked;
|
|
|
|
// TAS Codes 1-46 exept 25 and 30 use cols DI, TA, BF, AB:
|
|
if (tasCode >= 1 && tasCode <= 46 && tasCode != 25 && tasCode != 30)
|
|
if (index.column() != DirectImpact &&
|
|
index.column() != TopAttack &&
|
|
index.column() != BurstOfFire &&
|
|
index.column() != AirBurst)
|
|
return QVariant();
|
|
// TAS Codes 25 and 30 are for FF charges:
|
|
if (tasCode == 25 || tasCode == 30)
|
|
if (index.column() != FireAndForget)
|
|
return QVariant();
|
|
// TAS Codes 77-79 are for SS charges
|
|
if (tasCode >= 77 && tasCode <=79)
|
|
if (index.column() != ShortTimeScanning)
|
|
return QVariant();
|
|
// TAS Codes 47-74 and 15xx, 16xx, 17xx, 18xx and 19xx (xx = 47-74) are ST charges
|
|
// Note: Not ommitting e.g. 13xx!
|
|
if (tasCode % 100 >= 47 && tasCode % 100 <= 76)
|
|
if (index.column() != ShortTime)
|
|
return QVariant();
|
|
|
|
// Now that all columns not relevant for charge do NOT show any CheckBoxes,
|
|
// we fill the remaining columns with synchronized checked CheckBoxes.
|
|
return m_visibleCharges.contains(ct.id()) ? Qt::Checked : Qt::Unchecked;
|
|
}
|
|
|
|
// TAS Codes > 2000
|
|
if (index.column() == IsVisible)
|
|
{
|
|
// Parent / Child are treated identically
|
|
// Direct Hit / Top Attack is the same kind
|
|
|
|
int sum = 0;
|
|
if (m_visibleCharges.contains(tasCode + DirectImpactGrandparent) || m_visibleCharges.contains(tasCode + DirectImpactChild))
|
|
++sum;
|
|
if (m_visibleCharges.contains(tasCode + BurstOfFireParent) || m_visibleCharges.contains(tasCode + BurstOfFireChild))
|
|
++sum;
|
|
if (m_visibleCharges.contains(tasCode + AirBurstParent) || m_visibleCharges.contains(tasCode + AirBurstChild))
|
|
++sum;
|
|
if (m_visibleCharges.contains(tasCode + UnarmedParent) || m_visibleCharges.contains(tasCode + UnarmedChild))
|
|
++sum;
|
|
if (m_visibleCharges.contains(tasCode + FireAndForgetParent) || m_visibleCharges.contains(tasCode + FireAndForgetChild))
|
|
++sum;
|
|
if (m_visibleCharges.contains(tasCode + ShortTimeScanningParent) || m_visibleCharges.contains(tasCode + ShortTimeScanningChild))
|
|
++sum;
|
|
// Check if all / nothing / intermediate is checked and set CheckBox accordingly:
|
|
if (sum == 0)
|
|
return Qt::Unchecked;
|
|
if (sum == 6)
|
|
return Qt::Checked;
|
|
return Qt::PartiallyChecked;
|
|
}
|
|
|
|
// Now to the single CheckBoxes:
|
|
|
|
// Direct Impact and Top Attack are treated identically:
|
|
// Do not distinguish unless Offset differs.
|
|
if (index.column() == DirectImpact || index.column() == TopAttack)
|
|
return (m_visibleCharges.contains(tasCode + DirectImpactGrandparent) || m_visibleCharges.contains(tasCode + DirectImpactChild) ? Qt::Checked : Qt::Unchecked);
|
|
|
|
if (index.column() == BurstOfFire)
|
|
return (m_visibleCharges.contains(tasCode + BurstOfFireParent) || m_visibleCharges.contains(tasCode + BurstOfFireChild) ? Qt::Checked : Qt::Unchecked);
|
|
|
|
if (index.column() == AirBurst)
|
|
return (m_visibleCharges.contains(tasCode + AirBurstParent) || m_visibleCharges.contains(tasCode + AirBurstChild) ? Qt::Checked : Qt::Unchecked);
|
|
|
|
if (index.column() == Unarmed)
|
|
return (m_visibleCharges.contains(tasCode + UnarmedParent) || m_visibleCharges.contains(tasCode + UnarmedChild) ? Qt::Checked : Qt::Unchecked);
|
|
|
|
if (index.column() == FireAndForget)
|
|
return (m_visibleCharges.contains(tasCode + FireAndForgetParent) || m_visibleCharges.contains(tasCode + FireAndForgetChild) ? Qt::Checked : Qt::Unchecked);
|
|
|
|
if (index.column() == ShortTimeScanning)
|
|
return (m_visibleCharges.contains(tasCode + ShortTimeScanningParent) || m_visibleCharges.contains(tasCode + ShortTimeScanning) ? Qt::Checked : Qt::Unchecked);
|
|
}
|
|
|
|
if (role == Qt::DisplayRole)
|
|
{
|
|
switch (index.column())
|
|
{
|
|
case IsVisible:
|
|
if (m_isOrganiser)
|
|
return m_dtc->isVisible(ct.id()) ? tr("Yes") : tr("No");
|
|
else
|
|
return ct.id();
|
|
case Id:
|
|
return QString::number(ct.id());
|
|
case PredefinedName:
|
|
return QString::fromStdString(ct.predefinedName());
|
|
case ShortName:
|
|
return QString::fromStdString(ct.shortName());
|
|
case LongName:
|
|
return QString::fromStdString(ct.name());
|
|
case DisEntity:
|
|
return QString::fromStdString(ct.disEntity());
|
|
}
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
bool ChargeTableDialogModel::setData(const QModelIndex &idx, const QVariant &value, int role)
|
|
{
|
|
if (!indexIsValid(idx))
|
|
return false;
|
|
|
|
if (role != Qt::CheckStateRole)
|
|
return false;
|
|
|
|
bool bVal = value.toBool();
|
|
|
|
if (m_isOrganiser)
|
|
{
|
|
if (idx.column() != IsVisible)
|
|
return false;
|
|
|
|
|
|
// Get JSON Properties
|
|
ChargeType ct = getRowData(idx.row());
|
|
QJsonDocument propsDoc = QJsonDocument::fromJson(QByteArray::fromStdString(ct.properties()));
|
|
QJsonObject propsObj;
|
|
if (propsDoc.isObject()) // if the given properties are no valid JSON object, the properties will be made from scratch
|
|
propsObj = propsDoc.object();
|
|
|
|
// Update JSON Properties
|
|
if (bVal)
|
|
{
|
|
propsObj.remove(QLatin1String("suppressVisibility"));
|
|
m_visibleCharges.insert(m_vecData.at(idx.row()).id());
|
|
}
|
|
else
|
|
{
|
|
propsObj.insert(QLatin1String("suppressVisibility"), true);
|
|
m_visibleCharges.remove(m_vecData.at(idx.row()).id());
|
|
}
|
|
|
|
// Put back JSON Properties
|
|
ct.properties(QJsonDocument(propsObj).toJson(QJsonDocument::Compact).toStdString());
|
|
setRowData(idx.row(), ct);
|
|
|
|
if (m_dtc->isVisible(ct.id()) != bVal)
|
|
m_differences.insert(ct.id());
|
|
else
|
|
m_differences.remove(ct.id());
|
|
|
|
|
|
emit chargeVisibilityChanged(!m_differences.isEmpty());
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
const int tasCode = m_vecData.at(idx.row()).id();
|
|
if (tasCode < 1000)
|
|
{
|
|
if (bVal)
|
|
m_visibleCharges.insert(tasCode);
|
|
else
|
|
m_visibleCharges.remove(tasCode);
|
|
|
|
// Grandparents 47 - 76 have Children that are implicitly checked:
|
|
if (tasCode >= 47 && tasCode <= 76)
|
|
{
|
|
if (bVal)
|
|
{
|
|
for (const auto &type : ALL_TAS)
|
|
m_visibleCharges.insert(type + tasCode);
|
|
}
|
|
else
|
|
{
|
|
for (const auto &type : ALL_TAS)
|
|
m_visibleCharges.remove(type + tasCode);
|
|
}
|
|
}
|
|
}
|
|
else if (tasCode > 2000)
|
|
{
|
|
if (bVal)
|
|
{
|
|
// Check all Types
|
|
if (idx.column() == IsVisible)
|
|
{
|
|
for (const auto &type : ALL_ULEIS)
|
|
m_visibleCharges.insert(tasCode + type);
|
|
}
|
|
// For each type check both uleis codes:
|
|
if (idx.column() == DirectImpact)
|
|
{
|
|
m_visibleCharges.insert(tasCode + DirectImpactGrandparent);
|
|
m_visibleCharges.insert(tasCode + DirectImpactChild);
|
|
}
|
|
if (idx.column() == TopAttack)
|
|
{
|
|
m_visibleCharges.insert(tasCode + TopAttackGrandparent);
|
|
m_visibleCharges.insert(tasCode + TopAttackChild);
|
|
}
|
|
if (idx.column() == BurstOfFire)
|
|
{
|
|
m_visibleCharges.insert(tasCode + BurstOfFireParent);
|
|
m_visibleCharges.insert(tasCode + BurstOfFireChild);
|
|
}
|
|
if (idx.column() == AirBurst)
|
|
{
|
|
m_visibleCharges.insert(tasCode + AirBurstParent);
|
|
m_visibleCharges.insert(tasCode + AirBurstChild);
|
|
}
|
|
if (idx.column() == Unarmed)
|
|
{
|
|
m_visibleCharges.insert(tasCode + UnarmedParent);
|
|
m_visibleCharges.insert(tasCode + UnarmedChild);
|
|
}
|
|
if (idx.column() == FireAndForget)
|
|
{
|
|
m_visibleCharges.insert(tasCode + FireAndForgetParent);
|
|
m_visibleCharges.insert(tasCode + FireAndForgetChild);
|
|
}
|
|
if (idx.column() == ShortTimeScanning)
|
|
{
|
|
m_visibleCharges.insert(tasCode + ShortTimeScanningParent);
|
|
m_visibleCharges.insert(tasCode + ShortTimeScanningChild);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Uncheck all types
|
|
if (idx.column() == IsVisible)
|
|
{
|
|
for (const auto &type : ALL_ULEIS)
|
|
m_visibleCharges.remove(tasCode + type);
|
|
}
|
|
// For each type uncheck both uleis codes:
|
|
if (idx.column() == DirectImpact)
|
|
{
|
|
m_visibleCharges.remove(tasCode + DirectImpactGrandparent);
|
|
m_visibleCharges.remove(tasCode + DirectImpactChild);
|
|
}
|
|
if (idx.column() == TopAttack)
|
|
{
|
|
m_visibleCharges.remove(tasCode + TopAttackGrandparent);
|
|
m_visibleCharges.remove(tasCode + TopAttackChild);
|
|
}
|
|
if (idx.column() == BurstOfFire)
|
|
{
|
|
m_visibleCharges.remove(tasCode + BurstOfFireParent);
|
|
m_visibleCharges.remove(tasCode + BurstOfFireChild);
|
|
}
|
|
if (idx.column() == AirBurst)
|
|
{
|
|
m_visibleCharges.remove(tasCode + AirBurstParent);
|
|
m_visibleCharges.remove(tasCode + AirBurstChild);
|
|
}
|
|
if (idx.column() == Unarmed)
|
|
{
|
|
m_visibleCharges.remove(tasCode + UnarmedParent);
|
|
m_visibleCharges.remove(tasCode + UnarmedChild);
|
|
}
|
|
if (idx.column() == FireAndForget)
|
|
{
|
|
m_visibleCharges.remove(tasCode + FireAndForgetParent);
|
|
m_visibleCharges.remove(tasCode + FireAndForgetChild);
|
|
}
|
|
if (idx.column() == ShortTimeScanning)
|
|
{
|
|
m_visibleCharges.remove(tasCode + ShortTimeScanningParent);
|
|
m_visibleCharges.remove(tasCode + ShortTimeScanningChild);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Tas Code == 1000 - 2000: Do nothing, they are invalid...
|
|
}
|
|
emit dataChanged(index(idx.row(), 0), index(idx.row(), columnCount() - 1));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QVector<ChargeType> ChargeTableDialogModel::getChargeTypesWithChangedVisibility() const
|
|
{
|
|
QVector<ChargeType> cts;
|
|
for (const auto &ct : m_vecData)
|
|
if (m_differences.contains(ct.id()))
|
|
cts << ct;
|
|
return cts;
|
|
}
|
|
|
|
bool ChargeTableDialogModel::isFiltered(int chargeTypeId) const
|
|
{
|
|
// Filter anything?
|
|
if (m_isOrganiser)
|
|
return false;
|
|
|
|
if (!m_gearClasses.contains(m_dtc->gearClassFromChargeTypeId(baseCharge(chargeTypeId))))
|
|
return true;
|
|
|
|
return !isBaseCharge(chargeTypeId);
|
|
}
|
|
|
|
bool ChargeTableDialogModel::isFiltered(const ProjectDataManagement::ChargeType &data, DataModification modType) const
|
|
{
|
|
Q_UNUSED(modType);
|
|
|
|
return isFiltered(data.id());
|
|
}
|
|
|
|
QSet<int> ChargeTableDialogModel::selectedCharges() const
|
|
{
|
|
return m_visibleCharges;
|
|
}
|
|
|
|
int ChargeTableDialogModel::baseCharge(int chargeTypeId)
|
|
{
|
|
if (isBaseCharge(chargeTypeId))
|
|
return chargeTypeId;
|
|
|
|
if (chargeTypeId < 2000)
|
|
return (chargeTypeId % 100);
|
|
|
|
return ((chargeTypeId % 1000) + 2000);
|
|
}
|
|
|
|
|
|
} // namespace ProjectDataManagement
|