# Copyright 2022 (c) Anna Schumaker. """Easy access to the settings table in our database.""" import sqlite3 from gi.repository import GObject from . import idle from . import table class Setting(table.Row): """Base class for settings.""" key = GObject.Property(type=str) @property def primary_key(self) -> str: """Get the primary key for this setting.""" return self.key class IntSetting(Setting): """An integer setting.""" value = GObject.Property(type=int) class FloatSetting(Setting): """A float setting.""" value = GObject.Property(type=float) class BoolSetting(Setting): """A boolean setting.""" value = GObject.Property(type=bool, default=False) class StringSetting(Setting): """A string setting.""" value = GObject.Property(type=str) class Table(table.Table): """Creates and manages our settings properties.""" def __init__(self, sql: GObject.TYPE_PYOBJECT): """Initialize the settings table.""" super().__init__(sql, queue=idle.Queue(enabled=False)) def __getitem__(self, key: str) -> int | float | str | bool | None: """Get the value for a specific settings key.""" if (setting := self.lookup(key)) is not None: return setting.value def do_construct(self, type: str, value: any, **kwargs) -> table.Row: """Construct a new settings row.""" match type: case "gint": return IntSetting(value=int(value), **kwargs) case "gdouble": return FloatSetting(value=float(value), **kwargs) case "gboolean": value = str(value) == "True" return BoolSetting(value=value, **kwargs) case "gchararray": return StringSetting(value=value, **kwargs) def do_get_sort_key(self, setting: table.Row) -> list[str]: """Get the sort key for a specific setting.""" return setting.key.casefold().split(".") def do_sql_delete(self, setting: table.Row) -> sqlite3.Cursor: """Delete a setting.""" return self.sql("DELETE FROM settings WHERE key=?", setting.key) def do_sql_glob(self, glob: str) -> sqlite3.Cursor: """Filter the settings table.""" return self.sql("""SELECT key FROM settings WHERE CASEFOLD(key) GLOB ?""", glob) def do_sql_insert(self, key: str, type: str, value) -> sqlite3.Cursor: """Create a new settings row.""" return self.sql("""INSERT INTO settings (key, type, value) VALUES (?, ?, ?) RETURNING *""", key, type, str(value)) def do_sql_select_all(self) -> sqlite3.Cursor: """Load settings from the database.""" return self.sql("SELECT * FROM settings ORDER BY CASEFOLD(key)") def do_sql_select_one(self, key: str) -> int | None: """Look up a setting by key.""" return self.sql("SELECT key FROM settings WHERE key=?", key) def do_sql_update(self, setting: table.Row, column: str, newval: any) -> sqlite3.Cursor: """Update a Setting.""" return self.sql(f"UPDATE settings SET {column}=? WHERE key=?", str(newval), setting.key) def bind_setting(self, key: str, target: GObject.GObject, property: str) -> None: """Bind a setting to a target property.""" if (setting := self.lookup(key=key)) is None: param = target.find_property(property) setting = self.create(key=key, type=param.value_type.name, value=target.get_property(property)) else: target.set_property(property, setting.value) setting.bind_property("value", target, property, GObject.BindingFlags.BIDIRECTIONAL)