-
-
Notifications
You must be signed in to change notification settings - Fork 204
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
396 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,177 @@ | ||
from gettext import gettext as _ | ||
from typing import Optional, Tuple | ||
from typing import Any, Optional, Tuple | ||
import logging | ||
|
||
from blueman.bluez.Device import Device | ||
from blueman.gui.DeviceList import DeviceList | ||
from blueman.gui.DeviceSelectorWidget import DeviceSelectorWidget | ||
from blueman.bluez.Device import Device, AnyDevice | ||
from blueman.bluez.Manager import Manager | ||
from blueman.Functions import adapter_path_to_name | ||
from blueman.bluemantyping import ObjectPath | ||
from blueman.main.Builder import Builder | ||
|
||
import gi | ||
gi.require_version("Gtk", "3.0") | ||
from gi.repository import Gtk | ||
|
||
|
||
class DeviceSelectorDialog(Gtk.Dialog): | ||
selection: Optional[Tuple[str, Optional[Device]]] | ||
class DeviceRow(Gtk.ListBoxRow): | ||
def __init__( | ||
self, | ||
device_path: ObjectPath, | ||
adapter_path: ObjectPath = "/org/bluez/hci0", | ||
device_icon: str = "blueman", | ||
alias: str = _("Unnamed device"), | ||
paired: bool = False, | ||
trusted: bool = False | ||
) -> None: | ||
super().__init__() | ||
|
||
def __init__(self, title: str = _("Select Device"), parent: Optional[Gtk.Container] = None, discover: bool = True, | ||
adapter_name: Optional[str] = None) -> None: | ||
super().__init__(title=title, name="DeviceSelectorDialog", parent=parent, icon_name="blueman", resizable=False) | ||
self.add_buttons(_("_Cancel"), Gtk.ResponseType.REJECT, _("_OK"), Gtk.ResponseType.ACCEPT) | ||
self.adapter_path = adapter_path | ||
self.device_path = device_path | ||
builder = Builder("sendto-rowbox.ui") | ||
self.__box = builder.get_widget("row_box", Gtk.Box) | ||
self._device_icon = builder.get_widget("row_icon", Gtk.Image) | ||
self._row_label = builder.get_widget("row_label", Gtk.Label) | ||
self._row_paired = builder.get_widget("revealer_paired", Gtk.Revealer) | ||
self._row_trusted = builder.get_widget("revealer_trusted", Gtk.Revealer) | ||
|
||
self.vbox.props.halign = Gtk.Align.CENTER | ||
self.vbox.props.valign = Gtk.Align.CENTER | ||
self.vbox.props.hexpand = True | ||
self.vbox.props.vexpand = True | ||
self.vbox.props.margin = 6 | ||
self.add(self.__box) | ||
|
||
self.selector = DeviceSelectorWidget(adapter_name=adapter_name, visible=True) | ||
self.vbox.pack_start(self.selector, True, True, 0) | ||
self.device_icon_name = device_icon | ||
self.row_description = f"{alias} ({adapter_path_to_name(adapter_path)})" | ||
self.paired = paired | ||
self.trusted = trusted | ||
|
||
selected_device = self.selector.List.get_selected_device() | ||
if selected_device is not None: | ||
self.selection = selected_device["Adapter"], selected_device | ||
@property | ||
def device_icon_name(self) -> str: | ||
return self._device_icon.get_icon_name() | ||
|
||
@device_icon_name.setter | ||
def device_icon_name(self, icon_name: str) -> None: | ||
self._device_icon.set_from_icon_name(icon_name, size=Gtk.IconSize.SMALL_TOOLBAR) | ||
|
||
@property | ||
def row_description(self) -> str: | ||
return self._row_label.get_label() | ||
|
||
@row_description.setter | ||
def row_description(self, text: str) -> None: | ||
self._row_label.set_label(text) | ||
|
||
@property | ||
def paired(self) -> bool: | ||
return self._row_paired.get_reveal_child() | ||
|
||
@paired.setter | ||
def paired(self, paired: bool) -> None: | ||
self._row_paired.set_reveal_child(paired) | ||
|
||
@property | ||
def trusted(self) -> bool: | ||
return self._row_trusted.get_reveal_child() | ||
|
||
@trusted.setter | ||
def trusted(self, trusted: bool): | ||
self._row_trusted.set_reveal_child(trusted) | ||
|
||
|
||
class DeviceSelector: | ||
selection: Optional[Tuple[ObjectPath, Optional[ObjectPath]]] | ||
|
||
def __init__(self, discover: bool = True, adapter_name: str = "any") -> None: | ||
self._rows: dict[ObjectPath, DeviceRow] = {} | ||
builder = Builder("sendto-device-dialog.ui") | ||
self.dialog = builder.get_widget("select_device_dialog", Gtk.Dialog) | ||
self._adapter_combo = builder.get_widget("adapter_combo", Gtk.ComboBox) | ||
|
||
self._listbox = builder.get_widget("device_listbox", Gtk.ListBox) | ||
self._listbox.set_filter_func(self.__list_filter_func) | ||
self._listbox.connect("row-selected", self.__on_row_selected) | ||
|
||
self._manager = Manager() | ||
self.__any_device = AnyDevice() | ||
|
||
adapter_names = sorted([adapter_path_to_name(a.get_object_path()) for a in self._manager.get_adapters()]) | ||
for name in adapter_names: | ||
pos = int(name[-1]) + 1 | ||
self._adapter_combo.insert(pos, name, name) | ||
|
||
self._adapter_combo.connect("changed", lambda _: self._listbox.invalidate_filter()) | ||
if adapter_name in adapter_names: | ||
self._adapter_combo.set_active_id(adapter_name) | ||
else: | ||
self.selection = None | ||
logging.debug(adapter_names) | ||
logging.debug(adapter_name) | ||
logging.warning(f"Adapter {adapter_name} not found!") | ||
|
||
self.selector.List.connect("device-selected", self.on_device_selected) | ||
self.selector.List.connect("adapter-changed", self.on_adapter_changed) | ||
if discover: | ||
self.selector.List.discover_devices() | ||
self._manager.connect_signal("adapter-added", self.__on_manager_signal, "adapter-added") | ||
self._manager.connect_signal("adapter-removed", self.__on_manager_signal, "adapter-removed") | ||
self._manager.connect_signal("device-created", self.__on_manager_signal, "device-added") | ||
self._manager.connect_signal("device-removed", self.__on_manager_signal, "device-removed") | ||
|
||
self.selector.List.connect("row-activated", self.on_row_activated) | ||
self.__any_device.connect_signal("property-changed", self.__on_device_property_changed) | ||
|
||
def close(self) -> None: | ||
self.selector.destroy() | ||
super().close() | ||
self._manager.populate_devices() | ||
|
||
def __list_filter_func(self, row: Gtk.ListBoxRow) -> bool: | ||
active_id = self._adapter_combo.get_active_id() | ||
adapter_name = adapter_path_to_name(row.adapter_path) | ||
if active_id == "any" or active_id == adapter_name: | ||
return True | ||
else: | ||
return False | ||
|
||
def __on_manager_signal(self, _manager: Manager, object_path: ObjectPath, signal_name: str): | ||
logging.debug(f"{object_path} {signal_name}") | ||
match signal_name: | ||
case "adapter-added": | ||
adapter_name = adapter_path_to_name(object_path) | ||
pos = int(adapter_name[-1]) + 1 | ||
self._adapter_combo.insert(pos, adapter_name, adapter_name) | ||
self._manager.populate_devices(adapter_path=object_path) | ||
case "adapter-removed": | ||
for key in self._rows: | ||
if self._rows[key].adapter_path == object_path: | ||
row = self._rows.pop(key) | ||
self._listbox.remove(row) | ||
|
||
def on_row_activated(self, _treeview: Gtk.TreeView, _path: Gtk.TreePath, _view_column: Gtk.TreeViewColumn, | ||
*_args: object) -> None: | ||
self.response(Gtk.ResponseType.ACCEPT) | ||
adapter_name = adapter_path_to_name(object_path) | ||
if adapter_name == self._adapter_combo.set_active_id: | ||
self._adapter_combo.set_active_id(adapter_name) | ||
|
||
def on_adapter_changed(self, _devlist: DeviceList, _adapter: str) -> None: | ||
self.selection = None | ||
pos = int(adapter_name[-1]) + 1 | ||
self._adapter_combo.remove(pos) | ||
|
||
def on_device_selected(self, devlist: DeviceList, device: Optional[Device], _tree_iter: Gtk.TreeIter) -> None: | ||
assert devlist.Adapter is not None | ||
self.selection = (devlist.Adapter.get_object_path(), device) | ||
case "device-added": | ||
props = Device(obj_path=object_path).get_properties() | ||
row = DeviceRow(object_path, props["Adapter"], props["Icon"], props['Alias'], props["Paired"], props["Trusted"]) | ||
row.show_all() | ||
self._listbox.add(row) | ||
self._rows[object_path] = row | ||
case "device-removed": | ||
row = self._rows.pop(object_path) | ||
self._listbox.remove(row) | ||
case _: | ||
raise ValueError(f"Unhandled signal {signal_name}") | ||
|
||
def __on_device_property_changed(self, _device: AnyDevice, key: str, value: Any, object_path: ObjectPath) -> None: | ||
row = self._rows.get(object_path, None) | ||
if row is None: | ||
return | ||
|
||
match key: | ||
case "Trusted": | ||
row.trusted = value | ||
case "Paired": | ||
row.paired = value | ||
|
||
def __on_row_selected(self, _listbox, row): | ||
logging.debug(f"{row.device_path}") | ||
device = Device(obj_path=row.device_path) | ||
self.selection = row.adapter_path, device | ||
|
||
def run(self) -> int: | ||
return self.dialog.run() | ||
|
||
def close(self) -> None: | ||
# FIXME implement a destroy method self.selector.destroy() | ||
self.dialog.close() |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.