/** * @RDE_HEADER@ * SaaDialogModel * $Id$ * $HeadURL$ * $Author$ * * Created by Steve Kemayou, ESZS, 2025-10-15 */ #include #include #include #include #include #include "saa_dialog_model.h" namespace SAAInterfaceAdapterAdler { using namespace SAAUtils; SaaDialogModel::SaaDialogModel(QObject *parent) : LtsWidgets::LtsAbstractTableModel({tr("Id"), tr("Name"), tr("scenario is running"), tr("Used by Party")}, parent) , m_ppmDtc(nullptr) , m_logger(getLogger("SaaDialogModel")) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } SaaDialogModel::~SaaDialogModel() { stopPing(); TRACE_LOG(m_logger) << LOGFUNCTION << " START"; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } bool SaaDialogModel::initModel(LtsSession::LtsSession *session) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; m_session = session; if (!m_session->getDtc(m_ppmDtc)) { ERROR_LOG(m_logger) << " ppmDtc not set!!! " << m_logger.getLoggerName(); return false; } if (!m_session->getDtc(m_asmDtc)) { ERROR_LOG(m_logger) << " asmDtc not set!!! " << m_logger.getLoggerName(); return false; } connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::partyChanged, this, &SaaDialogModel::onPartyDataChanged); connect(m_asmDtc.get(), &AssetManagement::Interface::Dtc::assetChanged, this, &SaaDialogModel::slotAssetChanged); m_asmDtc->assets( [this](const AssetManagement::Asset &asset) { if (asset.id() <= 1 || asset.assetTypeId() != AssetManagement::AssetType_def::AdlerSAA) return; AsmAssetProps asmProps(QString::fromStdString(asset.properties())); if (asmProps.hasExerciseId() && asmProps.exId != m_session->exerciseId()) return; // set init Saa ping item list PingItem pi; pi.assetId = asset.id(); pi.process = new QProcess(this); pi.host = asmProps.host; // asset column name is ip addr pi.port = asmProps.port; // test m_saaPingItems.insert(asset.id(), pi); //-- onDataChanged(asset, DataModification::eAdded); }); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; return true; } void SaaDialogModel::pingAllSaa() { DEBUG_LOG(m_logger) << "====> pingAllSaa: saaList count: " << m_saaPingItems.count(); if (m_saaPingItems.isEmpty()) return; // iterate over saa list and start ping for each one. for (auto &pi : m_saaPingItems) { // clean up previous process if exists if (pi.process) { pi.process->kill(); pi.process->deleteLater(); pi.process = nullptr; } // create new process pi.process = new QProcess(this); // on finished check exit code connect(pi.process, QOverload::of(&QProcess::finished), this, [this, &pi](int exitCode, QProcess::ExitStatus) { ParticipantManagement::Party party; getPartyWithAssetId(pi.assetId, party); DEBUG_LOG(m_logger) << " ping assetId: " << pi.assetId << " reacheable ? " << (exitCode == 0) << " Szenar ? " << (party.id() > 0) << " Ip: " << pi.host << " PortNumb: " << pi.port; pi.reachable = (exitCode == 0); pi.process->kill(); pi.process->deleteLater(); pi.process = nullptr; }); QStringList args = {QStringLiteral("-z"), QStringLiteral("-w"), QStringLiteral("1"), pi.host, QString::number(pi.port)}; pi.process->start(QStringLiteral("nc"), args); } updateView(); } void SaaDialogModel::saaConnected(int assetId, bool state) { PingItem &saaItem = m_saaPingItems[assetId]; saaItem.connected = state; } void SaaDialogModel::stopPing() { WARNING_LOG(m_logger) << ">> stop ping saa..."; for (auto &pi : m_saaPingItems) { // clean up previous process if exists if (pi.process) { WARNING_LOG(m_logger) << ">> kill process saaId: " << pi.assetId; pi.process->kill(); pi.process->deleteLater(); pi.process = nullptr; } } m_saaPingItems.clear(); } void SaaDialogModel::updateView() { beginResetModel(); endResetModel(); } void SaaDialogModel::onPartyDataChanged(const ParticipantManagement::Party &data, DataModification modType) { Q_UNUSED(modType) DEBUG_LOG(m_logger) << ">>> SAA Dialog Party Data Changed: " << data.id() << " properties: " << data.properties(); update(); } bool SaaDialogModel::isFiltered(const AssetManagement::Asset &data, DataModification modType) const { // no pool and support if (data.id() <= 1 || data.assetTypeId() != AssetManagement::AssetType_def::AdlerSAA) return true; // only the current saa for current ex is viewed AsmAssetProps asmProps(QString::fromStdString(data.properties())); if (asmProps.hasExerciseId() && asmProps.exId != m_session->exerciseId()) return true; return LtsWidgets::LtsAbstractTableModel::isFiltered(data, modType); } void SaaDialogModel::slotAssetChanged(const AssetManagement::Asset &data, DataModification modType) { // no pool and support if (data.id() <= 1 || data.assetTypeId() != AssetManagement::AssetType_def::AdlerSAA) return; AsmAssetProps asmProps(QString::fromStdString(data.properties())); if (asmProps.hasExerciseId() && asmProps.exId != m_session->exerciseId()) return; switch (modType) { case DataModification::eAdded: { onDataChanged(data, DataModification::eAdded); PingItem pi; pi.assetId = data.id(); pi.process = new QProcess(this); pi.host = asmProps.host; pi.port = asmProps.port; m_saaPingItems.insert(data.id(), pi); } break; case DataModification::eModified: { onDataChanged(data, DataModification::eModified); PingItem pi = m_saaPingItems.take(data.id()); if (pi.process != nullptr && pi.process->state() != QProcess::NotRunning) { pi.process->kill(); pi.process->deleteLater(); } pi.process = nullptr; pi.assetId = data.id(); pi.host = asmProps.host; pi.port = asmProps.port; pi.connected = false; pi.reachable = false; pi.process = new QProcess(this); m_saaPingItems.insert(data.id(), pi); } break; case DataModification::eRemoved: onDataChanged(data, DataModification::eRemoved); auto pi = m_saaPingItems.take(data.id()); // take will remove item from list if (pi.process != nullptr && pi.process->state() != QProcess::NotRunning) { pi.process->kill(); pi.process->deleteLater(); } pi.process = nullptr; break; } } void SaaDialogModel::getPartyWithAssetId(int assetId, ParticipantManagement::Party &party) const { const auto &partys = m_ppmDtc->partys(); for (const auto &p : partys) { SaaProps saaprops(QString::fromStdString(p.properties())); if (!saaprops.hasAsset()) continue; if (saaprops.assetId == assetId) { party = p; return; } } } QVariant SaaDialogModel::data(const QModelIndex &index, int role) const { if (!indexIsValid(index)) return {}; const AssetManagement::Asset &asset = m_vecData.at(index.row()); const AsmAssetProps assetProps(QString::fromStdString(asset.properties())); // check first that asset is saa and is connected to current exercise ParticipantManagement::Party party; if (asset.assetTypeId() == AssetManagement::AssetType_def::AdlerSAA && assetProps.hasExerciseId()) getPartyWithAssetId(asset.id(), party); if (role == Qt::DisplayRole) { switch (index.column()) { case Id: return asset.id(); case Name: return QString::fromStdString(asset.name()); case IsUseByParty: return party.id() > 0 ? ParticipantManagement::trPartyName(party.name()) : QStringLiteral("--"); default: return {}; } } else if (role == Qt::DecorationRole) { if (index.column() != Connected) return {}; /// green: ping = 1 | szenar = 1 /// gray: ping = 0 | szenar = 0 /// red: ping = 0 | szenar = 1 /// yellow: ping = 1 | szenar = 0 static const QIcon green(QLatin1String("icon:green_light.svg")); static const QIcon red(QLatin1String("icon:red_light.svg")); static const QIcon yellow(QLatin1String("icon:yellow_light.svg")); static const QIcon gray(QLatin1String("icon:gray_light.svg")); const bool reacheable = m_saaPingItems.value(asset.id()).reachable; switch (index.column()) { case Connected: { const bool szenar = (party.id() > 0); // entry is assetId available in party.properties if (szenar && reacheable) return green; if (szenar && !reacheable) return red; if (!szenar && reacheable) return yellow; return gray; } default: return {}; } } return {}; } } // namespace SAAInterfaceAdapterAdler