auto-sd-paint-ext/frontends/krita/krita_diff/config.py

88 lines
3.2 KiB
Python

from dataclasses import asdict
from typing import Any
from krita import QObject, QReadWriteLock, QSettings
from .defaults import CFG_FOLDER, CFG_NAME, DEFAULTS, ERR_MISSING_CONFIG
class Config(QObject):
def __init__(self, folder=CFG_FOLDER, name=CFG_NAME, model=DEFAULTS):
"""Sorta like a controller for QSettings.
I'm going to treat this as a singleton global app state, but implemented
correctly such that it should be theoretically possible to have multiple
instances (maybe multiple dockers controlling multiple remotes?)
If model is None, Config will not check if keys exist.
Args:
folder (str, optional): Which folder to store settings in. Defaults to CFG_FOLDER.
name (str, optional): Name of settings file. Defaults to CFG_NAME.
model (Any, optional): Data model representing config & defaults. Defaults to DEFAULTS.
"""
# See: https://doc.qt.io/qt-6/qsettings.html#accessing-settings-from-multiple-threads-or-processes-simultaneously
# but im too lazy to figure out creating separate QSettings per worker, so we will just lock
super(Config, self).__init__()
self.model = model # is immutable
self.lock = QReadWriteLock()
self.config = QSettings(QSettings.IniFormat, QSettings.UserScope, folder, name)
# add in new config settings
self.restore_defaults(overwrite=False)
def __call__(self, key: str, type: type = str):
"""Shorthand for Config.get()"""
return self.get(key, type)
def get(self, key: str, type: type = str):
"""Get config value by key & cast to type.
Args:
key (str): Name of config option.
type (type, optional): Type to cast config value to. Defaults to str.
Returns:
Any: Config value.
"""
self.lock.lockForRead()
try:
# notably QSettings assume strings too unless specified
if self.model is not None:
assert self.config.contains(key) and hasattr(
self.model, key
), ERR_MISSING_CONFIG
val = self.config.value(key, type=type)
return val
finally:
self.lock.unlock()
def set(self, key: str, val: Any, overwrite: bool = True):
"""Set config value by key.
Args:
key (str): Name of config option.
val (Any): Config value.
overwrite (bool, optional): Whether to overwrite an existing value. Defaults to False.
"""
self.lock.lockForWrite()
try:
if self.model is not None:
assert hasattr(self.model, key), ERR_MISSING_CONFIG
if overwrite or not self.config.contains(key):
self.config.setValue(key, val)
finally:
self.lock.unlock()
def restore_defaults(self, overwrite: bool = True):
"""Reset settings to default.
Args:
overwrite (bool, optional): Whether to overwrite existing settings, else add only new ones. Defaults to True.
"""
if self.model is None:
return
defaults = asdict(self.model)
for k, v in defaults.items():
self.set(k, v, overwrite)