/** * @RDE_HEADER@ * AreaEffectSimulation - Contamination Edit Dialog * $Id$ * $HeadURL$ * $Author$ * Created by Patric Karwat, SLSE, 2016-07-07 */ #include "aes_base_edit.h" #include #include #include #include #include #include #include #include #include #include namespace AreaEffectSimulation { BaseEdit::BaseEdit(const QString &menuGroup, const QString &loggerName, QWidget *parent, LtsWidgets::ButtonCombination buttonCombination) : LtsWidgets::LtsDialog(parent, buttonCombination) , m_aesItem() , m_dtc(nullptr) , m_ftc(nullptr) , m_sitMapGuiIfc(nullptr) , m_ppmGuiCbxIfc(nullptr) , m_session(nullptr) , m_menuGroup(menuGroup) , m_requestHelper(new LtsUtils::RequestHelper(this)) , m_logger(getLogger(loggerName)) { m_aesItem.id(0); connect(this, &BaseEdit::visibilityChanged, this, &BaseEdit::onVisibilityChanged); } void BaseEdit::setCombobxToValueIfPossible(QComboBox *cbx, int val) { int idx = cbx->findData(val); if (idx >= 0) cbx->setCurrentIndex(idx); } void BaseEdit::onAesItemCreateReply(const Core::FunctionReplyObject &replyObject) { m_requestHelper->requestReply(replyObject); if (!replyObject.error() && m_sitMapGuiIfc) m_sitMapGuiIfc->removePreviewObject(); } void BaseEdit::onAesItemModifyReply(const Core::FunctionReplyObject &replyObject) { m_requestHelper->requestReply(replyObject); if (!replyObject.error() && m_sitMapGuiIfc ) m_sitMapGuiIfc->removePreviewObject(); } bool BaseEdit::isModifiable() const { AesEffectState effectState = m_aesItem.effectStateId(); return (effectState == AreaEffectSimulation::AesEffectState_def::EsPaused || effectState == AreaEffectSimulation::AesEffectState_def::EsActivated || effectState == AreaEffectSimulation::AesEffectState_def::EsPrepared || effectState == AreaEffectSimulation::AesEffectState_def::EsCreated || effectState == AreaEffectSimulation::AesEffectState_def::EsUnknown || effectState == AreaEffectSimulation::AesEffectState_def::EsReceived) && (!m_session->isReplayPartition()) && (m_session->app() != LtsAppDescriptor::App::OC); // not OC-App } bool BaseEdit::isOnlyNameModifiable() const { AesEffectState effectState = m_aesItem.effectStateId(); return (effectState == AreaEffectSimulation::AesEffectState_def::EsPaused || effectState == AreaEffectSimulation::AesEffectState_def::EsActivated) && (!m_session->isReplayPartition()) && (m_session->app() != LtsAppDescriptor::App::OC); // not OC-App } void BaseEdit::correctSpinBoxValue() { QSpinBox *sb = qobject_cast(sender()); if (sb) return correctSpinBoxValueInternal(sb); QDoubleSpinBox *dsb = qobject_cast(sender()); if (dsb) return correctSpinBoxValueInternal(dsb); } void BaseEdit::onVisibilityChanged(bool visible) { if (!m_sitMapGuiIfc) return; if (!visible) m_sitMapGuiIfc->removePreviewObject(); else showPreviewObject(); } void BaseEdit::correctSpinBoxValueInternal(QSpinBox *sb) { if (!sb) return; int step = sb->singleStep(); if (step == 1) return; int value = sb->value(); int remainder = (value - sb->minimum()) % step; if (remainder == 0) return; if (2 * remainder > step) value += (step - remainder); else value -= remainder; if (value > sb->maximum()) value -= step; if(value < sb->minimum()) value = sb->minimum(); sb->setValue(value); } void BaseEdit::correctSpinBoxValueInternal(QDoubleSpinBox *sb) { if (!sb) return; double step = sb->singleStep(); if (qFuzzyCompare(step, pow(10, sb->decimals()))) return; double value = sb->value(); double remainder = fmod(value - sb->minimum(), step); if (qFuzzyCompare(remainder, 0)) return; if (2 * remainder > step) value += (step - remainder); else value -= remainder; if (value > sb->maximum()) value -= step; if (value < sb->minimum()) value = sb->minimum(); sb->setValue(value); } bool BaseEdit::hasValidEffectStart(LtsWidgets::LtsDateTimeEdit *dte) const { if (isOnlyNameModifiable()) return true; // if there is visible a enabled/disable checkbox -> also allow 0 as effect start if (dte->isCheckable() && !dte->isChecked()) return true; const auto ms = dte->msecsSinceEpoch(); return ms > m_session->partitionTime(); } void BaseEdit::setEffectStartEnabled(LtsWidgets::LtsDateTimeEdit *dte, bool enable) { if (enable) { int exerciseId = m_session->exerciseId(); std::shared_ptr exmDtc; m_session->getDtc(exmDtc); ExerciseManagement::Exercise exercise = exmDtc->exercise(exerciseId); // Enablen der gesamten Checkbox nur, wenn Übung läuft: enable = (exercise.state() == ExerciseManagement::ExerciseState_def::Started || exercise.state() == ExerciseManagement::ExerciseState_def::Paused); // In Übungsvorbereitung keine Eingabe einer Zeit möglich: if (exercise.state() == ExerciseManagement::ExerciseState_def::Created) dte->setChecked(false); else // Ansonsten Status gemäß eingetragener Zeit. dte->setChecked(dte->msecsSinceEpoch() > 0); } else // Ansonsten Status gemäß eingetragener Zeit. dte->setChecked(dte->msecsSinceEpoch() > 0); // Gesamtstatus übernehmen. dte->setEnabled(enable); } bool BaseEdit::has2DMap(bool showMsgBoxIfNot2D) { if (!m_sitMapGuiIfc) return false; if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D) { if (showMsgBoxIfNot2D) LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode")); return false; } return true; } void BaseEdit::setCoordinates(const QVector &coords, bool reverse) { // Reverse if Frontline is chosen and width is taken to the right (like drawing an L) clearCoordinates(); const auto cWidgets(coordWidgets()); if (!reverse) { for (size_t i = 0; i < cWidgets.size() && i < static_cast(coords.size()); ++i) cWidgets.at(i)->setCoordinate(coords.at(i)); } else { auto copy(coords); std::reverse(std::begin(copy), std::end(copy)); for (size_t i = 0; i < cWidgets.size() && i < static_cast(copy.size()); ++i) cWidgets.at(i)->setCoordinate(copy.at(i)); } } void BaseEdit::setCoordinates(const std::vector &coords) { clearCoordinates(); const auto cWidgets(coordWidgets()); for (size_t i = 0; i < cWidgets.size() && i < static_cast(coords.size()); ++i) cWidgets.at(i)->setCoordinate(coords.at(i).lon(), coords.at(i).lat()); } std::vector BaseEdit::getCoordinates() const { std::vector segments; const auto cWidgets(coordWidgets()); segments.reserve(cWidgets.size()); for (const auto cw : cWidgets) { const QPointF coord = cw->coordinate(); if (coord.isNull()) break; segments.emplace_back(Core::GeoPosition2D(coord.x(), coord.y())); } return segments; } QVector BaseEdit::getCoordinatesQPointF() const { QVector segments; const auto cWidgets(coordWidgets()); segments.reserve(cWidgets.size()); for (const auto *cw : cWidgets) { const QPointF coord = cw->coordinate(); if (coord.isNull()) break; segments.push_back(coord); } return segments; } void BaseEdit::clearCoordinates() { for (auto *cw : coordWidgets()) cw->clear(); } void BaseEdit::enabledCoordinates(bool enable) { for (auto *cw : coordWidgets()) cw->setEnabled(enable); } void BaseEdit::onAreaChanged(const AesItem &data, DataModification modType) { // No, we don't update the UI elements (yet). If we wanted to, we had to // implement a virtual method such as enableUiElements... if (data.id() != m_aesItem.id()) return; if (modType == DataModification::eRemoved || data.effectStateId() == AesEffectState_def::EsRemoved) { // As a simple 'close()' does not work: __unchange__(); closeRequest(); return; } m_aesItem = data; enableUiElements(isModifiable() && !isOnlyNameModifiable()); } bool BaseEdit::init(int aesItemId, LtsSession::LtsSession *session) { if (m_session) { ERROR_LOG(m_logger) << "double init()!"; return false; } m_session = session; m_aesItem.id(aesItemId); if (!m_session->getDtc(m_dtc)) return false; if (!m_session->getFtc(m_ftc)) return false; m_session->getForeignGuiInterface(m_sitMapGuiIfc); if (!m_session->getForeignGuiInterface(m_ppmGuiCbxIfc)) return false; if (m_session->isReplayPartition() || (LtsAppDescriptor::App::OC == m_session->app())) setUnchangeable(); if (aesItemId == 0) { m_aesItem.effectSourceId(ProjectDataManagement::EffectSource_def::ES_Internal); m_buttonBox->setText(LtsWidgets::DialogButton::Ok, tr("Add")); } return true; } double BaseEdit::distance(const Core::GeoPosition2D &p1, const Core::GeoPosition2D &p2) { LtsCoordTrans::UtmCoordinate start = LtsCoordTrans::UtmCoordinate::fromGeographic(p1.lon(), p1.lat()); LtsCoordTrans::UtmCoordinate end = LtsCoordTrans::UtmCoordinate::fromGeographic(p2.lon(), p2.lat(), start.zone); double dx = start.x - end.x; double dy = start.y - end.y; return std::sqrt(dx*dx + dy*dy); } bool BaseEdit::checkSegementLengths(QWidget *parent) const { auto segments = getCoordinates(); for (auto i=0; i<((int) segments.size() - 1); ++i) { double dis = distance(segments[i], segments[i+1]); if (getMaxLength() != 0 && dis > getMaxLength()) { LtsWidgets::LtsMessageDialog::showMessage(parent, tr("The distance between Coordinate %1 and %2 is too long.\nThe segment is %3m long, but the maximum segment length is %4m.") .arg(i+1).arg(i+2).arg(QString::number(dis,'d',2),QString::number(getMaxLength(),'d',2))); return false; } } return true; } } // namespace AreaEffectSimulation