/** * @RDE_HEADER@ * Model to handle datail data for the different event types * $Id$ * $HeadURL$ * $Author$ * * Created by Mike Wille, SLSE, 2017-09-04 */ #include "detail_data.h" #include "logger.h" #include "tln_legend.h" #include "attribute_value_lookup.h" #include #include #include #include // Dtc lookups: (data ifc libs) #include #include #include #include #include #include // Enums only: (svc libs only) #include #include #include #include #include #include #include #include #include namespace Timeline { static inline QString removeSpaces(const QString &str) { // no QString::erase(it) available... QString ret; ret.reserve(str.size()); for (const QChar c : str) { if (!c.isSpace()) ret += c; } return ret; } DetailData::DetailData(LtsSession::LtsSession *session, QObject *parent) : QObject(parent) , m_session(session) , __already_populated__(false) , m_logger(getLogger("DetailData")) { populate(); } void DetailData::addRedirectedAttributeType(const QString &newAttributeTypeId, const QString &attributeText, const QString &redirectToAttributeTypeId) { attributeTypeLookup.addAttributeText(newAttributeTypeId, attributeText); attributeRedirectionLookup.addRedirection(newAttributeTypeId, redirectToAttributeTypeId); } void DetailData::addAttributeType(const QString &attributeTypeId, const QString &attributeText, const int uiTypeId, const int interpreterTypeId) { attributeTypeLookup.addAttributeText(attributeTypeId, attributeText); attributeUITypeLookup.addUITypeToAttribute(attributeTypeId, uiTypeId); attributeInterpreterLookup.addInterpreterTypeToAttribute(attributeTypeId, interpreterTypeId); } void DetailData::addEventType(int eventTypeId, const QString &eventTypeString) // with default attribute types [time, etc.] { eventTypeLookup.addEventType(eventTypeId, eventTypeString); attributeEventLookup.addAttributesToEvent(eventTypeId, {QStringLiteral("TimeRange")}); } void DetailData::addEventType(const ProjectDataManagement::EventType &eventType) // with default attribute types [time, etc.] { addEventType(eventType.underlying(), ProjectDataManagement::toString(eventType)); } void DetailData::populate() // call on any retranslate { if (__already_populated__) // TODO: repopulate!! return; __already_populated__ = true; // TODO: clear all lookups ! // populate Event Types - see build/Lts/Services/ExerciseEventManagement/eem_enums.hpp // * retrieved as of 2017-09-01 addEventType(0, tr("General")); // would be type 'unknown' in EventType_def DE: "Allgemein" addEventType(markerTypeId, tr("Marker")); attributeEventLookup.addAttributesToEvent(markerTypeId, {QStringLiteral("MarkerName"), QStringLiteral("MarkerNote"), QStringLiteral("Operator"), QStringLiteral("MarkerOffset"), QStringLiteral("IsSituationType"), QStringLiteral("IsVideoType"), QStringLiteral("IsAudioType")}); using namespace ProjectDataManagement; const auto possibleEventTypes = TimelineLegendDialog::possibleEvents(); for (const auto eventType : possibleEventTypes) { switch (eventType.underlying()) { case EventType::Hit: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("VulnerabilityState"), QStringLiteral("OriginatorChargeTypeId"), QStringLiteral("FriendlyFire"), //QStringLiteral("OriginatorId"), // TODO: kann ich nix mit anfangen.. //QStringLiteral("OriginatorType"), // not really useful - see EEM HandlerDynamicParticipantData::tryCreateHitEvent() QStringLiteral("OriginatorEquipmentNumber")}); break; case EventType::BiteMessage: break; case EventType::WeaponAssignment: case EventType::FireEvent: attributeEventLookup.addAttributesToEvent(eventType, {//<< QStringLiteral("GearId"), // is a unique serial number not known to excon operator QStringLiteral("GearTypeId"), QStringLiteral("ChargeTypeId")}); break; case EventType::HitBuilding: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesType"), QStringLiteral("ChargeTypeId"), QStringLiteral("OriginatorEquipmentNumber"), QStringLiteral("MainStructureElementId"), QStringLiteral("VulnerabilityState"), QStringLiteral("damagePercent"), // range //QStringLiteral("damagePercentOld"), }); // range break; case EventType::Manipulation: break; case EventType::Sanitation: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("Vitality"), QStringLiteral("SanitationProceduresNeeded"), QStringLiteral("SanitationProceduresTaken")}); break; case EventType::CameraVideo: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("PartyId"), QStringLiteral("MainStructureElementId"), QStringLiteral("duration"), QStringLiteral("streamName")}); break; case EventType::RadioCnr: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("PartyId"), QStringLiteral("duration"), QStringLiteral("streamName")}); break; case EventType::RadioTvc: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("duration"), QStringLiteral("streamName")}); break; case EventType::HitEffectSimulation: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesType"), QStringLiteral("AesName"), QStringLiteral("OriginatorChargeTypeId")}); break; case EventType::HitC: case EventType::HitB: case EventType::HitMine: case EventType::EnterMineArea: case EventType::LeaveMineArea: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName"), QStringLiteral("OriginatorChargeTypeId")}); break; case EventType::HitN: case EventType::HitGasPipe: case EventType::EnterDangerArea: case EventType::LeaveDangerArea: case EventType::CrossLocalBorderline: case EventType::CrossGlobalBorderline: case EventType::EnterFunctionalArea: case EventType::LeaveFunctionalArea: case EventType::EnterNuclear: case EventType::LeaveNuclear: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName")}); break; case EventType::Borderline: case EventType::NContamination: case EventType::DangerArea: case EventType::FunctionalArea: case EventType::MineCorridor: case ProjectDataManagement::EventType::GasPipe: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName"), QStringLiteral("duration")}); break; case EventType::MineArea: case EventType::BCContamination: attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName"), QStringLiteral("duration"), QStringLiteral("ChargeTypeId")}); break; case EventType::Unknown: case EventType::FriendlyFire: case EventType::TechnicalArea: case EventType::EquipmentErrorReport: case EventType::EmergencyCall: Q_ASSERT(false); continue; } addEventType(eventType); } // populate Attribute Types - see /home/ref/TDS/src/Lts/Services/ExerciseEventManagement/eem_service.xml:52 /* * retrieved as of 2017-09-04 * * * FireEvent: * GearId * GearTypeId * ChargeTypeId * Remain * * WeaponAssignment: * GearId * GearTypeId * DryFire * * Manipulation: => show bite window * DeviceType * BiteMessage * BatteryState * BiteState * ConfigState * JsonArray BiteErrors: * ErrorNo * CanDeviceNumber * SubDeviceNumber * UniqueId * * HitBuilding: * ChargetTypeId * damagePercent * damagePercentOld * AesId * VunerabilityState * OriginatorParticipantId * MainStructureElementId * * * >>> Ab hier bin ich mir nicht mehr Sicher, was genau im Comment gemeint ist... * HitIndrect: * HitMine: * HitN: * HitC: * EnterDangerArea: * LeaveDangerArea: * CES: * AesId * FriendlyFire */ /* Jedes Attribute benoetigt einen Interpreter Typen. Ein Interpreter Typ sagt dem Interpreter, wie er den Wert eines Attributs auf den Filter anwenden kann. Hier als Beispiel: * "OriginatorChargeTypeId" ist ein Attribut, welches bloß eine Value ID zurueckgibt. D.h. id:9000 (wird dann später einem lesbaren Wert zugeordnet: z.B: "30mm Irgendwas") * SOll der Wert im Filter also verglichen werden, muessen hier die IDs verglichen werden. Id 9000 => Id 9000. * Hier ist also folgender Interpreter korrekt: INTERPRETER_TYPE_ID_COMPARE * * Anderes Beispiel: * Zeit. Wird als Filter eine Zeit zwischen X und Y angegeben, muss geschaut werden, ob die Zeit Z sich zwischen X und Y befindet. Mit "INTERPRETER_TYPE_ID_COMPARE" wuerde das * nicht funktionieren, da sonst nur EINE Zeit (naemlich genau Zeitpunkt Z) beim Interpreter korrekt ist. Fuer diesen Fall gibt es "INTERPRETER_TYPE_RANGE". * Dieser Interpreter prueft, ob etwas in der Range zwischen X und Y ist. */ // AttributeUiTypeLookup: Wie wird das Attribut angezeigt? Bei einer Liste aus Einträgen: COmboBox, oder wenn z.B. es nur 2 Zustände gib: FriendlyFire => Yes / No => CheckBox addAttributeType(QStringLiteral("TimeRange"), tr("Time range:"), ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET /* TODO: none! */, INTERPRETER_TYPE_TIME); // is added in getDetailData as dummy so that the filter has a value to filter with TimeRange // Vulnerability State: addAttributeType(QStringLiteral("VulnerabilityState"), tr("Vulnerability State:")); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::CombatReady); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::LightDamage); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::MediumDamage); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::HeavyDamage); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::MobilityKill); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::VisibleMobilityKill); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::WeaponSystemDamage); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::VisibleWeaponSystemDamage); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::CatastrophicKill); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::TemporarySeverance); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::NearMiss); addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::HitWithNoEffect); //addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::NotReady); // Marker Types: addAttributeTypeWithYesAndNo(QStringLiteral("IsSituationType"), tr("Is situation type:")); addAttributeTypeWithYesAndNo(QStringLiteral("IsVideoType"), tr("Is video type:")); addAttributeTypeWithYesAndNo(QStringLiteral("IsAudioType"), tr("Is audio type:")); // AES Types: // addRedirectedAttributeType(QStringLiteral("AesId"), tr("Aes Type:"), QStringLiteral("AesType")); // because the result type is Aes Type (but has to be resolved by looking at the AES behind the AesId addAttributeType(QStringLiteral("AesType"), tr("Aes Type:")); //addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtUnknown); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtNContamination); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtBCContamination); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtExplosionArea); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtExplosionSingle); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineArea); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtDangerArea); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtFunctionalArea); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineCorridor); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtBorderline); //addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtTechnicalArea); //addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtExplosionAreaSingleExplosions); addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineAreaSingleMines); // Friendly Fire addAttributeTypeWithYesAndNo(QStringLiteral("FriendlyFire"), tr("Friendly Fire:")); // Attribute: Dry Fire addAttributeTypeWithYesAndNo(QStringLiteral("DryFire"), tr("Dry Fire:")); // non-filterables: addAttributeType(QStringLiteral("MarkerName"), tr("Name:"), ATTRIBUTE_UI_TYPE_CHECKBOX /* TODO: FIXME: none! */, INTERPRETER_TYPE_NONE); addAttributeType(QStringLiteral("MarkerNote"), tr("Note:"), ATTRIBUTE_UI_TYPE_CHECKBOX /* TODO: FIXME: none! */, INTERPRETER_TYPE_NONE); // TODO: //(QStringLiteral("Remain"), tr("Remain:")); was ist "remain" ? // Marker offset: addAttributeType(QStringLiteral("MarkerOffset"), tr("Offset [msecs]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET /* 0 - x */, INTERPRETER_TYPE_RANGE); { DetailData::AttributeParameterLookup::ParameterMap pm; pm.insert(DetailData::UI_PARAM_TYPE_MIN, QVariant::fromValue(0)); pm.insert(DetailData::UI_PARAM_TYPE_MAX, QVariant::fromValue(9999999)); pm.insert(DetailData::UI_PARAM_TYPE_SUFFIX, QVariant::fromValue(QString())); pm.insert(DetailData::UI_PARAM_TYPE_PREFIX, QVariant::fromValue(QString())); attributeParameterLookup.addParameter(QStringLiteral("MarkerOffset"), pm); } // Duration: addAttributeType(QStringLiteral("duration"), tr("Duration [msecs]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET /* 0 - x */, INTERPRETER_TYPE_RANGE); { DetailData::AttributeParameterLookup::ParameterMap pm; pm.insert(DetailData::UI_PARAM_TYPE_MIN, QVariant::fromValue(0)); pm.insert(DetailData::UI_PARAM_TYPE_MAX, QVariant::fromValue(99999999)); pm.insert(DetailData::UI_PARAM_TYPE_SUFFIX, QVariant::fromValue(QString())); pm.insert(DetailData::UI_PARAM_TYPE_PREFIX, QVariant::fromValue(QString())); attributeParameterLookup.addParameter(QStringLiteral("duration"), pm); } // Damage: addAttributeType(QStringLiteral("damagePercent"), tr("Damage [%]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET /* 0 - 100 */, INTERPRETER_TYPE_RANGE); addRedirectedAttributeType(QStringLiteral("damagePercentOld"), tr("Damage before [%]:"), QStringLiteral("damagePercent")); { DetailData::AttributeParameterLookup::ParameterMap pm; pm.insert(DetailData::UI_PARAM_TYPE_MIN, QVariant::fromValue(0)); pm.insert(DetailData::UI_PARAM_TYPE_MAX, QVariant::fromValue(100)); pm.insert(DetailData::UI_PARAM_TYPE_SUFFIX, QVariant::fromValue(tr(" %"))); pm.insert(DetailData::UI_PARAM_TYPE_PREFIX, QVariant::fromValue(QString())); attributeParameterLookup.addParameter(QStringLiteral("damagePercent"), pm); // only for filters (event filter), so only filtereable attributes like MUNITION_LEFT_BETWEEN (not MUNITION_LEFT!) } // Equipment Numbers: (Achtung! Uebersetzt nur direkt eqid zu eqid !) std::shared_ptr dtcPpm; m_session->getDtc(dtcPpm); addAttributeType(QStringLiteral("EquipmentNumber"), tr("Equip. No.:")); m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("EquipmentNumber"), new AvmEquipmentNumber(dtcPpm)); addRedirectedAttributeType(QStringLiteral("OriginatorEquipmentNumber"), tr("Equip. No. of Originator:"), QStringLiteral("EquipmentNumber")); std::shared_ptr dtcPdm; m_session->getDtc(dtcPdm); // Charge Types: addAttributeType(QStringLiteral("ChargeTypeId"), tr("Charge Type:")); // Achtung: OriginatorChargeTypeId wird auf den Generellen Typ "ChargeTypeId" weitergeleitet, daher muss nur der Interpreter Type des Haupt-Typen gesetzt werden! addRedirectedAttributeType(QStringLiteral("OriginatorChargeTypeId"), tr("Originator Charge Type:"), QStringLiteral("ChargeTypeId")); m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("ChargeTypeId"), new AvmChargeType(dtcPdm)); // Gear Types: addAttributeType(QStringLiteral("GearTypeId"), tr("Gear Type:")); m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("GearTypeId"), new AvmGearType(dtcPdm)); // Originator Types: addAttributeType(QStringLiteral("OriginatorType"), tr("Originator Type:")); addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Unknown); addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Participant); addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation); addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::ObserverController); addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::ExerciseControl); //addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::WoundTreatmentDevice); //addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::MaintainanceDevice); addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::FunctionalArea); addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Initialization); addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::ImprovisedExplosiveDevice); addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::DusMine); const bool showPvSan = LtsUtils::ProjectSettings::isFunctionEnabled(QStringLiteral("ParticipantInformation"), QStringLiteral("HasPvSan")); if (showPvSan) addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Sanitation); // (ISM) Structure Elements: std::shared_ptr dtcIsm; m_session->getDtc(dtcIsm); addAttributeType(QStringLiteral("MainStructureElementId"), tr("Building:")); m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("MainStructureElementId"), new AvmBuilding(dtcIsm)); // (PPM) Parties addAttributeType(QStringLiteral("PartyId"), tr("Party:")); m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("PartyId"), new AvmParty(dtcPpm)); // (OPM) Operator Management: std::shared_ptr dtcOpm; m_session->getDtc(dtcOpm); addAttributeType(QStringLiteral("Operator"), tr("Operator:")); m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("Operator"), new AvmOperator(dtcOpm)); // (AVM) Streams std::shared_ptr dtcAvm; m_session->getDtc(dtcAvm); addAttributeType(QStringLiteral("streamName"), tr("Stream Name:")); m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("streamName"), new AvmStreamName(dtcAvm)); } DetailData::GetDetailDataResultList DetailData::getDetailData(const LtsTimelineClassic::Event *event) { GetDetailDataResultList result; if (event->detailData().isEmpty()) // no detail data so search in return result; const QJsonObject &root = event->detailData(); for (auto i = root.constBegin(); i != root.constEnd(); ++i) { DEBUG_LOG(m_logger) << "Adding Detail Data for: " << i.key(); result.append(getDetailDataForAttribute(i.key(), *i)); } return result; } DetailData::GetDetailDataForAttributeResult DetailData::getDetailDataForAttribute(const LtsTimelineClassic::Event *event, const QString &attributeType) { GetDetailDataForAttributeResult result; const QJsonObject &root = event->detailData(); root[QStringLiteral("TimeRange")] = event->startTime() / 1000 /* as value would be too big for int => see getDetailDataForAttribute(..) */; // event time as temporary detail data root[QStringLiteral("PartyId")] = event->partyId(); const QJsonValue attribute = root[attributeType]; if (attribute.isNull() || attribute.isUndefined()) { WARNING_LOG(m_logger) << "DetailData::getDetailDataForAttribute: no attribute type " << attributeType << " in " << QJsonDocument(root).toJson(); result.requestResult = DetailData::RequestResult::InvalidAttributeType; return result; } return getDetailDataForAttribute(attributeType, attribute); } DetailData::GetDetailDataForAttributeResult DetailData::getDetailDataForAttribute(const QString &attributeType, const QJsonValue &attributeValueJson) { GetDetailDataForAttributeResult result; result.attributeTypeId = attributeType; result.attributeValueId = -1; result.requestResult = DetailData::RequestResult::Error; QString attributeTypeTranslated = attributeTypeLookup.getAttributeText(attributeType); if (attributeTypeTranslated.isEmpty()) { result.requestResult = DetailData::RequestResult::InvalidAttributeType; //ERROR_LOG(m_logger) << "getDetailDataForAttribute: Invalid Attribute Type for " << attributeType; return result; } result.attributeType = attributeTypeTranslated; int attributeValueId = -1; /* enum Type { Null = 0x0, Bool = 0x1, Double = 0x2, String = 0x3, Array = 0x4, Object = 0x5, Undefined = 0x80 }; */ switch (attributeValueJson.type()) { // sorted by frequency of occurrence case QJsonValue::Double: { attributeValueId = attributeValueJson.toInt(-1); break; } case QJsonValue::Null: case QJsonValue::Undefined: { WARNING_LOG(m_logger) << "Timeline: DetailData::getDetailDataForAttribute: attribute value is null or undefined! " << attributeValueJson.toString(); result.requestResult = DetailData::RequestResult::InvalidAttributeTypeJson; return result; } case QJsonValue::Bool: { attributeValueId = attributeValueJson.toBool() ? 1 : 0; break; } case QJsonValue::String: { bool k = false; QString attributeValueString = attributeValueJson.toString(); if (attributeValueString.isEmpty()) { attributeValueId = -1; break; } attributeValueId = attributeValueString.toInt(&k); if (!k) // not a number but treat as text... NOTE: has no id { result.attributeValue = attributeValueString; result.requestResult = DetailData::RequestResult::Okay; return result; } break; } default: { WARNING_LOG(m_logger) << "Timeline: DetailData::getDetailDataForAttribute: attribute value cannot be handled. Type " << attributeValueJson.type() << attributeValueJson.toString(); result.requestResult = DetailData::RequestResult::InvalidAttributeType; return result; } } if (attributeValueId == -1) { result.requestResult = DetailData::RequestResult::InvalidAttributeType; return result; } result.attributeValueId = attributeValueId; // there are values that do not have to be translated: int attributeUiType = attributeUITypeLookup.getUIType(attributeType); switch (attributeUiType) { // do not translate case ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET: case ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET: case ATTRIBUTE_UI_TYPE_RAD_RANGE_WIDGET: case ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET: { result.attributeValue = QString::number(attributeValueId); // use "id" as "translated" string result.requestResult = DetailData::RequestResult::Okay; break; } // translate case ATTRIBUTE_UI_TYPE_COMBO_BOX: case ATTRIBUTE_UI_TYPE_CHECKBOX: { result.attributeValue = attributeValueLookup.getValueStringFromValueId(attributeType, attributeValueId); if (result.attributeValue.isEmpty()) result.attributeValue = m_attributeValueLookupDtc.getValueStringFromValueId(attributeType, attributeValueId); result.requestResult = DetailData::RequestResult::Okay; break; } default: // -1 { // maybe the type was redirected? QString concreteAttributeType = attributeRedirectionLookup.getRedirection(attributeType); if (concreteAttributeType == attributeType) // it was not redirected - give up! { ERROR_LOG(m_logger) << "getDetailDataForAttribute: attribute type " << attributeType << " does not have an UiType !!!"; result.requestResult = DetailData::RequestResult::NoUiTypeForAttribute; } else // there is a redirection, try this method with the redirection { //qWarning() << "trying redirection for attribute type" << attributeType; // save some results, as getDetailDataForAttribute will set ALL the results for the redirection, instead of ONLY the value.. QString attributeType = result.attributeType; QString attributeTypeId = result.attributeTypeId; result = getDetailDataForAttribute(concreteAttributeType, attributeValueJson); result.attributeType = attributeType; result.attributeTypeId = attributeTypeId; } break; } } return result; } void DetailData::createRetrieveCurrentTimeCallback(LtsWidgets::LtsDateTimeEdit *dateTimeEdit) { dateTimeEdit->setRetrieveCurrentTimeCallback([this]() { return m_session->partitionTime(); }); } // LOOKUP BASE DetailData::LookupBase::LookupBase(const QString &lookupClassName) : m_lookupClassName(lookupClassName) , m_logger(getLogger(QStringLiteral("DetailData.") + lookupClassName)) { } // EVENT TYPE LOOKUP DetailData::EventTypeLookup::EventTypeLookup() : LookupBase(QStringLiteral("EventTypeLookup")) { } void DetailData::EventTypeLookup::addEventType(const int key, const QString &value) { m_eventTypeMap.insert(key, value); } int DetailData::EventTypeLookup::getEventType(const QString &eventText) const { // as eventText is simplified, method 'key' would not work const QString paramText = removeSpaces(eventText); for (auto i = m_eventTypeMap.constBegin(); i != m_eventTypeMap.constEnd(); ++i) { const QString mapText = removeSpaces(i.value()); if (mapText == paramText) return i.key(); } return -1; // -1 = invalid ! } QString DetailData::EventTypeLookup::getEventText(const int eventType) const { return m_eventTypeMap.value(eventType); } bool DetailData::EventTypeLookup::isEventExists(const int eventType) const { return m_eventTypeMap.contains(eventType); } QStringList DetailData::EventTypeLookup::getEventTexts() const { return m_eventTypeMap.values(); } // ATTRIBUTE EVENT LOOKUP DetailData::AttributeEventLookup::AttributeEventLookup() : LookupBase(QStringLiteral("AttributeEventLookup")) { } void DetailData::AttributeEventLookup::addAttributesToEvent(const int eventType, const AttributeList &attributeTypeList) { AttributeList &al = m_attributeEventLookupMap[eventType]; al += attributeTypeList; } void DetailData::AttributeEventLookup::addAttributesToEvent(const ProjectDataManagement::EventType &eventType, const AttributeList &attributeTypeList) { addAttributesToEvent(eventType.underlying(), attributeTypeList); } bool DetailData::AttributeEventLookup::isAttributeInEvent(const int eventType, const QString &attributeType) { auto eventTypeIt = m_attributeEventLookupMap.constFind(eventType); if (eventTypeIt == m_attributeEventLookupMap.constEnd()) return false; // event does not even exist const AttributeList &attributeList = *eventTypeIt; if (attributeList.contains(attributeType)) return true; return false; } DetailData::AttributeEventLookup::AttributeList DetailData::AttributeEventLookup::getEventsAttributeList(const int eventType) const // get all attribute types from the event { return m_attributeEventLookupMap.value(eventType); } // ATTRIBUTE TEXT LOOKUP DetailData::AttributeTypeLookup::AttributeTypeLookup() : LookupBase(QStringLiteral("AttributeTypeLookup")) { } void DetailData::AttributeTypeLookup::addAttributeText(const QString &attributeType, const QString &attributeText) { m_attributeTypeLookupMap.insert(attributeType, attributeText); } QString DetailData::AttributeTypeLookup::getAttributeType(const QString &attributeText) const { const QString paramText = removeSpaces(attributeText); // as eventText is simplified, method 'key' would not work for (auto i = m_attributeTypeLookupMap.constBegin(); i != m_attributeTypeLookupMap.constEnd(); ++i) { const QString mapText = removeSpaces(i.value()); if (mapText == paramText) return i.key(); } WARNING_LOG(m_logger) << "getAttributeType: attribute type not found by text '" << attributeText << "'"; return QString(); // invalid } DetailData::AttributeTypeLookup::AttributeTypeList DetailData::AttributeTypeLookup::getAttributeTypes() const { return m_attributeTypeLookupMap.keys(); } QString DetailData::AttributeTypeLookup::getAttributeText(const QString &attributeType, const QString &defaultReturnValue) const { return m_attributeTypeLookupMap.value(attributeType, defaultReturnValue); } DetailData::AttributeTypeLookup::AttributeTextList DetailData::AttributeTypeLookup::getAttributeTexts() const { return m_attributeTypeLookupMap.values(); } // ATTRIBUTE PARAMETER LOOKUP DetailData::AttributeParameterLookup::AttributeParameterLookup() : LookupBase(QStringLiteral("AttributeParameterLookup")) { } void DetailData::AttributeParameterLookup::addParameter(const QString &attributeType, const ParameterMap ¶meterMap) { if (!parameterMap.count()) { WARNING_LOG(m_logger) << "addParameter: parameter map is empty!"; return; } m_attributeParameterMap.insert(attributeType, parameterMap); } DetailData::AttributeParameterLookup::ParameterMap DetailData::AttributeParameterLookup::getParameterMap(const QString &attributeType) const { return m_attributeParameterMap.value(attributeType); } QVariant DetailData::AttributeParameterLookup::getParameterValue(const QString &attributeType, const int parameterType) const { const ParameterMap &pm = getParameterMap(attributeType); auto pmci = pm.constFind(parameterType); if (pmci == pm.constEnd()) // exists? FIXME: in NGLDAO Timeline: "!=" !! return QVariant(); return *pmci; } // ATTRIBUTE UI TYPE DetailData::AttributeUITypeLookup::AttributeUITypeLookup() : LookupBase(QStringLiteral("AttributeUITypeLookup")) { } void DetailData::AttributeUITypeLookup::addUITypeToAttribute(const QString &attributeType, const int uiType) { m_attributeUITypeLookupMap.insert(attributeType, uiType); } int DetailData::AttributeUITypeLookup::getUIType(const QString &attributeType) const { return m_attributeUITypeLookupMap.value(attributeType, -1); // -1 = invalid } // INTERPRETER LOOKUP DetailData::AttributeInterpreterLookup::AttributeInterpreterLookup() : LookupBase(QStringLiteral("AttributeInterpreterLookup")) { } void DetailData::AttributeInterpreterLookup::addInterpreterTypeToAttribute(const QString &attributeType, const int interpreterType) { m_attributeInterpreterLookupMap.insert(attributeType, interpreterType); } int DetailData::AttributeInterpreterLookup::getInterpreterType(const QString &attributeType) const { return m_attributeInterpreterLookupMap.value(attributeType); } // ATTRIBUTE VALUE LOOKUP DetailData::AttributeValueLookup::AttributeValueLookup() : LookupBase(QStringLiteral("AttributeValueLookup")) { } void DetailData::AttributeValueLookup::removeValueFromAttributeValueMap(const QString &attributeType, const int valueKey) { auto attributeTypeValueMapIt = m_attributeTypeValueMap.find(attributeType); if (attributeTypeValueMapIt == m_attributeTypeValueMap.end()) // there are currently no values for this attribute type, insert all new values return; // attribute type not even found! AttributeValueMap ¤tAttributeValueMap = *attributeTypeValueMapIt; currentAttributeValueMap.remove(valueKey); } void DetailData::AttributeValueLookup::addValueToAttributeValueMap(const QString &attributeType, const int valueKey, const QString &valueValue) { AttributeValueMap &avm = m_attributeTypeValueMap[attributeType]; avm.insert(valueKey, valueValue); } void DetailData::AttributeValueLookup::addValuesToAttributeValueMap(const QString &attributeType, const AttributeValueMap &avm) // add a VALUE (consisting of id & string) to the map coresponding to the attribute type { AttributeValueMap &thisAvm = m_attributeTypeValueMap[attributeType]; for (auto i = avm.constBegin(); i != avm.constEnd(); ++i) { thisAvm.insert(i.key(), i.value()); } } AttributeValueMap DetailData::AttributeValueLookup::getAttributeValueMap(const QString &attributeType) const { return m_attributeTypeValueMap.value(attributeType); } QString DetailData::AttributeValueLookup::getValueStringFromValueId(const QString &attributeType, const int attributeValueId, const QString& defaultValue) const { return getAttributeValueMap(attributeType).value(attributeValueId, defaultValue); } void DetailData::AttributeValueLookup::clear() { m_attributeTypeValueMap.clear(); } // ATTRIBUTE REDIRECTION LOOKUP DetailData::AttributeRedirectionLookup::AttributeRedirectionLookup() : LookupBase(QStringLiteral("AttributeRedirectionLookup")) { } void DetailData::AttributeRedirectionLookup::addRedirection(const QString &attributeType, const QString &redirectTo) { m_attributeRedirectionMap.insert(attributeType, redirectTo); } QString DetailData::AttributeRedirectionLookup::getRedirection(const QString &attributeType) const { auto it = m_attributeRedirectionMap.find(attributeType); if (it == m_attributeRedirectionMap.end()) return attributeType; return it.value(); } } // namespace Timeline