ui: add device selector to Set rule editor
This commit is contained in:
parent
3947a4a083
commit
6022c37325
|
@ -27,7 +27,6 @@ from math import sqrt as _sqrt
|
||||||
|
|
||||||
import _thread
|
import _thread
|
||||||
import psutil
|
import psutil
|
||||||
import solaar.ui.window as _window
|
|
||||||
|
|
||||||
from solaar.ui.config_panel import change_setting as _change_setting
|
from solaar.ui.config_panel import change_setting as _change_setting
|
||||||
from yaml import add_representer as _yaml_add_representer
|
from yaml import add_representer as _yaml_add_representer
|
||||||
|
@ -701,6 +700,9 @@ class Set(Action):
|
||||||
return 'Set: ' + ' '.join([str(a) for a in self.args])
|
return 'Set: ' + ' '.join([str(a) for a in self.args])
|
||||||
|
|
||||||
def evaluate(self, feature, notification, device, status, last_result):
|
def evaluate(self, feature, notification, device, status, last_result):
|
||||||
|
import solaar.ui.window as _window
|
||||||
|
# importing here to avoid circular imports
|
||||||
|
|
||||||
if len(self.args) < 3:
|
if len(self.args) < 3:
|
||||||
return None
|
return None
|
||||||
if _log.isEnabledFor(_INFO):
|
if _log.isEnabledFor(_INFO):
|
||||||
|
|
|
@ -96,7 +96,7 @@ def ui_async(function, *args, **kwargs):
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
from . import notify, tray, window # isort:skip # noqa: E402
|
from . import diversion_rules, notify, tray, window # isort:skip # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
def _startup(app, startup_hook, use_tray, show_window):
|
def _startup(app, startup_hook, use_tray, show_window):
|
||||||
|
@ -177,6 +177,7 @@ def _status_changed(device, alert, reason, refresh=False):
|
||||||
|
|
||||||
need_popup = alert & ALERT.SHOW_WINDOW
|
need_popup = alert & ALERT.SHOW_WINDOW
|
||||||
window.update(device, need_popup, refresh)
|
window.update(device, need_popup, refresh)
|
||||||
|
diversion_rules.update_devices()
|
||||||
|
|
||||||
if alert & (ALERT.NOTIFICATION | ALERT.ATTENTION):
|
if alert & (ALERT.NOTIFICATION | ALERT.ATTENTION):
|
||||||
notify.show(device, reason)
|
notify.show(device, reason)
|
||||||
|
|
|
@ -671,6 +671,10 @@ class DiversionDialog:
|
||||||
menu_copy.show()
|
menu_copy.show()
|
||||||
return menu_copy
|
return menu_copy
|
||||||
|
|
||||||
|
def update_devices(self):
|
||||||
|
for rc in self.ui.values():
|
||||||
|
rc.update_devices()
|
||||||
|
|
||||||
|
|
||||||
## Not currently used
|
## Not currently used
|
||||||
#
|
#
|
||||||
|
@ -763,6 +767,9 @@ class RuleComponentUI:
|
||||||
for c in self.panel.get_children():
|
for c in self.panel.get_children():
|
||||||
self.panel.remove(c)
|
self.panel.remove(c)
|
||||||
|
|
||||||
|
def update_devices(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedRuleComponentUI(RuleComponentUI):
|
class UnsupportedRuleComponentUI(RuleComponentUI):
|
||||||
|
|
||||||
|
@ -1597,6 +1604,30 @@ def _all_settings():
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
|
||||||
|
def _all_devices():
|
||||||
|
devices = []
|
||||||
|
|
||||||
|
def dev_in_row(_store, _treepath, row):
|
||||||
|
device = _dev_model.get_value(row, 7)
|
||||||
|
if device and device.kind:
|
||||||
|
devices.append(device)
|
||||||
|
|
||||||
|
_dev_model.foreach(dev_in_row)
|
||||||
|
return devices
|
||||||
|
|
||||||
|
|
||||||
|
def _device_display_name(device):
|
||||||
|
id = device.serial or device.unitId
|
||||||
|
name = device.codename
|
||||||
|
return name if not id else name + ' (' + id + ')'
|
||||||
|
|
||||||
|
|
||||||
|
def _find_device(devices, search):
|
||||||
|
if not search:
|
||||||
|
return None
|
||||||
|
return next((d for d in devices if search in [d.unitId, d.serial, _device_display_name(d)]), None)
|
||||||
|
|
||||||
|
|
||||||
class SetUI(ActionUI):
|
class SetUI(ActionUI):
|
||||||
|
|
||||||
CLASS = _DIV.Set
|
CLASS = _DIV.Set
|
||||||
|
@ -1606,21 +1637,16 @@ class SetUI(ActionUI):
|
||||||
MULTIPLE = [_SKIND.multiple_toggle, _SKIND.map_choice, _SKIND.multiple_range]
|
MULTIPLE = [_SKIND.multiple_toggle, _SKIND.map_choice, _SKIND.multiple_range]
|
||||||
|
|
||||||
def create_widgets(self):
|
def create_widgets(self):
|
||||||
|
self.devices = []
|
||||||
|
|
||||||
self.widgets = {}
|
self.widgets = {}
|
||||||
|
|
||||||
self._old_device_values = {}
|
lbl = Gtk.Label(_('Device'), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True, vexpand=True)
|
||||||
|
|
||||||
lbl = Gtk.Label(_('Same device'), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True, vexpand=True)
|
|
||||||
self.widgets[lbl] = (0, 0, 1, 1)
|
|
||||||
self.same_device_chk = Gtk.Switch()
|
|
||||||
self.same_device_chk.connect('state-set', self._changed_same_device)
|
|
||||||
self.widgets[self.same_device_chk] = (0, 1, 1, 1)
|
|
||||||
|
|
||||||
lbl = Gtk.Label(_('Serial or Unit ID'), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True, vexpand=True)
|
|
||||||
self.widgets[lbl] = (1, 0, 1, 1)
|
self.widgets[lbl] = (1, 0, 1, 1)
|
||||||
self.device_field = Gtk.ComboBoxText.new_with_entry()
|
self.device_field = Gtk.ComboBoxText.new_with_entry()
|
||||||
self.device_field.get_child().set_text('')
|
self.device_field.get_child().set_text('')
|
||||||
self.device_field.set_valign(Gtk.Align.START)
|
self.device_field.set_valign(Gtk.Align.START)
|
||||||
|
self.device_field.set_size_request(300, 0)
|
||||||
self.device_field.connect('changed', self._on_update)
|
self.device_field.connect('changed', self._on_update)
|
||||||
self.widgets[self.device_field] = (1, 1, 1, 1)
|
self.widgets[self.device_field] = (1, 1, 1, 1)
|
||||||
|
|
||||||
|
@ -1687,17 +1713,6 @@ class SetUI(ActionUI):
|
||||||
keys = None
|
keys = None
|
||||||
return setting, val_class, kind, keys
|
return setting, val_class, kind, keys
|
||||||
|
|
||||||
def _changed_same_device(self, *args):
|
|
||||||
same = self.same_device_chk.get_active()
|
|
||||||
if same:
|
|
||||||
self._old_device_values[self.component] = self.device_field.get_child().get_text()
|
|
||||||
self.device_field.get_child().set_text(_('[originating device]'))
|
|
||||||
self.device_field.set_sensitive(False)
|
|
||||||
else:
|
|
||||||
self.device_field.get_child().set_text(self._old_device_values.get(self.component, ''))
|
|
||||||
self.device_field.set_sensitive(True)
|
|
||||||
self.device_field.grab_focus()
|
|
||||||
|
|
||||||
def _changed_setting(self, *args):
|
def _changed_setting(self, *args):
|
||||||
setting_name = self.setting_field.get_active_id() or None
|
setting_name = self.setting_field.get_active_id() or None
|
||||||
setting, val_class, kind, keys = self._setting_attributes(setting_name)
|
setting, val_class, kind, keys = self._setting_attributes(setting_name)
|
||||||
|
@ -1719,11 +1734,34 @@ class SetUI(ActionUI):
|
||||||
CompletionEntry.add_completion_to_entry(self.key_field.get_child(), map(str, keys))
|
CompletionEntry.add_completion_to_entry(self.key_field.get_child(), map(str, keys))
|
||||||
for k in sorted(keys, key=str):
|
for k in sorted(keys, key=str):
|
||||||
self.key_field.append(str(int(k)), str(k))
|
self.key_field.append(str(int(k)), str(k))
|
||||||
self._update_visibility()
|
|
||||||
|
def update_devices(self):
|
||||||
|
device_value = self.collect_value()[0]
|
||||||
|
self.devices = _all_devices()
|
||||||
|
if not self.component:
|
||||||
|
return
|
||||||
|
self.device_field.remove_all()
|
||||||
|
self.device_field.append('', _('Originating device'))
|
||||||
|
acceptable_values = []
|
||||||
|
for device in self.devices:
|
||||||
|
display_name = _device_display_name(device)
|
||||||
|
acceptable_values += [display_name, device.unitId, device.serial]
|
||||||
|
self.device_field.append(device.serial or device.unitId, display_name)
|
||||||
|
CompletionEntry.add_completion_to_entry(self.device_field.get_child(), filter(lambda v: v, acceptable_values))
|
||||||
|
device = _find_device(self.devices, device_value)
|
||||||
|
with self.ignore_changes():
|
||||||
|
if device or not device_value:
|
||||||
|
self.device_field.set_active_id((device.serial or device.unitId) if device else '')
|
||||||
|
else:
|
||||||
|
self.device_field.get_child().set_text(device_value or '')
|
||||||
|
|
||||||
def _update_visibility(self):
|
def _update_visibility(self):
|
||||||
|
if not self.component:
|
||||||
|
return
|
||||||
a = iter(self.component.args)
|
a = iter(self.component.args)
|
||||||
next(a, None) # device - currently not checked
|
device_str = next(a, None)
|
||||||
|
icon = 'dialog-warning' if device_str and not _find_device(self.devices, device_str) else ''
|
||||||
|
self.device_field.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)
|
||||||
setting_name = next(a, '')
|
setting_name = next(a, '')
|
||||||
setting, val_class, kind, keys = self._setting_attributes(setting_name)
|
setting, val_class, kind, keys = self._setting_attributes(setting_name)
|
||||||
multiple = kind in self.MULTIPLE
|
multiple = kind in self.MULTIPLE
|
||||||
|
@ -1742,16 +1780,16 @@ class SetUI(ActionUI):
|
||||||
|
|
||||||
def show(self, component, editable):
|
def show(self, component, editable):
|
||||||
super().show(component, editable)
|
super().show(component, editable)
|
||||||
|
self.update_devices()
|
||||||
a = iter(component.args)
|
a = iter(component.args)
|
||||||
with self.ignore_changes():
|
with self.ignore_changes():
|
||||||
device = next(a, None)
|
device_str = next(a, None)
|
||||||
same = device is None
|
same = not device_str
|
||||||
self._old_device_values[self.component] = device or ''
|
device = _find_device(self.devices, device_str)
|
||||||
self.device_field.get_child().set_text(device or '')
|
if device or same:
|
||||||
if self.same_device_chk.get_active() != same:
|
self.device_field.set_active_id((device.serial or device.unitId) if device else '')
|
||||||
self.same_device_chk.set_active(same)
|
|
||||||
else:
|
else:
|
||||||
self._changed_same_device()
|
self.device_field.get_child().set_text(device_str or '')
|
||||||
setting_name = next(a, '')
|
setting_name = next(a, '')
|
||||||
setting, _v, kind, keys = self._setting_attributes(setting_name)
|
setting, _v, kind, keys = self._setting_attributes(setting_name)
|
||||||
self.setting_field.set_active_id(setting.name if setting else '')
|
self.setting_field.set_active_id(setting.name if setting else '')
|
||||||
|
@ -1766,8 +1804,12 @@ class SetUI(ActionUI):
|
||||||
self._update_visibility()
|
self._update_visibility()
|
||||||
|
|
||||||
def collect_value(self):
|
def collect_value(self):
|
||||||
same = self.same_device_chk.get_active()
|
device_str = self.device_field.get_active_id()
|
||||||
device = None if same else self.device_field.get_active_id() or self.device_field.get_active_text().strip()
|
if device_str is None:
|
||||||
|
device_str = self.device_field.get_active_text().strip()
|
||||||
|
same = device_str in ['', _('Originating device')]
|
||||||
|
device = None if same else _find_device(self.devices, device_str)
|
||||||
|
device_value = (device.serial or device.unitId) if device else None if same else device_str
|
||||||
setting_name = self.setting_field.get_active_id() or None
|
setting_name = self.setting_field.get_active_id() or None
|
||||||
setting, val_class, kind, keys = self._setting_attributes(setting_name)
|
setting, val_class, kind, keys = self._setting_attributes(setting_name)
|
||||||
key_value = []
|
key_value = []
|
||||||
|
@ -1776,16 +1818,18 @@ class SetUI(ActionUI):
|
||||||
key = _from_named_ints(key, keys)
|
key = _from_named_ints(key, keys)
|
||||||
key_value.append(keys[key] if keys else key)
|
key_value.append(keys[key] if keys else key)
|
||||||
key_value.append(self.value_field.get_value())
|
key_value.append(self.value_field.get_value())
|
||||||
return [device, setting_name, *key_value]
|
return [device_value, setting_name, *key_value]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def right_label(cls, component):
|
def right_label(cls, component):
|
||||||
a = iter(component.args)
|
a = iter(component.args)
|
||||||
device = next(a, None)
|
device_str = next(a, None)
|
||||||
disp = [_('[originating device]') if device is None else device]
|
device = None if not device_str else _find_device(_all_devices(), device_str)
|
||||||
|
device_disp = _('Originating device'
|
||||||
|
) if not device_str else _device_display_name(device) if device else shlex_quote(device_str)
|
||||||
setting_name = next(a, None)
|
setting_name = next(a, None)
|
||||||
setting, val_class, kind, keys = cls._setting_attributes(setting_name)
|
setting, val_class, kind, keys = cls._setting_attributes(setting_name)
|
||||||
disp.append(setting.label if setting else setting_name)
|
disp = [setting.label if setting else setting_name]
|
||||||
if kind in cls.MULTIPLE:
|
if kind in cls.MULTIPLE:
|
||||||
key = next(a, None)
|
key = next(a, None)
|
||||||
disp.append(_from_named_ints(key, keys) if keys else key)
|
disp.append(_from_named_ints(key, keys) if keys else key)
|
||||||
|
@ -1795,7 +1839,7 @@ class SetUI(ActionUI):
|
||||||
if all_values:
|
if all_values:
|
||||||
value = all_values[value]
|
value = all_values[value]
|
||||||
disp.append(value)
|
disp.append(value)
|
||||||
return ' '.join(map(lambda s: shlex_quote(str(s)), [*disp, *a]))
|
return device_disp + ': ' + ' '.join(map(lambda s: shlex_quote(str(s)), [*disp, *a]))
|
||||||
|
|
||||||
|
|
||||||
COMPONENT_UI = {
|
COMPONENT_UI = {
|
||||||
|
@ -1820,9 +1864,17 @@ COMPONENT_UI = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def show_window(trigger=None):
|
def update_devices():
|
||||||
|
global _diversion_dialog
|
||||||
|
if _diversion_dialog:
|
||||||
|
_diversion_dialog.update_devices()
|
||||||
|
|
||||||
|
|
||||||
|
def show_window(model):
|
||||||
GObject.type_register(RuleComponentWrapper)
|
GObject.type_register(RuleComponentWrapper)
|
||||||
global _diversion_dialog
|
global _diversion_dialog
|
||||||
|
global _dev_model
|
||||||
|
_dev_model = model
|
||||||
if _diversion_dialog is None:
|
if _diversion_dialog is None:
|
||||||
_diversion_dialog = DiversionDialog()
|
_diversion_dialog = DiversionDialog()
|
||||||
_diversion_dialog.window.present()
|
_diversion_dialog.window.present()
|
||||||
|
|
|
@ -323,7 +323,9 @@ def _create_window_layout():
|
||||||
bottom_buttons_box.add(quit_button)
|
bottom_buttons_box.add(quit_button)
|
||||||
about_button = _new_button(_('About %s') % NAME, 'help-about', _SMALL_BUTTON_ICON_SIZE, clicked=_show_about_window)
|
about_button = _new_button(_('About %s') % NAME, 'help-about', _SMALL_BUTTON_ICON_SIZE, clicked=_show_about_window)
|
||||||
bottom_buttons_box.add(about_button)
|
bottom_buttons_box.add(about_button)
|
||||||
diversion_button = _new_button(_('Rule Editor'), '', _SMALL_BUTTON_ICON_SIZE, clicked=_show_diversion_window)
|
diversion_button = _new_button(
|
||||||
|
_('Rule Editor'), '', _SMALL_BUTTON_ICON_SIZE, clicked=lambda *_trigger: _show_diversion_window(_model)
|
||||||
|
)
|
||||||
bottom_buttons_box.add(diversion_button)
|
bottom_buttons_box.add(diversion_button)
|
||||||
bottom_buttons_box.set_child_secondary(diversion_button, True)
|
bottom_buttons_box.set_child_secondary(diversion_button, True)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue