Skip to content

Commit

Permalink
feat: listing ecfmp flow measures
Browse files Browse the repository at this point in the history
  • Loading branch information
AndyTWF committed Aug 15, 2023
1 parent a46ea25 commit a5d04ac
Show file tree
Hide file tree
Showing 13 changed files with 373 additions and 5 deletions.
1 change: 1 addition & 0 deletions docs/TAG_FUNCTIONS.md
Expand Up @@ -23,3 +23,4 @@
9020 - Trigger Missed Approach
9021 - Acknowledge Missed Approach
9022 - Open Squawk Assignment Menu
9023 - Display Relevant ECFMP Flow Measures
22 changes: 22 additions & 0 deletions resource/UKControllerPlugin.rc
Expand Up @@ -359,6 +359,15 @@ BEGIN
LTEXT "Please go to your web browser and log in to the UK Controller Plugin page. This window will close automatically once your API key has been received. If you are unable to find the page, you can click the button below to re-open it.",IDC_API_KEY_STATIC,7,7,249,89
END

IDD_FLOW_MEASURE_LIST DIALOGEX 0, 0, 367, 297
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Close",IDOK,310,276,50,14
EDITTEXT IDC_FLOW_MEASURES_INFO,7,7,353,264,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL
END


/////////////////////////////////////////////////////////////////////////////
//
Expand Down Expand Up @@ -497,6 +506,14 @@ BEGIN
TOPMARGIN, 7
BOTTOMMARGIN, 120
END

IDD_FLOW_MEASURE_LIST, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 360
TOPMARGIN, 7
BOTTOMMARGIN, 290
END
END
#endif // APSTUDIO_INVOKED

Expand Down Expand Up @@ -586,6 +603,11 @@ BEGIN
0
END

IDD_FLOW_MEASURE_LIST AFX_DIALOG_LAYOUT
BEGIN
0
END


/////////////////////////////////////////////////////////////////////////////
//
Expand Down
5 changes: 4 additions & 1 deletion resource/resource.h
Expand Up @@ -30,6 +30,7 @@
#define IDD_MISSED_APPROACH_ACKNOWLEDGE 139
#define IDD_DEPARTURE_RELEASE_REJECT 141
#define IDD_API_KEY_REPLACE 143
#define IDD_FLOW_MEASURE_LIST 145
#define IDC_CHECK_DEGRADING 1001
#define IDC_CHECK_FADING 1002
#define IDC_CHECK_AA 1003
Expand Down Expand Up @@ -133,13 +134,15 @@
#define IDC_DEPARTURE_RELEASE_APPROVE_CALLSIGN 1087
#define MISSED_APPROACH_DRAW_DURATION 1087
#define IDC_RELEASE_REJECT_REMARKS 1087
#define IDC_FLOW_MEASURES_DETAILS 1087
#define IDC_NOTES_STATIC 1088
#define IDC_HOLD_PARAMS_MIN_STATIC 1089
#define IDC_NOTIFICATION_BODY 1089
#define IDC_HOLD_PARAMS_MAX_STATIC 1090
#define IDC_HOLD_MIN_SPIN 1091
#define IDC_HOLD_MAX 1092
#define IDC_HOLD_MAXIMUM 1092
#define IDC_FLOW_MEASURES_INFO 1092
#define IDC_SPIN2 1093
#define IDC_HOLD_MAX_SPIN 1093
#define IDC_NOTIFICATION_LINK 1094
Expand Down Expand Up @@ -209,7 +212,7 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 145
#define _APS_NEXT_RESOURCE_VALUE 147
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1146
#define _APS_NEXT_SYMED_VALUE 101
Expand Down
2 changes: 1 addition & 1 deletion src/plugin/CMakeLists.txt
Expand Up @@ -179,7 +179,7 @@ source_group("src\\dependency" FILES ${src__dependency})

set(src__ecfmp

ecfmp/ECFMPModuleFactory.cpp ecfmp/ECFMPModuleFactory.h ecfmp/Logger.cpp ecfmp/Logger.h ecfmp/HttpClient.cpp ecfmp/HttpClient.h ecfmp/ECFMPBootstrapProvider.cpp ecfmp/ECFMPBootstrapProvider.h ecfmp/TriggerEcfmpEventLoop.cpp ecfmp/TriggerEcfmpEventLoop.h ecfmp/AircraftFlowMeasureMap.cpp ecfmp/AircraftFlowMeasureMap.h ecfmp/AircraftFlowMeasureMapInterface.h ecfmp/AircraftFlowMeasureTagItem.cpp ecfmp/AircraftFlowMeasureTagItem.h)
ecfmp/ECFMPModuleFactory.cpp ecfmp/ECFMPModuleFactory.h ecfmp/Logger.cpp ecfmp/Logger.h ecfmp/HttpClient.cpp ecfmp/HttpClient.h ecfmp/ECFMPBootstrapProvider.cpp ecfmp/ECFMPBootstrapProvider.h ecfmp/TriggerEcfmpEventLoop.cpp ecfmp/TriggerEcfmpEventLoop.h ecfmp/AircraftFlowMeasureMap.cpp ecfmp/AircraftFlowMeasureMap.h ecfmp/AircraftFlowMeasureMapInterface.h ecfmp/AircraftFlowMeasureTagItem.cpp ecfmp/AircraftFlowMeasureTagItem.h ecfmp/ListAircraftFlowMeasures.cpp ecfmp/ListAircraftFlowMeasures.h ecfmp/AircraftFlowMeasuresDialog.cpp ecfmp/AircraftFlowMeasuresDialog.h ecfmp/HomeFirsFlowMeasureFilter.cpp ecfmp/HomeFirsFlowMeasureFilter.h)

set(src__euroscope
"euroscope/AsrEventHandlerCollection.cpp"
Expand Down
1 change: 0 additions & 1 deletion src/plugin/ecfmp/AircraftFlowMeasureTagItem.cpp
Expand Up @@ -2,7 +2,6 @@
#include "AircraftFlowMeasureMapInterface.h"
#include "euroscope/EuroScopeCFlightPlanInterface.h"
#include "tag/TagData.h"
#include <string>

namespace UKControllerPlugin::ECFMP {

Expand Down
69 changes: 69 additions & 0 deletions src/plugin/ecfmp/AircraftFlowMeasuresDialog.cpp
@@ -0,0 +1,69 @@
#include "AircraftFlowMeasuresDialog.h"
#include "dialog/DialogCallArgument.h"

namespace UKControllerPlugin::ECFMP {
/*
Public facing window procedure
*/
LRESULT AircraftFlowMeasuresDialog::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_INITDIALOG) {
LogInfo("Aircraft flow measures dialog opened");
SetWindowLongPtr(
hwnd, GWLP_USERDATA, reinterpret_cast<Dialog::DialogCallArgument*>(lParam)->dialogArgument);
} else if (msg == WM_DESTROY) {
SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
LogInfo("Aircraft flow measures dialog closed");
}

AircraftFlowMeasuresDialog* dialog =
reinterpret_cast<AircraftFlowMeasuresDialog*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
return dialog ? dialog->_WndProc(hwnd, msg, wParam, lParam) : FALSE;
}

/*
Private window procedure bound to the objects
*/
LRESULT AircraftFlowMeasuresDialog::_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
// Initialise
case WM_INITDIALOG: {
this->InitDialog(hwnd, lParam);
return TRUE;
}
// Dialog Closed
case WM_CLOSE: {
EndDialog(hwnd, wParam);
return TRUE;
}
// Buttons pressed
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case IDOK: {
EndDialog(hwnd, wParam);
return TRUE;
}
default:
return FALSE;
}
}
}

return FALSE;
}

void AircraftFlowMeasuresDialog::InitDialog(HWND hwnd, LPARAM lParam)
{
auto* data = reinterpret_cast<AircraftFlowMeasuresDialogData*>(
reinterpret_cast<Dialog::DialogCallArgument*>(lParam)->contextArgument);

// Set the the dialog box title
std::wstring title = L"ECFMP flow Measures for " + data->callsign;
SetWindowText(hwnd, title.c_str());

// Set the flow measures text
std::wstring description = data->flowMeasures;
SetDlgItemText(hwnd, IDC_FLOW_MEASURES_INFO, description.c_str());
}
} // namespace UKControllerPlugin::ECFMP
23 changes: 23 additions & 0 deletions src/plugin/ecfmp/AircraftFlowMeasuresDialog.h
@@ -0,0 +1,23 @@
#pragma once

namespace UKControllerPlugin::ECFMP {

struct AircraftFlowMeasuresDialogData
{
// The aircraft callsign
std::wstring callsign;

// The description of the flow measures
std::wstring flowMeasures;
};

class AircraftFlowMeasuresDialog
{
public:
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

private:
LRESULT _WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void InitDialog(HWND hwnd, LPARAM lParam);
};
} // namespace UKControllerPlugin::ECFMP
25 changes: 25 additions & 0 deletions src/plugin/ecfmp/ECFMPBootstrapProvider.cpp
@@ -1,10 +1,15 @@
#include "AircraftFlowMeasureMap.h"
#include "AircraftFlowMeasureTagItem.h"
#include "AircraftFlowMeasuresDialog.h"
#include "ECFMPBootstrapProvider.h"
#include "ECFMPModuleFactory.h"
#include "ListAircraftFlowMeasures.h"
#include "TriggerEcfmpEventLoop.h"
#include "bootstrap/ModuleFactories.h"
#include "bootstrap/PersistenceContainer.h"
#include "dialog/DialogManager.h"
#include "plugin/FunctionCallEventHandler.h"
#include "tag/TagFunction.h"
#include "tag/TagItemCollection.h"
#include "timedevent/TimedEventCollection.h"

Expand All @@ -20,5 +25,25 @@ namespace UKControllerPlugin::ECFMP {
const auto aircraftFlowMeasureMap = std::make_shared<AircraftFlowMeasureMap>(*container.plugin);
container.tagHandler->RegisterTagItem(
131, std::make_shared<AircraftFlowMeasureTagItem>(aircraftFlowMeasureMap));

// Create the dialog for displaying flow measures for an aircraft
auto ecfmpFlowMeasuresDialog = std::make_shared<AircraftFlowMeasuresDialog>();
container.dialogManager->AddDialog(
{IDD_FLOW_MEASURE_LIST,
"ECFMP Flow Measures",
reinterpret_cast<DLGPROC>(ecfmpFlowMeasuresDialog->WndProc), // NOLINT
reinterpret_cast<LPARAM>(ecfmpFlowMeasuresDialog.get()), // NOLINT
ecfmpFlowMeasuresDialog});

// Create the tag function that triggers the flow measure dialog
auto listAircraftFlowMeasuresTagFunctionHandler =
std::make_shared<ListAircraftFlowMeasures>(aircraftFlowMeasureMap, *container.dialogManager);
auto listAircraftFlowMeasuresTagFunction = Tag::TagFunction{
9023,
"ECFMP List Aircraft Flow Measures",
[listAircraftFlowMeasuresTagFunctionHandler](const auto& flightplan, const auto&, auto, const auto&) {
listAircraftFlowMeasuresTagFunctionHandler->ListForAircraft(flightplan);
}};
container.pluginFunctionHandlers->RegisterFunctionCall(listAircraftFlowMeasuresTagFunction);
}
} // namespace UKControllerPlugin::ECFMP
48 changes: 48 additions & 0 deletions src/plugin/ecfmp/ListAircraftFlowMeasures.cpp
@@ -0,0 +1,48 @@
#include "AircraftFlowMeasuresDialog.h"
#include "AircraftFlowMeasureMapInterface.h"
#include "ListAircraftFlowMeasures.h"
#include "dialog/DialogManager.h"
#include "euroscope/EuroScopeCFlightPlanInterface.h"
#include "helper/HelperFunctions.h"

namespace UKControllerPlugin::ECFMP {
ListAircraftFlowMeasures::ListAircraftFlowMeasures(
std::shared_ptr<const AircraftFlowMeasureMapInterface> flowMeasureMap,
const Dialog::DialogManager& dialogManager)
: flowMeasureMap(std::move(flowMeasureMap)), dialogManager(dialogManager)
{
assert(this->flowMeasureMap != nullptr && "Flow measure map cannot be null");
}

void ListAircraftFlowMeasures::ListForAircraft(const Euroscope::EuroScopeCFlightPlanInterface& flightplan)
{
const auto flowMeasuresForCallsign = flowMeasureMap->GetFlowMeasuresForCallsign(flightplan.GetCallsign());
if (flowMeasuresForCallsign.empty()) {
return;
}

// Write the flow measures to a string
std::string flowMeasureString;
for (const auto& flowMeasure : flowMeasuresForCallsign) {
flowMeasureString += "Measure: " + flowMeasure->Identifier() + "\r\n\r\n";
flowMeasureString += flowMeasure->Measure().MeasureDescription() + "\r\n\r\n";

flowMeasureString += "Applicable To:\r\n\r\n";

for (const auto& description : flowMeasure->Filters().FilterDescriptions()) {
flowMeasureString += description + "\r\n";
}

flowMeasureString += "\r\n";
flowMeasureString += "End of measure " + flowMeasure->Identifier() + "\r\n\r\n";
}

// Open dialog
AircraftFlowMeasuresDialogData dialogData{
.callsign = HelperFunctions::ConvertToWideString(flightplan.GetCallsign()),
.flowMeasures =
HelperFunctions::ConvertToWideString(flowMeasureString.substr(0, flowMeasureString.size() - 4))};

dialogManager.OpenDialog(IDD_FLOW_MEASURE_LIST, reinterpret_cast<LPARAM>(&dialogData));
}
} // namespace UKControllerPlugin::ECFMP
31 changes: 31 additions & 0 deletions src/plugin/ecfmp/ListAircraftFlowMeasures.h
@@ -0,0 +1,31 @@
#pragma once

namespace UKControllerPlugin {
namespace Dialog {
class DialogManager;
} // namespace Dialog
namespace Euroscope {
class EuroScopeCFlightPlanInterface;
} // namespace Euroscope
} // namespace UKControllerPlugin

namespace UKControllerPlugin::ECFMP {
class AircraftFlowMeasureMapInterface;

class ListAircraftFlowMeasures
{
public:
ListAircraftFlowMeasures(
std::shared_ptr<const AircraftFlowMeasureMapInterface> flowMeasureMap,
const Dialog::DialogManager& dialogManager);
void ListForAircraft(const Euroscope::EuroScopeCFlightPlanInterface& flightplan);

private:
// The flow measure map
std::shared_ptr<const AircraftFlowMeasureMapInterface> flowMeasureMap;

// Dialog manager
const Dialog::DialogManager& dialogManager;
};

} // namespace UKControllerPlugin::ECFMP
2 changes: 1 addition & 1 deletion test/plugin/CMakeLists.txt
Expand Up @@ -109,7 +109,7 @@ set(test__dependency
)
source_group("test\\dependency" FILES ${test__dependency})

set(test__ecfmp ecfmp/HttpClientTest.cpp ecfmp/TriggerEcfmpEventLoopTest.cpp ecfmp/ECFMPModuleFactoryTest.cpp ecfmp/ECFMPBootstrapProviderTest.cpp ecfmp/AircraftFlowMeasureMapTest.cpp ecfmp/AircraftFlowMeasureTagItemTest.cpp)
set(test__ecfmp ecfmp/HttpClientTest.cpp ecfmp/TriggerEcfmpEventLoopTest.cpp ecfmp/ECFMPModuleFactoryTest.cpp ecfmp/ECFMPBootstrapProviderTest.cpp ecfmp/AircraftFlowMeasureMapTest.cpp ecfmp/AircraftFlowMeasureTagItemTest.cpp ecfmp/ListAircraftFlowMeasuresTest.cpp ecfmp/HomeFirsFlowMeasureFilterTest.cpp)
source_group("test\\ecfmp" FILES ${test__ecfmp})

set(test__euroscope
Expand Down
21 changes: 20 additions & 1 deletion test/plugin/ecfmp/ECFMPBootstrapProviderTest.cpp
@@ -1,6 +1,9 @@
#include "dialog/DialogManager.h"
#include "ecfmp/ECFMPBootstrapProvider.h"
#include "test/BootstrapProviderTestCase.h"
#include "mock/MockDialogProvider.h"
#include "plugin/FunctionCallEventHandler.h"
#include "tag/TagItemCollection.h"
#include "test/BootstrapProviderTestCase.h"
#include "timedevent/TimedEventCollection.h"

namespace UKControllerPluginTest::ECFMP {
Expand All @@ -9,8 +12,10 @@ namespace UKControllerPluginTest::ECFMP {
public:
ECFMPBootstrapProviderTest()
{
container.dialogManager = std::make_unique<UKControllerPlugin::Dialog::DialogManager>(mockDialogProvider);
}

testing::NiceMock<Dialog::MockDialogProvider> mockDialogProvider;
UKControllerPlugin::ECFMP::ECFMPBootstrapProvider provider;
};

Expand All @@ -27,4 +32,18 @@ namespace UKControllerPluginTest::ECFMP {
EXPECT_EQ(1, container.tagHandler->CountHandlers());
EXPECT_EQ(1, container.tagHandler->HasHandlerForItemId(131));
}

TEST_F(ECFMPBootstrapProviderTest, ItRegistersTheFlowMeasuresDialog)
{
RunBootstrapPlugin(provider);
EXPECT_EQ(1, container.dialogManager->CountDialogs());
EXPECT_EQ(1, container.dialogManager->HasDialog(IDD_FLOW_MEASURE_LIST));
}

TEST_F(ECFMPBootstrapProviderTest, ItRegistersTheListFlowMeasuresTagFunction)
{
RunBootstrapPlugin(provider);
EXPECT_EQ(1, container.pluginFunctionHandlers->CountTagFunctions());
EXPECT_EQ(1, container.pluginFunctionHandlers->HasTagFunction(9023));
}
} // namespace UKControllerPluginTest::ECFMP

0 comments on commit a5d04ac

Please sign in to comment.