Commit 449376d6 authored by Roman Alifanov's avatar Roman Alifanov

refactoring

parent 13319c90
from .base import Backend
from .gsettings import GSettingsBackend
from .file import FileBackend
from .binary import BinaryBackend
class BackendFactory:
def __init__(self):
self.backends = {
'gsettings': GSettingsBackend,
'file': FileBackend,
'binary': BinaryBackend,
}
def get_backend(self, backend_name, params=None):
backend_class = self.backends.get(backend_name)
if backend_class:
# Передаем параметры в конструктор бэкенда, если они есть
return backend_class(params) if params else backend_class()
return None
backend_factory = BackendFactory()
class RootBackendFactory:
def __init__(self):
self.backends = {
'file': FileBackend,
'binary': BinaryBackend,
}
def get_backend(self, backend_name, params=None):
backend_class = self.backends.get(backend_name)
if backend_class:
# Передаем параметры в конструктор бэкенда, если они есть
return backend_class(params) if params else backend_class()
return None
root_backend_factory = RootBackendFactory()
class Backend:
def __init__(self, params=None):
# Параметры, передаваемые при инициализации
self.params = params or {}
def get_value(self, key, gtype):
raise NotImplementedError("Метод get_value должен быть реализован")
def get_range(self, key, gtype):
raise NotImplementedError("Метод get_range должен быть реализован")
def set_value(self, key, value, gtype):
raise NotImplementedError("Метод set_value должен быть реализован")
import ast
import os
import subprocess
from .base import Backend
class BinaryBackend(Backend):
def __init__(self, params=None):
super().__init__(params)
self.binary_path = os.path.join(
self.params.get('module_path'),
self.params.get('binary_path')
)
self.binary_name = self.params.get('binary_name')
def _run_binary(self, command, *args):
try:
full_command = (
[self.binary_path + self.binary_name, command]
+ [x for x in args if x is not None]
)
result = subprocess.run(full_command, capture_output=True, text=True, check=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"[ERROR] Ошибка при выполнении команды {command}: {e}")
return None
def get_value(self, key, gtype):
print(f"[DEBUG] Получение значения: key={key}, gtype={gtype}")
result = self._run_binary('get_value', key)
if result:
try:
return ast.literal_eval(result)
except (ValueError, SyntaxError) as e:
print(f"[ERROR] Ошибка при преобразовании результата {result}: {e}")
return result
return None
def get_range(self, key, gtype):
print(f"[DEBUG] Получение диапазона: key={key}, gtype={gtype}")
result = self._run_binary('get_range', key)
if not result:
print(f"[ERROR] Пустой результат или ошибка при выполнении команды get_range для ключа {key}")
return None
try:
parsed_result = ast.literal_eval(result)
return parsed_result
except (ValueError, SyntaxError) as e:
print(f"[ERROR] Ошибка при преобразовании результата {result} для ключа {key}: {e}")
return None
def set_value(self, key, value, gtype):
print(f"[DEBUG] Установка значения: key={key}, value={value}, gtype={gtype}")
result = self._run_binary('set_value', key, str(value))
if result:
try:
return ast.literal_eval(result)
except (ValueError, SyntaxError) as e:
print(f"[ERROR] Ошибка при преобразовании результата {result}: {e}")
return None
from gi.repository import Gio, GLib import os
import os, re import re
import ast, subprocess
class Backend: from .base import Backend
def __init__(self, params=None):
# Параметры, передаваемые при инициализации
self.params = params or {}
def get_value(self, key, gtype):
raise NotImplementedError("Метод get_value должен быть реализован")
def get_range(self, key, gtype):
raise NotImplementedError("Метод get_range должен быть реализован")
def set_value(self, key, value, gtype):
raise NotImplementedError("Метод set_value должен быть реализован")
class GSettingsBackend(Backend):
def get_value(self, key, gtype):
schema_name, key_name = key.rsplit('.', 1)
schema = Gio.Settings.new(schema_name)
print(f"[DEBUG] Получение значения: schema={schema_name}, key={key_name}, gtype={gtype}")
try:
value = schema.get_value(key_name)
return value.unpack()
except Exception as e:
print(f"[ERROR] Ошибка при получении значения {key}: {e}")
return None
def get_range(self, key, gtype):
schema_name, key_name = key.rsplit('.', 1)
schema = Gio.Settings.new(schema_name)
print(f"[DEBUG] Получение значения: schema={schema_name}, key={key_name}, gtype={gtype}")
try:
value = schema.get_range(key_name)
return value.unpack()[1]
except Exception as e:
print(f"[ERROR] Ошибка при получении значения {key}: {e}")
return None
def set_value(self, schema_key, value, gtype):
schema_name, key_name = schema_key.rsplit('.', 1)
schema = Gio.Settings.new(schema_name)
print(f"[DEBUG] Установка значения: schema={schema_name}, key={key_name}, value={value}, gtype={gtype}")
try:
schema.set_value(key_name, GLib.Variant(gtype, value))
except Exception as e:
print(f"[ERROR] Ошибка при установке значения {schema_key}: {e}")
class FileBackend(Backend): class FileBackend(Backend):
def __init__(self, params=None): def __init__(self, params=None):
super().__init__(params) super().__init__(params)
...@@ -186,104 +138,3 @@ class FileBackend(Backend): ...@@ -186,104 +138,3 @@ class FileBackend(Backend):
self.lines.append(line + '\n') self.lines.append(line + '\n')
self._save_file() self._save_file()
class BinaryBackend(Backend):
def __init__(self, params=None):
super().__init__(params)
self.binary_path = os.path.join(
self.params.get('module_path'),
self.params.get('binary_path')
)
self.binary_name = self.params.get('binary_name')
def _run_binary(self, command, *args):
try:
full_command = (
[self.binary_path + self.binary_name, command]
+ [x for x in args if x is not None]
)
result = subprocess.run(full_command, capture_output=True, text=True, check=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"[ERROR] Ошибка при выполнении команды {command}: {e}")
return None
def get_value(self, key, gtype):
print(f"[DEBUG] Получение значения: key={key}, gtype={gtype}")
result = self._run_binary('get_value', key)
if result:
try:
return ast.literal_eval(result)
except (ValueError, SyntaxError) as e:
print(f"[ERROR] Ошибка при преобразовании результата {result}: {e}")
return result
return None
def get_range(self, key, gtype):
print(f"[DEBUG] Получение диапазона: key={key}, gtype={gtype}")
result = self._run_binary('get_range', key)
if not result:
print(f"[ERROR] Пустой результат или ошибка при выполнении команды get_range для ключа {key}")
return None
try:
parsed_result = ast.literal_eval(result)
return parsed_result
except (ValueError, SyntaxError) as e:
print(f"[ERROR] Ошибка при преобразовании результата {result} для ключа {key}: {e}")
return None
def set_value(self, key, value, gtype):
print(f"[DEBUG] Установка значения: key={key}, value={value}, gtype={gtype}")
result = self._run_binary('set_value', key, str(value))
if result:
try:
return ast.literal_eval(result)
except (ValueError, SyntaxError) as e:
print(f"[ERROR] Ошибка при преобразовании результата {result}: {e}")
return None
class BackendFactory:
def __init__(self):
self.backends = {
'gsettings': GSettingsBackend,
'file': FileBackend,
'binary': BinaryBackend,
}
def get_backend(self, backend_name, params=None):
backend_class = self.backends.get(backend_name)
if backend_class:
# Передаем параметры в конструктор бэкенда, если они есть
return backend_class(params) if params else backend_class()
return None
backend_factory = BackendFactory()
class RootBackendFactory:
def __init__(self):
self.backends = {
'file': FileBackend,
'binary': BinaryBackend,
}
def get_backend(self, backend_name, params=None):
backend_class = self.backends.get(backend_name)
if backend_class:
# Передаем параметры в конструктор бэкенда, если они есть
return backend_class(params) if params else backend_class()
return None
root_backend_factory = RootBackendFactory()
from gi.repository import Gio, GLib
from .base import Backend
class GSettingsBackend(Backend):
def get_value(self, key, gtype):
schema_name, key_name = key.rsplit('.', 1)
schema = Gio.Settings.new(schema_name)
print(f"[DEBUG] Получение значения: schema={schema_name}, key={key_name}, gtype={gtype}")
try:
value = schema.get_value(key_name)
return value.unpack()
except Exception as e:
print(f"[ERROR] Ошибка при получении значения {key}: {e}")
return None
def get_range(self, key, gtype):
schema_name, key_name = key.rsplit('.', 1)
schema = Gio.Settings.new(schema_name)
print(f"[DEBUG] Получение значения: schema={schema_name}, key={key_name}, gtype={gtype}")
try:
value = schema.get_range(key_name)
return value.unpack()[1]
except Exception as e:
print(f"[ERROR] Ошибка при получении значения {key}: {e}")
return None
def set_value(self, schema_key, value, gtype):
schema_name, key_name = schema_key.rsplit('.', 1)
schema = Gio.Settings.new(schema_name)
print(f"[DEBUG] Установка значения: schema={schema_name}, key={key_name}, value={value}, gtype={gtype}")
try:
schema.set_value(key_name, GLib.Variant(gtype, value))
except Exception as e:
print(f"[ERROR] Ошибка при установке значения {schema_key}: {e}")
from gi.repository import Adw, Gtk from .module import Module
from .page import Page
import os from .sections import SectionFactory
import gettext
import locale
from .backends import backend_factory
from .daemon_client import dclient
from .tools.yml_tools import load_modules from .tools.yml_tools import load_modules
from .tools.gvariant import convert_by_gvariant
from .widgets import WidgetFactory
from .widgets.panel_row import TuneItPanelRow
from .widgets.service_dialog import ServiceNotStartedDialog
dialog_presented = False
class Setting:
def __init__(self, setting_data, module):
self._ = module.get_translation
self.name = self._(setting_data['name'])
self.root = setting_data.get('root', False)
self.backend = setting_data.get('backend')
self.params = {
**setting_data.get('params', {}),
'module_path': module.path
}
self.type = setting_data['type']
self.help = setting_data.get('help', None)
if self.help is not None:
self.help = self._(self.help)
self.key = setting_data.get('key')
self.default = setting_data.get('default')
self.gtype = setting_data.get('gtype', [])
self.map = setting_data.get('map')
if self.map is None:
self.map = self._default_map()
if isinstance(self.map, dict) and self.type == 'choice':
self.map = {
self._(key) if isinstance(key, str) else key: value
for key, value in self.map.items()
}
if len(self.gtype) > 2:
self.gtype = self.gtype[0]
else:
self.gtype = self.gtype
def _default_map(self):
if self.type == 'boolean':
# Дефолтная карта для булевых настроек
return {True: True, False: False}
if self.type == 'choice':
# Дефолтная карта для выборов
map = {}
range = self._get_backend_range()
if range is None:
return {}
for var in range:
print(var)
map[var[0].upper() + var[1:]] = var
return map
if self.type == 'number':
map = {}
range = self._get_backend_range()
if range is None:
return {}
map["upper"] = range[1]
map["lower"] = range[0]
# Кол-во после запятой
map["digits"] = len(str(range[0]).split('.')[-1]) if '.' in str(range[0]) else 0
# Минимальное число с этим количеством
map["step"] = 10 ** -map["digits"] if map["digits"] > 0 else 0
return map
return {}
def create_row(self):
if self.root is True:
print("Root is true")
if dclient is not None:
widget = WidgetFactory.create_widget(self)
return widget.create_row() if widget else None
else:
global dialog_presented
if dialog_presented is False:
from ..main import get_main_window
dialog = ServiceNotStartedDialog()
dialog.present(get_main_window())
dialog_presented = True
return None
widget = WidgetFactory.create_widget(self)
return widget.create_row() if widget else None
def _get_selected_row_index(self):
current_value = self._get_backend_value()
return list(self.map.values()).index(current_value) if current_value in self.map.values() else 0
def _get_default_row_index(self):
return list(self.map.values()).index(self.default) if self.default in self.map.values() else None
def _get_backend_value(self):
value = None
backend = self._get_backend()
if backend:
value = backend.get_value(self.key, self.gtype)
if value is None:
value = self.default
return value
def _get_backend_range(self):
backend = self._get_backend()
if backend:
return backend.get_range(self.key, self.gtype)
def _set_backend_value(self, value):
backend = self._get_backend()
if backend:
backend.set_value(self.key, convert_by_gvariant(value, self.gtype), self.gtype)
def _get_backend(self):
if self.root is True:
backend = dclient
backend.set_backend_name(self.backend)
backend.set_backend_params(self.params)
else:
backend = backend_factory.get_backend(self.backend, self.params)
if not backend:
print(f"Бекенд {self.backend} не зарегистрирован.")
return backend
class Module:
def __init__(self, module_data):
self.name = module_data['name']
self.weight = module_data.get('weight', 0)
self.path = module_data.get("module_path")
print(self.path)
self.pages = {
page['name']: page for page in module_data.get('pages', [])
}
self.sections = []
self.system_lang_code = self.get_system_language()
def add_section(self, section):
self.sections.append(section)
def get_sorted_sections(self):
return sorted(self.sections, key=lambda s: s.weight)
@staticmethod
def get_system_language():
lang, _ = locale.getdefaultlocale()
return lang.split('_')[0] if lang else 'en'
def get_translation(self, text, lang_code=None):
if text.startswith('_'):
text = text[1:]
locales_path = os.path.join(self.path, "locale")
if os.path.exists(locales_path):
text = gettext.translation(
domain='messages',
localedir=locales_path,
fallback=True
).gettext(text)
return text
class Section:
def __init__(self, section_data, strategy, module):
self.name = module.get_translation(section_data['name'])
self.weight = section_data.get('weight', 0)
self.page = section_data.get('page')
self.settings = [Setting(s, module) for s in section_data.get('settings', [])]
self.strategy = strategy
self.module = module
self.module.add_section(self)
def create_preferences_group(self):
return self.strategy.create_preferences_group(self)
class SectionStrategy:
def create_preferences_group(self, section):
raise NotImplementedError("Метод create_preferences_group должен быть реализован")
class ClassicSectionStrategy(SectionStrategy):
def create_preferences_group(self, section):
group = Adw.PreferencesGroup(title=section.name, description=section.module.name)
not_empty = False
for setting in section.settings:
row = setting.create_row()
if row:
print(f"Добавление строки для настройки: {setting.name}")
group.add(row)
not_empty = True
else:
print(f"Не удалось создать строку для настройки: {setting.name}")
if not_empty:
return group
else:
return None
class NewSectionStrategy(SectionStrategy):
def create_preferences_group(self, section):
group = Adw.PreferencesGroup(title=section.name)
print(f"Создание секции нового типа: {section.name}")
for setting in section.settings:
row = setting.create_row()
group.add(row)
return group
class SectionFactory:
def __init__(self):
self.strategies = {
'classic': ClassicSectionStrategy(),
}
def create_section(self, section_data, module):
section_type = section_data.get('type', 'classic')
strategy = self.strategies.get(section_type)
if not strategy:
raise ValueError(f"Неизвестный тип секции: {section_type}")
return Section(section_data, strategy, module)
class Page:
def __init__(self, name, icon=None):
self.name = name
self.icon = icon or "preferences-system" # Значение по умолчанию
self.sections = []
def add_section(self, section):
self.sections.append(section)
def sort_sections(self):
self.sections = sorted(self.sections, key=lambda s: s.weight)
def create_stack_page(self, stack, listbox):
pref_page = Adw.PreferencesPage()
not_empty = False
for section in self.sections:
preferences_group = section.create_preferences_group()
if preferences_group:
pref_page.add(preferences_group)
not_empty = True
else:
print(f"Секция {section.name} не создала виджетов.")
if not_empty:
stack_page = stack.add_child(pref_page)
stack_page.set_title(self.name)
stack_page.set_name(self.name)
row = TuneItPanelRow()
row.props.name = self.name
row.props.title = self.name
row.props.icon_name = self.icon
listbox.append(row)
else:
print(f"the page {self.name} is empty, ignored")
def init_settings_stack(stack, listbox, split_view): def init_settings_stack(stack, listbox, split_view):
yaml_data = load_modules() yaml_data = load_modules()
......
import gettext
import locale
import os
class Module:
def __init__(self, module_data):
self.name = module_data['name']
self.weight = module_data.get('weight', 0)
self.path = module_data.get("module_path")
print(self.path)
self.pages = {
page['name']: page for page in module_data.get('pages', [])
}
self.sections = []
self.system_lang_code = self.get_system_language()
def add_section(self, section):
self.sections.append(section)
def get_sorted_sections(self):
return sorted(self.sections, key=lambda s: s.weight)
@staticmethod
def get_system_language():
lang, _ = locale.getdefaultlocale()
return lang.split('_')[0] if lang else 'en'
def get_translation(self, text, lang_code=None):
if text.startswith('_'):
text = text[1:]
locales_path = os.path.join(self.path, "locale")
if os.path.exists(locales_path):
text = gettext.translation(
domain='messages',
localedir=locales_path,
fallback=True
).gettext(text)
return text
from gi.repository import Adw
from src.settings.widgets.panel_row import TuneItPanelRow
class Page:
def __init__(self, name, icon=None):
self.name = name
self.icon = icon or "preferences-system" # Значение по умолчанию
self.sections = []
def add_section(self, section):
self.sections.append(section)
def sort_sections(self):
self.sections = sorted(self.sections, key=lambda s: s.weight)
def create_stack_page(self, stack, listbox):
pref_page = Adw.PreferencesPage()
not_empty = False
for section in self.sections:
preferences_group = section.create_preferences_group()
if preferences_group:
pref_page.add(preferences_group)
not_empty = True
else:
print(f"Секция {section.name} не создала виджетов.")
if not_empty:
stack_page = stack.add_child(pref_page)
stack_page.set_title(self.name)
stack_page.set_name(self.name)
row = TuneItPanelRow()
row.props.name = self.name
row.props.title = self.name
row.props.icon_name = self.icon
listbox.append(row)
else:
print(f"the page {self.name} is empty, ignored")
from ..setting.setting import Setting
from .base_strategy import SectionStrategy
from .classic import ClassicSectionStrategy
class Section:
def __init__(self, section_data, strategy, module):
self.name = module.get_translation(section_data['name'])
self.weight = section_data.get('weight', 0)
self.page = section_data.get('page')
self.settings = [Setting(s, module) for s in section_data.get('settings', [])]
self.strategy = strategy
self.module = module
self.module.add_section(self)
def create_preferences_group(self):
return self.strategy.create_preferences_group(self)
class SectionFactory:
def __init__(self):
self.strategies = {
'classic': ClassicSectionStrategy(),
}
def create_section(self, section_data, module):
section_type = section_data.get('type', 'classic')
strategy = self.strategies.get(section_type)
if not strategy:
raise ValueError(f"Неизвестный тип секции: {section_type}")
return Section(section_data, strategy, module)
class SectionStrategy:
def create_preferences_group(self, section):
raise NotImplementedError("Метод create_preferences_group должен быть реализован")
from gi.repository import Adw
from .base_strategy import SectionStrategy
class ClassicSectionStrategy(SectionStrategy):
def create_preferences_group(self, section):
group = Adw.PreferencesGroup(title=section.name, description=section.module.name)
not_empty = False
for setting in section.settings:
row = setting.create_row()
if row:
print(f"Добавление строки для настройки: {setting.name}")
group.add(row)
not_empty = True
else:
print(f"Не удалось создать строку для настройки: {setting.name}")
if not_empty:
return group
else:
return None
from .widgets import WidgetFactory
from ..backends import backend_factory
from ..daemon_client import dclient
from ..tools.gvariant import convert_by_gvariant
from ..widgets.service_dialog import ServiceNotStartedDialog
dialog_presented = False
class Setting:
def __init__(self, setting_data, module):
self._ = module.get_translation
self.name = self._(setting_data['name'])
self.root = setting_data.get('root', False)
self.backend = setting_data.get('backend')
self.params = {
**setting_data.get('params', {}),
'module_path': module.path
}
self.type = setting_data['type']
self.help = setting_data.get('help', None)
if self.help is not None:
self.help = self._(self.help)
self.key = setting_data.get('key')
self.default = setting_data.get('default')
self.gtype = setting_data.get('gtype', [])
self.map = setting_data.get('map')
if self.map is None:
self.map = self._default_map()
if isinstance(self.map, dict) and self.type == 'choice':
self.map = {
self._(key) if isinstance(key, str) else key: value
for key, value in self.map.items()
}
if len(self.gtype) > 2:
self.gtype = self.gtype[0]
else:
self.gtype = self.gtype
def _default_map(self):
if self.type == 'boolean':
# Дефолтная карта для булевых настроек
return {True: True, False: False}
if self.type == 'choice':
# Дефолтная карта для выборов
map = {}
range = self._get_backend_range()
if range is None:
return {}
for var in range:
print(var)
map[var[0].upper() + var[1:]] = var
return map
if self.type == 'number':
map = {}
range = self._get_backend_range()
if range is None:
return {}
map["upper"] = range[1]
map["lower"] = range[0]
# Кол-во после запятой
map["digits"] = len(str(range[0]).split('.')[-1]) if '.' in str(range[0]) else 0
# Минимальное число с этим количеством
map["step"] = 10 ** -map["digits"] if map["digits"] > 0 else 0
return map
return {}
def create_row(self):
if self.root is True:
print("Root is true")
if dclient is not None:
widget = WidgetFactory.create_widget(self)
return widget.create_row() if widget else None
else:
global dialog_presented
if dialog_presented is False:
from ..main import get_main_window
dialog = ServiceNotStartedDialog()
dialog.present(get_main_window())
dialog_presented = True
return None
widget = WidgetFactory.create_widget(self)
return widget.create_row() if widget else None
def _get_selected_row_index(self):
current_value = self._get_backend_value()
return list(self.map.values()).index(current_value) if current_value in self.map.values() else 0
def _get_default_row_index(self):
return list(self.map.values()).index(self.default) if self.default in self.map.values() else None
def _get_backend_value(self):
value = None
backend = self._get_backend()
if backend:
value = backend.get_value(self.key, self.gtype)
if value is None:
value = self.default
return value
def _get_backend_range(self):
backend = self._get_backend()
if backend:
return backend.get_range(self.key, self.gtype)
def _set_backend_value(self, value):
backend = self._get_backend()
if backend:
backend.set_value(self.key, convert_by_gvariant(value, self.gtype), self.gtype)
def _get_backend(self):
if self.root is True:
backend = dclient
backend.set_backend_name(self.backend)
backend.set_backend_params(self.params)
else:
backend = backend_factory.get_backend(self.backend, self.params)
if not backend:
print(f"Бекенд {self.backend} не зарегистрирован.")
return backend
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment