From 63e8a4661e33edc0acf6cbb3ad5e45bd77fa7c7c Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Thu, 29 Aug 2024 19:23:49 -0700 Subject: [PATCH] Expose detected model variants in clone box This should make it more obvious for people looking for model variantions (like RT95 VOX). Related to #11509 --- chirp/wxui/clone.py | 52 +++++++++++++++++++++++++---- tests/unit/test_wxui_radiothread.py | 18 ++++++++++ 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/chirp/wxui/clone.py b/chirp/wxui/clone.py index 9591fa385..2ba15fc2a 100644 --- a/chirp/wxui/clone.py +++ b/chirp/wxui/clone.py @@ -247,6 +247,34 @@ def model_value(rclass): return ('%s %s' % (rclass.MODEL, rclass.VARIANT)).strip() +def detected_value(parent_rclass, rclass): + """Try to calculate a label for detected classes. + + This should be short and only represent the difference between them (like + a VARIANT or different MODEL). + """ + if parent_rclass.MODEL != rclass.MODEL: + # If the model is different, use that + label = rclass.MODEL + # If the detected class is a modified MODEL (i.e. 'RT95' and 'RT95 VOX' + # then strip off the prefix and the delimiter, if any. + if label.startswith(parent_rclass.MODEL): + label = label.replace(parent_rclass.MODEL, '').strip(' -_') + else: + # Assume the VARIANT is the distinguisher + label = rclass.VARIANT + + # In case the detected class is a different vendor, prefix that + if parent_rclass.VENDOR != rclass.VENDOR: + label = '%s %s' % (rclass.VENDOR, label) + + label = label.strip() + if not label: + LOG.error('Calculated blank detected value of %s from %s', + rclass, parent_rclass) + return label + + # Make this global so it sticks for a session CUSTOM_PORTS = [] @@ -284,7 +312,8 @@ def _add_grid(label, control): _add_grid(_('Vendor'), self._vendor) self.Bind(wx.EVT_CHOICE, self._selected_vendor, self._vendor) - self._model = wx.Choice(self, choices=[]) + self._model_choices = [] + self._model = wx.Choice(self, choices=self._model_choices) _add_grid(_('Model'), self._model) self.Bind(wx.EVT_CHOICE, self._selected_model, self._model) @@ -475,9 +504,19 @@ def _selected_port(self, event): self._persist_choices() def _select_vendor(self, vendor): - models = [model_value(x) - for x in self._vendors[vendor]] - self._model.Set(models) + display_models = [] + actual_models = [] + for rclass in self._vendors[vendor]: + display = model_value(rclass) + actual_models.append(display) + detected = ','.join(detected_value(rclass, x) for x in + rclass.detected_models(include_self=False)) + if detected: + display += ' (+ %s)' % detected + display_models.append(display) + + self._model_choices = actual_models + self._model.Set(display_models) self._model.SetSelection(0) def _selected_vendor(self, event): @@ -490,7 +529,7 @@ def _selected_model(self, event): def select_vendor_model(self, vendor, model): self._vendor.SetSelection(self._vendor.GetItems().index(vendor)) self._select_vendor(vendor) - self._model.SetSelection(self._model.GetItems().index(model)) + self._model.SetSelection(self._model_choices.index(model)) def _status(self, status): def _safe_status(): @@ -635,7 +674,8 @@ def _action(self, event): def _persist_choices(self): # On download, persist the selections from the actual UI boxes CONF.set('last_vendor', self._vendor.GetStringSelection(), 'state') - CONF.set('last_model', self._model.GetStringSelection(), 'state') + CONF.set('last_model', self._model_choices[self._model.GetSelection()], + 'state') CONF.set('last_port', self.get_selected_port(), 'state') diff --git a/tests/unit/test_wxui_radiothread.py b/tests/unit/test_wxui_radiothread.py index 9039ab4eb..02770341e 100644 --- a/tests/unit/test_wxui_radiothread.py +++ b/tests/unit/test_wxui_radiothread.py @@ -16,6 +16,8 @@ # These need to be imported after the above mock so that we don't require # wx to be present for these tests from tests.unit import base # noqa +from chirp import chirp_common # noqa +from chirp import directory # noqa from chirp.wxui import clone # noqa from chirp.wxui import config # noqa from chirp.wxui import radiothread # noqa @@ -156,6 +158,22 @@ def test_sort_ports_windows(self, system): [clone.port_label(p) for p in sorted(ports, key=clone.port_sort_key)]) + def test_detected_model_labels(self): + # Make sure all our detected model labels will be reasonable + # (and nonzero) in length. If the full label is too long, it will not + # be visible in the model box. + for rclass in [x for x in directory.DRV_TO_RADIO.values() + if issubclass(x, chirp_common.DetectableInterface)]: + labels = [] + for child_rclass in rclass.detected_models(include_self=False): + label = clone.detected_value(rclass, child_rclass) + self.assertNotEqual('', label) + labels.append(label) + if labels: + label = '%s (+ %s)' % (rclass.MODEL, ','.join(labels)) + self.assertLessEqual(len(label), 32, + 'Label %r is too long' % label) + class TestException(Exception): pass