Skip to content

Commit

Permalink
Merge pull request #91 from MartinHlavna/87-overridable-configs
Browse files Browse the repository at this point in the history
#87 - Overidovateľné nastavenia
  • Loading branch information
MartinHlavna authored Feb 13, 2025
2 parents 45b67ba + e7b537f commit 09421c3
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 54 deletions.
19 changes: 18 additions & 1 deletion src/backend/service/config_service.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import copy
import json
import os
import string

from src.domain.config import Config
from src.domain.project import ProjectItem, Project


class ConfigService:
"""Service for manipulation of global config"""
@staticmethod
def load(path: string):
def load(path: string) -> Config:
"""Load config from file"""
if os.path.exists(path):
with open(path, 'r') as file:
Expand All @@ -22,3 +24,18 @@ def save(c: Config, path: string):
"""Save config to file"""
with open(path, 'w') as file:
json.dump(c.to_dict(), file, indent=4)

@staticmethod
def select_config(global_config: Config, project: Project, item: ProjectItem) -> Config:
"""Selects config based on priority"""
if item is not None:
i = item
while i is not None:
if i.config is None:
i = i.parent
else:
return i.config

if project is not None and project.config is not None:
return project.config
return global_config
1 change: 1 addition & 0 deletions src/backend/service/project_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def new_item(p: Project, name: str, parent_item: DirectoryProjectItem, item_type
item.path = os.path.relpath(path, data_dir)
item.name = name
if parent_item is not None:
item.parent = parent_item
parent_item.subitems.append(item)
else:
p.items.append(item)
Expand Down
11 changes: 11 additions & 0 deletions src/domain/config.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from enum import Enum


class Config:
def __init__(self, data=None):
"""
Expand Down Expand Up @@ -121,3 +124,11 @@ def to_dict(self):
"paragraph_lmargin1": self.paragraph_lmargin1,
"paragraph_spacing3": self.paragraph_spacing3,
}


class ConfigLevel(str, Enum):
"""Enum with available ConfigLevels"""
GLOBAL = "GLOBAL"
PROJECT = "PROJECT"
ITEM = "ITEM"

37 changes: 26 additions & 11 deletions src/domain/project.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from enum import Enum

from src.const.values import CURRENT_PROJECT_VERSION
from src.domain.config import Config


class Project:
Expand All @@ -20,11 +21,15 @@ def __init__(self, data=None, path=None):
self.description = data.get('description', None)
self.path = path
self.items = []
self.config = None
config = data.get('config', None)
if config is not None:
self.config = Config(config)
for i in data.get('items', []):
item = Project.construct_project_item(i)
item = Project.construct_project_item(i, None)
self.items.append(item)

def to_dict(self):
def to_dict(self) -> dict:
"""
Exports the current state of the object to a dictionary.
Expand All @@ -34,26 +39,28 @@ def to_dict(self):
for i in self.items:
item = i.to_dict()
items.append(item)
return {
output = {
'name': self.name,
'description': self.description,
'version': self.version,
'items': items

}
if self.config is not None:
output['config'] = self.config.to_dict()
return output

@staticmethod
def construct_project_item(data):
def construct_project_item(data, parent):
"""Helper function that construct ProjectItem or appropiate subclass"""
if data.get('type', ProjectItemType.UNKNOWN) == ProjectItemType.DIRECTORY:
return DirectoryProjectItem(data)
return ProjectItem(data)
return DirectoryProjectItem(data, parent)
return ProjectItem(data, parent)


class ProjectItem:
"""Single file or directory in project"""

def __init__(self, data=None):
def __init__(self, data=None, parent=None):
"""
Constructor accepts a dictionary and sets the class attributes.
If a key is not provided in the dictionary, the default value is used.
Expand All @@ -66,27 +73,35 @@ def __init__(self, data=None):
self.path = data.get('path', '')
self.name = data.get('name', '')
self.imported_path = data.get('imported_path', '')
self.config = None
config = data.get('config', None)
if config is not None:
self.config = Config(config)
# TRANSIENT
self.contents = None
self.parent = parent

def to_dict(self):
"""
Exports the current state of the object to a dictionary.
:return: Dictionary containing the current state of the object.
"""
return {
output = {
'name': self.name,
'type': self.type,
'path': self.path,
'imported_path': self.imported_path,
}
if self.config is not None:
output['config'] = self.config.to_dict()
return output


class DirectoryProjectItem(ProjectItem):
"""Special ProjectItem used for directories. Stores opened state and subitems"""

def __init__(self, data=None):
def __init__(self, data=None, parent=None):
"""
Constructor accepts a dictionary and sets the class attributes.
If a key is not provided in the dictionary, the default value is used.
Expand All @@ -99,7 +114,7 @@ def __init__(self, data=None):
self.subitems = []
self.opened = data.get("opened", False)
for i in data.get('subitems', []):
item = Project.construct_project_item(i)
item = Project.construct_project_item(i, parent)
self.subitems.append(item)

def to_dict(self):
Expand Down
27 changes: 23 additions & 4 deletions src/gui/modal/analysis_settings_modal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@
import tkinter as tk
from tkinter import ttk, messagebox

from src.backend.run_context import RunContext
from src.backend.service.config_service import ConfigService
from src.backend.service.project_service import ProjectService
from src.const.fonts import HELVETICA_FONT_NAME, BOLD_FONT
from src.const.paths import CONFIG_FILE_PATH
from src.domain.config import AnalysisSettings
from src.domain.config import AnalysisSettings, ConfigLevel
from src.domain.project import ProjectItem


class AnalysisSettingsModal:
def __init__(self, root, config, on_config_change):
def __init__(self, root, config, on_config_change, config_level: ConfigLevel, item: ProjectItem):
self.root = root
self.config = config
self.on_config_change = on_config_change
self.toplevel = tk.Toplevel(self.root)
self.toplevel.title("Nastavenia analýzy")
self.level = config_level
self.item = item
if config_level == ConfigLevel.GLOBAL:
self.toplevel.title("Globálne nastavenia analýzy")
elif config_level == ConfigLevel.PROJECT:
self.toplevel.title("Projektové nastavenia analýzy")
elif config_level == ConfigLevel.ITEM:
self.toplevel.title("Nastavenia analýzy - pre súbor")
row = 0
# Frequent words settings
tk.Label(self.toplevel, text="Často použité slová", font=(HELVETICA_FONT_NAME, 12, BOLD_FONT),
Expand Down Expand Up @@ -246,7 +256,16 @@ def save_settings(self):
self.config.analysis_settings.enable_spellcheck = self.spellcheck_var.get()
self.config.analysis_settings.enable_partial_nlp = self.partial_nlp_var.get()
self.config.analysis_settings.enable_quote_corrections = self.quote_corrections_var.get()
ConfigService.save(self.config, CONFIG_FILE_PATH)
if self.level == ConfigLevel.GLOBAL:
ConfigService.save(self.config, CONFIG_FILE_PATH)
elif self.level == ConfigLevel.PROJECT:
ctx = RunContext()
ctx.project.config = self.config
ProjectService().save(ctx.project, ctx.project.path)
elif self.level == ConfigLevel.ITEM and self.item is not None:
ctx = RunContext()
self.item.config = self.config
ProjectService().save(ctx.project, ctx.project.path)
self.on_config_change()
self.toplevel.destroy()

Expand Down
Loading

0 comments on commit 09421c3

Please sign in to comment.