Skip to content

Commit 4e7cd35

Browse files
committed
feat(template overview): If an FC is connected only present templates for that vehicle type
1 parent 6369ebf commit 4e7cd35

8 files changed

+220
-24
lines changed

ardupilot_methodic_configurator/__main__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def component_editor(
164164
sys_exit(1)
165165

166166

167-
def main() -> None:
167+
def main() -> None: # pylint: disable=too-many-locals
168168
args = create_argument_parser().parse_args()
169169

170170
logging_basicConfig(level=logging_getLevelName(args.loglevel), format="%(asctime)s - %(levelname)s - %(message)s")
@@ -209,7 +209,9 @@ def main() -> None:
209209

210210
vehicle_dir_window = None
211211
if not files:
212-
vehicle_dir_window = VehicleDirectorySelectionWindow(local_filesystem, len(flight_controller.fc_parameters) > 0)
212+
fc_connected = len(flight_controller.fc_parameters) > 0
213+
connected_fc_vehicle_type = flight_controller.info.vehicle_type if fc_connected else ""
214+
vehicle_dir_window = VehicleDirectorySelectionWindow(local_filesystem, fc_connected, connected_fc_vehicle_type)
213215
vehicle_dir_window.root.mainloop()
214216

215217
component_editor(args, flight_controller, local_filesystem.vehicle_type, local_filesystem, vehicle_dir_window)

ardupilot_methodic_configurator/frontend_tkinter_directory_selection.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from ardupilot_methodic_configurator.frontend_tkinter_template_overview import TemplateOverviewWindow
3131

3232

33-
class DirectorySelectionWidgets:
33+
class DirectorySelectionWidgets: # pylint: disable=too-many-instance-attributes
3434
"""
3535
A class to manage directory selection widgets in the GUI.
3636
@@ -49,12 +49,14 @@ def __init__( # pylint: disable=too-many-arguments, too-many-positional-argumen
4949
dir_tooltip: str,
5050
button_tooltip: str,
5151
is_template_selection: bool,
52+
connected_fc_vehicle_type: str,
5253
) -> None:
5354
self.parent = parent
5455
self.directory: str = deepcopy(initialdir)
5556
self.label_text = label_text
5657
self.autoresize_width = autoresize_width
5758
self.is_template_selection = is_template_selection
59+
self.connected_fc_vehicle_type = connected_fc_vehicle_type
5860

5961
# Create a new frame for the directory selection label and button
6062
self.container_frame = ttk.Frame(parent_frame)
@@ -89,7 +91,7 @@ def __init__( # pylint: disable=too-many-arguments, too-many-positional-argumen
8991
def on_select_directory(self) -> bool:
9092
if self.is_template_selection:
9193
if isinstance(self.parent.root, tk.Tk): # this keeps mypy and pyright happy
92-
to = TemplateOverviewWindow(self.parent.root)
94+
to = TemplateOverviewWindow(self.parent.root, connected_fc_vehicle_type=self.connected_fc_vehicle_type)
9395
to.run_app()
9496
selected_directory = ProgramSettings.get_recently_used_dirs()[0]
9597
logging_info(_("Selected template directory: %s"), selected_directory)
@@ -158,6 +160,7 @@ def __init__( # pylint: disable=too-many-arguments, too-many-positional-argumen
158160
local_filesystem: LocalFilesystem,
159161
initial_dir: str,
160162
destroy_parent_on_open: bool,
163+
connected_fc_vehicle_type: str = "",
161164
) -> None:
162165
# Call the parent constructor with the necessary arguments
163166
super().__init__(
@@ -177,6 +180,7 @@ def __init__( # pylint: disable=too-many-arguments, too-many-positional-argumen
177180
if destroy_parent_on_open
178181
else "",
179182
is_template_selection=False,
183+
connected_fc_vehicle_type=connected_fc_vehicle_type,
180184
)
181185
self.local_filesystem = local_filesystem
182186
self.destroy_parent_on_open = destroy_parent_on_open
@@ -231,9 +235,12 @@ class VehicleDirectorySelectionWindow(BaseWindow): # pylint: disable=too-many-i
231235
vehicle configuration directory.
232236
"""
233237

234-
def __init__(self, local_filesystem: LocalFilesystem, fc_connected: bool = False) -> None:
238+
def __init__(
239+
self, local_filesystem: LocalFilesystem, fc_connected: bool = False, connected_fc_vehicle_type: str = ""
240+
) -> None:
235241
super().__init__()
236242
self.local_filesystem = local_filesystem
243+
self.connected_fc_vehicle_type = connected_fc_vehicle_type
237244
self.root.title(
238245
_("Amilcar Lucas's - ArduPilot methodic configurator ")
239246
+ __version__
@@ -259,7 +266,7 @@ def __init__(self, local_filesystem: LocalFilesystem, fc_connected: bool = False
259266
)
260267
introduction_label.pack(expand=False, fill=tk.X, padx=6, pady=6)
261268
template_dir, new_base_dir, vehicle_dir = LocalFilesystem.get_recently_used_dirs()
262-
self.create_option1_widgets(template_dir, new_base_dir, _("MyVehicleName"), fc_connected)
269+
self.create_option1_widgets(template_dir, new_base_dir, _("MyVehicleName"), fc_connected, connected_fc_vehicle_type)
263270
self.create_option2_widgets(vehicle_dir)
264271
self.create_option3_widgets(vehicle_dir)
265272

@@ -269,8 +276,13 @@ def __init__(self, local_filesystem: LocalFilesystem, fc_connected: bool = False
269276
def close_and_quit(self) -> None:
270277
sys_exit(0)
271278

272-
def create_option1_widgets( # pylint: disable=too-many-locals
273-
self, initial_template_dir: str, initial_base_dir: str, initial_new_dir: str, fc_connected: bool
279+
def create_option1_widgets( # pylint: disable=too-many-locals,too-many-arguments,too-many-positional-arguments
280+
self,
281+
initial_template_dir: str,
282+
initial_base_dir: str,
283+
initial_new_dir: str,
284+
fc_connected: bool,
285+
connected_fc_vehicle_type: str,
274286
) -> None:
275287
# Option 1 - Create a new vehicle configuration directory based on an existing template
276288
option1_label = ttk.Label(text=_("New vehicle"), style="Bold.TLabel")
@@ -293,6 +305,7 @@ def create_option1_widgets( # pylint: disable=too-many-locals
293305
dir_tooltip=template_dir_edit_tooltip,
294306
button_tooltip=template_dir_btn_tooltip,
295307
is_template_selection=True,
308+
connected_fc_vehicle_type=connected_fc_vehicle_type,
296309
)
297310
self.template_dir.container_frame.pack(expand=False, fill=tk.X, padx=3, pady=5, anchor=tk.NW)
298311
blank_component_data_checkbox = ttk.Checkbutton(
@@ -364,6 +377,7 @@ def create_option1_widgets( # pylint: disable=too-many-locals
364377
dir_tooltip=new_base_dir_edit_tooltip,
365378
button_tooltip=new_base_dir_btn_tooltip,
366379
is_template_selection=False,
380+
connected_fc_vehicle_type="",
367381
)
368382
self.new_base_dir.container_frame.pack(expand=False, fill=tk.X, padx=3, pady=5, anchor=tk.NW)
369383
new_dir_edit_tooltip = _(
@@ -404,7 +418,12 @@ def create_option2_widgets(self, initial_dir: str) -> None:
404418
)
405419
option2_label.pack(expand=False, fill=tk.X, padx=6)
406420
self.connection_selection_widgets = VehicleDirectorySelectionWidgets(
407-
self, option2_label_frame, self.local_filesystem, initial_dir, destroy_parent_on_open=True
421+
self,
422+
option2_label_frame,
423+
self.local_filesystem,
424+
initial_dir,
425+
destroy_parent_on_open=True,
426+
connected_fc_vehicle_type=self.connected_fc_vehicle_type,
408427
)
409428
self.connection_selection_widgets.container_frame.pack(expand=True, fill=tk.X, padx=3, pady=5, anchor=tk.NW)
410429

@@ -423,6 +442,7 @@ def create_option3_widgets(self, last_vehicle_dir: str) -> None:
423442
dir_tooltip=_("Last used vehicle configuration directory"),
424443
button_tooltip="",
425444
is_template_selection=False,
445+
connected_fc_vehicle_type="",
426446
)
427447
last_dir.container_frame.pack(expand=False, fill=tk.X, padx=3, pady=5, anchor=tk.NW)
428448

ardupilot_methodic_configurator/frontend_tkinter_parameter_editor.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,14 @@ def __create_conf_widgets(self, version: str) -> None:
205205

206206
# Create a new frame inside the config_subframe for the intermediate parameter file directory selection labels
207207
# and directory selection button
208+
connected_vehicle_type = self.flight_controller.info.vehicle_type if self.flight_controller.info.vehicle_type else ""
208209
directory_selection_frame = VehicleDirectorySelectionWidgets(
209-
self, config_subframe, self.local_filesystem, self.local_filesystem.vehicle_dir, destroy_parent_on_open=False
210+
self,
211+
config_subframe,
212+
self.local_filesystem,
213+
self.local_filesystem.vehicle_dir,
214+
destroy_parent_on_open=False,
215+
connected_fc_vehicle_type=connected_vehicle_type,
210216
)
211217
if self.gui_complexity != "simple":
212218
directory_selection_frame.container_frame.pack(side=tk.LEFT, fill="x", expand=False, padx=(4, 6))

ardupilot_methodic_configurator/frontend_tkinter_template_overview.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def __init__(
7777
parent: Optional[tk.Tk] = None,
7878
vehicle_components_provider: Optional[VehicleComponentsProviderProtocol] = None,
7979
program_settings_provider: Optional[ProgramSettingsProviderProtocol] = None,
80+
connected_fc_vehicle_type: Optional[str] = None,
8081
) -> None:
8182
"""
8283
Initialize the TemplateOverviewWindow.
@@ -85,6 +86,7 @@ def __init__(
8586
parent: Optional parent Tk window
8687
vehicle_components_provider: Optional provider for vehicle components (for dependency injection)
8788
program_settings_provider: Optional provider for program settings (for dependency injection)
89+
connected_fc_vehicle_type: Optional firmware type of connected flight controller for filtering templates
8890
8991
"""
9092
super().__init__(parent)
@@ -101,7 +103,7 @@ def __init__(
101103
self._configure_window()
102104
self._initialize_ui_components()
103105
self._setup_layout()
104-
self._configure_treeview()
106+
self._configure_treeview(connected_fc_vehicle_type or "")
105107
self._bind_events()
106108

107109
def _configure_window(self) -> None:
@@ -163,11 +165,11 @@ def run_app(self) -> None:
163165
elif isinstance(self.root, tk.Tk):
164166
self.root.mainloop()
165167

166-
def _configure_treeview(self) -> None:
168+
def _configure_treeview(self, connected_fc_vehicle_type: str) -> None:
167169
"""Configure the treeview with styling and data."""
168170
self._setup_treeview_style()
169171
self._setup_treeview_columns()
170-
self._populate_treeview()
172+
self._populate_treeview(connected_fc_vehicle_type)
171173
self._adjust_treeview_column_widths()
172174
self.tree.pack(fill=tk.BOTH, expand=True)
173175

@@ -213,11 +215,19 @@ def _setup_treeview_columns(self) -> None:
213215
for col in self.tree["columns"]:
214216
self.tree.heading(col, text=col)
215217

216-
def _populate_treeview(self) -> None:
217-
"""Populate the treeview with data from vehicle components."""
218+
def _populate_treeview(self, connected_fc_vehicle_type: str) -> None:
219+
"""
220+
Populate the treeview with data from vehicle components.
221+
222+
Args:
223+
connected_fc_vehicle_type: Optional firmware type to filter templates by
224+
225+
"""
218226
for key, template_overview in self.vehicle_components_provider.get_vehicle_components_overviews().items():
219227
attribute_names = template_overview.attributes()
220228
values = (key, *(getattr(template_overview, attr, "") for attr in attribute_names))
229+
if connected_fc_vehicle_type and connected_fc_vehicle_type not in key:
230+
continue
221231
self.tree.insert("", "end", text=key, values=values)
222232

223233
def _adjust_treeview_column_widths(self) -> None:

tests/test_frontend_tkinter_component_editor_base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from ardupilot_methodic_configurator.backend_filesystem_vehicle_components import VehicleComponents
2323
from ardupilot_methodic_configurator.data_model_vehicle_components import ComponentDataModel
2424
from ardupilot_methodic_configurator.frontend_tkinter_component_editor_base import (
25-
VEICLE_IMAGE_WIDTH_PIX,
25+
VEHICLE_IMAGE_WIDTH_PIX,
2626
WINDOW_WIDTH_PIX,
2727
ComponentEditorWindowBase,
2828
EntryWidget,
@@ -666,10 +666,10 @@ class TestModuleConstants:
666666
def test_window_dimensions_are_reasonable(self) -> None:
667667
"""Test that window dimensions are reasonable values."""
668668
assert WINDOW_WIDTH_PIX == 880
669-
assert VEICLE_IMAGE_WIDTH_PIX == 100
670-
assert WINDOW_WIDTH_PIX > VEICLE_IMAGE_WIDTH_PIX
669+
assert VEHICLE_IMAGE_WIDTH_PIX == 100
670+
assert WINDOW_WIDTH_PIX > VEHICLE_IMAGE_WIDTH_PIX
671671
assert WINDOW_WIDTH_PIX > 500 # Minimum reasonable width
672-
assert VEICLE_IMAGE_WIDTH_PIX > 50 # Minimum reasonable image width
672+
assert VEHICLE_IMAGE_WIDTH_PIX > 50 # Minimum reasonable image width
673673

674674
def test_entry_widget_type_alias_definition(self) -> None:
675675
"""Test that EntryWidget type alias is correctly defined."""

tests/test_frontend_tkinter_directory_selection.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ def directory_selection_widgets(root: tk.Tk, base_parent: MagicMock) -> Generato
151151
dir_tooltip="Test directory tooltip",
152152
button_tooltip="Select directory button tooltip",
153153
is_template_selection=False,
154+
connected_fc_vehicle_type="",
154155
)
155156
yield widget
156157

@@ -214,6 +215,7 @@ def test_directory_selection_widgets_template_selection(base_parent, root) -> No
214215
dir_tooltip="Template directory tooltip",
215216
button_tooltip="Select template button tooltip",
216217
is_template_selection=True,
218+
connected_fc_vehicle_type="ArduCopter",
217219
)
218220

219221
# Call the method to select a template
@@ -250,6 +252,7 @@ def test_directory_selection_widgets_autoresize_width(base_parent, root) -> None
250252
dir_tooltip="Tooltip",
251253
button_tooltip="Button tooltip",
252254
is_template_selection=False,
255+
connected_fc_vehicle_type="ArduCopter",
253256
)
254257

255258
# Test with autoresize_width=False
@@ -262,6 +265,7 @@ def test_directory_selection_widgets_autoresize_width(base_parent, root) -> None
262265
dir_tooltip="Another tooltip",
263266
button_tooltip="Another button tooltip",
264267
is_template_selection=False,
268+
connected_fc_vehicle_type="ArduCopter",
265269
)
266270

267271
# Verify the difference in behavior when selecting a directory
@@ -297,6 +301,7 @@ def test_directory_selection_widgets_extremely_long_path(base_parent, root) -> N
297301
dir_tooltip="Test tooltip",
298302
button_tooltip="Button tooltip",
299303
is_template_selection=False,
304+
connected_fc_vehicle_type="ArduCopter",
300305
)
301306

302307
# Create an extremely long path
@@ -335,6 +340,7 @@ def test_directory_selection_widgets_special_characters(base_parent, root) -> No
335340
dir_tooltip="Test tooltip",
336341
button_tooltip="Button tooltip",
337342
is_template_selection=False,
343+
connected_fc_vehicle_type="ArduCopter",
338344
)
339345

340346
# Test with paths containing special characters
@@ -1165,11 +1171,19 @@ def test_create_option1_widgets(root, photo_patcher, icon_patcher, mock_local_fi
11651171
with patch.object(window, "create_option1_widgets", mock_create_option1):
11661172
# Call the method via the patched object
11671173
window.create_option1_widgets(
1168-
"/template/dir", "/base/dir", "vehicle_name", fc_connected=True
1174+
"/template/dir",
1175+
"/base/dir",
1176+
"vehicle_name",
1177+
fc_connected=True,
1178+
connected_fc_vehicle_type="ArduCopter",
11691179
)
11701180
# Verify it was called with the correct arguments
11711181
mock_create_option1.assert_called_once_with(
1172-
"/template/dir", "/base/dir", "vehicle_name", fc_connected=True
1182+
"/template/dir",
1183+
"/base/dir",
1184+
"vehicle_name",
1185+
fc_connected=True,
1186+
connected_fc_vehicle_type="ArduCopter",
11731187
)
11741188

11751189

@@ -1203,6 +1217,7 @@ def test_ui_interaction_directory_selection_widgets() -> None:
12031217
dir_tooltip="Test tooltip",
12041218
button_tooltip="Select directory",
12051219
is_template_selection=True,
1220+
connected_fc_vehicle_type="ArduCopter",
12061221
)
12071222

12081223
# Verify initial state

tests/test_frontend_tkinter_directory_selection_integration.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ def test_directory_selection_widgets_interaction(root: tk.Tk, monkeypatch: pytes
345345
dir_tooltip="Test tooltip",
346346
button_tooltip="Select directory",
347347
is_template_selection=False,
348+
connected_fc_vehicle_type="ArduCopter",
348349
)
349350

350351
# Update UI
@@ -383,6 +384,7 @@ def test_keyboard_navigation(root: tk.Tk, monkeypatch: pytest.MonkeyPatch) -> No
383384
dir_tooltip="Test tooltip",
384385
button_tooltip="Test button tooltip",
385386
is_template_selection=False,
387+
connected_fc_vehicle_type="ArduCopter",
386388
)
387389

388390
# Ensure widgets are created and displayed

0 commit comments

Comments
 (0)