/** * @RDE_HEADER@ * HMI Plugin for ExerciseManangement - Exercise Overview Dialog Model * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2016-02-29 */ #include "exm_dialog_model.h" #include #include #include namespace ExerciseManagement { //--------------------------------- // ExerciseManagementDialogModel //--------------------------------- ExerciseManagementDialogModel::ExerciseManagementDialogModel(QObject *parent) : LtsWidgets::LtsAbstractTableModel({tr("Id"), tr("Name"), tr("Training Area"), tr("Begin"), tr("End"), tr("Started"), tr("Stopped"), tr("Status"), tr("Radio Group"), tr("Active Phase"), tr("Created"), tr("Time Zone"), tr("Forces"), tr("Description"), tr("Linked Exercise"), tr("Transferred"), tr("HLA"), tr("Image")}, parent) , m_exmDtc(nullptr) , m_asmDtc(nullptr) , m_pdmDtc(nullptr) , m_logger(getLogger("ExerciseManagementDialogModel")) {} bool ExerciseManagementDialogModel::initModel(const std::shared_ptr &dtc, const std::shared_ptr &ftc, const std::shared_ptr &asmDtc, const std::shared_ptr &pdmDtc, bool addAdminExercise, bool preloadExerciseImages) { m_exmDtc = dtc; m_exmFtc = ftc; m_asmDtc = asmDtc; m_pdmDtc = pdmDtc; connect(m_exmDtc.get(), &ExerciseManagement::Interface::Dtc::exerciseChanged, this, [this, preloadExerciseImages](const ExerciseManagement::Exercise &ex, DataModification mod) { onDataChanged(ex, mod); if (mod != DataModification::eAdded) return; if (preloadExerciseImages) addImagePreload(ex.id()); }); if (addAdminExercise) { // insert admin session manually ExerciseManagement::Exercise adminExercise; adminExercise.name(tr("Superordinate Config / Administration").toStdString()); adminExercise.id(0); insertRow(adminExercise); } // insert Model m_exmDtc->exercises([this, preloadExerciseImages](const ExerciseManagement::Exercise &ex) { insertRow(ex); if (preloadExerciseImages) addImagePreload(ex.id()); }); INFO_LOG(m_logger) << "initModel - #exercises: " << m_vecData.size(); return true; } int ExerciseManagementDialogModel::getId(const ExerciseManagement::Exercise &data) const { return data.id(); } void ExerciseManagementDialogModel::addImagePreload(int32_t exId) // one image at a time - only fetch next image if last one already received { if (m_exerciseImages.contains(exId)) // don't preload mages that are already loaded return; m_preloadImages += exId; if (m_imagePreloadPending) // only start preloading if not currently preloading one currently return; m_imagePreloadPending = true; preloadNextImage(); } void ExerciseManagementDialogModel::preloadNextImage() { if (m_preloadImages.isEmpty()) return; m_exmFtc->enableGetExerciseImage(); m_exmFtc->getExerciseImageRequest(GetExerciseImageRequest(m_preloadImages.takeFirst(), m_imageSize.height(), m_imageSize.width(), false), createGetExerciseImageRequester()); } GetExerciseImageRequester *ExerciseManagementDialogModel::createGetExerciseImageRequester() { auto r = GetExerciseImageRequester::createGetExerciseImageRequester(); connect(r, &GetExerciseImageRequester::signalDone, this, [this, r]() { m_imagePreloadPending = false; const GetExerciseImageReply &reply(r->reply()); if (reply.errorString().empty()) { m_exerciseImages.insert(reply.id(), LtsUtils::toQByteArray(reply.imageData())); // tell the view that it should reload the image QModelIndex idx(findIndexForId(reply.id(), 0)); // XXX: Florian's Workaround - dataChanged works with column 0, but not with Columns::Image! Works for now! Better than resetting the model. emit dataChanged(idx, idx, { Qt::DisplayRole }); } else { QString msg(QString::fromStdString(reply.errorString())); for (const std::string &arg : qAsConst(reply.errorParams())) msg = msg.arg(QString::fromStdString(arg)); ERROR_LOG(m_logger) << "image preload failed: " << msg; } QTimer::singleShot(1, this, &ExerciseManagementDialogModel::preloadNextImage); // schedule requester deletion before asking for the next image (not really necessary but 100 times cleaner) }); return r; } void ExerciseManagementDialogModel::setImageSizeConstraints(const QSize &size) { m_imageSize = size; } QVariant ExerciseManagementDialogModel::data(const QModelIndex &index, int role) const { if ((role != Qt::DisplayRole && role != Qt::UserRole && role != Qt::TextColorRole) || !indexIsValid(index)) return QVariant(); const ExerciseManagement::Exercise &ex = m_vecData.at(index.row()); if (role == Qt::DisplayRole) { switch (index.column()) { case ExerciseManagementDialogModel::Columns::Name: return QString::fromStdString(ex.name()); case ExerciseManagementDialogModel::Columns::TrainingArea: { const AssetManagement::TrainingArea ta = m_asmDtc->trainingArea(ex.trainingAreaId()); return QString::fromStdString(ta.name()); } case ExerciseManagementDialogModel::Columns::Begin: return QDateTime::fromMSecsSinceEpoch(ex.beginTime()); case ExerciseManagementDialogModel::Columns::End: return QDateTime::fromMSecsSinceEpoch(ex.endTime()); case ExerciseManagementDialogModel::Columns::Started: return QDateTime::fromMSecsSinceEpoch(ex.startTime()); case ExerciseManagementDialogModel::Columns::Stopped: return QDateTime::fromMSecsSinceEpoch(ex.stopTime()); case ExerciseManagementDialogModel::Columns::Status: return ExerciseManagement::toString(ex.state()); case ExerciseManagementDialogModel::Columns::RadioGroup: if (ex.radioGroupId().is_set()) return m_pdmDtc->trRadioGroupName(ex.radioGroupId().get()); return QStringLiteral(" - "); case ExerciseManagementDialogModel::Columns::ActivePhase: return QString::fromStdString(m_exmDtc->exercisePhase(ex.activePhaseId()).name()); case ExerciseManagementDialogModel::Columns::Created: return QDateTime::fromMSecsSinceEpoch(ex.created()); case ExerciseManagementDialogModel::Columns::TimeZone: return (ex.defaultTimeZone() == 0) ? QStringLiteral("-") : QString(QLatin1Char(ex.defaultTimeZone())); case ExerciseManagementDialogModel::Columns::Forces: return QString::fromStdString(ex.forces()); case ExerciseManagementDialogModel::Columns::Description: return QString::fromStdString(ex.description()); case ExerciseManagementDialogModel::Columns::Image: return m_exerciseImages.value(ex.id()); case ExerciseManagementDialogModel::Columns::Id: return ex.id(); case ExerciseManagementDialogModel::Columns::LinkedId: { if (ex.linkedExerciseId() == 0) return QVariant(); const int row = findRowForId(ex.linkedExerciseId()); if (row < 0) return QStringLiteral("????? - %1").arg(ex.linkedExerciseId()); return QString(QString::fromStdString(m_vecData.at(row).name()) + QStringLiteral(" (%1)").arg(ex.linkedExerciseId())); } case ExerciseManagementDialogModel::Columns::Transferred: return ex.transferred() ? tr("Yes") : tr("No"); case ExerciseManagementDialogModel::Columns::HasHlaInterface: return ex.hasHlaInterface() ? tr("Yes") : tr("No"); } } else if (role == Qt::UserRole) // sorting order { if (ex.id() == 0) return 0; switch (ex.state().underlying()) { case ExerciseState::Unknown: return 6; case ExerciseState::Created: return 3; case ExerciseState::Started: return 1; case ExerciseState::Paused: return 2; case ExerciseState::Stopped: return 4; case ExerciseState::Terminated: return 5; } return 99; } else if (role == Qt::TextColorRole) { if (index.column() == ExerciseManagementDialogModel::Columns::Status) { switch (ex.state().underlying()) { case ExerciseState::Unknown: return QColor(Qt::black); case ExerciseState::Created: return QColor(Qt::cyan); case ExerciseState::Started: return QColor(Qt::darkGreen); case ExerciseState::Paused: return QColor(Qt::darkYellow); case ExerciseState::Stopped: return QColor(Qt::magenta); case ExerciseState::Terminated: return QColor(Qt::red); } } } return QVariant(); } // // ExerciseManagementProxyModel // void ExerciseManagementProxyModel::setAdminExerciseVisible(bool bAdminVisible) { if (m_bAdminVisible == bAdminVisible) return; m_bAdminVisible = bAdminVisible; invalidateFilter(); } void ExerciseManagementProxyModel::setVisibleExerciseIds(const QVector &exIds) { if (m_exIds == exIds) return; m_exIds = exIds; invalidateFilter(); } void ExerciseManagementProxyModel::setVisibleExerciseStates(const QVector &visibleStates) { if (m_visibleStates == visibleStates) return; m_visibleStates = visibleStates; invalidateFilter(); } void ExerciseManagementProxyModel::setSourceModel(QAbstractItemModel *sourceModel) { m_sourceModel = qobject_cast(sourceModel); LtsWidgets::LtsColumnFilterProxyModel::setSourceModel(sourceModel); } bool ExerciseManagementProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { if (!m_sourceModel || source_parent.isValid() || source_row < 0 || source_row >= m_sourceModel->m_vecData.size()) return LtsWidgets::LtsColumnFilterProxyModel::filterAcceptsRow(source_row, source_parent); const auto &ex = m_sourceModel->m_vecData.at(source_row); if (ex.id() == 0) { if (!m_bAdminVisible) return false; return LtsWidgets::LtsColumnFilterProxyModel::filterAcceptsRow(source_row, source_parent); } if (!m_exIds.contains(ex.id()) && !m_exIds.contains(-1)) return false; if (!m_visibleStates.contains(ex.state()) && !m_visibleStates.isEmpty()) return false; return LtsWidgets::LtsColumnFilterProxyModel::filterAcceptsRow(source_row, source_parent); } } // namespace ExerciseManagement