/** * @RDE_HEADER@ * ExerciseManangement - Exercise Overview Dialog * $Id$ * $HeadURL$ * $Author$ * * Created by Mike Wille, SLSE, 2017-02-10 */ #include "tln_legend.h" #include "ui_tln_legend.h" #include "detail_data.h" #include "tln_dialog_model.h" #include #include #include #include #include #include #include #include #include namespace Timeline { TimelineLegendDialog::TimelineLegendDialog(QWidget *parent) : LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel) , m_ui(new Ui::TimelineLegendDialog) , m_logger(getLogger("TimelineLegendDialog")) { m_ui->setupUi(this); m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->hide(); // apply() always returns false (because it can't be executed with async ops), resulting in the window not closing on OK - only use apply button until apply() can have async ops connect(m_ui->cbCheckAll, &QCheckBox::toggled, this, [this](bool toggled) { const auto cbList = findChildren(); for (QCheckBox *cb : cbList) { if (cb == m_ui->cbCheckAll) // needed? maybe recursion? continue; cb->setChecked(toggled); } }); } TimelineLegendDialog::~TimelineLegendDialog() { delete m_ui; } void TimelineLegendDialog::retranslate() { translate(m_ui, tr("Timeline Legend")); } void TimelineLegendDialog::setActiveEventTypeIds(const QSet &activeEventTypeIds) { setUnchangeable(); // first, deactivate all checkboxes, as we can't keep track on WHICH event types are now inactive const QList cbs(findChildren()); // yes, even the "check all" cb for (QCheckBox *cb : cbs) cb->setChecked(false); for (int activeEventType : activeEventTypeIds) { QCheckBox *cb = checkBox(activeEventType); if (cb != nullptr) cb->setChecked(true); else WARNING_LOG(m_logger) << "cb for event type " << activeEventType << " not found!"; } setUnchangeable(false); } QVector TimelineLegendDialog::possibleEvents() { QVector ret ({ // ProjectDataManagement::EventType::Unknown, ProjectDataManagement::EventType::Hit, ProjectDataManagement::EventType::WeaponAssignment, ProjectDataManagement::EventType::BiteMessage, ProjectDataManagement::EventType::FireEvent, ProjectDataManagement::EventType::HitBuilding, ProjectDataManagement::EventType::Manipulation, ProjectDataManagement::EventType::CameraVideo, ProjectDataManagement::EventType::RadioCnr, ProjectDataManagement::EventType::RadioTvc, ProjectDataManagement::EventType::HitEffectSimulation, // ProjectDataManagement::EventType::HitMine, // HitEffectSimulation // ProjectDataManagement::EventType::HitN, // HitEffectSimulation // ProjectDataManagement::EventType::HitC, // HitEffectSimulation // ProjectDataManagement::EventType::EnterDangerArea, // showEnterLeaveEvents // ProjectDataManagement::EventType::LeaveDangerArea, // showEnterLeaveEvents // ProjectDataManagement::EventType::EnterMineArea, // showEnterLeaveEvents // ProjectDataManagement::EventType::LeaveMineArea, // showEnterLeaveEvents ProjectDataManagement::EventType::CrossLocalBorderline, // ProjectDataManagement::EventType::EnterFunctionalArea, // showEnterLeaveEvents // ProjectDataManagement::EventType::LeaveFunctionalArea, // showEnterLeaveEvents // ProjectDataManagement::EventType::EnterNuclear, // showEnterLeaveEvents // ProjectDataManagement::EventType::LeaveNuclear, // showEnterLeaveEvents ProjectDataManagement::EventType::CrossGlobalBorderline, // ProjectDataManagement::EventType::HitB, // HitEffectSimulation // ProjectDataManagement::EventType::FriendlyFire, // currently not displayed // ProjectDataManagement::EventType::HitGasPipe, // HitEffectSimulation // ProjectDataManagement::EventType::MineArea, // showEffectSimulationEvents // ProjectDataManagement::EventType::NContamination, // showEffectSimulationEvents // ProjectDataManagement::EventType::BCContamination, // showEffectSimulationEvents // ProjectDataManagement::EventType::DangerArea, // showEffectSimulationEvents // ProjectDataManagement::EventType::FunctionalArea, // showEffectSimulationEvents // ProjectDataManagement::EventType::MineCorridor, // showEffectSimulationEvents // ProjectDataManagement::EventType::Borderline, // showEffectSimulationEvents // ProjectDataManagement::EventType::TechnicalArea, // ProjectDataManagement::EventType::GasPipe, // separate // ProjectDataManagement::EventType::EquipmentErrorReport, // ProjectDataManagement::EventType::EmergencyCall, }); LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance(); if (ps->value(QStringLiteral("tln"), QStringLiteral("showEffectSimulationEvents")).toBool()) { ret += ProjectDataManagement::EventType::MineArea; ret += ProjectDataManagement::EventType::DangerArea; ret += ProjectDataManagement::EventType::FunctionalArea; ret += ProjectDataManagement::EventType::MineCorridor; ret += ProjectDataManagement::EventType::Borderline; if (ps->value(QStringLiteral("aes"), QStringLiteral("enableNuclearContaminations")).toBool()) ret += ProjectDataManagement::EventType::NContamination; if (ps->value(QStringLiteral("aes"), QStringLiteral("enableNuclearContaminations")).toBool() || ps->value(QStringLiteral("aes"), QStringLiteral("enableNuclearContaminations")).toBool()) ret += ProjectDataManagement::EventType::BCContamination; } if (ps->value(QStringLiteral("tln"), QStringLiteral("showEnterLeaveEvents")).toBool()) { ret += ProjectDataManagement::EventType::EnterDangerArea; ret += ProjectDataManagement::EventType::LeaveDangerArea; ret += ProjectDataManagement::EventType::EnterMineArea; ret += ProjectDataManagement::EventType::LeaveMineArea; ret += ProjectDataManagement::EventType::EnterFunctionalArea; ret += ProjectDataManagement::EventType::LeaveFunctionalArea; if (ps->value(QStringLiteral("aes"), QStringLiteral("enableNuclearContaminations")).toBool()) { ret += ProjectDataManagement::EventType::EnterNuclear; ret += ProjectDataManagement::EventType::LeaveNuclear; } } if (ps->value(QStringLiteral("aes"), QStringLiteral("enableGasPipes")).toBool()) { ret += ProjectDataManagement::EventType::GasPipe; //ret += ProjectDataManagement::EventType::HitGasPipe; covered by HitEffectSimulation yes or no ?? } const bool showPvSan = LtsUtils::ProjectSettings::isFunctionEnabled(QStringLiteral("ParticipantInformation"), QStringLiteral("HasPvSan")); if (showPvSan) ret += ProjectDataManagement::EventType::Sanitation; return ret; } // helper for grouped sorting static int categoryFromEventType(ProjectDataManagement::EventType et) { switch (et.underlying()) { case ProjectDataManagement::EventType::Unknown: return 0; case ProjectDataManagement::EventType::Hit: case ProjectDataManagement::EventType::WeaponAssignment: case ProjectDataManagement::EventType::BiteMessage: case ProjectDataManagement::EventType::FireEvent: case ProjectDataManagement::EventType::FriendlyFire: case ProjectDataManagement::EventType::Manipulation: return 1; case ProjectDataManagement::EventType::CameraVideo: case ProjectDataManagement::EventType::RadioCnr: case ProjectDataManagement::EventType::RadioTvc: return 5; case ProjectDataManagement::EventType::HitBuilding: case ProjectDataManagement::EventType::HitEffectSimulation: case ProjectDataManagement::EventType::HitMine: case ProjectDataManagement::EventType::HitN: case ProjectDataManagement::EventType::HitB: case ProjectDataManagement::EventType::HitC: case ProjectDataManagement::EventType::HitGasPipe: return 2; case ProjectDataManagement::EventType::EnterDangerArea: case ProjectDataManagement::EventType::LeaveDangerArea: case ProjectDataManagement::EventType::EnterMineArea: case ProjectDataManagement::EventType::LeaveMineArea: case ProjectDataManagement::EventType::CrossLocalBorderline: case ProjectDataManagement::EventType::EnterFunctionalArea: case ProjectDataManagement::EventType::LeaveFunctionalArea: case ProjectDataManagement::EventType::EnterNuclear: case ProjectDataManagement::EventType::LeaveNuclear: case ProjectDataManagement::EventType::CrossGlobalBorderline: case ProjectDataManagement::EventType::Sanitation: return 3; case ProjectDataManagement::EventType::MineArea: case ProjectDataManagement::EventType::NContamination: case ProjectDataManagement::EventType::BCContamination: case ProjectDataManagement::EventType::DangerArea: case ProjectDataManagement::EventType::FunctionalArea: case ProjectDataManagement::EventType::MineCorridor: case ProjectDataManagement::EventType::Borderline: case ProjectDataManagement::EventType::GasPipe: return 6; case ProjectDataManagement::EventType::TechnicalArea: case ProjectDataManagement::EventType::EquipmentErrorReport: case ProjectDataManagement::EventType::EmergencyCall: return 0; } Q_ASSERT(false); return 0; } bool TimelineLegendDialog::init(DDSTimelineModel *model, const QSet &activeEventTypeIds) { struct WidgetSortHelper { QLabel *lbl = nullptr; QCheckBox *cbx = nullptr; ProjectDataManagement::EventType et = ProjectDataManagement::EventType::Unknown; }; QImage p(16, 24, QImage::Format_ARGB32); QColor c; // dummy LtsTimelineClassic::Event::EventPaintFunc paintFunc; WidgetSortHelper wsh; const auto events = possibleEvents(); std::vector helperCont; helperCont.reserve(events.size()); for (const ProjectDataManagement::EventType eventType : events) { model->setColorPaintFun(paintFunc, c, eventType.underlying()); if (paintFunc == nullptr) { WARNING_LOG(m_logger) << "No draw function for event " << eventType; Q_ASSERT(false); continue; } p.fill(Qt::transparent); QPainter pp(&p); pp.setRenderHint(QPainter::Antialiasing); pp.setBrush(QBrush(c)); paintFunc(&pp, p.rect().adjusted(0, 0, -1, -1)); wsh.lbl = new QLabel(this); wsh.lbl->setPixmap(QPixmap::fromImage(p)); wsh.et = eventType; wsh.cbx = new QCheckBox(ProjectDataManagement::toString(eventType), this); wsh.cbx->setObjectName(checkBoxName(eventType)); wsh.cbx->setChecked(activeEventTypeIds.contains(eventType.underlying())); wsh.cbx->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); helperCont.push_back(wsh); } std::sort(helperCont.begin(), helperCont.end(), [](const WidgetSortHelper &a, const WidgetSortHelper &b) { const auto et1 = categoryFromEventType(a.et); const auto et2 = categoryFromEventType(b.et); if (et1 != et2) return et1 < et2; return a.cbx->text() < b.cbx->text(); }); int curGridRow = 1; // 0 is 'Check all' for (const auto &ele : helperCont) { m_ui->gridLayout->addWidget(ele.lbl, curGridRow, 0); m_ui->gridLayout->addWidget(ele.cbx, curGridRow, 1); m_ui->gridLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), curGridRow, 2); ++curGridRow; } m_ui->gridLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), curGridRow, 0); return true; } bool TimelineLegendDialog::apply() { QSet activeEventTypeIds; const auto events = possibleEvents(); for (const ProjectDataManagement::EventType eventType : events) { if (checkBox(eventType)->isChecked()) activeEventTypeIds.insert(eventType.underlying()); } emit signalEventTypesChanged(activeEventTypeIds); return false; // because this has to happen async.. (reset changes after async ops are (successfully) done) } } // namespace Timeline //