Source code for sublime_music.ui.configure_provider
import uuid
from enum import Enum
from typing import Any, Optional, Type
from gi.repository import Gio, GObject, Gtk, Pango
from ..adapters import AdapterManager, UIInfo
from ..adapters.filesystem import FilesystemAdapter
from ..config import ConfigurationStore, ProviderConfiguration
[docs]class AdapterTypeModel(GObject.GObject):
adapter_type = GObject.Property(type=object)
[docs] def __init__(self, adapter_type: Type):
GObject.GObject.__init__(self)
self.adapter_type = adapter_type
[docs]class ConfigureProviderDialog(Gtk.Dialog):
_current_index = -1
stage = DialogStage.SELECT_ADAPTER
[docs] def set_title(self, editing: bool, provider_config: ProviderConfiguration | None = None):
if editing:
assert provider_config is not None
title = f"Edit {provider_config.name}"
else:
title = "Add New Music Source"
self.header.props.title = title
[docs] def __init__(self, parent: Any, provider_config: Optional[ProviderConfiguration]):
Gtk.Dialog.__init__(self, transient_for=parent, flags=Gtk.DialogFlags.MODAL)
self.provider_config = provider_config
self.editing = provider_config is not None
self.set_default_size(400, 350)
# HEADER
self.header = Gtk.HeaderBar()
self.set_title(self.editing, provider_config)
self.cancel_back_button = Gtk.Button(label="Cancel")
self.cancel_back_button.connect("clicked", self._on_cancel_back_clicked)
self.header.pack_start(self.cancel_back_button)
self.next_add_button = Gtk.Button(label="Edit" if self.editing else "Next")
self.next_add_button.get_style_context().add_class("suggested-action")
self.next_add_button.connect("clicked", self._on_next_add_clicked)
self.header.pack_end(self.next_add_button)
self.set_titlebar(self.header)
content_area = self.get_content_area()
self.stack = Gtk.Stack()
self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
# ADAPTER TYPE OPTIONS
adapter_type_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.adapter_type_store = Gio.ListStore()
self.adapter_options_list = Gtk.ListBox(
name="ground-truth-adapter-options-list", activate_on_single_click=False
)
self.adapter_options_list.connect("row-activated", self._on_next_add_clicked)
def create_row(model: AdapterTypeModel) -> Gtk.ListBoxRow:
ui_info: UIInfo = model.adapter_type.get_ui_info()
row = Gtk.ListBoxRow()
rowbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
rowbox.pack_start(
Gtk.Image.new_from_icon_name(ui_info.icon_name(), Gtk.IconSize.DND),
False,
False,
5,
)
rowbox.add(
Gtk.Label(
label=f"<b>{ui_info.name}</b>\n{ui_info.description}",
use_markup=True,
margin=8,
halign=Gtk.Align.START,
ellipsize=Pango.EllipsizeMode.END,
)
)
row.add(rowbox)
row.show_all()
return row
self.adapter_options_list.bind_model(self.adapter_type_store, create_row)
available_ground_truth_adapters = filter(
lambda a: a.can_be_ground_truth, AdapterManager.available_adapters
)
for adapter_type in sorted(
available_ground_truth_adapters, key=lambda a: a.get_ui_info().name
):
self.adapter_type_store.append(AdapterTypeModel(adapter_type))
adapter_type_box.pack_start(self.adapter_options_list, True, True, 10)
self.stack.add_named(adapter_type_box, "select")
self.configure_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.stack.add_named(self.configure_box, "configure")
content_area.pack_start(self.stack, True, True, 0)
self.show_all()
if self.editing:
assert self.provider_config
for i, adapter_type in enumerate(self.adapter_type_store):
if adapter_type.adapter_type == self.provider_config.ground_truth_adapter_type:
row = self.adapter_options_list.get_row_at_index(i)
self.adapter_options_list.select_row(row)
break
self._name_is_valid = True
self._on_next_add_clicked()
def _on_cancel_back_clicked(self, _):
if self.stage == DialogStage.SELECT_ADAPTER:
self.close()
else:
self.stack.set_visible_child_name("select")
self.stage = DialogStage.SELECT_ADAPTER
self.cancel_back_button.set_label("Cancel")
self.next_add_button.set_label("Next")
self.next_add_button.set_sensitive(True)
def _on_next_add_clicked(self, *args):
if self.stage == DialogStage.SELECT_ADAPTER:
index = self.adapter_options_list.get_selected_row().get_index()
if index != self._current_index:
for c in self.configure_box.get_children():
self.configure_box.remove(c)
name_entry_grid = Gtk.Grid(
column_spacing=10,
row_spacing=5,
margin_left=10,
margin_right=10,
name="music-source-config-name-entry-grid",
)
name_label = Gtk.Label(label="Music Source Name:")
name_entry_grid.attach(name_label, 0, 0, 1, 1)
self.name_field = Gtk.Entry(
text=self.provider_config.name if self.provider_config else "",
hexpand=True,
)
self.name_field.connect("changed", self._on_name_change)
name_entry_grid.attach(self.name_field, 1, 0, 1, 1)
self.configure_box.add(name_entry_grid)
self.configure_box.add(Gtk.Separator())
self.adapter_type = self.adapter_type_store[index].adapter_type
self.config_store = (
self.provider_config.ground_truth_adapter_config
if self.provider_config
else ConfigurationStore()
)
form = self.adapter_type.get_configuration_form(self.config_store)
form.connect("config-valid-changed", self._on_config_form_valid_changed)
self.configure_box.pack_start(form, True, True, 0)
self.configure_box.show_all()
self._adapter_config_is_valid = False
self.stack.set_visible_child_name("configure")
self.stage = DialogStage.CONFIGURE_ADAPTER
self.cancel_back_button.set_label("Change Type" if self.editing else "Back")
self.next_add_button.set_label("Edit" if self.editing else "Add")
self.next_add_button.set_sensitive(
index == self._current_index and self._adapter_config_is_valid
)
self._current_index = index
else:
if self.provider_config is None:
self.provider_config = ProviderConfiguration(
str(uuid.uuid4()),
self.name_field.get_text(),
self.adapter_type,
self.config_store,
)
if self.adapter_type.can_be_cached:
self.provider_config.caching_adapter_type = FilesystemAdapter
self.provider_config.caching_adapter_config = ConfigurationStore()
else:
self.provider_config.name = self.name_field.get_text()
self.provider_config.ground_truth_adapter_config = self.config_store
self.response(Gtk.ResponseType.APPLY)
_name_is_valid = False
_adapter_config_is_valid = False
def _update_add_button_sensitive(self):
self.next_add_button.set_sensitive(self._name_is_valid and self._adapter_config_is_valid)
def _on_name_change(self, entry: Gtk.Entry):
if entry.get_text():
self._name_is_valid = True
entry.get_style_context().remove_class("invalid")
entry.set_tooltip_markup(None)
if self.editing:
assert self.provider_config
self.provider_config.name = entry.get_text()
self.set_title(self.editing, self.provider_config)
else:
self._name_is_valid = False
entry.get_style_context().add_class("invalid")
entry.set_tooltip_markup("This field is required")
self._update_add_button_sensitive()
def _on_config_form_valid_changed(self, _, valid: bool):
self._adapter_config_is_valid = valid
self._update_add_button_sensitive()