|
@@ -13,6 +13,7 @@
|
|
|
|
|
|
#include <algorithm>
|
|
|
#include <cctype>
|
|
|
+#include <regex>
|
|
|
|
|
|
#include <gsl/gsl>
|
|
|
#include <Shlwapi.h>
|
|
@@ -71,6 +72,7 @@ PlugIn::PlugIn() :
|
|
|
this->RegisterTagItemType("Delta time", static_cast<int>(PlugIn::TagItemElement::DeltaTime));
|
|
|
this->RegisterTagItemType("Fixed plan indicator", static_cast<int>(PlugIn::TagItemElement::FixedPlanIndicator));
|
|
|
this->RegisterTagItemFunction("Force planning", static_cast<int>(PlugIn::TagItemFunction::ForceToBackendMenu));
|
|
|
+ this->RegisterTagItemFunction("Runway selection", static_cast<int>(PlugIn::TagItemFunction::RunwaySelectMenu));
|
|
|
|
|
|
this->DisplayUserMessage(PLUGIN_NAME, "INFO", (std::string("Loaded ") + PLUGIN_NAME + " " + PLUGIN_VERSION).c_str(), true, true, false, false, false);
|
|
|
|
|
@@ -207,6 +209,8 @@ EuroScopePlugIn::CRadarScreen* PlugIn::OnRadarScreenCreated(const char* displayN
|
|
|
if (nullptr == this->m_screen)
|
|
|
this->m_screen = std::make_shared<RadarScreen>();
|
|
|
|
|
|
+ this->OnAirportRunwayActivityChanged();
|
|
|
+
|
|
|
return this->m_screen.get();
|
|
|
}
|
|
|
|
|
@@ -454,6 +458,10 @@ void PlugIn::generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarT
|
|
|
report->set_allocated_dynamics(dynamics);
|
|
|
report->set_allocated_position(coordinate);
|
|
|
|
|
|
+ auto selectedRwyIt = this->m_selectedRunway.find(radarTarget.GetCallsign());
|
|
|
+ if (this->m_selectedRunway.cend() != selectedRwyIt)
|
|
|
+ report->set_requestedrunway(selectedRwyIt->second);
|
|
|
+
|
|
|
/* set the report time */
|
|
|
std::stringstream stream;
|
|
|
const auto reportTime = std::chrono::utc_clock::now();
|
|
@@ -476,8 +484,6 @@ bool PlugIn::OnCompileCommand(const char* cmdline) {
|
|
|
|
|
|
if (std::string::npos != message.find("RELOAD")) {
|
|
|
this->validateBackendData();
|
|
|
- this->m_sweatboxValid = false;
|
|
|
- this->m_playbackValid = false;
|
|
|
retval = true;
|
|
|
}
|
|
|
else if (std::string::npos != message.find("SWEATBOX")) {
|
|
@@ -603,9 +609,9 @@ void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RE
|
|
|
this->OpenPopupList(area, "AMAN", 1);
|
|
|
bool inList = this->m_forcedToBackendCallsigns.cend() != std::find(this->m_forcedToBackendCallsigns.cbegin(), this->m_forcedToBackendCallsigns.cend(), callsign);
|
|
|
this->AddPopupListElement("Add to AMAN", "", static_cast<int>(PlugIn::TagItemFunction::ForceToBackendSelect),
|
|
|
- false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, true == inList);
|
|
|
+ false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, true == inList);
|
|
|
this->AddPopupListElement("Remove from AMAN", "", static_cast<int>(PlugIn::TagItemFunction::ForceToBackendSelect),
|
|
|
- false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, false == inList);
|
|
|
+ false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, false == inList);
|
|
|
break;
|
|
|
}
|
|
|
case PlugIn::TagItemFunction::ForceToBackendSelect:
|
|
@@ -633,6 +639,45 @@ void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RE
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
+ case PlugIn::TagItemFunction::RunwaySelectMenu:
|
|
|
+ {
|
|
|
+ std::string destination(radarTarget.GetCorrelatedFlightPlan().GetFlightPlanData().GetDestination());
|
|
|
+ std::transform(destination.begin(), destination.end(), destination.begin(), ::toupper);
|
|
|
+
|
|
|
+ std::lock_guard guard(this->m_updateQueueLock);
|
|
|
+ auto it = this->m_updateQueue.find(destination);
|
|
|
+
|
|
|
+ if (this->m_updateQueue.cend() != it) {
|
|
|
+ this->OpenPopupList(area, "Select runway", 1);
|
|
|
+ bool inList = this->m_selectedRunway.find(callsign) != this->m_selectedRunway.cend();
|
|
|
+ this->AddPopupListElement("Remove", "", static_cast<int>(PlugIn::TagItemFunction::RunwaySelect),
|
|
|
+ false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, false == inList);
|
|
|
+
|
|
|
+ for (const auto& rwy : std::as_const(it->second.arrivalRunways))
|
|
|
+ this->AddPopupListElement(rwy.c_str(), "", static_cast<int>(PlugIn::TagItemFunction::RunwaySelect));
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case PlugIn::TagItemFunction::RunwaySelect:
|
|
|
+ {
|
|
|
+ std::lock_guard guard(this->m_updateQueueLock);
|
|
|
+
|
|
|
+ if (0 == std::strcmp(itemString, "Remove")) {
|
|
|
+ auto it = this->m_selectedRunway.find(callsign);
|
|
|
+ if (this->m_selectedRunway.end() != it)
|
|
|
+ this->m_selectedRunway.erase(it);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ auto it = this->m_selectedRunway.find(callsign);
|
|
|
+ if (this->m_selectedRunway.end() != it)
|
|
|
+ it->second = itemString;
|
|
|
+ else
|
|
|
+ this->m_selectedRunway.insert({ callsign, itemString });
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
@@ -651,8 +696,17 @@ void PlugIn::addUpdateQueue(EuroScopePlugIn::CRadarTarget& radarTarget) {
|
|
|
#pragma warning(default: 4244)
|
|
|
|
|
|
auto it = this->m_updateQueue.find(destination);
|
|
|
- if (this->m_updateQueue.end() != it)
|
|
|
- it->second.push_back(radarTarget.GetCallsign());
|
|
|
+ if (this->m_updateQueue.end() != it) {
|
|
|
+ /* check that an active arrival runway is selected */
|
|
|
+ auto selectedIt = this->m_selectedRunway.find(radarTarget.GetCallsign());
|
|
|
+ if (this->m_selectedRunway.end() != selectedIt) {
|
|
|
+ auto activeRwyIt = std::find(it->second.arrivalRunways.cbegin(), it->second.arrivalRunways.cend(), selectedIt->second);
|
|
|
+ if (it->second.arrivalRunways.cend() == activeRwyIt)
|
|
|
+ this->m_selectedRunway.erase(selectedIt);
|
|
|
+ }
|
|
|
+
|
|
|
+ it->second.inboundUpdates.push_back(radarTarget.GetCallsign());
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void PlugIn::updateInbound(EuroScopePlugIn::CRadarTarget& radarTarget) {
|
|
@@ -726,8 +780,15 @@ void PlugIn::updateSequence(std::shared_ptr<aman::AircraftSequence>& sequence) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (false == found)
|
|
|
+ if (false == found) {
|
|
|
+ /* delete the forced runway selection */
|
|
|
+ std::lock_guard guard(this->m_updateQueueLock);
|
|
|
+ auto selected = this->m_selectedRunway.find(it->first);
|
|
|
+ if (this->m_selectedRunway.end() != selected)
|
|
|
+ this->m_selectedRunway.erase(selected);
|
|
|
+
|
|
|
it = this->m_inbounds.erase(it);
|
|
|
+ }
|
|
|
else
|
|
|
++it;
|
|
|
}
|
|
@@ -764,7 +825,7 @@ void PlugIn::OnTimer(int counter) {
|
|
|
if (true == this->m_connectedToNetwork) {
|
|
|
std::lock_guard guardUpdate(this->m_updateQueueLock);
|
|
|
for (auto& airport : this->m_updateQueue)
|
|
|
- airport.second.clear();
|
|
|
+ airport.second.inboundUpdates.clear();
|
|
|
|
|
|
std::lock_guard guardInbound(this->m_inboundsQueueLock);
|
|
|
this->m_inbounds.clear();
|
|
@@ -785,10 +846,10 @@ void PlugIn::OnTimer(int counter) {
|
|
|
aman::AircraftUpdate update;
|
|
|
update.set_airport(airport.first);
|
|
|
|
|
|
- if (0 != airport.second.size()) {
|
|
|
+ if (0 != airport.second.inboundUpdates.size()) {
|
|
|
for (auto target = this->RadarTargetSelectFirst(); true == target.IsValid(); target = this->RadarTargetSelectNext(target)) {
|
|
|
- auto it = std::find(airport.second.begin(), airport.second.end(), target.GetCallsign());
|
|
|
- if (airport.second.end() != it) {
|
|
|
+ auto it = std::find(airport.second.inboundUpdates.begin(), airport.second.inboundUpdates.end(), target.GetCallsign());
|
|
|
+ if (airport.second.inboundUpdates.end() != it) {
|
|
|
auto report = update.add_reports();
|
|
|
this->generateAircraftReportMessage(target, report);
|
|
|
}
|
|
@@ -802,8 +863,34 @@ void PlugIn::OnTimer(int counter) {
|
|
|
else
|
|
|
this->updateSequence(sequence);
|
|
|
|
|
|
- airport.second.clear();
|
|
|
+ airport.second.inboundUpdates.clear();
|
|
|
}
|
|
|
|
|
|
this->m_updateQueueLock.unlock();
|
|
|
}
|
|
|
+
|
|
|
+void PlugIn::OnAirportRunwayActivityChanged() {
|
|
|
+ std::lock_guard guard(this->m_updateQueueLock);
|
|
|
+
|
|
|
+ /* cleanup the arrival airports */
|
|
|
+ for (auto& airport : this->m_updateQueue)
|
|
|
+ airport.second.arrivalRunways.clear();
|
|
|
+
|
|
|
+ EuroScopePlugIn::CSectorElement rwy;
|
|
|
+ for (rwy = this->SectorFileElementSelectFirst(EuroScopePlugIn::SECTOR_ELEMENT_RUNWAY); true == rwy.IsValid();
|
|
|
+ rwy = this->SectorFileElementSelectNext(rwy, EuroScopePlugIn::SECTOR_ELEMENT_RUNWAY)) {
|
|
|
+ /* remove leading and trailing whitespaces */
|
|
|
+ std::string airport(rwy.GetAirportName());
|
|
|
+ airport = std::regex_replace(airport, std::regex("^ +| +$|( ) +"), "$1");
|
|
|
+
|
|
|
+ if (true == rwy.IsElementActive(false, 0) || true == rwy.IsElementActive(false, 1)) {
|
|
|
+ auto airportData = this->m_updateQueue.find(airport);
|
|
|
+ if (this->m_updateQueue.end() != airportData) {
|
|
|
+ if (true == rwy.IsElementActive(false, 0))
|
|
|
+ airportData->second.arrivalRunways.push_back(rwy.GetRunwayName(0));
|
|
|
+ if (true == rwy.IsElementActive(false, 1))
|
|
|
+ airportData->second.arrivalRunways.push_back(rwy.GetRunwayName(1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|