From 7fc8afd27654fc4a47ac78afc255fecdd60153cd Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Fri, 2 Aug 2024 22:44:00 +0800 Subject: [PATCH 01/39] [#11] Split rules and little fixed in docs --- docs/tips'n'tricks/audio.md | 8 +- docs/tips'n'tricks/game_optimization.md | 8 +- docs/ui_rule_configurator.md | 14 +- mypy.ini | 8 + src/configuration/config.py | 11 +- src/configuration/logs.py | 2 +- src/configuration/rule.py | 72 +++--- src/constants/app_info.py | 2 +- src/constants/ui.py | 14 +- src/enums/rules.py | 15 ++ src/service/config_service.py | 30 ++- src/service/processes_info_service.py | 14 +- src/service/rules_service.py | 32 ++- src/ui/editor.py | 206 ++++++------------ src/ui/tray.py | 3 +- src/ui/widget/common/button.py | 6 +- src/ui/widget/common/treeview/editable.py | 84 ++++++- .../widget/editor/{actions.py => buttons.py} | 30 ++- src/ui/widget/editor/rules_list.py | 107 +++++---- src/ui/widget/editor/rules_tab.py | 132 +++++++++++ 20 files changed, 503 insertions(+), 295 deletions(-) create mode 100644 mypy.ini create mode 100644 src/enums/rules.py rename src/ui/widget/editor/{actions.py => buttons.py} (78%) create mode 100644 src/ui/widget/editor/rules_tab.py diff --git a/docs/tips'n'tricks/audio.md b/docs/tips'n'tricks/audio.md index 5e4e94f..82996d1 100644 --- a/docs/tips'n'tricks/audio.md +++ b/docs/tips'n'tricks/audio.md @@ -209,15 +209,15 @@ Example of the enabled **Run on Startup** option: ### Creating Rules -#### Opening the Rule Configurator +#### Opening the Rules Configurator 1. Launch **Process Governor** if it is not already running. 2. Click on the application icon in the system tray to open the menu. -3. Select the **Configure Rules** option to open the rule configurator. +3. Select the **Configure Rules** option to open the rules configurator. #### Adding a Rule for process Voicemeeter -1. In the rule configurator interface, press the **Add** button to add a new rule. +1. In the rules configurator interface, press the **Add** button to add a new rule. 2. Enter the corresponding values in the columns: - **Process Selector:** `voicemeeter8x64.exe` - **Priority:** `Realtime` @@ -250,7 +250,7 @@ Similarly, add the remaining rules in accordance with the screenshot: ### Saving the Settings -Once all the rules are configured, save them by pressing the **Save** button. Then you can close the rule configurator. +Once all the rules are configured, save them by pressing the **Save** button. Then you can close the rules configurator. After that, the program will regularly apply the rules to the corresponding processes and manage PC resources. ## Conclusion diff --git a/docs/tips'n'tricks/game_optimization.md b/docs/tips'n'tricks/game_optimization.md index 3f21a4b..c917f69 100644 --- a/docs/tips'n'tricks/game_optimization.md +++ b/docs/tips'n'tricks/game_optimization.md @@ -44,15 +44,15 @@ Let's look at setting up optimization for two popular games: Let's proceed to set up the rules. -### Opening the Rule Configurator +### Opening the Rules Configurator 1. Launch **Process Governor** if it is not already running. 2. Click on the application icon in the system tray to open the menu. -3. Select the **Configure Rules** option to open the rule configurator. +3. Select the **Configure Rules** option to open the rules configurator. ### Adding a Rule for Starfield -1. In the rule configurator interface, press the **Add** button to add a new rule. +1. In the rules configurator interface, press the **Add** button to add a new rule. 2. Enter the corresponding values in the columns: - **Process Selector:** `starfield.exe`. - **Priority:** `High`. @@ -78,7 +78,7 @@ from use. ![game_optimization_rule_configurator_screenshot.png](../images/game_optimization_rule_configurator_screenshot.png) -Once all the rules are configured, save them by pressing the **Save** button. Then you can close the rule configurator. +Once all the rules are configured, save them by pressing the **Save** button. Then you can close the rules configurator. ### Game Process Monitoring diff --git a/docs/ui_rule_configurator.md b/docs/ui_rule_configurator.md index 171e524..0f8e47a 100644 --- a/docs/ui_rule_configurator.md +++ b/docs/ui_rule_configurator.md @@ -4,19 +4,19 @@ --- -## Opening the Rule Configurator +## Opening the Rules Configurator 1. Launch the **Process Governor**. 2. Click on the application icon in the system tray to open the menu. -3. Select the **Configure Rules** option to open the rule configurator. +3. Select the **Configure Rules** option to open the rules configurator. ![tray_menu_screenshot.png](images/tray_menu_screenshot.png) -## Interface of the Rule Configurator +## Interface of the Rules Configurator ![rule_configurator_screenshot.png](images/rule_configurator_screenshot.png) -The rule configurator interface is a table with several columns: +The rules configurator interface is a table with several columns: - **Process Selector**: Specifies the process name or pattern to match. You can use wildcards, including `*` and `?`, to match multiple processes. @@ -75,14 +75,14 @@ The rule configurator interface is a table with several columns: changes. 2. A confirmation message will appear upon successful save. -### Closing the Rule Configurator +### Closing the Rules Configurator -1. To close the rule configurator, close the window in the usual way. +1. To close the rules configurator, close the window in the usual way. 2. If there are unsaved changes in the table, the program will offer to save them before closing. ### Tooltips -- In the rule configurator interface, tooltips are present at the top, describing the functions of buttons and fields. +- In the rules configurator interface, tooltips are present at the top, describing the functions of buttons and fields. - Hover over an interface element to view the tooltip. ### Error Handling diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..e458629 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,8 @@ +[mypy] +check_untyped_defs = True + +[mypy-pystray.*] +ignore_missing_imports = True + +[mypy-pyuac.*] +ignore_missing_imports = True diff --git a/src/configuration/config.py b/src/configuration/config.py index cdc0222..a6da321 100644 --- a/src/configuration/config.py +++ b/src/configuration/config.py @@ -3,7 +3,7 @@ from pydantic import BaseModel, Field from configuration.logs import Logs -from configuration.rule import Rule +from configuration.rule import ProcessRule, ServiceRule class Config(BaseModel): @@ -25,7 +25,12 @@ class Config(BaseModel): Default settings are provided by the Logs class. """ - rules: List[Rule] = Field(default_factory=list) + processRules: List[ProcessRule] = Field(default_factory=list) """ - A list of Rule objects that specify how application manages processes and services based on user-defined rules. + A list of Rule objects that specify how application manages processes based on user-defined rules. """ + + serviceRules: List[ServiceRule] = Field(default_factory=list) + """ + A list of Rule objects that specify how application manages services based on user-defined rules. + """ \ No newline at end of file diff --git a/src/configuration/logs.py b/src/configuration/logs.py index eeaa197..2792013 100644 --- a/src/configuration/logs.py +++ b/src/configuration/logs.py @@ -32,7 +32,7 @@ class Logs(BaseModel): backupCount: int = Field(default=1) """ The number of backup log files to keep. When log rotation occurs, old log files beyond this count will be deleted. - Default is 2 backup log files. + Default is 1 backup log files. """ def level_as_int(self): diff --git a/src/configuration/rule.py b/src/configuration/rule.py index 01f3a70..0cfbd44 100644 --- a/src/configuration/rule.py +++ b/src/configuration/rule.py @@ -1,69 +1,75 @@ from typing import Optional -from pydantic import BaseModel, Field, model_validator -from pydantic_core import PydanticCustomError +from pydantic import BaseModel, Field from configuration.handler.affinity import Affinity from configuration.handler.io_priority import IOPriorityStr from configuration.handler.priority import PriorityStr -from constants.any import BOTH_SELECTORS_SET -class Rule(BaseModel): - processSelector: Optional[str] = Field( - default=None, +class ProcessRule(BaseModel): + selector: str = Field( title="Process Selector", description="Specifies the __name or pattern__ of the __process__ to which this rule applies.\n\n" "**Supports wildcards:** `\*` (matches any characters) and `?` (matches any single character).\n" - "**Examples:** `name.exe` or `logioptionsplus_*.exe`." + "**Examples:** `name.exe` or `logioptionsplus_*.exe`.", + default_ui="*", + stretchable_column_ui=True + ) + + priority: Optional[PriorityStr] = Field( + default=None, + title="Priority", + description="Sets the **priority level** for the __process__.\n" + "Higher priority tasks are allocated more CPU time compared to lower priority tasks." ) - serviceSelector: Optional[str] = Field( + ioPriority: Optional[IOPriorityStr] = Field( default=None, + title="I/O Priority", + description="Sets the **I/O priority** for the __process__.\n" + "Higher I/O priority means more disk resources and better I/O performance." + ) + + affinity: Optional[Affinity] = Field( + default=None, + title="Affinity", + description="Sets the **CPU core affinity** for the __process__, " + "defining which CPU cores are allowed for execution.\n\n" + "**Format:** range `0-3`, specific cores `0;2;4`, combination `1;3-5`.", + scale_width_ui=3 + ) + + +class ServiceRule(BaseModel): + selector: str = Field( title="Service Selector", description="Specifies the __name or pattern__ of the __service__ to which this rule applies.\n\n" "**Supports wildcards:** `\*` (matches any characters) and `?` (matches any single character).\n" - "**Examples:** `ServiceName` or `Audio*`." + "**Examples:** `ServiceName` or `Audio*`.", + default_ui="*", + stretchable_column_ui=True ) priority: Optional[PriorityStr] = Field( default=None, title="Priority", - description="Sets the **priority level** for the __process or service__.\n" + description="Sets the **priority level** for the __service__.\n" "Higher priority tasks are allocated more CPU time compared to lower priority tasks." ) ioPriority: Optional[IOPriorityStr] = Field( default=None, title="I/O Priority", - description="Sets the **I/O priority** for the __process or service__.\n" + description="Sets the **I/O priority** for the __service__.\n" "Higher I/O priority means more disk resources and better I/O performance." ) affinity: Optional[Affinity] = Field( default=None, title="Affinity", - description="Sets the **CPU core affinity** for the __process or service__, " + description="Sets the **CPU core affinity** for the __service__, " "defining which CPU cores are allowed for execution.\n\n" - "**Format:** range `0-3`, specific cores `0;2;4`, combination `1;3-5`." + "**Format:** range `0-3`, specific cores `0;2;4`, combination `1;3-5`.", + scale_width_ui=3 ) - - @model_validator(mode="after") - def check_exclusive_fields(self): - fields = self.model_fields - process_selector_title = fields["processSelector"].title - service_selector_title = fields["serviceSelector"].title - - if self.processSelector and self.serviceSelector: - raise PydanticCustomError( - BOTH_SELECTORS_SET, - f'Only one of **{process_selector_title}** or **{service_selector_title}** can be set' - ) - - if not self.processSelector and not self.serviceSelector: - raise PydanticCustomError( - BOTH_SELECTORS_SET, - f'At least one of the **{process_selector_title}** or **{service_selector_title}** must be installed' - ) - - return self diff --git a/src/constants/app_info.py b/src/constants/app_info.py index 7db74ed..3afad6c 100644 --- a/src/constants/app_info.py +++ b/src/constants/app_info.py @@ -5,7 +5,7 @@ from util.utils import is_portable APP_NAME: Final[str] = "Process Governor" -APP_VERSION: Final[str] = "1.2.1" +APP_VERSION: Final[str] = "1.2.2" APP_AUTHOR: Final[str] = "System X - Files" CURRENT_TAG: Final[str] = f"v{APP_VERSION}" diff --git a/src/constants/ui.py b/src/constants/ui.py index b46b54a..ca71f72 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -1,17 +1,13 @@ from typing import Final -from pydantic.fields import FieldInfo - -from configuration.rule import Rule - -RULE_COLUMNS: dict[str, FieldInfo] = Rule.model_fields - -UI_PADDING = 15 +UI_PADDING = 12 +BUTTON_SIZE = 7 ERROR_COLOR = "#e57373" ERROR_ROW_COLOR = "#ffcdd2" TOOLTIP_ICON_SIZE = 75 RC_WIN_SIZE = (900, 600) RC_TITLE = "Rules Configurator" +RC_TRAY_TITLE = f"Configure Rules" class ActionEvents: @@ -19,6 +15,7 @@ class ActionEvents: DELETE: Final[str] = "<>" UP: Final[str] = "<>" DOWN: Final[str] = "<>" + CANCEL: Final[str] = "<>" SAVE: Final[str] = "<>" @@ -30,8 +27,7 @@ class EditableTreeviewEvents: CHANGE: Final[str] = "<>" ESCAPE: Final[str] = "<>" START_EDIT_CELL: Final[str] = "<>" - - _SAVE_CELL: Final[str] = "<>" + SAVE_CELL: Final[str] = "<>" class ScrollableTreeviewEvents: diff --git a/src/enums/rules.py b/src/enums/rules.py new file mode 100644 index 0000000..4e22c0b --- /dev/null +++ b/src/enums/rules.py @@ -0,0 +1,15 @@ +from enum import Enum + +from configuration.rule import ProcessRule, ServiceRule +from util.ui import icon16px + + +class RuleType(Enum): + PROCESS = ProcessRule, "processRules", "Process Rules", lambda:icon16px("list", fill="#3F888F") + SERVICE = ServiceRule, "serviceRules", "Service Rules", lambda:icon16px("cogs", fill="#6495ED") + + def __init__(self, clazz, field_in_config, title, get_icon): + self.clazz = clazz + self.field_in_config = field_in_config + self.title = title + self.get_icon = get_icon diff --git a/src/service/config_service.py b/src/service/config_service.py index 34166bf..ea745ac 100644 --- a/src/service/config_service.py +++ b/src/service/config_service.py @@ -6,8 +6,9 @@ from configuration.config import Config from configuration.logs import Logs -from configuration.rule import Rule +from configuration.rule import ProcessRule, ServiceRule from constants.any import CONFIG_FILE_NAME, CONFIG_FILE_ENCODING +from enums.rules import RuleType from util.decorators import cached @@ -78,13 +79,13 @@ def reload_if_changed(cls, prev_config: Optional[Config]) -> tuple[Config, bool] return prev_config, False @classmethod - def load_rules_raw(cls) -> List[Any]: + def load_rules_raw(cls, rule_type: RuleType) -> List[Any]: if not exists(CONFIG_FILE_NAME): cls.save_config(Config()) with open(CONFIG_FILE_NAME, 'r', encoding=CONFIG_FILE_ENCODING) as file: json_data = json.load(file) - return json_data.get('rules', []) + return json_data.get(rule_type.field_in_config, []) @classmethod def load_logs(cls) -> Logs: @@ -97,26 +98,31 @@ def load_logs(cls) -> Logs: return Logs(**json_data['logging']) @classmethod - def save_rules(cls, rules: List[Rule]): + def save_rules(cls, rule_type: RuleType, rules: List[ProcessRule | ServiceRule]): if rules is None: raise ValueError("rules is None") config = cls.load_config(False) - config.rules = rules + setattr(config, rule_type.field_in_config, rules) cls.save_config(config) @classmethod def rules_has_error(cls) -> bool: try: - rules: List[Any] = cls.load_rules_raw() - - try: - for rule in rules: - Rule(**rule) - except: - return True + for rule_type in RuleType: + rules: List[Any] = cls.load_rules_raw(rule_type) + + try: + for rule in rules: + rule_type.clazz(**rule) + except: + return True except: pass # Yes, this is indeed a pass. return False + + +if __name__ == '__main__': + print(ConfigService.rules_has_error()) diff --git a/src/service/processes_info_service.py b/src/service/processes_info_service.py index b0b82e9..b1b1f8d 100644 --- a/src/service/processes_info_service.py +++ b/src/service/processes_info_service.py @@ -1,5 +1,5 @@ from abc import ABC -from typing import List +from typing import List, Set import psutil from psutil import NoSuchProcess @@ -23,9 +23,9 @@ def get_list(cls) -> dict[int, Process]: representing the running processes. """ result: dict[int, Process] = {} - cls.__prev_pids = psutil.pids() + current_pids: List[int] = psutil.pids() - for pid in cls.__prev_pids: + for pid in current_pids: try: process = psutil.Process(pid) info = process.as_dict(attrs=['name', 'exe', 'nice', 'ionice', 'cpu_affinity']) @@ -41,9 +41,10 @@ def get_list(cls) -> dict[int, Process]: except NoSuchProcess: pass + cls.__prev_pids = set(current_pids) return result - __prev_pids: List[int] = [] + __prev_pids: Set[int] = [] @classmethod def get_new_processes(cls) -> dict[int, Process]: @@ -55,7 +56,7 @@ def get_new_processes(cls) -> dict[int, Process]: representing the newly created processes. """ result: dict[int, Process] = {} - current_pids = psutil.pids() + current_pids: List[int] = psutil.pids() for pid in current_pids: if pid not in cls.__prev_pids: @@ -74,6 +75,5 @@ def get_new_processes(cls) -> dict[int, Process]: except NoSuchProcess: pass - cls.__prev_pids = current_pids - + cls.__prev_pids = set(current_pids) return result diff --git a/src/service/rules_service.py b/src/service/rules_service.py index be68ecd..4d8ca96 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -7,7 +7,7 @@ from pyuac import isUserAdmin from configuration.config import Config -from configuration.rule import Rule +from configuration.rule import ProcessRule, ServiceRule from constants.any import LOG from constants.priority_mappings import iopriority_to_str, priority_to_str from enums.process import ProcessParameter @@ -42,7 +42,7 @@ def apply_rules(cls, config: Config, force=False): Returns: None """ - if not config.rules: + if not (config.serviceRules or config.processRules): return cls.__light_gc_ignored_process_parameters() @@ -59,14 +59,14 @@ def apply_rules(cls, config: Config, force=False): cls.__handle_processes(config, processes, services) @classmethod - def __handle_processes(cls, config, processes, services): + def __handle_processes(cls, config: Config, processes: dict[int, Process], services: dict[int, Service]): for pid, process_info in processes.items(): if pid in cls.__ignore_pids: continue try: service_info: Service = ServicesInfoService.get_by_pid(pid, services) - rule: Rule = cls.__first_rule_by_name(config.rules, service_info, process_info) + rule: Optional[ProcessRule | ServiceRule] = cls.__first_rule_by_name(config, service_info, process_info) if not rule: continue @@ -95,7 +95,7 @@ def __handle_processes(cls, config, processes, services): LOG.warning(f"No such process: {pid}") @classmethod - def __set_ionice(cls, not_success, process_info, rule: Rule): + def __set_ionice(cls, not_success, process_info, rule: ProcessRule | ServiceRule): if not rule.ioPriority or process_info.ionice == rule.ioPriority: return @@ -109,7 +109,7 @@ def __set_ionice(cls, not_success, process_info, rule: Rule): not_success.append(parameter) @classmethod - def __set_nice(cls, not_success, process_info, rule: Rule): + def __set_nice(cls, not_success, process_info, rule: ProcessRule | ServiceRule): if not rule.priority or process_info.nice == rule.priority: return @@ -123,7 +123,7 @@ def __set_nice(cls, not_success, process_info, rule: Rule): not_success.append(parameter) @classmethod - def __set_affinity(cls, not_success, process_info: Process, rule: Rule): + def __set_affinity(cls, not_success, process_info: Process, rule: ProcessRule | ServiceRule): if not rule.affinity: return @@ -140,13 +140,21 @@ def __set_affinity(cls, not_success, process_info: Process, rule: Rule): not_success.append(parameter) @classmethod - def __first_rule_by_name(cls, rules: List[Rule], service: Service, process: Process) -> Optional[Rule]: - for rule in rules: - if service and fnmatch_cached(service.name, rule.serviceSelector): + def __first_rule_by_name( + cls, + config: Config, + service: Service, + process: Process + ) -> Optional[ProcessRule | ServiceRule]: + if service: + for rule in config.serviceRules: + if fnmatch_cached(service.name, rule.selector): + return rule + + for rule in config.processRules: + if fnmatch_cached(process.name, rule.selector): return rule - if fnmatch_cached(process.name, rule.processSelector): - return rule return None @classmethod diff --git a/src/ui/editor.py b/src/ui/editor.py index 227b0fa..8582081 100644 --- a/src/ui/editor.py +++ b/src/ui/editor.py @@ -1,28 +1,28 @@ import os import tkinter as tk from threading import Thread -from tkinter import ttk, messagebox +from tkinter import messagebox, ttk from constants.any import LOG, LOG_FILE_NAME from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.resources import APP_ICON -from constants.ui import RULE_COLUMNS, UI_PADDING, RC_WIN_SIZE, ActionEvents, RulesListEvents, EditableTreeviewEvents, \ - RC_TITLE -from ui.widget.editor.actions import ActionsFrame -from ui.widget.editor.rules_list import RulesList +from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, RC_TITLE, RulesListEvents, EditableTreeviewEvents +from enums.rules import RuleType +from ui.widget.editor.buttons import EditorButtons +from ui.widget.editor.rules_tab import RulesTabs from ui.widget.editor.tooltip import Tooltip from util.messages import yesno_error_box -class RuleConfigurator(tk.Tk): +class RulesConfigurator(tk.Tk): _DEFAULT_TOOLTIP = ( "To add a new rule, click the **Add** button.\n" "To edit a rule, **double-click** on the corresponding cell." ) - _tree = None + _tabs = None _tooltip = None - _actions = None + _buttons = None def __init__(self): super().__init__() @@ -63,7 +63,7 @@ def _center_window(self): def _create_widgets(self): self._create_tooltips() - self._create_treeview() + self._create_tabs() self._create_buttons() def _create_tooltips(self): @@ -72,15 +72,6 @@ def _create_tooltips(self): self._tooltip.set(self._DEFAULT_TOOLTIP) - def _set_tooltip_by_tree(self, event): - if not event or not isinstance(event.widget, ttk.Treeview): - return - - cell = self._tree.get_cell_info(event) - - if cell: - self._tooltip.set(RULE_COLUMNS[cell.column_name].description) - def _setup_tooltip(self, widget, text: str, error: bool = False, leave: bool = True, enter: bool = True): if enter: def on_enter(_): @@ -94,163 +85,94 @@ def on_leave(_): widget.bind("", on_leave) - def _setup_tooltip_cell_editor(self, _=None): - cell = self._tree.current_cell() - - if cell: - self._setup_tooltip( - self._tree.popup(), - RULE_COLUMNS[cell.column_name].description, - leave=False - ) - - def _create_treeview(self): - self._tree = tree = RulesList(self) - - tree.bind("<>", self._update_buttons_state, "+") - tree.bind("", self._on_key_press_tree, "+") - tree.bind("", self._delete_selected, "+") - tree.bind("", self._set_tooltip_by_tree, "+") - tree.bind(RulesListEvents.UNSAVED_CHANGES_STATE, self._update_buttons_state, "+") - tree.bind(EditableTreeviewEvents.START_EDIT_CELL, self._setup_tooltip_cell_editor, "+") - - tree.pack(fill=tk.BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) - - tree.error_icon_created = lambda icon, tooltip: self._setup_tooltip(icon, tooltip, True, False) - - self._setup_tooltip(tree, "", enter=False) - - def _on_key_press_tree(self, event): - ctrl = (event.state & 0x4) != 0 - - if ctrl and event.keycode == ord('A'): - self._select_all(event) + def _create_callback_for_set_tooltip_by_tree(self, rule_type: RuleType): + def callback(event): + if not event or not isinstance(event.widget, ttk.Treeview): + return - def _create_buttons(self): - self._actions = actions = ActionsFrame(self) - actions.pack(fill=tk.X, padx=UI_PADDING, pady=(0, UI_PADDING)) - actions.bind(ActionEvents.ADD, lambda _: self._add(), "+") - actions.bind(ActionEvents.DELETE, lambda _: self._delete_selected(), "+") - actions.bind(ActionEvents.UP, lambda _: self._move_item_up(), "+") - actions.bind(ActionEvents.DOWN, lambda _: self._move_item_down(), "+") - actions.bind(ActionEvents.SAVE, lambda _: self._save(), "+") - - self._setup_tooltip(actions.add, "__Adds__ a rule after the current") - self._setup_tooltip(actions.delete, "__Deletes__ the selected rules") - self._setup_tooltip(actions.move_up, "__Moves__ the current rule __up__") - self._setup_tooltip(actions.move_down, "__Moves__ the current rule __down__") - self._setup_tooltip(actions.save, "__Saves__ the settings") - - self._update_buttons_state() - - def _move_item_up(self): - selected_items = self._tree.selection() + cell = self._tabs.current_list_of_tab().get_cell_info(event) - if selected_items: - selected_item = selected_items[0] - index = self._tree.index(selected_item) + if cell: + self._tooltip.set(rule_type.clazz.model_fields[cell.column_name].description) - if index > 0: - self._tree.move(selected_item, '', index - 1) - self._tree.selection_set(selected_item) - self._update_buttons_state() + return callback - def _move_item_down(self): - selected_items = self._tree.selection() + def _create_callback_for_setup_tooltip_cell_editor(self, rule_type: RuleType): + def callback(_=None): + lst = self._tabs.current_list_of_tab() + cell = lst.current_cell() - if selected_items: - selected_item = selected_items[0] - index = self._tree.index(selected_item) - next_index = index + 1 + if cell: + self._setup_tooltip( + lst.popup(), + rule_type.clazz.model_fields[cell.column_name].description, + leave=False + ) - if next_index < len(self._tree.get_children()): - self._tree.move(selected_item, '', next_index) - self._tree.selection_set(selected_item) - self._update_buttons_state() + return callback - def _save(self): - if not self._tree.save_data(): - messagebox.showerror(f"Error Detected - {APP_NAME_WITH_VERSION}", "An error occurred while saving.") + def _create_tabs(self): + self._tabs = tabs = RulesTabs(self) - def _add(self): - selected_items = self._tree.selection() + tabs.pack(fill=tk.BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) + tabs.load_data() - if selected_items: - selected_item = selected_items[0] - index = self._tree.index(selected_item) - - self._tree.insert('', index + 1) - self._tree.selection_set(self._tree.get_children()[index + 1]) - else: - self._tree.insert('', 'end') - - self._update_buttons_state() + tabs.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_buttons_state(), "+") - def _delete_selected(self, _=None): - selected_items = self._tree.selection() + for rt, lst in tabs.list_by_rt().items(): + lst.bind("", self._create_callback_for_set_tooltip_by_tree(rt), "+") + lst.bind( + EditableTreeviewEvents.START_EDIT_CELL, + self._create_callback_for_setup_tooltip_cell_editor(rt), + "+" + ) - if selected_items: - index = self._tree.index(selected_items[0]) + lst.error_icon_created = lambda icon, tooltip: self._setup_tooltip(icon, tooltip, True, False) + self._setup_tooltip(lst, "", enter=False) - for item in selected_items: - self._tree.delete(item) + def _create_buttons(self): + self._buttons = buttons = EditorButtons(self) - children = self._tree.get_children() + buttons.pack(fill=tk.X, padx=UI_PADDING, pady=(0, UI_PADDING)) + buttons.bind(ActionEvents.SAVE, lambda _: self._tabs.save_data(), "+") - if len(children) <= index: - index -= 1 + self._setup_tooltip(buttons.save, "__Adds__ a rule after the current") - if children and len(children) > index: - self._tree.selection_set(children[index]) + for rt, btns in self._tabs.buttons_by_rt().items(): + self._setup_tooltip(btns.add, "__Adds__ a rule after the current") + self._setup_tooltip(btns.delete, "__Deletes__ the selected rules") + self._setup_tooltip(btns.move_up, "__Moves__ the current rule __up__") + self._setup_tooltip(btns.move_down, "__Moves__ the current rule __down__") self._update_buttons_state() - def _select_all(self, _): - items = self._tree.get_children() - - if items: - self._tree.selection_set(items) - self._update_buttons_state() - def _on_window_closing(self): - if self._tree.unsaved_changes: - if self._tree.has_error(): - message = "There are unsaved changes. Do you want to discard them and exit?" + if self._tabs.has_unsaved_changes(): + if self._tabs.has_error(): + message = ("There are errors in the rules, and they can't be saved. " + "Do you want to DISCARD them and exit?") result = messagebox.askyesno(f"{RC_TITLE} - {APP_NAME_WITH_VERSION}", message) if not result: return else: - message = "There are unsaved changes. Do you want to save them before exiting?" + message = ("There are unsaved changes. " + "Do you want to save them before exiting?") result = messagebox.askyesnocancel(f"{RC_TITLE} - {APP_NAME_WITH_VERSION}", message) if result is None: return - if result and not self._tree.save_data(): - messagebox.showerror(f"Error Detected - {APP_NAME_WITH_VERSION}", "An error occurred while saving.") + if result and not self._tabs.save_data(): return self.destroy() def _update_buttons_state(self, _=None): - tree = self._tree - actions = self._actions - selected_items = tree.selection() - - if selected_items: - selected_item = selected_items[0] - index = tree.index(selected_item) - total_items = len(tree.get_children()) - - actions.move_up["state"] = tk.NORMAL if index > 0 else tk.DISABLED - actions.move_down["state"] = tk.NORMAL if index < total_items - 1 else tk.DISABLED - else: - actions.move_up["state"] = tk.DISABLED - actions.move_down["state"] = tk.DISABLED + tabs = self._tabs + buttons = self._buttons - actions.save["state"] = tk.NORMAL if tree.unsaved_changes and not tree.has_error() else tk.DISABLED - actions.delete["state"] = tk.NORMAL if selected_items else tk.DISABLED + buttons.save["state"] = tk.NORMAL if tabs.has_unsaved_changes() and not tabs.has_error() else tk.DISABLED is_editor_open = False @@ -264,7 +186,7 @@ def editor(): try: is_editor_open = True - app = RuleConfigurator() + app = RulesConfigurator() app.mainloop() except: LOG.exception(f"An unexpected error occurred in the {RC_TITLE} of {APP_NAME}.") @@ -290,5 +212,5 @@ def show_rule_editor_error_message(): if __name__ == "__main__": - test_app = RuleConfigurator() + test_app = RulesConfigurator() test_app.mainloop() diff --git a/src/ui/tray.py b/src/ui/tray.py index 6009931..a8db4c3 100644 --- a/src/ui/tray.py +++ b/src/ui/tray.py @@ -9,6 +9,7 @@ from constants.any import CONFIG_FILE_NAME, LOG_FILE_NAME from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.resources import APP_ICON +from constants.ui import RC_TRAY_TITLE from constants.updates import UPDATE_URL from ui.editor import open_rule_editor from util.messages import yesno_error_box, show_error, show_info @@ -59,7 +60,7 @@ def init_tray() -> Icon: MenuItem(APP_NAME_WITH_VERSION, None, enabled=False), Menu.SEPARATOR, - MenuItem('Configure Rules', lambda item: open_rule_editor(), default=True), + MenuItem(RC_TRAY_TITLE, lambda item: open_rule_editor(), default=True), Menu.SEPARATOR, MenuItem('Open config file', lambda item: os.startfile(CONFIG_FILE_NAME)), diff --git a/src/ui/widget/common/button.py b/src/ui/widget/common/button.py index 7fb8d52..c6ecdb5 100644 --- a/src/ui/widget/common/button.py +++ b/src/ui/widget/common/button.py @@ -1,10 +1,12 @@ from tkinter import ttk, LEFT +from constants.ui import BUTTON_SIZE + class IconedButton(ttk.Button): - def __init__(self, *args, image=None, compound=LEFT, **kwargs): + def __init__(self, *args, image=None, compound=LEFT, width=BUTTON_SIZE, **kwargs): self._image = image - super().__init__(*args, image=image, compound=compound, **kwargs) + super().__init__(*args, image=image, compound=compound, width=width, **kwargs) def config(self, *args, **kwargs): image = kwargs.get('image') diff --git a/src/ui/widget/common/treeview/editable.py b/src/ui/widget/common/treeview/editable.py index 2fc82da..8b90a4e 100644 --- a/src/ui/widget/common/treeview/editable.py +++ b/src/ui/widget/common/treeview/editable.py @@ -1,4 +1,5 @@ import tkinter as tk +import traceback from dataclasses import dataclass from tkinter import ttk from typing import Optional, Literal, List @@ -33,7 +34,7 @@ def __init__( def _setup_widgets(self, master, *args, **kwargs): def on_change(_): - self.event_generate(EditableTreeviewEvents._SAVE_CELL) + self.event_generate(EditableTreeviewEvents.SAVE_CELL) def on_escape(_): self.event_generate(EditableTreeviewEvents.ESCAPE) @@ -41,6 +42,7 @@ def on_escape(_): if self._cell.type == "text": entry_popup = ttk.Entry(master, *args, justify='center', **kwargs) entry_popup.insert(0, self._cell.value) + entry_popup.select_range(0, tk.END) entry_popup.bind("", on_change, '+') else: entry_popup = ttk.Combobox( @@ -140,7 +142,7 @@ def popup(self): return self._popup def _on_dbl_click(self, event): - self._destroy_popup() + self._destroy_editor() self._cell = self.get_cell_info(event) self._create_editor() @@ -150,8 +152,8 @@ def _create_editor(self): self._popup = entry_popup = CellEditor(self, self._cell) - entry_popup.bind(EditableTreeviewEvents._SAVE_CELL, self._save_and_destroy_popup, '+') - entry_popup.bind(EditableTreeviewEvents.ESCAPE, self._destroy_popup, '+') + entry_popup.bind(EditableTreeviewEvents.SAVE_CELL, self._save_and_destroy_popup, '+') + entry_popup.bind(EditableTreeviewEvents.ESCAPE, self._destroy_editor, '+') entry_popup.bind("", self._on_popup_destroy, '+') self._place_popup() @@ -172,10 +174,12 @@ def _place_popup(self, _=None): def _save_and_destroy_popup(self, _=None): if self._popup: self._save_cell_changes() - self._destroy_popup() + self._destroy_editor() - def _destroy_popup(self, _=None): + def _destroy_editor(self, _=None): if self._popup: + print("sadfsdfasdfsd") + traceback.print_stack() self._popup.destroy() def _save_cell_changes(self): @@ -189,6 +193,72 @@ def _on_popup_destroy(self, _=None): self._cell = None def edit_cell(self, row_id, column_id): - self._destroy_popup() + self._destroy_editor() self._cell = self._get_cell_info(row_id, column_id) self._create_editor() + + def select_all_rows(self): + items = self.get_children() + + if items: + self.selection_set(items) + + def move_rows_up(self): + selected_items = self.selection() + + if selected_items: + for selected_item in selected_items: + index = self.index(selected_item) + next_index = index - 1 + + if index <= 0: + break + + self.move(selected_item, '', next_index) + + self.selection_set(selected_items) + + def move_rows_down(self): + selected_items = self.selection() + count_items = len(self.get_children()) + + if selected_items: + for selected_item in reversed(selected_items): + index = self.index(selected_item) + next_index = index + 1 + + if next_index >= count_items: + break + + self.move(selected_item, '', next_index) + + self.selection_set(selected_items) + + def add_row(self, values=[]): + selected_items = self.selection() + + if selected_items: + selected_item = selected_items[-1] + index = self.index(selected_item) + + self.insert('', index + 1, values=values) + self.selection_set(self.get_children()[index + 1]) + else: + self.insert('', tk.END, values=values) + + def delete_selected_rows(self): + selected_items = self.selection() + + if selected_items: + index = self.index(selected_items[0]) + + for item in selected_items: + self.delete(item) + + children = self.get_children() + + if len(children) <= index: + index -= 1 + + if children and len(children) > index: + self.selection_set(children[index]) diff --git a/src/ui/widget/editor/actions.py b/src/ui/widget/editor/buttons.py similarity index 78% rename from src/ui/widget/editor/actions.py rename to src/ui/widget/editor/buttons.py index 9af8897..e230450 100644 --- a/src/ui/widget/editor/actions.py +++ b/src/ui/widget/editor/buttons.py @@ -6,7 +6,23 @@ from util.ui import icon16px -class ActionsFrame(ttk.Frame): +class EditorButtons(ttk.Frame): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._setup_btn() + + def _setup_btn(self): + self.save = save = IconedButton( + self, + text=" Apply", + command=lambda: self.event_generate(ActionEvents.SAVE), + image=icon16px("check", fill="cornflowerblue") + ) + right_btn_pack = dict(side=tk.RIGHT, padx=(UI_PADDING, 0)) + save.pack(**right_btn_pack) + + +class RulesListButtons(ttk.Frame): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._setup_btn() @@ -21,9 +37,9 @@ def _setup_btn(self): self.delete = delete = IconedButton( self, - text=" Delete", + text=" Del", command=lambda: self.event_generate(ActionEvents.DELETE), - image=icon16px("trash-alt", fill="red") + image=icon16px("trash-alt", fill="firebrick") ) self.move_up = move_up = IconedButton( @@ -40,16 +56,8 @@ def _setup_btn(self): image=icon16px("arrow-down", fill="#1a1a1a") ) - self.save = save = IconedButton( - self, - text=" Save", - command=lambda: self.event_generate(ActionEvents.SAVE), - image=icon16px("check", fill="cornflowerblue") - ) - left_btn_pack = dict(side=tk.LEFT, padx=(0, UI_PADDING)) add.pack(**left_btn_pack) delete.pack(**left_btn_pack) move_up.pack(**left_btn_pack) move_down.pack(**left_btn_pack) - save.pack(side=tk.RIGHT) diff --git a/src/ui/widget/editor/rules_list.py b/src/ui/widget/editor/rules_list.py index e4f0050..afdd567 100644 --- a/src/ui/widget/editor/rules_list.py +++ b/src/ui/widget/editor/rules_list.py @@ -1,18 +1,18 @@ import enum import json +import tkinter as tk from tkinter import ttk from tkinter.font import Font from typing import Optional, Any, List from psutil._pswindows import Priority -from pydantic import ValidationError +from pydantic import ValidationError, BaseModel -from configuration.rule import Rule -from constants.any import LOG, BOTH_SELECTORS_SET +from configuration.rule import ServiceRule, ProcessRule +from constants.any import BOTH_SELECTORS_SET from constants.priority_mappings import str_to_priority, str_to_iopriority -from constants.ui import RULE_COLUMNS, ERROR_COLOR, ERROR_ROW_COLOR, RulesListEvents, EditableTreeviewEvents, \ +from constants.ui import ERROR_COLOR, ERROR_ROW_COLOR, RulesListEvents, EditableTreeviewEvents, \ ScrollableTreeviewEvents -from service.config_service import ConfigService from ui.widget.common.label import Image from ui.widget.common.treeview.editable import EditableTreeview from util.ui import icon16px, full_visible_bbox @@ -20,20 +20,24 @@ class RulesList(EditableTreeview): - unsaved_changes = False - _error_icons: dict[tuple[str, str], Image] = {} + def __init__(self, model: BaseModel, *args, **kwargs): + self.has_unsaved_changes = False - def __init__(self, *args, **kwargs): - super().__init__(*args, columns=list(RULE_COLUMNS.keys()), **kwargs, show='headings') + self._model = model + self._error_icons: dict[tuple[str, str], Image] = {} + + super().__init__(*args, columns=list(self._model.model_fields.keys()), **kwargs, show='headings') self._setup_look() self.bind(EditableTreeviewEvents.CHANGE, lambda _: self._changed(), '+') self.bind(ScrollableTreeviewEvents.SCROLL, self._place_icons, '+') self.bind("", self._handle_click, '+') + self.bind("", self._handle_click, '+') self.bind("", lambda _: self.after(1, self._place_icons), '+') + self.bind("", self._on_key_press_tree, "+") + self.bind("", lambda _: self.delete_selected_rows(), "+") self._setup_columns() - self._load_data() def _handle_click(self, event): row_id = self.identify_row(event.y) @@ -43,12 +47,14 @@ def _handle_click(self, event): return "break" def _setup_columns(self): + model_fields = self._model.model_fields + for column_name in self["columns"]: - field_info = RULE_COLUMNS.get(column_name) + field_info = model_fields.get(column_name) if field_info: title = field_info.title - width = self.font.measure(title) + 40 + max_width_value_in_column = title typ = extract_type(field_info.annotation) values = [] @@ -57,15 +63,25 @@ def _setup_columns(self): if issubclass(typ, enum.Enum): values += list(str_to_priority.keys() if typ == Priority else str_to_iopriority.keys()) + max_width_value_in_column = max(values + [max_width_value_in_column], key=len) self.column_type(column_name, "list") self.column_values(column_name, values) else: title = "?" - width = self.font.measure(title) + 40 + max_width_value_in_column = title + + extra = field_info.json_schema_extra or dict() if field_info else dict() + stretch = extra.get('stretchable_column_ui', False) + width = extra.get( + 'width_ui', + int(self.font.measure(max_width_value_in_column) * 1.5) + if title else None + ) + width = width * extra.get('scale_width_ui', 1) if width else None self.heading(column_name, text=title) - self.column(column_name, width=width, anchor='center', minwidth=width) + self.column(column_name, anchor='center', width=width, minwidth=width, stretch=stretch) def _setup_look(self): self.font = Font(family="TkDefaultFont") @@ -77,32 +93,20 @@ def _setup_look(self): self._error_icon = icon16px("exclamation-triangle", ERROR_COLOR) - def _load_data(self): + def set_raw_data(self, rules_raw: List[Any]): self.delete(*self.get_children()) - fields = self["columns"] - rules = ConfigService.load_rules_raw() - for rule in rules: + for rule in rules_raw: values = [rule.get(field_name, '') or '' for field_name in fields] - self.insert('', 'end', values=values) - - self._save_state(False) - - def save_data(self) -> bool: - try: - if self.has_error(): - return False + self.insert('', tk.END, values=values) - ConfigService.save_rules(self._to_rules()) + self.set_unsaved_changes(False) - self._save_state(False) - return True - except: - LOG.exception("Error when saving file.") - return False + def get_data(self) -> List[Optional[ProcessRule | ServiceRule | tuple[Any, Any]]]: + return self._to_rules() - def _to_rule(self, row_id) -> Rule | tuple[Any, Any]: + def _to_rule(self, row_id) -> ProcessRule | ServiceRule | tuple[Any, Any]: keys = self["columns"] values = self.item(row_id, 'values') dct = { @@ -111,25 +115,27 @@ def _to_rule(self, row_id) -> Rule | tuple[Any, Any]: } try: - return Rule(**dct) + # noinspection PyCallingNonCallable + return self._model(**dct) except ValidationError as e: return row_id, json.loads(e.json()) - def _to_rules(self) -> List[Optional[Rule | tuple[Any, Any]]]: + def _to_rules(self) -> List[Optional[ProcessRule | ServiceRule | tuple[Any, Any]]]: return [self._to_rule(row_id) for row_id in self.get_children()] def _errors(self) -> dict[Any, Any]: - return {rule[0]: rule[1] for rule in self._to_rules() if rule and not isinstance(rule, Rule)} + return {rule[0]: rule[1] for rule in self._to_rules() if + rule and not isinstance(rule, (ProcessRule, ServiceRule))} def has_error(self): return len(self._errors()) > 0 - def _save_state(self, state: bool): - self.unsaved_changes = state + def set_unsaved_changes(self, state: bool): + self.has_unsaved_changes = state self.event_generate(RulesListEvents.UNSAVED_CHANGES_STATE) def _changed(self): - self._save_state(True) + self.set_unsaved_changes(True) self._handle_errors() def _handle_errors(self): @@ -209,3 +215,26 @@ def _highlights_error(self, row_id, has_error: bool): def error_icon_created(self, icon, tooltip): pass + + def _on_key_press_tree(self, event): + ctrl = (event.state & 0x4) != 0 + + if ctrl and event.keycode == ord('A'): + self.select_all_rows() + + def _get_default_values(self) -> List[Any]: + result = [] + model_fields = self._model.model_fields + + for column_name in self["columns"]: + field_info = model_fields.get(column_name) + extra = field_info.json_schema_extra or dict() if field_info else dict() + default_value = extra.get('default_ui', '') + result.append(default_value) + + return result + + def add_row(self, values=[]): + if not values: + values = self._get_default_values() + super().add_row(values) diff --git a/src/ui/widget/editor/rules_tab.py b/src/ui/widget/editor/rules_tab.py new file mode 100644 index 0000000..08e6dbc --- /dev/null +++ b/src/ui/widget/editor/rules_tab.py @@ -0,0 +1,132 @@ +import tkinter as tk +from tkinter import ttk, LEFT, messagebox + +from constants.any import LOG +from constants.app_info import APP_NAME_WITH_VERSION +from constants.ui import UI_PADDING, ActionEvents, RulesListEvents +from enums.rules import RuleType +from service.config_service import ConfigService +from ui.widget.editor.buttons import RulesListButtons +from ui.widget.editor.rules_list import RulesList + + +class RulesTabs(ttk.Notebook): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self._list_by_rt: dict[RuleType, RulesList] = {} + self._frame_to_rt: dict[str, RuleType] = {} + self._buttons_by_rt = {} + self._create_tabs() + + def _create_tabs(self): + for rt in RuleType: + frame = ttk.Frame(self) + frame._icon = rt.get_icon() # hard reference - fix missing icon bug + key = str(frame) + + self._frame_to_rt[key] = rt + self._list_by_rt[rt] = rules_list = self._create_rules_list(frame, rt) + self._buttons_by_rt[rt] = buttons = self._create_buttons(frame, rules_list) + + buttons.pack(fill=tk.X, padx=UI_PADDING, pady=(UI_PADDING, 0)) + rules_list.pack(fill=tk.BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) + + self.add(frame, text=f" {rt.title} ", image=frame._icon, compound=LEFT) + self._update_buttons_state(key) + + def _create_rules_list(self, frame, rule_type: RuleType): + rules_list = RulesList(rule_type.clazz, frame) + + rules_list.bind("<>", lambda _: self._update_buttons_state(), "+") + rules_list.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_buttons_state(), "+") + + return rules_list + + def _create_buttons(self, frame, rules_list: RulesList): + buttons = RulesListButtons(frame) + + buttons.bind(ActionEvents.ADD, lambda _: rules_list.add_row(), "+") + buttons.bind(ActionEvents.DELETE, lambda _: rules_list.delete_selected_rows(), "+") + buttons.bind(ActionEvents.UP, lambda _: rules_list.move_rows_up(), "+") + buttons.bind(ActionEvents.DOWN, lambda _: rules_list.move_rows_down(), "+") + + return buttons + + def current_list_of_tab(self, frame=None) -> RulesList: + key = self._frame_to_rt[frame or self.select()] + return self._list_by_rt[key] + + def current_buttons_of_tab(self, frame=None) -> RulesListButtons: + key = self._frame_to_rt[frame or self.select()] + return self._buttons_by_rt[key] + + def _update_buttons_state(self, frame=None): + rules_list = self.current_list_of_tab(frame) + buttons = self.current_buttons_of_tab(frame) + selected_items = rules_list.selection() + + if selected_items: + first_selected_item = selected_items[0] + last_selected_item = selected_items[-1] + first_index = rules_list.index(first_selected_item) + last_index = rules_list.index(last_selected_item) + total_items = len(rules_list.get_children()) + + buttons.move_up["state"] = tk.NORMAL if first_index > 0 else tk.DISABLED + buttons.move_down["state"] = tk.NORMAL if last_index < total_items - 1 else tk.DISABLED + else: + buttons.move_up["state"] = tk.DISABLED + buttons.move_down["state"] = tk.DISABLED + + buttons.delete["state"] = tk.NORMAL if selected_items else tk.DISABLED + + self.event_generate(RulesListEvents.UNSAVED_CHANGES_STATE) + + def has_unsaved_changes(self) -> bool: + for rule_list in self._list_by_rt.values(): + if rule_list.has_unsaved_changes: + return True + return False + + def has_error(self) -> bool: + for rule_list in self._list_by_rt.values(): + if rule_list.has_error(): + return True + return False + + def load_data(self): + for rt, lst in self._list_by_rt.items(): + rules = ConfigService.load_rules_raw(rt) + lst.set_raw_data(rules) + + def save_data(self) -> bool: + try: + if not self.has_unsaved_changes(): + return True + + if self.has_error(): + messagebox.showerror( + f"Error Detected - {APP_NAME_WITH_VERSION}", + "Unable to save: The current rules are invalid. " + "Ensure all rules are correct before saving." + ) + return False + + for rt, lst in self._list_by_rt.items(): + rules = lst.get_data() + ConfigService.save_rules(rt, rules) + lst.set_unsaved_changes(False) + + return True + except: + LOG.exception("Error when saving file.") + messagebox.showerror(f"Error Detected - {APP_NAME_WITH_VERSION}", "An error occurred while saving.") + return False + + def list_by_rt(self) -> dict[RuleType, RulesList]: + return self._list_by_rt + + def buttons_by_rt(self) -> dict[RuleType, RulesListButtons]: + return self._buttons_by_rt + From 2463e704a78748017ef7623f9a6c69d10b4ea864 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 4 Aug 2024 02:54:42 +0800 Subject: [PATCH 02/39] [#11 #12] Added migration and removed log config from json --- build_portable.py | 2 +- src/configuration/config.py | 17 ++-- src/configuration/migration/all_migration.py | 53 +++++++++++ src/configuration/migration/base.py | 35 +++++++ .../m0_rules_to_split_rules_config.py | 35 +++++++ src/constants/any.py | 16 ---- src/constants/app_info.py | 2 + src/constants/files.py | 7 ++ src/{util/logs.py => constants/log.py} | 30 +++--- src/main_loop.py | 7 +- src/service/config_service.py | 91 ++++++++++++++++++- src/service/rules_service.py | 2 +- src/service/services_info_service.py | 2 +- src/ui/editor.py | 3 +- src/ui/tray.py | 2 +- src/ui/widget/editor/rules_list.py | 8 +- src/ui/widget/editor/rules_tab.py | 2 +- src/util/decorators.py | 4 +- src/util/lock_instance.py | 2 +- src/util/scheduler.py | 2 +- src/util/startup.py | 2 +- 21 files changed, 257 insertions(+), 67 deletions(-) create mode 100644 src/configuration/migration/all_migration.py create mode 100644 src/configuration/migration/base.py create mode 100644 src/configuration/migration/m0_rules_to_split_rules_config.py delete mode 100644 src/constants/any.py create mode 100644 src/constants/files.py rename src/{util/logs.py => constants/log.py} (64%) diff --git a/build_portable.py b/build_portable.py index 7a02fc3..a662229 100644 --- a/build_portable.py +++ b/build_portable.py @@ -5,8 +5,8 @@ import PyInstaller.__main__ import pyinstaller_versionfile -from constants.any import CONFIG_FILE_NAME from constants.app_info import APP_NAME, APP_VERSION, APP_AUTHOR, APP_NAME_WITH_VERSION +from constants.files import CONFIG_FILE_NAME # Setting paths and configuration parameters VERSION_FILE = "versionfile.txt" diff --git a/src/configuration/config.py b/src/configuration/config.py index a6da321..5d19ebd 100644 --- a/src/configuration/config.py +++ b/src/configuration/config.py @@ -1,8 +1,7 @@ -from typing import List +from typing import List, Optional from pydantic import BaseModel, Field -from configuration.logs import Logs from configuration.rule import ProcessRule, ServiceRule @@ -13,16 +12,16 @@ class Config(BaseModel): It defines the structure of the configuration, including rule application interval, logging settings, and rules. """ - ruleApplyIntervalSeconds: int = Field(default=1) + version: Optional[int] = Field(default=None) """ - The time interval (in seconds) at which rules are applied to processes and services. - Default is 1 second. + The version of the configuration. + This field can be None if the version is not set. """ - logging: Logs = Field(default_factory=Logs) + ruleApplyIntervalSeconds: int = Field(default=1) """ - An instance of the Logs class that defines logging settings for application. - Default settings are provided by the Logs class. + The time interval (in seconds) at which rules are applied to processes and services. + Default is 1 second. """ processRules: List[ProcessRule] = Field(default_factory=list) @@ -33,4 +32,4 @@ class Config(BaseModel): serviceRules: List[ServiceRule] = Field(default_factory=list) """ A list of Rule objects that specify how application manages services based on user-defined rules. - """ \ No newline at end of file + """ diff --git a/src/configuration/migration/all_migration.py b/src/configuration/migration/all_migration.py new file mode 100644 index 0000000..0cf55c8 --- /dev/null +++ b/src/configuration/migration/all_migration.py @@ -0,0 +1,53 @@ +import copy + +from configuration.migration.base import BaseMigration +from configuration.migration.m0_rules_to_split_rules_config import MigrationRules2SplitRulesConfig +from constants.app_info import APP_NAME_WITH_VERSION +from constants.log import LOG +from service.config_service import ConfigService +from util.messages import show_error + + +def run_all_migration(): + migrations: list[type[BaseMigration]] = [ + MigrationRules2SplitRulesConfig + ] + + config: dict = ConfigService.load_config_raw() + need_migrate = any(migration.should_migrate(config) for migration in migrations) + + if not need_migrate: + return + + LOG.info(f"Creating backup of the current configuration before migration") + ConfigService.backup_config() + + has_error = False + + for migration in migrations: + migration_name = migration.__name__ + + try: + if not migration.should_migrate(copy.deepcopy(config)): + continue + + LOG.info(f"[{migration_name}] Starting migration") + + migrated_config = migration.migrate(copy.deepcopy(config)) + migrated_config['version'] = migration.get_target_version() + + LOG.info(f"[{migration_name}] Migration completed to version {migrated_config['version']}") + config = migrated_config + except Exception as e: + has_error = True + LOG.exception(f"[{migration_name}] Migration failed") + show_error( + f"Error Detected - {APP_NAME_WITH_VERSION}", + f"Migration `{migration_name}` failed: \n{str(e)}" + ) + break + + if not has_error: + ConfigService.save_config_raw(config) + + diff --git a/src/configuration/migration/base.py b/src/configuration/migration/base.py new file mode 100644 index 0000000..620baa5 --- /dev/null +++ b/src/configuration/migration/base.py @@ -0,0 +1,35 @@ +from abc import ABC, abstractmethod + + +class BaseMigration(ABC): + @staticmethod + @abstractmethod + def should_migrate(config: dict) -> bool: + """ + Checks if migration is necessary. + + :param config: The current configuration dictionary. + :return: True if migration is required, otherwise False. + """ + pass + + @staticmethod + @abstractmethod + def migrate(config: dict) -> dict: + """ + Performs the migration and returns the updated configuration. + + :param config: The current configuration dictionary. + :return: Updated configuration after migration. + """ + pass + + @staticmethod + @abstractmethod + def get_target_version() -> int: + """ + Returns the target version for the configuration after migration. + + :return: The target version number. + """ + pass diff --git a/src/configuration/migration/m0_rules_to_split_rules_config.py b/src/configuration/migration/m0_rules_to_split_rules_config.py new file mode 100644 index 0000000..1dceb56 --- /dev/null +++ b/src/configuration/migration/m0_rules_to_split_rules_config.py @@ -0,0 +1,35 @@ +from typing import Optional + +from configuration.migration.base import BaseMigration + + +class MigrationRules2SplitRulesConfig(BaseMigration): + @staticmethod + def get_target_version() -> int: + return 1 + + @staticmethod + def should_migrate(config: dict) -> bool: + return 'version' not in config or config['version'] is None + + @staticmethod + def migrate(config: dict) -> Optional[dict]: + if 'rules' not in config: + return config + + process_rules = list(filter(lambda o: 'processSelector' in o, config['rules'])) + service_rules = list(filter(lambda o: 'serviceSelector' in o, config['rules'])) + + for processRule in process_rules: + processRule['selector'] = processRule['processSelector'] + del processRule['processSelector'] + + for serviceRule in service_rules: + serviceRule['selector'] = serviceRule['serviceSelector'] + del serviceRule['serviceSelector'] + + del config['rules'] + config['processRules'] = process_rules + config['serviceRules'] = service_rules + + return config diff --git a/src/constants/any.py b/src/constants/any.py deleted file mode 100644 index 818defe..0000000 --- a/src/constants/any.py +++ /dev/null @@ -1,16 +0,0 @@ -import logging -from logging import Logger -from typing import Final - -from constants.app_info import APP_NAME - -LOG: Final[Logger] = logging.getLogger("proc-gov") -LOG_FILE_NAME: Final[str] = "logging.txt" -LOCK_FILE_NAME: Final[str] = "pg.lock" - -STARTUP_TASK_NAME: Final[str] = f"{APP_NAME} Autostart" - -CONFIG_FILE_NAME: Final[str] = "config.json" -CONFIG_FILE_ENCODING: Final[str] = "utf-8" - -BOTH_SELECTORS_SET: Final[str] = "both_selectors_set" diff --git a/src/constants/app_info.py b/src/constants/app_info.py index 3afad6c..2ec1ecc 100644 --- a/src/constants/app_info.py +++ b/src/constants/app_info.py @@ -15,3 +15,5 @@ APP_PATH: Final[str] = sys._MEIPASS else: APP_PATH: Final[str] = os.getcwd() + +STARTUP_TASK_NAME: Final[str] = f"{APP_NAME} Autostart" diff --git a/src/constants/files.py b/src/constants/files.py new file mode 100644 index 0000000..a66a231 --- /dev/null +++ b/src/constants/files.py @@ -0,0 +1,7 @@ +from typing import Final + +LOCK_FILE_NAME: Final[str] = "pg.lock" + +CONFIG_FILE_NAME: Final[str] = "config.json" +CONFIG_FILE_ENCODING: Final[str] = "utf-8" +LOG_FILE_NAME: Final[str] = "logging.txt" diff --git a/src/util/logs.py b/src/constants/log.py similarity index 64% rename from src/util/logs.py rename to src/constants/log.py index 7efaf0d..86cea02 100644 --- a/src/util/logs.py +++ b/src/constants/log.py @@ -1,14 +1,14 @@ import logging import sys -from logging import StreamHandler +from logging import StreamHandler, Logger from logging.handlers import RotatingFileHandler +from typing import Final from configuration.logs import Logs -from constants.any import LOG, LOG_FILE_NAME -from service.config_service import ConfigService +from constants.files import LOG_FILE_NAME -def log_setup(): +def __log_setup() -> Logger: """ Sets up the logging configuration. @@ -16,25 +16,19 @@ def log_setup(): accordingly. If the logging configuration is disabled, the function does nothing. """ + log: Logger = logging.getLogger("proc-gov") log_cfg: Logs = Logs() - exception = None - try: - log_cfg = ConfigService.load_logs() - except BaseException as e: - exception = e - pass - - LOG.setLevel(log_cfg.level_as_int()) + log.setLevel(log_cfg.level_as_int()) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') console_handler = StreamHandler(sys.stdout) console_handler.setFormatter(formatter) - LOG.addHandler(console_handler) + log.addHandler(console_handler) if not log_cfg.enable: - return + return log file_handler = RotatingFileHandler( LOG_FILE_NAME, @@ -43,7 +37,9 @@ def log_setup(): encoding='utf-8', ) file_handler.setFormatter(formatter) - LOG.addHandler(file_handler) + log.addHandler(file_handler) + + return log + - if exception: - raise exception +LOG: Final[logging.Logger] = __log_setup() diff --git a/src/main_loop.py b/src/main_loop.py index eb9850c..cbf8643 100644 --- a/src/main_loop.py +++ b/src/main_loop.py @@ -8,14 +8,15 @@ from pystray._win32 import Icon from configuration.config import Config -from constants.any import LOG, LOG_FILE_NAME +from configuration.migration.all_migration import run_all_migration from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME +from constants.files import LOG_FILE_NAME +from constants.log import LOG from constants.ui import RC_TITLE from service.config_service import ConfigService from service.rules_service import RulesService from ui.editor import open_rule_editor, is_editor_open from ui.tray import init_tray -from util.logs import log_setup from util.messages import yesno_error_box, show_error from util.startup import update_startup @@ -88,8 +89,8 @@ def start_app(): tray: Optional[Icon] = None try: + run_all_migration() update_startup() - log_setup() priority_setup() tray: Icon = init_tray() diff --git a/src/service/config_service.py b/src/service/config_service.py index ea745ac..ebc8f70 100644 --- a/src/service/config_service.py +++ b/src/service/config_service.py @@ -1,13 +1,14 @@ import json import os.path from abc import ABC +from datetime import datetime from os.path import exists from typing import Optional, List, Any from configuration.config import Config from configuration.logs import Logs from configuration.rule import ProcessRule, ServiceRule -from constants.any import CONFIG_FILE_NAME, CONFIG_FILE_ENCODING +from constants.files import CONFIG_FILE_NAME, CONFIG_FILE_ENCODING from enums.rules import RuleType from util.decorators import cached @@ -33,8 +34,8 @@ def save_config(cls, config: Config): raise ValueError("config is None") with open(CONFIG_FILE_NAME, 'w', encoding=CONFIG_FILE_ENCODING) as file: - json = config.model_dump_json(indent=4, exclude_none=True, warnings=False) - file.write(json) + json_data = config.model_dump_json(indent=4, exclude_none=True, warnings=False) + file.write(json_data) @classmethod @cached(1) @@ -42,6 +43,9 @@ def load_config(cls, validate=True) -> Config: """ Load the configuration from a JSON file or create a new one if the file doesn't exist. + Args: + validate (bool): Whether to validate the configuration upon loading. Defaults to True. + Returns: Config: The loaded or newly created configuration object. """ @@ -62,7 +66,7 @@ def reload_if_changed(cls, prev_config: Optional[Config]) -> tuple[Config, bool] """ Reloads the configuration if it has changed since the last reload and returns the updated configuration and a flag indicating whether the configuration has changed. - Parameters: + Args: prev_config (Optional[Config]): The previous configuration object. Can be None if there is no previous configuration. Returns: @@ -80,6 +84,15 @@ def reload_if_changed(cls, prev_config: Optional[Config]) -> tuple[Config, bool] @classmethod def load_rules_raw(cls, rule_type: RuleType) -> List[Any]: + """ + Loads raw rules of a specific type from the configuration file. + + Args: + rule_type (RuleType): The type of rules to load. + + Returns: + List[Any]: A list of raw rule data. + """ if not exists(CONFIG_FILE_NAME): cls.save_config(Config()) @@ -89,6 +102,12 @@ def load_rules_raw(cls, rule_type: RuleType) -> List[Any]: @classmethod def load_logs(cls) -> Logs: + """ + Loads the logging configuration from the configuration file. + + Returns: + Logs: The logging configuration. + """ if not exists(CONFIG_FILE_NAME): cls.save_config(config := Config()) return config.logging @@ -99,6 +118,13 @@ def load_logs(cls) -> Logs: @classmethod def save_rules(cls, rule_type: RuleType, rules: List[ProcessRule | ServiceRule]): + """ + Save the rules of a specific type to the configuration file. + + Args: + rule_type (RuleType): The type of rules to save. + rules (List[ProcessRule | ServiceRule]): The list of rules to be saved. + """ if rules is None: raise ValueError("rules is None") @@ -109,6 +135,12 @@ def save_rules(cls, rule_type: RuleType, rules: List[ProcessRule | ServiceRule]) @classmethod def rules_has_error(cls) -> bool: + """ + Checks if there are any errors in the rules defined in the configuration. + + Returns: + bool: True if there are errors in the rules, otherwise False. + """ try: for rule_type in RuleType: rules: List[Any] = cls.load_rules_raw(rule_type) @@ -123,6 +155,57 @@ def rules_has_error(cls) -> bool: return False + @classmethod + def load_config_raw(cls) -> dict: + """ + Loads the raw configuration as a dictionary from the configuration file. + + Returns: + dict: The raw configuration data. + """ + if not exists(CONFIG_FILE_NAME): + cls.save_config(Config()) + + with open(CONFIG_FILE_NAME, 'r', encoding=CONFIG_FILE_ENCODING) as file: + return json.load(file) + + @classmethod + def save_config_raw(cls, config: dict): + """ + Saves the raw configuration dictionary to the configuration file. + + Args: + config (dict): The configuration data to be saved. + """ + if config is None: + raise ValueError("config is None") + + with open(CONFIG_FILE_NAME, 'w', encoding=CONFIG_FILE_ENCODING) as file: + json.dump(config, file, indent=4) + + @classmethod + def backup_config(cls): + """ + Creates a backup of the current configuration file in the same directory where the original configuration file is located. + + If the configuration file does not exist, no backup is created. + + Raises: + IOError: If the backup process fails. + """ + if not exists(CONFIG_FILE_NAME): + return + + base_name, ext = os.path.splitext(CONFIG_FILE_NAME) + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + backup_filename = f"{base_name}_backup_{timestamp}.{ext}" + + try: + with open(CONFIG_FILE_NAME, 'r', encoding=CONFIG_FILE_ENCODING) as src_file: + with open(backup_filename, 'w', encoding=CONFIG_FILE_ENCODING) as dst_file: + dst_file.write(src_file.read()) + except IOError as e: + raise IOError(f"Failed to create backup: {e}") if __name__ == '__main__': print(ConfigService.rules_has_error()) diff --git a/src/service/rules_service.py b/src/service/rules_service.py index 4d8ca96..d0bd593 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -8,7 +8,7 @@ from configuration.config import Config from configuration.rule import ProcessRule, ServiceRule -from constants.any import LOG +from constants.log import LOG from constants.priority_mappings import iopriority_to_str, priority_to_str from enums.process import ProcessParameter from model.process import Process diff --git a/src/service/services_info_service.py b/src/service/services_info_service.py index 0b13fee..e5cb475 100644 --- a/src/service/services_info_service.py +++ b/src/service/services_info_service.py @@ -5,7 +5,7 @@ from psutil import STATUS_STOPPED, NoSuchProcess, ZombieProcess, AccessDenied from psutil._pswindows import WindowsService -from constants.any import LOG +from constants.log import LOG from model.service import Service from util.decorators import suppress_exception diff --git a/src/ui/editor.py b/src/ui/editor.py index 8582081..49427b3 100644 --- a/src/ui/editor.py +++ b/src/ui/editor.py @@ -3,8 +3,9 @@ from threading import Thread from tkinter import messagebox, ttk -from constants.any import LOG, LOG_FILE_NAME from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME +from constants.files import LOG_FILE_NAME +from constants.log import LOG from constants.resources import APP_ICON from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, RC_TITLE, RulesListEvents, EditableTreeviewEvents from enums.rules import RuleType diff --git a/src/ui/tray.py b/src/ui/tray.py index a8db4c3..5436bfc 100644 --- a/src/ui/tray.py +++ b/src/ui/tray.py @@ -6,8 +6,8 @@ from pystray import MenuItem, Menu from pystray._win32 import Icon -from constants.any import CONFIG_FILE_NAME, LOG_FILE_NAME from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME +from constants.files import CONFIG_FILE_NAME, LOG_FILE_NAME from constants.resources import APP_ICON from constants.ui import RC_TRAY_TITLE from constants.updates import UPDATE_URL diff --git a/src/ui/widget/editor/rules_list.py b/src/ui/widget/editor/rules_list.py index afdd567..d19380f 100644 --- a/src/ui/widget/editor/rules_list.py +++ b/src/ui/widget/editor/rules_list.py @@ -9,7 +9,6 @@ from pydantic import ValidationError, BaseModel from configuration.rule import ServiceRule, ProcessRule -from constants.any import BOTH_SELECTORS_SET from constants.priority_mappings import str_to_priority, str_to_iopriority from constants.ui import ERROR_COLOR, ERROR_ROW_COLOR, RulesListEvents, EditableTreeviewEvents, \ ScrollableTreeviewEvents @@ -150,12 +149,7 @@ def _handle_errors(self): if errors_by_columns: for column_error in errors_by_columns: - if column_error["type"] == BOTH_SELECTORS_SET: - columns = ["processSelector", "serviceSelector"] - else: - columns = column_error["loc"] - - for column in columns: + for column in column_error["loc"]: self._place_icon(row_id, column, column_error) def _destroy_error_icons(self): diff --git a/src/ui/widget/editor/rules_tab.py b/src/ui/widget/editor/rules_tab.py index 08e6dbc..503f2e2 100644 --- a/src/ui/widget/editor/rules_tab.py +++ b/src/ui/widget/editor/rules_tab.py @@ -1,8 +1,8 @@ import tkinter as tk from tkinter import ttk, LEFT, messagebox -from constants.any import LOG from constants.app_info import APP_NAME_WITH_VERSION +from constants.log import LOG from constants.ui import UI_PADDING, ActionEvents, RulesListEvents from enums.rules import RuleType from service.config_service import ConfigService diff --git a/src/util/decorators.py b/src/util/decorators.py index e5f81c8..3a6778c 100644 --- a/src/util/decorators.py +++ b/src/util/decorators.py @@ -3,9 +3,9 @@ from contextlib import suppress from functools import wraps from time import time -from typing import Callable, Optional, Type, TypeVar +from typing import Callable, Optional, TypeVar -from constants.any import LOG +from constants.log import LOG def run_in_thread(non_reentrant=True): diff --git a/src/util/lock_instance.py b/src/util/lock_instance.py index 45b2006..2a767a5 100644 --- a/src/util/lock_instance.py +++ b/src/util/lock_instance.py @@ -3,7 +3,7 @@ import psutil -from constants.any import LOCK_FILE_NAME +from constants.files import LOCK_FILE_NAME def is_process_running(pid): diff --git a/src/util/scheduler.py b/src/util/scheduler.py index a4cc62b..d4418f7 100644 --- a/src/util/scheduler.py +++ b/src/util/scheduler.py @@ -1,6 +1,6 @@ import subprocess -from constants.any import LOG +from constants.log import LOG class TaskScheduler: diff --git a/src/util/startup.py b/src/util/startup.py index 989e798..2410487 100644 --- a/src/util/startup.py +++ b/src/util/startup.py @@ -1,6 +1,6 @@ import sys -from constants.any import STARTUP_TASK_NAME +from constants.app_info import STARTUP_TASK_NAME from constants.resources import STARTUP_SCRIPT from util.scheduler import TaskScheduler from util.utils import is_portable From 042e474b435c2bd9e15dd6bceda739e63d05fe70 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 4 Aug 2024 02:58:54 +0800 Subject: [PATCH 03/39] [#11 #12] Little changes --- src/configuration/migration/all_migration.py | 22 +++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/configuration/migration/all_migration.py b/src/configuration/migration/all_migration.py index 0cf55c8..8990d42 100644 --- a/src/configuration/migration/all_migration.py +++ b/src/configuration/migration/all_migration.py @@ -7,14 +7,24 @@ from service.config_service import ConfigService from util.messages import show_error +MIGRATIONS: list[type[BaseMigration]] = [ + MigrationRules2SplitRulesConfig +] +""" +List of migration classes to be executed in order. +""" + def run_all_migration(): - migrations: list[type[BaseMigration]] = [ - MigrationRules2SplitRulesConfig - ] + """ + Runs all necessary migrations on the configuration. + Creates a backup before migration, applies each migration in order, + logs progress, and saves the updated configuration if successful. + Shows an error and stops if any migration fails. + """ config: dict = ConfigService.load_config_raw() - need_migrate = any(migration.should_migrate(config) for migration in migrations) + need_migrate = any(migration.should_migrate(config) for migration in MIGRATIONS) if not need_migrate: return @@ -24,7 +34,7 @@ def run_all_migration(): has_error = False - for migration in migrations: + for migration in MIGRATIONS: migration_name = migration.__name__ try: @@ -49,5 +59,3 @@ def run_all_migration(): if not has_error: ConfigService.save_config_raw(config) - - From 43611f7b764e18c4b0d945c9e8b123e6afd23125 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 4 Aug 2024 03:04:34 +0800 Subject: [PATCH 04/39] [#11] Changed UI padding and tray menu --- src/constants/ui.py | 3 +-- src/ui/tray.py | 6 +----- src/ui/widget/common/treeview/editable.py | 3 --- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/constants/ui.py b/src/constants/ui.py index ca71f72..92d8d83 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -1,13 +1,12 @@ from typing import Final -UI_PADDING = 12 +UI_PADDING = 10 BUTTON_SIZE = 7 ERROR_COLOR = "#e57373" ERROR_ROW_COLOR = "#ffcdd2" TOOLTIP_ICON_SIZE = 75 RC_WIN_SIZE = (900, 600) RC_TITLE = "Rules Configurator" -RC_TRAY_TITLE = f"Configure Rules" class ActionEvents: diff --git a/src/ui/tray.py b/src/ui/tray.py index 5436bfc..21eb30c 100644 --- a/src/ui/tray.py +++ b/src/ui/tray.py @@ -9,7 +9,6 @@ from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.files import CONFIG_FILE_NAME, LOG_FILE_NAME from constants.resources import APP_ICON -from constants.ui import RC_TRAY_TITLE from constants.updates import UPDATE_URL from ui.editor import open_rule_editor from util.messages import yesno_error_box, show_error, show_info @@ -57,10 +56,7 @@ def init_tray() -> Icon: image: Image = Image.open(APP_ICON) menu: tuple[MenuItem, ...] = ( - MenuItem(APP_NAME_WITH_VERSION, None, enabled=False), - Menu.SEPARATOR, - - MenuItem(RC_TRAY_TITLE, lambda item: open_rule_editor(), default=True), + MenuItem(APP_NAME_WITH_VERSION, lambda item: open_rule_editor(), default=True), Menu.SEPARATOR, MenuItem('Open config file', lambda item: os.startfile(CONFIG_FILE_NAME)), diff --git a/src/ui/widget/common/treeview/editable.py b/src/ui/widget/common/treeview/editable.py index 8b90a4e..f56d633 100644 --- a/src/ui/widget/common/treeview/editable.py +++ b/src/ui/widget/common/treeview/editable.py @@ -1,5 +1,4 @@ import tkinter as tk -import traceback from dataclasses import dataclass from tkinter import ttk from typing import Optional, Literal, List @@ -178,8 +177,6 @@ def _save_and_destroy_popup(self, _=None): def _destroy_editor(self, _=None): if self._popup: - print("sadfsdfasdfsd") - traceback.print_stack() self._popup.destroy() def _save_cell_changes(self): From 7ca2bdd494870aab0fdb247505a3ffcdc6784db3 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 4 Aug 2024 03:11:02 +0800 Subject: [PATCH 05/39] [#11] Changed logging settings and removed unused method --- src/configuration/logs.py | 4 ++-- src/service/config_service.py | 17 ----------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/configuration/logs.py b/src/configuration/logs.py index 2792013..3d762bc 100644 --- a/src/configuration/logs.py +++ b/src/configuration/logs.py @@ -19,11 +19,11 @@ class Logs(BaseModel): level: Literal['CRITICAL', 'FATAL', 'ERROR', 'WARNING', 'WARN', 'INFO', 'DEBUG', 'NOTSET'] = Field(default='INFO') """ - The log level for filtering log messages. Default is 'WARN'. + The log level for filtering log messages. Default is 'INFO'. Valid log levels include: 'CRITICAL', 'FATAL', 'ERROR', 'WARNING', 'WARN', 'INFO', 'DEBUG', 'NOTSET'. """ - maxBytes: int = Field(default=1024) + maxBytes: int = Field(default=1024 * 1024) """ The maximum size (in bytes) of the log file. When the log file exceeds this size, it will be rotated. Default is 1 megabyte (1024 * 1024 bytes). diff --git a/src/service/config_service.py b/src/service/config_service.py index ebc8f70..4bd4781 100644 --- a/src/service/config_service.py +++ b/src/service/config_service.py @@ -6,7 +6,6 @@ from typing import Optional, List, Any from configuration.config import Config -from configuration.logs import Logs from configuration.rule import ProcessRule, ServiceRule from constants.files import CONFIG_FILE_NAME, CONFIG_FILE_ENCODING from enums.rules import RuleType @@ -100,22 +99,6 @@ def load_rules_raw(cls, rule_type: RuleType) -> List[Any]: json_data = json.load(file) return json_data.get(rule_type.field_in_config, []) - @classmethod - def load_logs(cls) -> Logs: - """ - Loads the logging configuration from the configuration file. - - Returns: - Logs: The logging configuration. - """ - if not exists(CONFIG_FILE_NAME): - cls.save_config(config := Config()) - return config.logging - - with open(CONFIG_FILE_NAME, 'r', encoding=CONFIG_FILE_ENCODING) as file: - json_data = json.load(file) - return Logs(**json_data['logging']) - @classmethod def save_rules(cls, rule_type: RuleType, rules: List[ProcessRule | ServiceRule]): """ From 6c6e6bf27e89902f315a6a06faebd258aff4b711 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 4 Aug 2024 03:34:27 +0800 Subject: [PATCH 06/39] [#11] Fixed false result of checking the application is running --- src/constants/app_info.py | 1 + src/util/lock_instance.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/constants/app_info.py b/src/constants/app_info.py index 2ec1ecc..2ebf018 100644 --- a/src/constants/app_info.py +++ b/src/constants/app_info.py @@ -7,6 +7,7 @@ APP_NAME: Final[str] = "Process Governor" APP_VERSION: Final[str] = "1.2.2" APP_AUTHOR: Final[str] = "System X - Files" +APP_PROCESSES = {"Process Governor.exe", "python.exe"} CURRENT_TAG: Final[str] = f"v{APP_VERSION}" APP_NAME_WITH_VERSION: Final[str] = f"{APP_NAME} {CURRENT_TAG}" diff --git a/src/util/lock_instance.py b/src/util/lock_instance.py index 2a767a5..c4cbaa4 100644 --- a/src/util/lock_instance.py +++ b/src/util/lock_instance.py @@ -3,6 +3,7 @@ import psutil +from constants.app_info import APP_PROCESSES from constants.files import LOCK_FILE_NAME @@ -18,7 +19,8 @@ def is_process_running(pid): """ try: process = psutil.Process(pid) - return process.is_running() + process_name = process.name() + return process.is_running() and process_name in APP_PROCESSES except psutil.NoSuchProcess: return False From abcd37bedfdabf5352e5850b04a077abb1c07e56 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 4 Aug 2024 03:42:00 +0800 Subject: [PATCH 07/39] [#11] Added a message if the application is already running --- process-governor.py | 13 +++++++------ src/util/lock_instance.py | 9 ++++++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/process-governor.py b/process-governor.py index 471638a..31493a0 100644 --- a/process-governor.py +++ b/process-governor.py @@ -4,21 +4,22 @@ import pyuac from constants.app_info import APP_NAME, APP_NAME_WITH_VERSION +from constants.log import LOG from main_loop import start_app from util.lock_instance import create_lock_file, remove_lock_file from util.messages import show_error if __name__ == "__main__": if not platform.system() == "Windows": - print(f"{APP_NAME} is intended to run on Windows only.") + LOG.error(f"{APP_NAME} is intended to run on Windows only.") sys.exit(1) if not pyuac.isUserAdmin(): - show_error( - f"Error Detected - {APP_NAME_WITH_VERSION}", - "This program requires administrator privileges to run.\n" - "Please run the program as an administrator to ensure proper functionality." - ) + message = ("This program requires administrator privileges to run.\n" + "Please run the program as an administrator to ensure proper functionality.") + + LOG.error(message) + show_error(f"Error Detected - {APP_NAME_WITH_VERSION}", message) sys.exit(1) create_lock_file() diff --git a/src/util/lock_instance.py b/src/util/lock_instance.py index c4cbaa4..a9a671d 100644 --- a/src/util/lock_instance.py +++ b/src/util/lock_instance.py @@ -3,8 +3,10 @@ import psutil -from constants.app_info import APP_PROCESSES +from constants.app_info import APP_PROCESSES, APP_NAME_WITH_VERSION from constants.files import LOCK_FILE_NAME +from constants.log import LOG +from util.messages import show_error def is_process_running(pid): @@ -42,6 +44,11 @@ def create_lock_file(): pid_str = file.read().strip() if pid_str: if is_process_running(int(pid_str)): + message = ("The application is already running.\n" + "Please close the existing instance before starting a new one.") + + LOG.error(message) + show_error(f"Error Detected - {APP_NAME_WITH_VERSION}", message) sys.exit(1) # Create the lock file with the current process's PID From 7cbbe71501087ac67586168677695ae2b84a8970 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 4 Aug 2024 14:35:47 +0800 Subject: [PATCH 08/39] [#11] Fixed display of column descriptions when hovering over the header --- src/ui/widget/common/treeview/editable.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ui/widget/common/treeview/editable.py b/src/ui/widget/common/treeview/editable.py index f56d633..efe104b 100644 --- a/src/ui/widget/common/treeview/editable.py +++ b/src/ui/widget/common/treeview/editable.py @@ -117,9 +117,6 @@ def get_cell_info(self, event): return self._get_cell_info(row_id, column_id) def _get_cell_info(self, row_id, column_id): - if not row_id or not column_id or column_id == "#0": - return None - column_name = self.column(column_id)["id"] cell_value = self.set(row_id, column_id) values = self._values.get(column_name, []) @@ -141,12 +138,11 @@ def popup(self): return self._popup def _on_dbl_click(self, event): - self._destroy_editor() - self._cell = self.get_cell_info(event) - self._create_editor() + row_id, column_id = self.identify_row(event.y), self.identify_column(event.x) + self.edit_cell(row_id, column_id) def _create_editor(self): - if not self._cell: + if not self._cell.row_id or not self._cell.column_id or self._cell.column_id == "#0": return self._popup = entry_popup = CellEditor(self, self._cell) From a949d895bad6f41e655a1349ee811351e5e4d7c4 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 4 Aug 2024 20:49:44 +0800 Subject: [PATCH 09/39] [#11] Changed the name of the settings in the docs and removed the RU version, because it creates support difficulties --- docs/README.md | 2 - docs/README.ru.md | 53 ---- docs/configuration_file.md | 2 +- docs/configuration_file.ru.md | 114 --------- docs/icons/gb.png | Bin 1988 -> 0 bytes docs/icons/ru.png | Bin 1752 -> 0 bytes docs/run_and_build.md | 2 +- docs/run_and_build.ru.md | 25 -- docs/tips'n'tricks/audio.md | 10 +- docs/tips'n'tricks/audio.ru.md | 268 --------------------- docs/tips'n'tricks/game_optimization.md | 12 +- docs/tips'n'tricks/game_optimization.ru.md | 123 ---------- docs/ui_rule_configurator.md | 20 +- docs/ui_rule_configurator.ru.md | 94 -------- 14 files changed, 23 insertions(+), 702 deletions(-) delete mode 100644 docs/README.ru.md delete mode 100644 docs/configuration_file.ru.md delete mode 100644 docs/icons/gb.png delete mode 100644 docs/icons/ru.png delete mode 100644 docs/run_and_build.ru.md delete mode 100644 docs/tips'n'tricks/audio.ru.md delete mode 100644 docs/tips'n'tricks/game_optimization.ru.md delete mode 100644 docs/ui_rule_configurator.ru.md diff --git a/docs/README.md b/docs/README.md index cd04f30..b91a950 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,5 @@ ![Logo Process Governor](images/github-banner-readme.png) -[![RU](icons/ru.png) Русская версия](README.ru.md) - --- **Process Governor** is a Python utility designed to manage Windows processes and services by adjusting their diff --git a/docs/README.ru.md b/docs/README.ru.md deleted file mode 100644 index e39eac9..0000000 --- a/docs/README.ru.md +++ /dev/null @@ -1,53 +0,0 @@ -![Logo Process Governor](images/github-banner-readme.png) - -[![EN](icons/gb.png) English version](README.md) - ---- - -**Process Governor** - это утилита на Python, предназначенная для управления процессами и службами в Windows путем -настройки их приоритетов, приоритетов ввода/вывода и привязки к ядрам на основе пользовательских правил. - -
- Скриншоты - - >![tray_menu_screenshot.png](images/tray_menu_screenshot.png) - > - >![audio_artiacle_rule_configurator_screenshot.png](images/audio_artiacle_rule_configurator_screenshot.png) - > - >![rule_configurator_with_error_screenshot.png](images/rule_configurator_with_error_screenshot.png) -
- -## Возможности - -- Настройка приоритетов процессов и служб для повышения производительности. -- Управление приоритетами ввода/вывода для оптимизации использования ресурсов. -- Определение привязки к ядрам для процессов. -- Тонкая настройка процессов и служб Windows на основе [пользовательских правил](ui_rule_configurator.ru.md). -- Непрерывный мониторинг файла конфигурации для применения правил. -- Возможность добавить Process Governor в автозапуск. - -## Начало работы - -Для начала работы с **Process Governor** выполните следующие шаги: - -1. Скачайте последнюю готовую сборку по - ссылке: [Latest Release](https://github.com/SystemXFiles/process-governor/releases/latest). -2. Запустите исполняемый файл `Process Governor.exe` с **правами администратора**. - Это важно, чтобы программа могла внести необходимые изменения в приоритеты процессов и служб, приоритеты ввода-вывода - и соответствие ядер. -3. [Настройте правила](ui_rule_configurator.ru.md) для процессов и сервисов. - -Программу можно закрыть, обратившись к значку в системном трее. - -## База знаний - -- [Конфигурирование правил](ui_rule_configurator.ru.md) -- [Файл конфигурации](configuration_file.ru.md) -- [Запуск из исходников и создание портабельной сборки](run_and_build.ru.md) -- **Советы и трюки** - - [Оптимизация звука](tips'n'tricks/audio.ru.md) - - [Оптимизация игр](tips'n'tricks/game_optimization.ru.md) - -## Лицензия - -Этот проект лицензирован согласно GNU General Public License v3.0 - см. файл [LICENSE](../LICENSE) для подробностей. \ No newline at end of file diff --git a/docs/configuration_file.md b/docs/configuration_file.md index 1aeb0ce..af467a7 100644 --- a/docs/configuration_file.md +++ b/docs/configuration_file.md @@ -1,6 +1,6 @@ # Configuration File -[![README](icons/readme.png) README](README.md) | [![RU](icons/ru.png) Русская версия](configuration_file.ru.md) +[![README](icons/readme.png) README](README.md) --- diff --git a/docs/configuration_file.ru.md b/docs/configuration_file.ru.md deleted file mode 100644 index e0d2bcd..0000000 --- a/docs/configuration_file.ru.md +++ /dev/null @@ -1,114 +0,0 @@ -# Файл конфигурации - -[![README](icons/readme.png) README](README.ru.md) | [![EN](icons/gb.png) English version](configuration_file.md) - ---- - -Файл конфигурации `config.json` служит для управления поведением приложения **Process Governor**. Он позволяет -определить, как приложение будет регулировать приоритеты процессов и служб, их I/O приоритеты и соответствие к ядрам -процессора. - -Файл конфигурации регулярно проверяется приложением и при наличии изменений - применяется. - -### Пример файла конфигурации - -В этом примере определены два правила: одно для процесса и одно для службы. - -```json -{ - "ruleApplyIntervalSeconds": 1, - "logging": { - "enable": true, - "level": "WARN", - "maxBytes": 1024, - "backupCount": 1 - }, - "rules": [ - { - "processSelector": "example.exe", - "priority": "High", - "ioPriority": "Normal", - "affinity": "1;3-5" - }, - { - "serviceSelector": "Audio*", - "priority": "Realtime", - "ioPriority": "High", - "affinity": "0;2;4" - } - ] -} -``` - -## Структура `config.json` - -Файл конфигурации состоит из нескольких ключевых секций: - -### `ruleApplyIntervalSeconds` - -Этот параметр определяет интервал в секундах, с которым правила будут применяться к процессам и службам. По умолчанию -установлено значение `1`, что означает применение правил каждую секунду. - -### `logging` - -Эта секция содержит настройки логирования. Она позволяет включить или отключить логирование, задать уровень логирования, -максимальный размер файла лога и количество резервных копий логов, которые необходимо хранить. - -#### Возможные параметры: - -- `enable`: Включает или отключает логирование. -- `level`: Уровень логирования (`INFO`, `WARN` и т.д.). -- `maxBytes`: Максимальный размер файла лога в байтах. -- `backupCount`: Количество резервных копий файла лога. - -### `rules` - -Это секция определяет список правил, по которым **Process Governor** будет управлять процессами и службами. Каждое -правило определяется объектом с -набором параметров. - -#### Возможные параметры: - -- `processSelector` (строка, опционально): Указывает имя процесса или шаблон для сопоставления. - Вы можете использовать подстановочные символы, включая `*` и `?`, чтобы сопоставить несколько процессов. - - Пример: `"processSelector": "example.exe"` - - Пример с подстановочными символами: `"processSelector": "logioptionsplus_*.exe"` - - -- `serviceSelector` (строка, опционально): Указывает имя службы или шаблон для сопоставления. - Вы можете использовать подстановочные символы, включая `*` и `?`, чтобы сопоставить несколько служб. - - Пример: `"serviceSelector": "MyService"` - - Пример с подстановочными символами: `"serviceSelector": "Audio*"` - - -- `priority` (строка, опционально): Устанавливает приоритет процесса или службы. - Допустимые значения: - - `"Idle"` - - `"BelowNormal"` - - `"Normal"` - - `"AboveNormal"` - - `"High"` - - `"Realtime"` - - Пример: `"priority": "High"` - - -- `ioPriority` (строка, опционально): Устанавливает приоритет ввода/вывода для процесса или службы. - Допустимые значения: - - `"VeryLow"` - - `"Low"` - - `"Normal"` - - `"High"`: Установка приоритета ввода-вывода на "High" может вызвать ошибку AccessDenied в большинстве случаев. - - Пример: `"ioPriority": "Normal"` - - -- `affinity` (строка, опционально): Определяет привязку процесса к ядру CPU. - Вы можете указать привязку следующим образом: - - Диапазон (включительно): `"affinity": "0-3"` - - Конкретные ядра: `"affinity": "0;2;4"` - - Комбинация: `"affinity": "1;3-5"` - -### Валидация - -Встроенная валидация предотвращает одновременное задание `processSelector` и `serviceSelector` в одном правиле. Если вы -попытаетесь задать оба параметра, программа уведомит вас об ошибке и потребует исправления правила. - diff --git a/docs/icons/gb.png b/docs/icons/gb.png deleted file mode 100644 index 0cab9d06d1422feaa9b9b01de228bf3a98e78e16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1988 zcmbVNYfKzf6dph+5Qt!Eq-|1$p-oYloyX2TX2MEg7t2}~D3Cz0CcS&-4m+|tcbpk^ z7c`MH*2Eu8_@Sn$k2F4L(^S*=2qZ>n#I%2mf!eCoKh~J^Mf6A2*c!z<%d({g+Qv<0 z=gz&~J?A^$J?Gq)x;uANRcx%FD5@&j5$PfCYVuT;6_fv;_aFO)yvogv-8Mye8r-KS z`)*5`qDlw#z5!<-_Jjg)$^%p!N1klTBxs6iZpoSe4kL$-qaoc0F~5E?!_c}KV)}hC zK4ykdLhl%}Q14i09~>KovdXkPN;hW}VjzVaKxb1)!&b5(CTCY6V|SWk=p4iu4l%8+ zLwX?AO^30CXupSNAB$nqDudGNCo&Pb!ouz6@Pvo(@ zGx8N;5{_dk9GA&tJQ=SCTSJ^6%QDA{oG7vc!P=vS1G21PH!NF-ARAh`>FC&?U5g-& zN1PBts4m5jG7Dx6JFgQ_jLQO(6Fj^dQx2%Y0?r( zu%;);g59&DjgGd5{etZGv!X}H(T&BFs9`(6fG8RXF+?1XuB%EgD8~Z<#$6tmIQARz{M{0w4oc_CZO4 zaj401flZgClZph%l~!F=DzWI7f^o@i;&C_abD5-c z=r%dy(R?BGqG$4>q)z9OM*+|+iVy?cY(OfLpVn8= z`6yf%$RMUIavfZLtL{09Dyoh~TKgJ%;k3Hx#_wkilx#D~uRJI`tQF6no;}i4cB!al z;zI5D`_}LJ=sj5){#zft`r7>U%FKsPk00;f8Tf4R&no7?WIdfawSS@X@IM#7ew8}M z*N#oS`OBeoXG_jrzc_p3#quX7d<%O%uDkTYwXx0H`(K~AQG4`YQDV!Su=Cme&$mwa z_FRh=D{KEYC6SY_Lz3))7R|((kyXZrMGt};q?uy#T#Ps*yepUBUfhVWN-Fr6L M-WhqnZSTH+0n2BVg8%>k diff --git a/docs/icons/ru.png b/docs/icons/ru.png deleted file mode 100644 index 58cb5bdf586295cc7f62c82aac59d010c2669f46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1752 zcmbVN&yU+g6gD7!6)N?>iPOl-p%sjO#dhLR&1#!0-AH7KwvoCZ4js>o6SJ|$9eb1P zo)8iTBo3Sq;tq!%5ErUnPQ-S$k=Uiv5*9hQfK z_X(4!LAi{Cu}E`3YueTAMNZj~C{ZNFNfzpV|MHuT5+3R|y@55zyJC{;ohotTbbrK7 zk66I3Wsz1uTo=_p9n2{nlY`!SwK4b#^+{Rg#5CvgxiN1UQjJYJ z2m;e`Ovk~1z{N>c(gn_ntu;eW6ig*~naB)Pj5LzRWvGLzs~FO}q0Nd~Cs52>(A=~Q ztBPp}4>`9zkon8s(dC;-#^t=Yvavz* zXemM+POXJ)3)`KM;}Fj!Zu@PkLo90r9Y~(UCuc$f(()gJLe6kn(x-wsBe7H|g@BWk zj)j?LV;wazlCGRe1%|=9*5-V_+Z`$yCsSA`4z6EA{oSr_2fmLT!(O^O7?6Helr&?a z-wSmR$4C-Rtf0dz$8BTYb~>1PF2&TcZS1#g?zJLcxZGLq?@4xCr9icRRSsM-;CSR7 zi>Md4Z68OTV`Im41&-nvMnSvfd4Uypop{amfl8nv>2#B|@`?jvC!oGhV-LrE9AV#f zJ>0Q5!*SFS5R~T!u~Vh}GLy(&QotFX)P;0I+^$E{1TB+?P*xR1sIw{?1lQ~7OXrAl5%w|GuxSvx+p&1EPgnF!GifEos6Gp38 z%~{6l5^qiil@dKls&nlWboOM4o-Jiov7af?W_A1@iE8=Tgl1y_t=!bBV9cuLtq$M( zZ(c0dHu~cl4o$ZjHtilhnhQf@K&{|9c<|)|30KKm{oc;#^6%`QhYz=3xbo@kOP}2O t@nio__nU8j`s(|8cYgkB_=l#QzV^n8U*CQC*Xr)+@9y`0xOVHae*yBLDSH3_ diff --git a/docs/run_and_build.md b/docs/run_and_build.md index c97970b..d9b7cae 100644 --- a/docs/run_and_build.md +++ b/docs/run_and_build.md @@ -1,6 +1,6 @@ # Running from source and creating a portable build -[![README](icons/readme.png) README](README.md) | [![RU](icons/ru.png) Русская версия](run_and_build.ru.md) +[![README](icons/readme.png) README](README.md) --- diff --git a/docs/run_and_build.ru.md b/docs/run_and_build.ru.md deleted file mode 100644 index 13cb42b..0000000 --- a/docs/run_and_build.ru.md +++ /dev/null @@ -1,25 +0,0 @@ -# Запуск из исходников и создание портабельной сборки - -[![README](icons/readme.png) README](README.ru.md) | [![EN](icons/gb.png) English version](run_and_build.md) - ---- - -## Запуск из исходников - -Для запуска **Process Governor** из исходников выполните следующие шаги: - -1. Склонируйте этот репозиторий. -2. Установите необходимые зависимости с помощью `pip`: `pip install -r requirements.txt` -3. Запустите скрипт `process-governor.py` с правами администратора: `python process-governor.py` -4. [Настройте правила](ui_rule_configurator.ru.md) для процессов и сервисов. - -## Создание портабельной сборки - -Вы можете создать портативную версию программы, используя **PyInstaller**. Чтобы создать портативную версию, выполните -следующие шаги: - -1. Установите PyInstaller с помощью `pip install pyinstaller`. -2. Запустите скрипт `python build_portable.py`. -3. После завершения скрипта, вы найдете портативную версию в папке `dist`. - -Теперь у вас есть портабельная версия программы, которую можно использовать без установки. diff --git a/docs/tips'n'tricks/audio.md b/docs/tips'n'tricks/audio.md index 82996d1..7efbb75 100644 --- a/docs/tips'n'tricks/audio.md +++ b/docs/tips'n'tricks/audio.md @@ -2,7 +2,7 @@ # Optimizing Audio using Process Governor -[![README](../icons/readme.png) README](../README.md) | [![RU](../icons/ru.png) Русская версия](audio.ru.md) +[![README](../icons/readme.png) README](../README.md) --- @@ -209,15 +209,15 @@ Example of the enabled **Run on Startup** option: ### Creating Rules -#### Opening the Rules Configurator +#### Opening the Settings 1. Launch **Process Governor** if it is not already running. 2. Click on the application icon in the system tray to open the menu. -3. Select the **Configure Rules** option to open the rules configurator. +3. Select the **Settings** option to open the settings. #### Adding a Rule for process Voicemeeter -1. In the rules configurator interface, press the **Add** button to add a new rule. +1. In the Settings interface, press the **Add** button to add a new rule. 2. Enter the corresponding values in the columns: - **Process Selector:** `voicemeeter8x64.exe` - **Priority:** `Realtime` @@ -250,7 +250,7 @@ Similarly, add the remaining rules in accordance with the screenshot: ### Saving the Settings -Once all the rules are configured, save them by pressing the **Save** button. Then you can close the rules configurator. +Once all the rules are configured, save them by pressing the **Apply** button. Then you can close Settings. After that, the program will regularly apply the rules to the corresponding processes and manage PC resources. ## Conclusion diff --git a/docs/tips'n'tricks/audio.ru.md b/docs/tips'n'tricks/audio.ru.md deleted file mode 100644 index 76d5172..0000000 --- a/docs/tips'n'tricks/audio.ru.md +++ /dev/null @@ -1,268 +0,0 @@ -![Logo Process Governor](../images/sound-theme-header.png) - -# Оптимизация звука с использованием Process Governor - -[![README](../icons/readme.png) README](../README.ru.md) | [![EN](../icons/gb.png) English version](audio.md) - ---- - -> **Предисловие:** -> -> Если вы занимаетесь музыкой, стримингом или просто стремитесь к идеальному звуку в дискорде или на работе и при этом -> используете обработку звука в реальном времени, эта статья для вас. Она расскажет о методах оптимизации системы для -> предотвращения проблем со звуком, таких как заикания или треск при высокой нагрузке на процессор. Предложенный подход -> поможет вам настроить процессорные ресурсы таким образом, чтобы аудиопроцессы получали приоритет и не страдали от -> конкуренции с другими задачами. - -## Введение - -В данной статье мы рассмотрим процесс оптимизации звука на компьютере с использованием инструмента **Process Governor**. -Этот метод позволяет повысить стабильность звука и уменьшить появление заиканий и потрескиваний, особенно при высокой -нагрузке на процессор. - -## Предыстория проблемы - -### Исходная ситуация - -Моя история началась с нестабильности звука на моем компьютере, особенно тогда, когда я активно использовал -аудиообработку в реальном времени. Заикания и потрескивания стали нормой в моменты онлайн-выступлений и приложений, -которые обрабатывали звук через несколько аудиоэффектов. Это было не только раздражающим, но и влияло на качество моих -аудио-проектов. - -### Поиск решения - -Я начал искать способы решения этой проблемы. Это включало в себя эксперименты с настройками аудиоинтерфейса, -оптимизацию параметров в операционной системе, и даже переустановку аудио-драйверов. Некоторые из этих методов приводили -к временному улучшению, но с ростом числа аудиоэффектов и обработчиков звука, проблема возвращалась. - -### Радикальное и эффективное решение - -Чтобы найти более радикальное и надежное решение, я пришел к идее перераспределения вычислительных ресурсов моего ПК. Я -предположил, что выделение отдельных ядер процессора для обработки аудиосигнала, а остальных ядер для обычных задач, -поможет решить проблему. Это должно было обеспечить стабильное воспроизведение звука даже при высокой нагрузке на ЦП. - -Поэтому, я решил вручную распределить основные аудиопроцессы на отдельные ядра и провести тестирование. Это оказалось -эффективным решением. Однако, чтобы упростить и автоматизировать этот процесс, я решил создать специальное приложение, -которое сможет управлять распределением процессорных ресурсов между аудиопроцессами и остальными задачами. - -### Рождение Process Governor - -Из этой необходимости родилась идея создать программу, которая способна управлять процессами/службами Windows и их -соответствиями к ядрам процессора. Так появился Process Governor. С его помощью, я смог оптимизировать аудиопроцессы и -службы, установив им высокий приоритет выполнения в режиме реального времени, а так же распределив их по ядрам -процессора. Это позволило обеспечить стабильное и качественное воспроизведение звука, даже в самых требовательных -сценариях. - -## Процессы и службы, влияющие на звук - -Для обработки звука, я использую следующие программы: - -1. **Voicemeeter** - виртуальный микшер. -2. **Equalizer APO** - для обработки звука на выходных устройствах Voicemeeter (наушники и колонки). -3. **Kushview Element** - DAW для обработки звука на входных устройствах Voicemeeter (микрофон). - -Кроме этого, существуют службы и процессы Windows, которые также взаимодействуют со звуком и являются общими для всех -пользователей Windows: - -1. Служба **AudioSrv**. -2. Служба **AudioEndpointBuilder**. -3. Процесс **Audiodg.exe**. - -## Подготовка к настройке - -### Список процессов и служб - -Для настройки, я создал список процессов и служб, ответственных за обработку звука: - -1. **voicemeeter8x64.exe** - Voicemeeter. -2. **voicemeeterclient.exe** - Процесс Equalizer APO для интеграции с Voicemeeter. -3. **element.exe** - Kushview Element. -4. **Audiodg.exe**. -5. Служба **AudioSrv**. -6. Служба **AudioEndpointBuilder**. - -### Распределение процессорных ресурсов - -> **Примечание:** -> -> 1. Process Governor воспринимает потоки как ядра, потому когда будет идти речь о ядрах, - > помните, что под ними подразумеваются еще и потоки. -> 2. Нумерация ядер начинается с 0. - -У меня установлен процессор с 12 ядрами (24 потоками), и я предлагаю следующее распределение ресурсов: - -1. Первые 8 ядер/16 потоков предназначены для всех процессов, кроме звука (с 0-го по 15-ый поток). -2. Последние 4 ядра/8 потоков отведены под звук (с 16-го по 23-й поток). - -Также, я рекомендую установить максимальный приоритет - реального времени - для всех процессов, отвечающих за звук. - -> **Примечание:** -> -> Опытным путем выяснил, что изменение соответствия ядер для сервисов: -> 1. **AudioSrv**; -> 2. **AudioEndpointBuilder**. -> -> Приведет к усугублению проблем в звуке. Потому для этих сервисов изменим только приоритет, -> а соответствие ядер трогать не будем. - -## Настройка Process Governor - -
- Старый метод настройки через файл конфигурации. - -> ### Предварительная подготовка -> -> Прежде чем приступить к настройке, ознакомьтесь с инструкциями по установке и начальной настройке **Process Governor** -> через файл конфигурации, доступными в разделах: -> -> - [Начало работы](../README.ru.md#начало-работы) -> - [Файл конфигурации](../configuration_file.ru.md) -> -> ### Файл конфигурации -> -> Исходя из README и информации о файле конфигурации, предлагаю следующий файл-конфигурации `config.json` для Process -> Governor: -> -> ```json -> { -> "ruleApplyIntervalSeconds": 1, -> "logging": { -> "enable": true, -> "level": "INFO", -> "maxBytes": 1024, -> "backupCount": 1 -> }, -> "rules": [ -> { -> "processSelector": "voicemeeter8x64.exe", -> "priority": "Realtime", -> "affinity": "16-23" -> }, -> { -> "processSelector": "voicemeeterclient.exe ", -> "priority": "Realtime", -> "affinity": "16-23" -> }, -> { -> "processSelector": "element.exe", -> "priority": "Realtime", -> "affinity": "16-23" -> }, -> { -> "processSelector": "Audiodg.exe", -> "priority": "Realtime", -> "affinity": "16-23" -> }, -> { -> "serviceSelector": "AudioSrv", -> "priority": "Realtime" -> }, -> { -> "serviceSelector": "AudioEndpointBuilder", -> "priority": "Realtime" -> }, -> { -> "processSelector": "*", -> "affinity": "0-15" -> } -> ] -> } -> ``` -> -> > **Обратите внимание**: -> > -> > - Указаны процессы и службы, ответственные за звук в `serviceSelector` и `processSelector`. -> > - Установлен приоритет "реального времени" для всех процессов, отвечающих за звук: `"priority": "Realtime"`. -> > - Указаны соответствия ядер CPU для различных сценариев в: `"affinity": "<номера ядер>"`. -> > - Для сервисов намеренно не указаны ядра, только приоритет. -> > -> > Так же обратите внимание на последнее правило и его `processSelector`: -> > -> > ```json -> > { -> > "processSelector": "*", -> > "affinity": "0-15" -> > } -> > ``` -> > -> > Здесь селектор равен `*`, что говорит о том, что ЛЮБОЙ процесс будет подвержен правилу с указанием ядер `0-15`. -> > Так как правила в Process Governor выполняются по порядку до первого совпадения и правило описано последним, то и -> > выполняться правило будет только в том случае, когда первые правила не сработали. Т.е. остальные процессы, которые -> > не относятся к звуку, автоматически отправятся на ядра `0-15`. -> -> ### Запуск Process Governor -> -> Для применения настроек, следует поместить файл конфигурации `config.json` рядом с программой Process Governor и -> запустить ее. Программа будет работать в фоне, регулярно применяя правила для новых процессов и доступна в системном -> трее. -
- -### Предварительная подготовка - -Прежде чем приступить к настройке, ознакомьтесь с инструкциями по установке и начальной настройке **Process Governor**, -доступными в разделах: - -- [Начало работы](../README.ru.md#начало-работы) -- [Конфигурирование правил](../ui_rule_configurator.ru.md) - -Для обеспечения автоматического запуска **Process Governor** вместе с Windows выполните следующие шаги: - -1. Запустите **Process Governor**. -2. Нажмите на иконку приложения в системном трее, чтобы открыть меню. -3. Включите опцию **Run on Startup**. - -Пример включенной опции **Run on Startup**: - -![tray_menu_screenshot.png](../images/tray_menu_screenshot.png) - -### Создание правил - -#### Открытие конфигуратора правила - -1. Запустите **Process Governor**, если еще не запущен. -2. Нажмите на иконку приложения в системном трее, чтобы открыть меню. -3. Выберите опцию **Configure Rules** для открытия конфигуратора правил. - -#### Добавление правила для процесса Voicemeeter - -1. В интерфейсе конфигуратора правил нажмите кнопку **Add** для добавления нового правила. -2. В колонках введите соответствующие значения: - - **Process Selector:** `voicemeeter8x64.exe` - - **Priority:** `Realtime` - - **Affinity:** `16-23` - -#### Добавление правила для службы AudioSrv - -1. Нажмите кнопку **Add**. -2. В колонках введите соответствующие значения: - - **Service Selector:** `AudioSrv` - - **Priority:** `Realtime` - -#### Добавление остальных правил - -Аналогичным образом добавьте остальные правила в соответствии со скриншотом: - -![audio_artiacle_rule_configurator_screenshot.png](../images/audio_artiacle_rule_configurator_screenshot.png) - -> **Обратите внимание**: -> -> - Указаны процессы и службы, ответственные за звук в **Process Selector** и **Service Selector**. -> - Установлен приоритет "реального времени" для всех процессов, отвечающих за звук: `Realtime`. -> - Указаны соответствия ядер CPU для различных сценариев. -> - Для сервисов намеренно не указаны ядра, только приоритет. -> -> Так же обратите внимание на последнее правило и его **Process Selector**. -> Его селектор равен `*`, что говорит о том, что ЛЮБОЙ процесс будет подвержен правилу с указанием ядер `0-15`. -> Так как правила в Process Governor выполняются по порядку до первого совпадения и правило описано последним, то и -> выполняться правило будет только в том случае, когда первые правила не сработали. Т.е. остальные процессы, которые не -> относятся к звуку, автоматически отправятся на ядра `0-15`. - -### Сохранение настроек - -Как только все правила будут настроены, сохраните их, нажав кнопку **Save**. Затем можете закрыть конфигуратор правил. -После этого программа будет регулярно применять правила к соответствующим процессам и управлять ресурсами ПК. - -## Заключение - -Настройка Process Governor предоставляет мощное средство для оптимизации звука на моем ПК, улучшая его стабильность и -качество. Я надеюсь, что данная статья поможет вам достичь лучших результатов в области аудиообработки. \ No newline at end of file diff --git a/docs/tips'n'tricks/game_optimization.md b/docs/tips'n'tricks/game_optimization.md index c917f69..07745c6 100644 --- a/docs/tips'n'tricks/game_optimization.md +++ b/docs/tips'n'tricks/game_optimization.md @@ -1,9 +1,9 @@ ![game-theme-header.png](../images/game-theme-header.png) -[![README](../icons/readme.png) README](../README.md) | [![RU](../icons/ru.png) Русская версия](game_optimization.ru.md) - # Optimizing Games using Process Governor +[![README](../icons/readme.png) README](../README.md) + --- ## Introduction @@ -44,15 +44,15 @@ Let's look at setting up optimization for two popular games: Let's proceed to set up the rules. -### Opening the Rules Configurator +### Opening the Settings 1. Launch **Process Governor** if it is not already running. 2. Click on the application icon in the system tray to open the menu. -3. Select the **Configure Rules** option to open the rules configurator. +3. Select the **Settings** option to open the settings. ### Adding a Rule for Starfield -1. In the rules configurator interface, press the **Add** button to add a new rule. +1. In the Settings interface, press the **Add** button to add a new rule. 2. Enter the corresponding values in the columns: - **Process Selector:** `starfield.exe`. - **Priority:** `High`. @@ -78,7 +78,7 @@ from use. ![game_optimization_rule_configurator_screenshot.png](../images/game_optimization_rule_configurator_screenshot.png) -Once all the rules are configured, save them by pressing the **Save** button. Then you can close the rules configurator. +Once all the rules are configured, save them by pressing the **Apply** button. Then you can close the settings. ### Game Process Monitoring diff --git a/docs/tips'n'tricks/game_optimization.ru.md b/docs/tips'n'tricks/game_optimization.ru.md deleted file mode 100644 index f9d21ff..0000000 --- a/docs/tips'n'tricks/game_optimization.ru.md +++ /dev/null @@ -1,123 +0,0 @@ -![game-theme-header.png](../images/game-theme-header.png) - -[![README](../icons/readme.png) README](../README.ru.md) | [![EN](../icons/gb.png) English version](game_optimization.md) - -# Оптимизация игр с использованием Process Governor - ---- - -## Введение - -Улучшение производительности и сокращение времени отклика игр на ПК, таких как **Starfield** и **Red Dead Redemption -2**, осуществляется через управление ресурсами системы. **Process Governor** — это инструмент, который дает пользователю -контроль над процессами и распределением ресурсов, что может значительно улучшить игровой опыт. В данном руководстве мы -подробно рассмотрим процесс настройки **Process Governor** для оптимизации этих популярных игр. - -## Предварительная подготовка - -Прежде чем приступить к настройке, ознакомьтесь с инструкциями по установке и начальной настройке **Process Governor**, -доступными в разделах: - -- [Начало работы](../README.ru.md#начало-работы) -- [Конфигурирование правил](../ui_rule_configurator.ru.md) - -Для обеспечения автоматического запуска **Process Governor** вместе с Windows выполните следующие шаги: - -1. Запустите **Process Governor**. -2. Нажмите на иконку приложения в системном трее, чтобы открыть меню. -3. Включите опцию **Run on Startup**. - -Пример включенной опции **Run on Startup**: - -![tray_menu_screenshot.png](../images/tray_menu_screenshot.png) - -## Создание правил для игр - -Давайте рассмотрим настройку оптимизации для двух популярных игр: - -1. **Starfield:** Для сокращения фризов и лагов оптимальной стратегией будет исключение 0-го ядра CPU из обработки - игры, тем самым уменьшая конкуренцию с системными процессами Windows за ресурсы. - -2. **Red Dead Redemption 2:** Чтобы уменьшить количество фризов, рекомендуется отключить использование - Hyper-threading, ограничив процесс игры работой только на физических ядрах процессора (четные номера "ядер"). - Так же может быть полезно ограничить использование CPU, например, используя первые 6 ядер. - -Приступим к настройке правил. - -### Открытие конфигуратора правила - -1. Запустите **Process Governor**, если еще не запущен. -2. Нажмите на иконку приложения в системном трее, чтобы открыть меню. -3. Выберите опцию **Configure Rules** для открытия конфигуратора правил. - -### Добавление правила для Starfield - -1. В интерфейсе конфигуратора правил нажмите кнопку **Add** для добавления нового правила. -2. В колонках введите соответствующие значения: - - **Process Selector:** `starfield.exe`. - - **Priority:** `High`. - - **I/O Priority:** `High`. - - **Affinity:** `1-N`, что означает использование всех ядер, кроме первого. - > Замените `N` на номер максимально доступного ядра/потока на вашем процессоре, начиная с 0. - Для системы с 12 ядрами и 24 потоками, как в моем примере, последнее доступное "ядро" имеет номер 23 начиная с 0. - Именно поэтому в текущем случае мы задаем диапазон ядер как `1-23`, исключая первое "ядро" из использования. - -### Добавление правила для RDR2 - -1. Нажмите кнопку **Add**. -2. В колонках введите соответствующие значения: - - **Process Selector:** `rdr2.exe`. - - **Priority:** `High`. - - **I/O Priority:** `High`. - - **Affinity:** `0;2;4;6;8;10`, что означает использование 6 ядер исключая многопоточность (нечетные ядра). - -### Сохранение настроек - -Проверьте введенные данные, чтобы убедиться, что настройки правил совпадают с вашей конфигурацией системы и -отображаемыми на скриншоте параметрами. - -![game_optimization_rule_configurator_screenshot.png](../images/game_optimization_rule_configurator_screenshot.png) - -Как только все правила будут настроены, сохраните их, нажав кнопку **Save**. Затем можете закрыть конфигуратор правил. - -### Мониторинг игрового процесса - -- После запуска игры, внимательно отслеживайте её производительность, а также загрузку графического и центрального - процессоров. -- При обнаружении проблем с производительностью вернитесь к настройкам в Process Governor и произведите необходимые - корректировки. -- Если игра **RDR2** требует больше ресурсов, рассмотрите возможность распределения игры на большее - количество ядер. - -## Альтернативный способ настройки - -Вы также можете настроить **Process Governor**, редактируя файл конфигурации JSON вручную, следуя -инструкции [здесь](../configuration_file.ru.md). - -Правильно настроенный файл конфигурации должен выглядеть так: - -```json -{ - "ruleApplyIntervalSeconds": 1, - "logging": { - "enable": true, - "level": "INFO", - "maxBytes": 1024, - "backupCount": 1 - }, - "rules": [ - { - "processSelector": "starfield.exe", - "priority": "High", - "ioPriority": "High", - "affinity": "1-23" - }, - { - "processSelector": "rdr2.exe", - "priority": "High", - "ioPriority": "High", - "affinity": "0;2;4;6;8;10" - } - ] -} -``` \ No newline at end of file diff --git a/docs/ui_rule_configurator.md b/docs/ui_rule_configurator.md index 0f8e47a..bede03b 100644 --- a/docs/ui_rule_configurator.md +++ b/docs/ui_rule_configurator.md @@ -1,22 +1,22 @@ # Configuring Rules -[![README](icons/readme.png) README](README.md) | [![RU](icons/ru.png) Русская версия](ui_rule_configurator.ru.md) +[![README](icons/readme.png) README](README.md) --- -## Opening the Rules Configurator +## Opening the Settings 1. Launch the **Process Governor**. 2. Click on the application icon in the system tray to open the menu. -3. Select the **Configure Rules** option to open the rules configurator. +3. Select the **Settings** option to open the settings. ![tray_menu_screenshot.png](images/tray_menu_screenshot.png) -## Interface of the Rules Configurator +## Interface of the Settings ![rule_configurator_screenshot.png](images/rule_configurator_screenshot.png) -The rules configurator interface is a table with several columns: +The Settings interface is a table with several columns: - **Process Selector**: Specifies the process name or pattern to match. You can use wildcards, including `*` and `?`, to match multiple processes. @@ -71,18 +71,18 @@ The rules configurator interface is a table with several columns: ### Saving Changes -1. After you have added, edited, or deleted rules, press the **Save** button at the bottom of the window to apply the +1. After you have added, edited, or deleted rules, press the **Apply** button at the bottom of the window to apply the changes. 2. A confirmation message will appear upon successful save. -### Closing the Rules Configurator +### Closing the Settings -1. To close the rules configurator, close the window in the usual way. +1. To close the Settings, close the window in the usual way. 2. If there are unsaved changes in the table, the program will offer to save them before closing. ### Tooltips -- In the rules configurator interface, tooltips are present at the top, describing the functions of buttons and fields. +- In the Settings interface, tooltips are present at the top, describing the functions of buttons and fields. - Hover over an interface element to view the tooltip. ### Error Handling @@ -90,6 +90,6 @@ The rules configurator interface is a table with several columns: - If the entered data is incorrect, the corresponding cell will be highlighted, and an error icon will appear next to it. - Hovering over the error icon will display a tooltip with the reason for the error. -- If there are errors, the **Save** button and the option to save upon closing are not available. +- If there are errors, the **Apply** button and the option to save upon closing are not available. ![rule_configurator_with_error_screenshot.png](images/rule_configurator_with_error_screenshot.png) \ No newline at end of file diff --git a/docs/ui_rule_configurator.ru.md b/docs/ui_rule_configurator.ru.md deleted file mode 100644 index 85e9fe9..0000000 --- a/docs/ui_rule_configurator.ru.md +++ /dev/null @@ -1,94 +0,0 @@ -# Конфигурирование правил - -[![README](icons/readme.png) README](README.ru.md) | [![EN](icons/gb.png) English version](ui_rule_configurator.md) - ---- - -## Открытие конфигуратора правил - -1. Запустите **Process Governor**. -2. Нажмите на иконку приложения в системном трее, чтобы открыть меню. -3. Выберите опцию **Configure Rules** для открытия конфигуратора правил. - -![tray_menu_screenshot.png](images/tray_menu_screenshot.png) - -## Интерфейс конфигуратора правил - -![rule_configurator_screenshot.png](images/rule_configurator_screenshot.png) - -Пользовательский интерфейс конфигуратора правил представляет собой таблицу с несколькими столбцами: - -- **Process Selector**: Указывает имя процесса или шаблон для сопоставления. - Вы можете использовать подстановочные символы, включая `*` и `?`, чтобы сопоставить несколько процессов. - - Пример: `example.exe` - - Пример с подстановочными символами: `logioptionsplus_*.exe` - - -- **Service Selector**: Указывает имя службы или шаблон для сопоставления. - Вы можете использовать подстановочные символы, включая `*` и `?`, чтобы сопоставить несколько служб. - - Пример: `MyService` - - Пример с подстановочными символами: `Audio*` - - -- **Priority**: Устанавливает приоритет процессов или служб. -- **I/O Priority**: Устанавливает приоритет ввода/вывода для процессов или служб. -- **Affinity**: Определяет привязку процесса к ядру CPU. - Вы можете указать привязку следующим образом: - - Диапазон (включительно): `0-3` - - Конкретные ядра: `0;2;4` - - Комбинация: `1;3-5` - -> **Примечание:** -> -> Не заполняйте одновременно поля **Process Selector** и **Service Selector** для одного правила. -> Если вы установите оба селектора одновременно, это может привести к конфликту или непредсказуемому поведению правила. -> -> Для предотвращения такой ситуации в программе реализована валидация, которая уведомит вас о необходимости исправить -> правило. - -## Работа с правилами - -### Добавление нового правила - -1. Нажмите кнопку **Add**. -2. Отредактируйте правило в соответствии с шагами, описанными в [Редактирование правила](#редактирование-правила) - -### Редактирование правила - -1. Дважды щелкните по ячейке правила, которое вы хотите отредактировать. -2. Введите новые данные в выбранную ячейку. -3. После редактирования ячейки, изменения будут автоматически сохранены в таблице. - -### Удаление правила - -1. Выберите правило(ила), которое хотите удалить, щелкнув по соответствующей строке. -2. Нажмите кнопку **Delete**. - -### Изменение порядка правил - -1. Выберите правило, порядок которого хотите изменить. -2. Используйте кнопки **Up** и **Down** для перемещения правила вверх или вниз по списку. - -### Сохранение изменений - -1. После того как вы добавили, отредактировали или удалили правила, нажмите кнопку **Save** в нижней части окна, чтобы - применить изменения. -2. В случае успешного сохранения появится сообщение с подтверждением. - -### Закрытие конфигуратора правил - -1. Для закрытия конфигуратора правил закройте окно стандартным способом. -2. Если в таблице остались несохраненные изменения, программа предложит сохранить их перед закрытием. - -### Всплывающие подсказки - -- В интерфейсе конфигуратора правил в верхней части присутствуют подсказки, которые описывают функции кнопок и полей. -- Для просмотра подсказки наведите курсор на элемент интерфейса. - -### Обработка ошибок - -- Если введенные данные некорректны, соответствующая ячейка будет выделена, и рядом появится иконка ошибки. -- При наведении на иконку ошибки будет показана подсказка с причиной ошибки. -- При наличии ошибок кнопка **Save** и возможность сохранить при закрытии недоступны. - -![rule_configurator_with_error_screenshot.png](images/rule_configurator_with_error_screenshot.png) \ No newline at end of file From 6e0d48b9b22140bfc333f01132ddeb4b718da3b2 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Wed, 7 Aug 2024 23:11:23 +0800 Subject: [PATCH 10/39] [#11] UI Refactoring --- src/configuration/rule.py | 4 +- src/constants/ui.py | 2 +- src/enums/rules.py | 9 +- src/main_loop.py | 10 +- src/service/config_service.py | 39 +--- src/ui/{editor.py => settings.py} | 204 ++++++++++-------- src/ui/tray.py | 8 +- src/ui/widget/common/treeview/editable.py | 31 +-- src/ui/widget/common/treeview/scrollable.py | 6 + src/ui/widget/editor/buttons.py | 63 ------ src/ui/widget/editor/rules_tab.py | 132 ------------ src/ui/widget/settings/settings_tabs.py | 69 ++++++ src/ui/widget/settings/tabs/base_tab.py | 46 ++++ .../settings/tabs/rules/base_rules_tab.py | 122 +++++++++++ .../tabs/rules}/rules_list.py | 30 +-- .../widget/settings/tabs/rules/rules_tab.py | 42 ++++ src/ui/widget/{editor => settings}/tooltip.py | 2 +- src/util/ui.py | 4 +- 18 files changed, 456 insertions(+), 367 deletions(-) rename src/ui/{editor.py => settings.py} (57%) delete mode 100644 src/ui/widget/editor/buttons.py delete mode 100644 src/ui/widget/editor/rules_tab.py create mode 100644 src/ui/widget/settings/settings_tabs.py create mode 100644 src/ui/widget/settings/tabs/base_tab.py create mode 100644 src/ui/widget/settings/tabs/rules/base_rules_tab.py rename src/ui/widget/{editor => settings/tabs/rules}/rules_list.py (92%) create mode 100644 src/ui/widget/settings/tabs/rules/rules_tab.py rename src/ui/widget/{editor => settings}/tooltip.py (95%) diff --git a/src/configuration/rule.py b/src/configuration/rule.py index 0cfbd44..f4e0df9 100644 --- a/src/configuration/rule.py +++ b/src/configuration/rule.py @@ -10,7 +10,7 @@ class ProcessRule(BaseModel): selector: str = Field( title="Process Selector", - description="Specifies the __name or pattern__ of the __process__ to which this rule applies.\n\n" + description="Specifies the **name** or **pattern** of the __process__ to which this rule applies.\n\n" "**Supports wildcards:** `\*` (matches any characters) and `?` (matches any single character).\n" "**Examples:** `name.exe` or `logioptionsplus_*.exe`.", default_ui="*", @@ -44,7 +44,7 @@ class ProcessRule(BaseModel): class ServiceRule(BaseModel): selector: str = Field( title="Service Selector", - description="Specifies the __name or pattern__ of the __service__ to which this rule applies.\n\n" + description="Specifies the **name** or **pattern** of the __service__ to which this rule applies.\n\n" "**Supports wildcards:** `\*` (matches any characters) and `?` (matches any single character).\n" "**Examples:** `ServiceName` or `Audio*`.", default_ui="*", diff --git a/src/constants/ui.py b/src/constants/ui.py index 92d8d83..9426d13 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -6,7 +6,7 @@ ERROR_ROW_COLOR = "#ffcdd2" TOOLTIP_ICON_SIZE = 75 RC_WIN_SIZE = (900, 600) -RC_TITLE = "Rules Configurator" +SETTINGS_TITLE = "Settings" class ActionEvents: diff --git a/src/enums/rules.py b/src/enums/rules.py index 4e22c0b..d4ebdec 100644 --- a/src/enums/rules.py +++ b/src/enums/rules.py @@ -1,15 +1,12 @@ from enum import Enum from configuration.rule import ProcessRule, ServiceRule -from util.ui import icon16px class RuleType(Enum): - PROCESS = ProcessRule, "processRules", "Process Rules", lambda:icon16px("list", fill="#3F888F") - SERVICE = ServiceRule, "serviceRules", "Service Rules", lambda:icon16px("cogs", fill="#6495ED") + PROCESS = (ProcessRule, "processRules") + SERVICE = (ServiceRule, "serviceRules") - def __init__(self, clazz, field_in_config, title, get_icon): + def __init__(self, clazz, field_in_config): self.clazz = clazz self.field_in_config = field_in_config - self.title = title - self.get_icon = get_icon diff --git a/src/main_loop.py b/src/main_loop.py index cbf8643..30fa08c 100644 --- a/src/main_loop.py +++ b/src/main_loop.py @@ -12,10 +12,10 @@ from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.files import LOG_FILE_NAME from constants.log import LOG -from constants.ui import RC_TITLE +from constants.ui import SETTINGS_TITLE from service.config_service import ConfigService from service.rules_service import RulesService -from ui.editor import open_rule_editor, is_editor_open +from ui.settings import open_settings, is_settings_open from ui.tray import init_tray from util.messages import yesno_error_box, show_error from util.startup import update_startup @@ -109,13 +109,13 @@ def show_rules_error_message(): title = f"Error Detected - {APP_NAME_WITH_VERSION}" message = "An error has occurred while loading or applying the rules.\n" - if is_editor_open: + if is_settings_open: message += "Please check the correctness of the rules." show_error(title, message) else: - message += f"Would you like to open the {RC_TITLE} to review and correct the rules?" + message += f"Would you like to open the {SETTINGS_TITLE} to review and correct the rules?" if yesno_error_box(title, message): - open_rule_editor() + open_settings() def show_abstract_error_message(will_closed: bool): diff --git a/src/service/config_service.py b/src/service/config_service.py index 4bd4781..aa63427 100644 --- a/src/service/config_service.py +++ b/src/service/config_service.py @@ -6,7 +6,6 @@ from typing import Optional, List, Any from configuration.config import Config -from configuration.rule import ProcessRule, ServiceRule from constants.files import CONFIG_FILE_NAME, CONFIG_FILE_ENCODING from enums.rules import RuleType from util.decorators import cached @@ -81,41 +80,6 @@ def reload_if_changed(cls, prev_config: Optional[Config]) -> tuple[Config, bool] return prev_config, False - @classmethod - def load_rules_raw(cls, rule_type: RuleType) -> List[Any]: - """ - Loads raw rules of a specific type from the configuration file. - - Args: - rule_type (RuleType): The type of rules to load. - - Returns: - List[Any]: A list of raw rule data. - """ - if not exists(CONFIG_FILE_NAME): - cls.save_config(Config()) - - with open(CONFIG_FILE_NAME, 'r', encoding=CONFIG_FILE_ENCODING) as file: - json_data = json.load(file) - return json_data.get(rule_type.field_in_config, []) - - @classmethod - def save_rules(cls, rule_type: RuleType, rules: List[ProcessRule | ServiceRule]): - """ - Save the rules of a specific type to the configuration file. - - Args: - rule_type (RuleType): The type of rules to save. - rules (List[ProcessRule | ServiceRule]): The list of rules to be saved. - """ - if rules is None: - raise ValueError("rules is None") - - config = cls.load_config(False) - setattr(config, rule_type.field_in_config, rules) - - cls.save_config(config) - @classmethod def rules_has_error(cls) -> bool: """ @@ -126,7 +90,7 @@ def rules_has_error(cls) -> bool: """ try: for rule_type in RuleType: - rules: List[Any] = cls.load_rules_raw(rule_type) + rules: List[Any] = cls.load_config_raw().get(rule_type.field_in_config, []) try: for rule in rules: @@ -190,5 +154,6 @@ def backup_config(cls): except IOError as e: raise IOError(f"Failed to create backup: {e}") + if __name__ == '__main__': print(ConfigService.rules_has_error()) diff --git a/src/ui/editor.py b/src/ui/settings.py similarity index 57% rename from src/ui/editor.py rename to src/ui/settings.py index 49427b3..5783502 100644 --- a/src/ui/editor.py +++ b/src/ui/settings.py @@ -7,15 +7,32 @@ from constants.files import LOG_FILE_NAME from constants.log import LOG from constants.resources import APP_ICON -from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, RC_TITLE, RulesListEvents, EditableTreeviewEvents -from enums.rules import RuleType -from ui.widget.editor.buttons import EditorButtons -from ui.widget.editor.rules_tab import RulesTabs -from ui.widget.editor.tooltip import Tooltip +from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, SETTINGS_TITLE, RulesListEvents, EditableTreeviewEvents +from ui.widget.common.button import IconedButton +from ui.widget.settings.settings_tabs import SettingsTabs +from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab +from ui.widget.settings.tooltip import Tooltip from util.messages import yesno_error_box +from util.ui import icon16px -class RulesConfigurator(tk.Tk): +class SettingsButtons(ttk.Frame): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._setup_btn() + + def _setup_btn(self): + self.save = save = IconedButton( + self, + text=" Apply", + command=lambda: self.event_generate(ActionEvents.SAVE), + image=icon16px("check", fill="cornflowerblue") + ) + right_btn_pack = dict(side=tk.RIGHT, padx=(UI_PADDING, 0)) + save.pack(**right_btn_pack) + + +class Settings(tk.Tk): _DEFAULT_TOOLTIP = ( "To add a new rule, click the **Add** button.\n" "To edit a rule, **double-click** on the corresponding cell." @@ -29,13 +46,14 @@ def __init__(self): super().__init__() self._setup_window() self._create_widgets() + self._setup_tooltips() def _setup_window(self): self._center_window() self.protocol("WM_DELETE_WINDOW", self._on_window_closing) self.iconbitmap(APP_ICON) - self.title(f"{RC_TITLE} - {APP_NAME_WITH_VERSION}") + self.title(f"{SETTINGS_TITLE} - {APP_NAME_WITH_VERSION}") self.minsize(*RC_WIN_SIZE) self.bind_all("", self._on_key_release, "+") @@ -68,83 +86,21 @@ def _create_widgets(self): self._create_buttons() def _create_tooltips(self): - self._tooltip = Tooltip(self, text="") + self._tooltip = Tooltip(self, text=self._DEFAULT_TOOLTIP) self._tooltip.pack(fill=tk.X, expand=False, side=tk.TOP, padx=UI_PADDING, pady=(UI_PADDING, 0)) - self._tooltip.set(self._DEFAULT_TOOLTIP) - - def _setup_tooltip(self, widget, text: str, error: bool = False, leave: bool = True, enter: bool = True): - if enter: - def on_enter(_): - self._tooltip.set(text, error) - - widget.bind("", on_enter) - - if leave: - def on_leave(_): - self._tooltip.set(self._DEFAULT_TOOLTIP) - - widget.bind("", on_leave) - - def _create_callback_for_set_tooltip_by_tree(self, rule_type: RuleType): - def callback(event): - if not event or not isinstance(event.widget, ttk.Treeview): - return - - cell = self._tabs.current_list_of_tab().get_cell_info(event) - - if cell: - self._tooltip.set(rule_type.clazz.model_fields[cell.column_name].description) - - return callback - - def _create_callback_for_setup_tooltip_cell_editor(self, rule_type: RuleType): - def callback(_=None): - lst = self._tabs.current_list_of_tab() - cell = lst.current_cell() - - if cell: - self._setup_tooltip( - lst.popup(), - rule_type.clazz.model_fields[cell.column_name].description, - leave=False - ) - - return callback - def _create_tabs(self): - self._tabs = tabs = RulesTabs(self) - - tabs.pack(fill=tk.BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) + self._tabs = tabs = SettingsTabs(self) tabs.load_data() - tabs.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_buttons_state(), "+") - - for rt, lst in tabs.list_by_rt().items(): - lst.bind("", self._create_callback_for_set_tooltip_by_tree(rt), "+") - lst.bind( - EditableTreeviewEvents.START_EDIT_CELL, - self._create_callback_for_setup_tooltip_cell_editor(rt), - "+" - ) - - lst.error_icon_created = lambda icon, tooltip: self._setup_tooltip(icon, tooltip, True, False) - self._setup_tooltip(lst, "", enter=False) + tabs.pack(fill=tk.BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) def _create_buttons(self): - self._buttons = buttons = EditorButtons(self) + self._buttons = buttons = SettingsButtons(self) buttons.pack(fill=tk.X, padx=UI_PADDING, pady=(0, UI_PADDING)) buttons.bind(ActionEvents.SAVE, lambda _: self._tabs.save_data(), "+") - self._setup_tooltip(buttons.save, "__Adds__ a rule after the current") - - for rt, btns in self._tabs.buttons_by_rt().items(): - self._setup_tooltip(btns.add, "__Adds__ a rule after the current") - self._setup_tooltip(btns.delete, "__Deletes__ the selected rules") - self._setup_tooltip(btns.move_up, "__Moves__ the current rule __up__") - self._setup_tooltip(btns.move_down, "__Moves__ the current rule __down__") - self._update_buttons_state() def _on_window_closing(self): @@ -152,14 +108,14 @@ def _on_window_closing(self): if self._tabs.has_error(): message = ("There are errors in the rules, and they can't be saved. " "Do you want to DISCARD them and exit?") - result = messagebox.askyesno(f"{RC_TITLE} - {APP_NAME_WITH_VERSION}", message) + result = messagebox.askyesno(f"{SETTINGS_TITLE} - {APP_NAME_WITH_VERSION}", message) if not result: return else: message = ("There are unsaved changes. " "Do you want to save them before exiting?") - result = messagebox.askyesnocancel(f"{RC_TITLE} - {APP_NAME_WITH_VERSION}", message) + result = messagebox.askyesnocancel(f"{SETTINGS_TITLE} - {APP_NAME_WITH_VERSION}", message) if result is None: return @@ -175,35 +131,103 @@ def _update_buttons_state(self, _=None): buttons.save["state"] = tk.NORMAL if tabs.has_unsaved_changes() and not tabs.has_error() else tk.DISABLED + def _setup_tooltips(self): + self._setup_tooltip(self._buttons.save, "__Adds__ a rule after the current") + + tabs = self._tabs + tabs.bind("", self._set_tooltip_by_tab, "+") + tabs.bind("", lambda _: self._tooltip.set(self._DEFAULT_TOOLTIP), "+") + + for tab in tabs.frames(): + btns = tab.buttons + self._setup_tooltip(btns.add, "__Adds__ a rule after the current") + self._setup_tooltip(btns.delete, "__Deletes__ the selected rules") + self._setup_tooltip(btns.move_up, "__Moves__ the current rule __up__") + self._setup_tooltip(btns.move_down, "__Moves__ the current rule __down__") + + rules_list = tab.rules_list + rules_list.bind("", self._set_tooltip_by_tree, "+") + rules_list.bind(EditableTreeviewEvents.START_EDIT_CELL, self._setup_tooltip_cell_editor, "+") + rules_list.error_icon_created = lambda icon, tooltip: self._setup_tooltip(icon, tooltip, True, False) + self._setup_tooltip(rules_list, "", enter=False) + + def _setup_tooltip(self, widget, text: str, error: bool = False, leave: bool = True, enter: bool = True): + if enter: + def on_enter(_): + self._tooltip.set(text, error) + + widget.bind("", on_enter) + + if leave: + def on_leave(_): + self._tooltip.set(self._DEFAULT_TOOLTIP) + + widget.bind("", on_leave) + + def _set_tooltip_by_tree(self, event): + if not event or not isinstance(event.widget, ttk.Treeview): + return + + tab = self._tabs.current_tab() + cell = tab.rules_list.get_cell_info(event) + + if cell: + self._tooltip.set(tab.rule_type.clazz.model_fields[cell.column_name].description) + + def _setup_tooltip_cell_editor(self, _=None): + tab = self._tabs.current_tab() + rules_list = tab.rules_list + cell = rules_list.current_cell() + + if not cell: + return + + self._setup_tooltip( + rules_list.popup(), + tab.rule_type.clazz.model_fields[cell.column_name].description, + leave=False + ) + + def _set_tooltip_by_tab(self, event): + try: + tab_index = event.widget.index("@%d,%d" % (event.x, event.y)) + except: + self._tooltip.set(self._DEFAULT_TOOLTIP) + return + + tabs = self._tabs + tab: BaseRulesTab = tabs.nametowidget(tabs.tabs()[tab_index]) + self._tooltip.set(tab.description()) + -is_editor_open = False +is_settings_open = False -def open_rule_editor(): - global is_editor_open +def open_settings(): + global is_settings_open - def editor(): - global is_editor_open + def settings(): + global is_settings_open try: - is_editor_open = True + is_settings_open = True - app = RulesConfigurator() + app = Settings() app.mainloop() except: - LOG.exception(f"An unexpected error occurred in the {RC_TITLE} of {APP_NAME}.") - show_rule_editor_error_message() + LOG.exception(f"An unexpected error occurred in the {SETTINGS_TITLE} of {APP_NAME}.") + show_settings_error_message() finally: - is_editor_open = False + is_settings_open = False - if not is_editor_open: - thread = Thread(target=editor) + if not is_settings_open: + thread = Thread(target=settings) thread.start() -def show_rule_editor_error_message(): +def show_settings_error_message(): title = f"Error Detected - {APP_NAME_WITH_VERSION}" message = ( - f"An error has occurred in the {RC_TITLE} of {APP_NAME}.\n" + f"An error has occurred in the {SETTINGS_TITLE} of {APP_NAME}.\n" f"To troubleshoot, please check the log file `{LOG_FILE_NAME}` for details.\n\n" f"Would you like to open the log file?" ) @@ -213,5 +237,5 @@ def show_rule_editor_error_message(): if __name__ == "__main__": - test_app = RulesConfigurator() + test_app = Settings() test_app.mainloop() diff --git a/src/ui/tray.py b/src/ui/tray.py index 21eb30c..488938b 100644 --- a/src/ui/tray.py +++ b/src/ui/tray.py @@ -9,8 +9,9 @@ from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.files import CONFIG_FILE_NAME, LOG_FILE_NAME from constants.resources import APP_ICON +from constants.ui import SETTINGS_TITLE from constants.updates import UPDATE_URL -from ui.editor import open_rule_editor +from ui.settings import open_settings from util.messages import yesno_error_box, show_error, show_info from util.startup import toggle_startup, is_in_startup from util.updates import check_latest_version @@ -56,7 +57,10 @@ def init_tray() -> Icon: image: Image = Image.open(APP_ICON) menu: tuple[MenuItem, ...] = ( - MenuItem(APP_NAME_WITH_VERSION, lambda item: open_rule_editor(), default=True), + MenuItem(APP_NAME_WITH_VERSION, None, enabled=False), + Menu.SEPARATOR, + + MenuItem(SETTINGS_TITLE, lambda item: open_settings(), default=True), Menu.SEPARATOR, MenuItem('Open config file', lambda item: os.startfile(CONFIG_FILE_NAME)), diff --git a/src/ui/widget/common/treeview/editable.py b/src/ui/widget/common/treeview/editable.py index efe104b..f7ee5f3 100644 --- a/src/ui/widget/common/treeview/editable.py +++ b/src/ui/widget/common/treeview/editable.py @@ -117,19 +117,22 @@ def get_cell_info(self, event): return self._get_cell_info(row_id, column_id) def _get_cell_info(self, row_id, column_id): - column_name = self.column(column_id)["id"] - cell_value = self.set(row_id, column_id) - values = self._values.get(column_name, []) - cell_type = self._types.get(column_name, "text") - - return CellInfo( - column_id, - row_id, - column_name, - cell_value, - values, - cell_type - ) + try: + column_name = self.column(column_id)["id"] + cell_value = self.set(row_id, column_id) + values = self._values.get(column_name, []) + cell_type = self._types.get(column_name, "text") + + return CellInfo( + column_id, + row_id, + column_name, + cell_value, + values, + cell_type + ) + except: + return None def current_cell(self): return self._cell @@ -142,7 +145,7 @@ def _on_dbl_click(self, event): self.edit_cell(row_id, column_id) def _create_editor(self): - if not self._cell.row_id or not self._cell.column_id or self._cell.column_id == "#0": + if not self._cell or not self._cell.row_id or not self._cell.column_id or self._cell.column_id == "#0": return self._popup = entry_popup = CellEditor(self, self._cell) diff --git a/src/ui/widget/common/treeview/scrollable.py b/src/ui/widget/common/treeview/scrollable.py index 583a78c..894c36e 100644 --- a/src/ui/widget/common/treeview/scrollable.py +++ b/src/ui/widget/common/treeview/scrollable.py @@ -20,6 +20,8 @@ def __init__(self, master=None, *args, **kwargs): self._scrollbar.pack(side=tk.RIGHT, fill=tk.Y) super().pack(fill=tk.BOTH, expand=True, side=tk.LEFT) + self.bind("<>", self.__on_select) + def on_scroll(self): pass @@ -52,3 +54,7 @@ def _on_scrollbar(self, *args): def _on_scrollbar_mouse(self, first, last): self._scrollbar.set(first, last) self.event_generate(ScrollableTreeviewEvents.SCROLL) + + def __on_select(self, _): + for item in self.selection(): + self.see(item) diff --git a/src/ui/widget/editor/buttons.py b/src/ui/widget/editor/buttons.py deleted file mode 100644 index e230450..0000000 --- a/src/ui/widget/editor/buttons.py +++ /dev/null @@ -1,63 +0,0 @@ -import tkinter as tk -from tkinter import ttk - -from constants.ui import UI_PADDING, ActionEvents -from ui.widget.common.button import IconedButton -from util.ui import icon16px - - -class EditorButtons(ttk.Frame): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._setup_btn() - - def _setup_btn(self): - self.save = save = IconedButton( - self, - text=" Apply", - command=lambda: self.event_generate(ActionEvents.SAVE), - image=icon16px("check", fill="cornflowerblue") - ) - right_btn_pack = dict(side=tk.RIGHT, padx=(UI_PADDING, 0)) - save.pack(**right_btn_pack) - - -class RulesListButtons(ttk.Frame): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._setup_btn() - - def _setup_btn(self): - self.add = add = IconedButton( - self, - text=" Add", - command=lambda: self.event_generate(ActionEvents.ADD), - image=icon16px("plus", fill="green") - ) - - self.delete = delete = IconedButton( - self, - text=" Del", - command=lambda: self.event_generate(ActionEvents.DELETE), - image=icon16px("trash-alt", fill="firebrick") - ) - - self.move_up = move_up = IconedButton( - self, - text=" Up", - command=lambda: self.event_generate(ActionEvents.UP), - image=icon16px("arrow-up", fill="#1a1a1a") - ) - - self.move_down = move_down = IconedButton( - self, - text=" Down", - command=lambda: self.event_generate(ActionEvents.DOWN), - image=icon16px("arrow-down", fill="#1a1a1a") - ) - - left_btn_pack = dict(side=tk.LEFT, padx=(0, UI_PADDING)) - add.pack(**left_btn_pack) - delete.pack(**left_btn_pack) - move_up.pack(**left_btn_pack) - move_down.pack(**left_btn_pack) diff --git a/src/ui/widget/editor/rules_tab.py b/src/ui/widget/editor/rules_tab.py deleted file mode 100644 index 503f2e2..0000000 --- a/src/ui/widget/editor/rules_tab.py +++ /dev/null @@ -1,132 +0,0 @@ -import tkinter as tk -from tkinter import ttk, LEFT, messagebox - -from constants.app_info import APP_NAME_WITH_VERSION -from constants.log import LOG -from constants.ui import UI_PADDING, ActionEvents, RulesListEvents -from enums.rules import RuleType -from service.config_service import ConfigService -from ui.widget.editor.buttons import RulesListButtons -from ui.widget.editor.rules_list import RulesList - - -class RulesTabs(ttk.Notebook): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self._list_by_rt: dict[RuleType, RulesList] = {} - self._frame_to_rt: dict[str, RuleType] = {} - self._buttons_by_rt = {} - self._create_tabs() - - def _create_tabs(self): - for rt in RuleType: - frame = ttk.Frame(self) - frame._icon = rt.get_icon() # hard reference - fix missing icon bug - key = str(frame) - - self._frame_to_rt[key] = rt - self._list_by_rt[rt] = rules_list = self._create_rules_list(frame, rt) - self._buttons_by_rt[rt] = buttons = self._create_buttons(frame, rules_list) - - buttons.pack(fill=tk.X, padx=UI_PADDING, pady=(UI_PADDING, 0)) - rules_list.pack(fill=tk.BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) - - self.add(frame, text=f" {rt.title} ", image=frame._icon, compound=LEFT) - self._update_buttons_state(key) - - def _create_rules_list(self, frame, rule_type: RuleType): - rules_list = RulesList(rule_type.clazz, frame) - - rules_list.bind("<>", lambda _: self._update_buttons_state(), "+") - rules_list.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_buttons_state(), "+") - - return rules_list - - def _create_buttons(self, frame, rules_list: RulesList): - buttons = RulesListButtons(frame) - - buttons.bind(ActionEvents.ADD, lambda _: rules_list.add_row(), "+") - buttons.bind(ActionEvents.DELETE, lambda _: rules_list.delete_selected_rows(), "+") - buttons.bind(ActionEvents.UP, lambda _: rules_list.move_rows_up(), "+") - buttons.bind(ActionEvents.DOWN, lambda _: rules_list.move_rows_down(), "+") - - return buttons - - def current_list_of_tab(self, frame=None) -> RulesList: - key = self._frame_to_rt[frame or self.select()] - return self._list_by_rt[key] - - def current_buttons_of_tab(self, frame=None) -> RulesListButtons: - key = self._frame_to_rt[frame or self.select()] - return self._buttons_by_rt[key] - - def _update_buttons_state(self, frame=None): - rules_list = self.current_list_of_tab(frame) - buttons = self.current_buttons_of_tab(frame) - selected_items = rules_list.selection() - - if selected_items: - first_selected_item = selected_items[0] - last_selected_item = selected_items[-1] - first_index = rules_list.index(first_selected_item) - last_index = rules_list.index(last_selected_item) - total_items = len(rules_list.get_children()) - - buttons.move_up["state"] = tk.NORMAL if first_index > 0 else tk.DISABLED - buttons.move_down["state"] = tk.NORMAL if last_index < total_items - 1 else tk.DISABLED - else: - buttons.move_up["state"] = tk.DISABLED - buttons.move_down["state"] = tk.DISABLED - - buttons.delete["state"] = tk.NORMAL if selected_items else tk.DISABLED - - self.event_generate(RulesListEvents.UNSAVED_CHANGES_STATE) - - def has_unsaved_changes(self) -> bool: - for rule_list in self._list_by_rt.values(): - if rule_list.has_unsaved_changes: - return True - return False - - def has_error(self) -> bool: - for rule_list in self._list_by_rt.values(): - if rule_list.has_error(): - return True - return False - - def load_data(self): - for rt, lst in self._list_by_rt.items(): - rules = ConfigService.load_rules_raw(rt) - lst.set_raw_data(rules) - - def save_data(self) -> bool: - try: - if not self.has_unsaved_changes(): - return True - - if self.has_error(): - messagebox.showerror( - f"Error Detected - {APP_NAME_WITH_VERSION}", - "Unable to save: The current rules are invalid. " - "Ensure all rules are correct before saving." - ) - return False - - for rt, lst in self._list_by_rt.items(): - rules = lst.get_data() - ConfigService.save_rules(rt, rules) - lst.set_unsaved_changes(False) - - return True - except: - LOG.exception("Error when saving file.") - messagebox.showerror(f"Error Detected - {APP_NAME_WITH_VERSION}", "An error occurred while saving.") - return False - - def list_by_rt(self) -> dict[RuleType, RulesList]: - return self._list_by_rt - - def buttons_by_rt(self) -> dict[RuleType, RulesListButtons]: - return self._buttons_by_rt - diff --git a/src/ui/widget/settings/settings_tabs.py b/src/ui/widget/settings/settings_tabs.py new file mode 100644 index 0000000..d1eaca5 --- /dev/null +++ b/src/ui/widget/settings/settings_tabs.py @@ -0,0 +1,69 @@ +from tkinter import ttk, messagebox +from typing import Optional + +from constants.app_info import APP_NAME_WITH_VERSION +from constants.log import LOG +from service.config_service import ConfigService +from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab +from ui.widget.settings.tabs.rules.rules_tab import ServiceRulesTab, ProcessRulesTab + + +class SettingsTabs(ttk.Notebook): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self._config: Optional[dict] = None + self._create_tabs() + + def _create_tabs(self): + ProcessRulesTab(self) + ServiceRulesTab(self) + + def current_tab(self) -> BaseRulesTab: + current_index = self.index(self.select()) + tab_id = self.tabs()[current_index] + return self.nametowidget(tab_id) + + def has_unsaved_changes(self) -> bool: + for tab in self.frames(): + if tab.has_unsaved_changes(): + return True + return False + + def has_error(self) -> bool: + for tab in self.frames(): + if tab.has_error(): + return True + return False + + def load_data(self): + self._config = ConfigService.load_config_raw() + + for tab in self.frames(): + tab.load_from_config(self._config) + + def save_data(self) -> bool: + try: + if not self.has_unsaved_changes() or self._config is None: + return True + + if self.has_error(): + messagebox.showerror( + f"Error Detected - {APP_NAME_WITH_VERSION}", + "Unable to save: The current rules are invalid. " + "Ensure all rules are correct before saving." + ) + return False + + for tab in self.frames(): + tab.save_to_config(self._config) + + ConfigService.save_config_raw(self._config) + return True + except: + LOG.exception("Error when saving file.") + messagebox.showerror(f"Error Detected - {APP_NAME_WITH_VERSION}", "An error occurred while saving.") + return False + + def frames(self) -> list[BaseRulesTab]: + return [self.nametowidget(tab_id) for tab_id in self.tabs()] diff --git a/src/ui/widget/settings/tabs/base_tab.py b/src/ui/widget/settings/tabs/base_tab.py new file mode 100644 index 0000000..c6697c7 --- /dev/null +++ b/src/ui/widget/settings/tabs/base_tab.py @@ -0,0 +1,46 @@ +from abc import ABC, abstractmethod +from tkinter import PhotoImage, ttk, LEFT +from tkinter.ttk import Notebook + + +class BaseTab(ttk.Frame, ABC): + def __init__(self, master: Notebook): + super().__init__(master) + + self.master: Notebook = master + self.__icon_tab: PhotoImage = self.icon() + + master.add(self, text=f" {self.title()} ", image=self.__icon_tab, compound=LEFT) + + @staticmethod + @abstractmethod + def icon() -> PhotoImage: + pass + + @staticmethod + @abstractmethod + def title() -> str: + pass + + @staticmethod + @abstractmethod + def description() -> str: + pass + + @abstractmethod + def load_from_config(self, config: dict): + pass + + @abstractmethod + def save_to_config(self, config: dict): + pass + + @abstractmethod + def has_unsaved_changes(self) -> bool: + pass + + @abstractmethod + def has_error(self) -> bool: + pass + + diff --git a/src/ui/widget/settings/tabs/rules/base_rules_tab.py b/src/ui/widget/settings/tabs/rules/base_rules_tab.py new file mode 100644 index 0000000..5216c5f --- /dev/null +++ b/src/ui/widget/settings/tabs/rules/base_rules_tab.py @@ -0,0 +1,122 @@ +import tkinter as tk +from abc import ABC +from tkinter import ttk +from tkinter.ttk import Notebook + +from constants.ui import UI_PADDING, RulesListEvents, ActionEvents +from enums.rules import RuleType +from ui.widget.common.button import IconedButton +from ui.widget.settings.tabs.base_tab import BaseTab +from ui.widget.settings.tabs.rules.rules_list import RulesList +from util.ui import icon16px + + +class BaseRulesTab(BaseTab, ABC): + def __init__(self, master: Notebook, rule_type: RuleType): + super().__init__(master) + + self.rule_type: RuleType = rule_type + self.rules_list = self._create_rules_list() + self.buttons = self._create_buttons() + + self._update_buttons_state() + self._pack() + + def _pack(self): + self.buttons.pack(fill=tk.X, padx=UI_PADDING, pady=(UI_PADDING, 0)) + self.rules_list.pack(fill=tk.BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) + + def _create_rules_list(self): + rules_list = RulesList(self.rule_type.clazz, self) + + rules_list.bind("<>", lambda _: self._update_buttons_state(), "+") + rules_list.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_buttons_state(), "+") + + return rules_list + + def _create_buttons(self): + buttons = RulesTabButtons(self) + + buttons.bind(ActionEvents.ADD, lambda _: self.rules_list.add_row(), "+") + buttons.bind(ActionEvents.DELETE, lambda _: self.rules_list.delete_selected_rows(), "+") + buttons.bind(ActionEvents.UP, lambda _: self.rules_list.move_rows_up(), "+") + buttons.bind(ActionEvents.DOWN, lambda _: self.rules_list.move_rows_down(), "+") + + return buttons + + def _update_buttons_state(self): + rules_list = self.rules_list + buttons = self.buttons + selected_items = rules_list.selection() + + if selected_items: + first_selected_item = selected_items[0] + last_selected_item = selected_items[-1] + first_index = rules_list.index(first_selected_item) + last_index = rules_list.index(last_selected_item) + total_items = len(rules_list.get_children()) + + buttons.move_up["state"] = tk.NORMAL if first_index > 0 else tk.DISABLED + buttons.move_down["state"] = tk.NORMAL if last_index < total_items - 1 else tk.DISABLED + else: + buttons.move_up["state"] = tk.DISABLED + buttons.move_down["state"] = tk.DISABLED + + buttons.delete["state"] = tk.NORMAL if selected_items else tk.DISABLED + + self.master.event_generate(RulesListEvents.UNSAVED_CHANGES_STATE) + + def load_from_config(self, config: dict): + self.rules_list.set_data(config.get(self.rule_type.field_in_config, [])) + + def save_to_config(self, config: dict): + rules_list = self.rules_list + config[self.rule_type.field_in_config] = rules_list.get_data() + rules_list.set_unsaved_changes(False) + + def has_unsaved_changes(self) -> bool: + return self.rules_list.has_unsaved_changes + + def has_error(self) -> bool: + return self.rules_list.has_error() + + +class RulesTabButtons(ttk.Frame): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._setup_btn() + + def _setup_btn(self): + self.add = add = IconedButton( + self, + text=" Add", + command=lambda: self.event_generate(ActionEvents.ADD), + image=icon16px("plus", fill="green") + ) + + self.delete = delete = IconedButton( + self, + text=" Del", + command=lambda: self.event_generate(ActionEvents.DELETE), + image=icon16px("trash-alt", fill="firebrick") + ) + + self.move_up = move_up = IconedButton( + self, + text=" Up", + command=lambda: self.event_generate(ActionEvents.UP), + image=icon16px("arrow-up", fill="#1a1a1a") + ) + + self.move_down = move_down = IconedButton( + self, + text=" Down", + command=lambda: self.event_generate(ActionEvents.DOWN), + image=icon16px("arrow-down", fill="#1a1a1a") + ) + + left_btn_pack = dict(side=tk.LEFT, padx=(0, UI_PADDING)) + add.pack(**left_btn_pack) + delete.pack(**left_btn_pack) + move_up.pack(**left_btn_pack) + move_down.pack(**left_btn_pack) diff --git a/src/ui/widget/editor/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py similarity index 92% rename from src/ui/widget/editor/rules_list.py rename to src/ui/widget/settings/tabs/rules/rules_list.py index d19380f..39ba483 100644 --- a/src/ui/widget/editor/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -8,7 +8,6 @@ from psutil._pswindows import Priority from pydantic import ValidationError, BaseModel -from configuration.rule import ServiceRule, ProcessRule from constants.priority_mappings import str_to_priority, str_to_iopriority from constants.ui import ERROR_COLOR, ERROR_ROW_COLOR, RulesListEvents, EditableTreeviewEvents, \ ScrollableTreeviewEvents @@ -92,7 +91,7 @@ def _setup_look(self): self._error_icon = icon16px("exclamation-triangle", ERROR_COLOR) - def set_raw_data(self, rules_raw: List[Any]): + def set_data(self, rules_raw: List[dict]): self.delete(*self.get_children()) fields = self["columns"] @@ -102,29 +101,36 @@ def set_raw_data(self, rules_raw: List[Any]): self.set_unsaved_changes(False) - def get_data(self) -> List[Optional[ProcessRule | ServiceRule | tuple[Any, Any]]]: - return self._to_rules() + def get_data(self) -> List[dict]: + return [self._to_rule_raw(row_id) for row_id in self.get_children()] - def _to_rule(self, row_id) -> ProcessRule | ServiceRule | tuple[Any, Any]: + def _to_rule_raw(self, row_id): keys = self["columns"] values = self.item(row_id, 'values') - dct = { + return { key: value for key, value in zip(keys, values) if value and value.strip() } + def get_error_if_available(self, row_id) -> Optional[tuple[Any, Any]]: try: # noinspection PyCallingNonCallable - return self._model(**dct) + self._model(**self._to_rule_raw(row_id)) + return None except ValidationError as e: return row_id, json.loads(e.json()) - def _to_rules(self) -> List[Optional[ProcessRule | ServiceRule | tuple[Any, Any]]]: - return [self._to_rule(row_id) for row_id in self.get_children()] - def _errors(self) -> dict[Any, Any]: - return {rule[0]: rule[1] for rule in self._to_rules() if - rule and not isinstance(rule, (ProcessRule, ServiceRule))} + errors = [ + self.get_error_if_available(row_id) + for row_id in self.get_children() + ] + + return { + error[0]: error[1] + for error in errors + if error is not None + } def has_error(self): return len(self._errors()) > 0 diff --git a/src/ui/widget/settings/tabs/rules/rules_tab.py b/src/ui/widget/settings/tabs/rules/rules_tab.py new file mode 100644 index 0000000..95a5cbb --- /dev/null +++ b/src/ui/widget/settings/tabs/rules/rules_tab.py @@ -0,0 +1,42 @@ +from tkinter import PhotoImage +from tkinter.ttk import Notebook + +from enums.rules import RuleType +from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab +from util.ui import icon16px + + +class ProcessRulesTab(BaseRulesTab): + def __init__(self, master: Notebook): + super().__init__(master, RuleType.PROCESS) + + @staticmethod + def icon() -> PhotoImage: + return icon16px("list", fill="#3F888F") + + @staticmethod + def title() -> str: + return "Process Rules" + + @staticmethod + def description() -> str: + return "Settings for defining **priority**, **I/O priority**, and **core affinity** for __processes__." + + +class ServiceRulesTab(BaseRulesTab): + def __init__(self, master: Notebook): + super().__init__(master, RuleType.SERVICE) + + @staticmethod + def icon() -> PhotoImage: + return icon16px("cogs", fill="#6495ED") + + @staticmethod + def title() -> str: + return "Service Rules" + + @staticmethod + def description() -> str: + return "Settings for defining **priority**, **I/O priority**, and **core affinity** for __services__." + + diff --git a/src/ui/widget/editor/tooltip.py b/src/ui/widget/settings/tooltip.py similarity index 95% rename from src/ui/widget/editor/tooltip.py rename to src/ui/widget/settings/tooltip.py index 7d757ea..390652e 100644 --- a/src/ui/widget/editor/tooltip.py +++ b/src/ui/widget/settings/tooltip.py @@ -8,7 +8,7 @@ class Tooltip(ttk.Frame): - def __init__(self, master=None, *args, **kwargs): + def __init__(self, master, *args, **kwargs): text = kwargs.pop("text", "") super().__init__(master, *args, **kwargs) diff --git a/src/util/ui.py b/src/util/ui.py index f19091c..d8cbabe 100644 --- a/src/util/ui.py +++ b/src/util/ui.py @@ -1,5 +1,5 @@ import tkinter -from tkinter import font, Widget +from tkinter import font, Widget, PhotoImage from tkinter.ttk import Treeview from tkfontawesome import icon_to_image @@ -42,5 +42,5 @@ def get_label_font(): return default_font -def icon16px(name: str, fill: str = None): +def icon16px(name: str, fill: str = None) -> PhotoImage: return icon_to_image(name, fill=fill, scale_to_width=16) From 183d19873896ebe64c00a4761517c1b6c8b082fc Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Tue, 13 Aug 2024 01:40:03 +0800 Subject: [PATCH 11/39] [#7] Support selector for path and command line --- requirements.txt | Bin 346 -> 346 bytes src/configuration/handler/io_priority.py | 36 ----------- src/configuration/handler/priority.py | 36 ----------- src/configuration/logs.py | 2 +- src/configuration/migration/all_migration.py | 12 ++-- .../migration/m1_new_field_selectorBy.py | 20 ++++++ src/configuration/rule.py | 59 +++++++++++------ src/constants/priority_mappings.py | 53 --------------- src/constants/ui.py | 2 +- src/enums/io_priority.py | 19 ++++++ src/enums/priority.py | 24 +++++++ src/enums/selector.py | 7 ++ src/model/process.py | 9 ++- src/service/processes_info_service.py | 50 ++++---------- src/service/rules_service.py | 48 +++++++++----- src/service/services_info_service.py | 16 ----- src/ui/settings.py | 13 +++- src/ui/widget/common/treeview/editable.py | 13 +++- .../widget/settings/tabs/rules/rules_list.py | 9 ++- src/ui/widget/settings/tooltip.py | 2 +- src/util/utils.py | 61 +++++++++++++++--- 21 files changed, 252 insertions(+), 239 deletions(-) delete mode 100644 src/configuration/handler/io_priority.py delete mode 100644 src/configuration/handler/priority.py create mode 100644 src/configuration/migration/m1_new_field_selectorBy.py delete mode 100644 src/constants/priority_mappings.py create mode 100644 src/enums/io_priority.py create mode 100644 src/enums/priority.py create mode 100644 src/enums/selector.py diff --git a/requirements.txt b/requirements.txt index d92e6101bb99852cceda349fd10b695bb20e85bf..408ce5ea50d0f94ca521c3b437ced2933a9807b4 100644 GIT binary patch delta 36 ncmcb`bc;#)|Gxr;Vun(N5{68M90pq;G-J?XFaY6=()Nr1&t?ef delta 36 ocmcb`bc;#)|Gxr;Vun(N5{68M90pq;G-c3Zumob$jnejv0MEk+_W%F@ diff --git a/src/configuration/handler/io_priority.py b/src/configuration/handler/io_priority.py deleted file mode 100644 index d696944..0000000 --- a/src/configuration/handler/io_priority.py +++ /dev/null @@ -1,36 +0,0 @@ -from psutil._pswindows import IOPriority -from pydantic import BeforeValidator, PlainSerializer, WithJsonSchema -from typing_extensions import Annotated - -from constants.priority_mappings import iopriority_to_str, str_to_iopriority - - -def __to_enum(value): - if isinstance(value, IOPriority): - return value - - try: - return str_to_iopriority[value] - except: - raise ValueError(f"expected: `{'`, `'.join(str_to_iopriority.keys())}`") - - -def __to_str(value): - if isinstance(value, IOPriority): - return iopriority_to_str[value] - - if value in str_to_iopriority.keys(): - return value - - if not (value and value.strip()): - return None - - raise ValueError("invalid IOPriority for string conversion") - - -IOPriorityStr = Annotated[ - IOPriority, - BeforeValidator(__to_enum), - PlainSerializer(__to_str, return_type=str), - WithJsonSchema({'type': 'string'}, mode='serialization'), -] diff --git a/src/configuration/handler/priority.py b/src/configuration/handler/priority.py deleted file mode 100644 index e621ea9..0000000 --- a/src/configuration/handler/priority.py +++ /dev/null @@ -1,36 +0,0 @@ -from psutil._pswindows import Priority -from pydantic import PlainSerializer, WithJsonSchema, BeforeValidator -from typing_extensions import Annotated - -from constants.priority_mappings import priority_to_str, str_to_priority - - -def __to_enum(value): - if isinstance(value, Priority): - return value - - try: - return str_to_priority[value] - except: - raise ValueError(f"expected: `{'`, `'.join(str_to_priority.keys())}`") - - -def __to_str(value): - if isinstance(value, Priority): - return priority_to_str[value] - - if value in str_to_priority.keys(): - return value - - if not (value and value.strip()): - return None - - raise ValueError("invalid Priority for string conversion") - - -PriorityStr = Annotated[ - Priority, - BeforeValidator(__to_enum), - PlainSerializer(__to_str, return_type=str), - WithJsonSchema({'type': 'string'}, mode='serialization'), -] diff --git a/src/configuration/logs.py b/src/configuration/logs.py index 3d762bc..b07fa01 100644 --- a/src/configuration/logs.py +++ b/src/configuration/logs.py @@ -17,7 +17,7 @@ class Logs(BaseModel): A boolean flag to enable or disable logging. Default is True (logging is enabled). """ - level: Literal['CRITICAL', 'FATAL', 'ERROR', 'WARNING', 'WARN', 'INFO', 'DEBUG', 'NOTSET'] = Field(default='INFO') + level: Literal['CRITICAL', 'FATAL', 'ERROR', 'WARNING', 'WARN', 'INFO', 'DEBUG', 'NOTSET'] = Field(default='DEBUG') """ The log level for filtering log messages. Default is 'INFO'. Valid log levels include: 'CRITICAL', 'FATAL', 'ERROR', 'WARNING', 'WARN', 'INFO', 'DEBUG', 'NOTSET'. diff --git a/src/configuration/migration/all_migration.py b/src/configuration/migration/all_migration.py index 8990d42..3e30259 100644 --- a/src/configuration/migration/all_migration.py +++ b/src/configuration/migration/all_migration.py @@ -2,13 +2,15 @@ from configuration.migration.base import BaseMigration from configuration.migration.m0_rules_to_split_rules_config import MigrationRules2SplitRulesConfig +from configuration.migration.m1_new_field_selectorBy import NewFieldSelectorBy from constants.app_info import APP_NAME_WITH_VERSION from constants.log import LOG from service.config_service import ConfigService from util.messages import show_error MIGRATIONS: list[type[BaseMigration]] = [ - MigrationRules2SplitRulesConfig + MigrationRules2SplitRulesConfig, + NewFieldSelectorBy ] """ List of migration classes to be executed in order. @@ -29,7 +31,7 @@ def run_all_migration(): if not need_migrate: return - LOG.info(f"Creating backup of the current configuration before migration") + LOG.info(f"Creating backup of the current configuration before migration...") ConfigService.backup_config() has_error = False @@ -41,16 +43,16 @@ def run_all_migration(): if not migration.should_migrate(copy.deepcopy(config)): continue - LOG.info(f"[{migration_name}] Starting migration") + LOG.info(f"[{migration_name}] Starting migration...") migrated_config = migration.migrate(copy.deepcopy(config)) migrated_config['version'] = migration.get_target_version() - LOG.info(f"[{migration_name}] Migration completed to version {migrated_config['version']}") + LOG.info(f"[{migration_name}] Migration completed to version {migrated_config['version']}.") config = migrated_config except Exception as e: has_error = True - LOG.exception(f"[{migration_name}] Migration failed") + LOG.exception(f"[{migration_name}] Migration failed.") show_error( f"Error Detected - {APP_NAME_WITH_VERSION}", f"Migration `{migration_name}` failed: \n{str(e)}" diff --git a/src/configuration/migration/m1_new_field_selectorBy.py b/src/configuration/migration/m1_new_field_selectorBy.py new file mode 100644 index 0000000..9a7b9a5 --- /dev/null +++ b/src/configuration/migration/m1_new_field_selectorBy.py @@ -0,0 +1,20 @@ +from typing import Optional + +from configuration.migration.base import BaseMigration + + +class NewFieldSelectorBy(BaseMigration): + @staticmethod + def get_target_version() -> int: + return 2 + + @staticmethod + def should_migrate(config: dict) -> bool: + return config['version'] == 1 + + @staticmethod + def migrate(config: dict) -> Optional[dict]: + for rule in config.get('processRules', []) + config.get('serviceRules', []): + rule['selectorBy'] = 'Name' + + return config diff --git a/src/configuration/rule.py b/src/configuration/rule.py index f4e0df9..dd6e6c6 100644 --- a/src/configuration/rule.py +++ b/src/configuration/rule.py @@ -3,18 +3,30 @@ from pydantic import BaseModel, Field from configuration.handler.affinity import Affinity -from configuration.handler.io_priority import IOPriorityStr -from configuration.handler.priority import PriorityStr +from enums.io_priority import IOPriorityStr +from enums.priority import PriorityStr +from enums.selector import SelectorType class ProcessRule(BaseModel): + selectorBy: SelectorType = Field( + title="Selector By", + description="Determines how the __Process Selector__ value is interpreted, influencing how the __process__ is matched.\n" + "**Options:**\n" + " - `Name` - matches by process name (e.g., `notepad.exe`);\n" + " - `Path` - matches by the full executable path (e.g., `C:/Windows/System32/notepad.exe`);\n" + " - `Command line` - matches by command line arguments (e.g., `App.exe Document.txt` or `D:/Folder/App.exe Document.txt`).", + default_ui=SelectorType.NAME.value + ) + selector: str = Field( - title="Process Selector", - description="Specifies the **name** or **pattern** of the __process__ to which this rule applies.\n\n" - "**Supports wildcards:** `\*` (matches any characters) and `?` (matches any single character).\n" - "**Examples:** `name.exe` or `logioptionsplus_*.exe`.", + title="Selector", + description="Specifies the **name**, **pattern** or **path** of the __process__ to which this rule applies.\n\n" + "**Supports wildcard:** `\*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" + "**Examples:** `name.exe`, `logioptionsplus_*.exe`, `D:/FolderName/App.exe` or `C:/Program Files/**/app.exe --file Document.txt`.", default_ui="*", - stretchable_column_ui=True + stretchable_column_ui=True, + justify_ui="left" ) priority: Optional[PriorityStr] = Field( @@ -34,21 +46,32 @@ class ProcessRule(BaseModel): affinity: Optional[Affinity] = Field( default=None, title="Affinity", - description="Sets the **CPU core affinity** for the __process__, " - "defining which CPU cores are allowed for execution.\n\n" + description="Sets the **CPU core affinity** for the __process__, defining which CPU cores are allowed for execution.\n\n" "**Format:** range `0-3`, specific cores `0;2;4`, combination `1;3-5`.", - scale_width_ui=3 + scale_width_ui=3, + justify_ui="left" ) class ServiceRule(BaseModel): + selectorBy: SelectorType = Field( + title="Selector By", + description="Determines how the __Service Selector__ value is interpreted, influencing how the __service__ is matched.\n" + "**Options:**\n" + " - `Name` - matches by service name (e.g., `Spooler`);\n" + " - `Path` - matches by the full executable path (e.g., `C:/Windows/System32/spoolsv.exe`);\n" + " - `Command line` - matches by command line arguments (e.g., `spoolsv.exe -k` or `C:/Windows/System32/spoolsv.exe -k`).", + default_ui=SelectorType.NAME.value + ) + selector: str = Field( - title="Service Selector", - description="Specifies the **name** or **pattern** of the __service__ to which this rule applies.\n\n" - "**Supports wildcards:** `\*` (matches any characters) and `?` (matches any single character).\n" - "**Examples:** `ServiceName` or `Audio*`.", + title="Selector", + description="Specifies the **name**, **pattern** or **path** of the __service__ to which this rule applies.\n\n" + "**Supports wildcard:** `\*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" + "**Examples:** `ServiceName`, `Audio*`, `D:/FolderName/Service.exe` or `C:/Windows/System32/**/service.exe --debug 1`.", default_ui="*", - stretchable_column_ui=True + stretchable_column_ui=True, + justify_ui="left" ) priority: Optional[PriorityStr] = Field( @@ -68,8 +91,8 @@ class ServiceRule(BaseModel): affinity: Optional[Affinity] = Field( default=None, title="Affinity", - description="Sets the **CPU core affinity** for the __service__, " - "defining which CPU cores are allowed for execution.\n\n" + description="Sets the **CPU core affinity** for the __service__, defining which CPU cores are allowed for execution.\n\n" "**Format:** range `0-3`, specific cores `0;2;4`, combination `1;3-5`.", - scale_width_ui=3 + scale_width_ui=3, + justify_ui="left" ) diff --git a/src/constants/priority_mappings.py b/src/constants/priority_mappings.py deleted file mode 100644 index dcd7b07..0000000 --- a/src/constants/priority_mappings.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import Final - -from psutil._pswindows import IOPriority, Priority - - -class IOPriorityStr: - VERYLOW: Final[str] = 'VeryLow' - LOW: Final[str] = 'Low' - NORMAL: Final[str] = 'Normal' - HIGH: Final[str] = 'High' - - -iopriority_to_str: Final[dict] = { - IOPriority.IOPRIO_VERYLOW: IOPriorityStr.VERYLOW, - IOPriority.IOPRIO_LOW: IOPriorityStr.LOW, - IOPriority.IOPRIO_NORMAL: IOPriorityStr.NORMAL, - IOPriority.IOPRIO_HIGH: IOPriorityStr.HIGH, -} - -str_to_iopriority: Final[dict] = { - IOPriorityStr.VERYLOW: IOPriority.IOPRIO_VERYLOW, - IOPriorityStr.LOW: IOPriority.IOPRIO_LOW, - IOPriorityStr.NORMAL: IOPriority.IOPRIO_NORMAL, - IOPriorityStr.HIGH: IOPriority.IOPRIO_HIGH, -} - - -class PriorityStr: - IDLE: Final[str] = 'Idle' - BELOW_NORMAL: Final[str] = 'BelowNormal' - NORMAL: Final[str] = 'Normal' - ABOVE_NORMAL: Final[str] = 'AboveNormal' - HIGH: Final[str] = 'High' - REALTIME: Final[str] = 'Realtime' - - -priority_to_str: Final[dict] = { - Priority.IDLE_PRIORITY_CLASS: PriorityStr.IDLE, - Priority.BELOW_NORMAL_PRIORITY_CLASS: PriorityStr.BELOW_NORMAL, - Priority.NORMAL_PRIORITY_CLASS: PriorityStr.NORMAL, - Priority.ABOVE_NORMAL_PRIORITY_CLASS: PriorityStr.ABOVE_NORMAL, - Priority.HIGH_PRIORITY_CLASS: PriorityStr.HIGH, - Priority.REALTIME_PRIORITY_CLASS: PriorityStr.REALTIME, -} - -str_to_priority: Final[dict] = { - PriorityStr.IDLE: Priority.IDLE_PRIORITY_CLASS, - PriorityStr.BELOW_NORMAL: Priority.BELOW_NORMAL_PRIORITY_CLASS, - PriorityStr.NORMAL: Priority.NORMAL_PRIORITY_CLASS, - PriorityStr.ABOVE_NORMAL: Priority.ABOVE_NORMAL_PRIORITY_CLASS, - PriorityStr.HIGH: Priority.HIGH_PRIORITY_CLASS, - PriorityStr.REALTIME: Priority.REALTIME_PRIORITY_CLASS, -} diff --git a/src/constants/ui.py b/src/constants/ui.py index 9426d13..134d3af 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -5,7 +5,7 @@ ERROR_COLOR = "#e57373" ERROR_ROW_COLOR = "#ffcdd2" TOOLTIP_ICON_SIZE = 75 -RC_WIN_SIZE = (900, 600) +RC_WIN_SIZE = (1280, 768) SETTINGS_TITLE = "Settings" diff --git a/src/enums/io_priority.py b/src/enums/io_priority.py new file mode 100644 index 0000000..4d0f915 --- /dev/null +++ b/src/enums/io_priority.py @@ -0,0 +1,19 @@ +from enum import Enum +from typing import Final + +from psutil._pswindows import IOPriority + + +class IOPriorityStr(Enum): + VERYLOW = 'VeryLow' + LOW = 'Low' + NORMAL = 'Normal' + HIGH = 'High' + + +to_iopriority: Final[dict[IOPriorityStr, IOPriority]] = { + IOPriorityStr.VERYLOW: IOPriority.IOPRIO_VERYLOW, + IOPriorityStr.LOW: IOPriority.IOPRIO_LOW, + IOPriorityStr.NORMAL: IOPriority.IOPRIO_NORMAL, + IOPriorityStr.HIGH: IOPriority.IOPRIO_HIGH +} diff --git a/src/enums/priority.py b/src/enums/priority.py new file mode 100644 index 0000000..7206bc5 --- /dev/null +++ b/src/enums/priority.py @@ -0,0 +1,24 @@ +from enum import Enum +from typing import Final + +from psutil._pswindows import Priority + + +class PriorityStr(Enum): + IDLE = 'Idle' + BELOW_NORMAL = 'BelowNormal' + NORMAL = 'Normal' + ABOVE_NORMAL = 'AboveNormal' + HIGH = 'High' + REALTIME = 'Realtime' + + +to_priority: Final[dict[PriorityStr, Priority]] = { + PriorityStr.IDLE: Priority.IDLE_PRIORITY_CLASS, + PriorityStr.BELOW_NORMAL: Priority.BELOW_NORMAL_PRIORITY_CLASS, + PriorityStr.NORMAL: Priority.NORMAL_PRIORITY_CLASS, + PriorityStr.ABOVE_NORMAL: Priority.ABOVE_NORMAL_PRIORITY_CLASS, + PriorityStr.HIGH: Priority.HIGH_PRIORITY_CLASS, + PriorityStr.REALTIME: Priority.REALTIME_PRIORITY_CLASS, + None: None +} diff --git a/src/enums/selector.py b/src/enums/selector.py new file mode 100644 index 0000000..68b2815 --- /dev/null +++ b/src/enums/selector.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class SelectorType(Enum): + NAME = "Name" + PATH = "Path" + CMDLINE = "Command line" diff --git a/src/model/process.py b/src/model/process.py index 43f6972..9cd74c8 100644 --- a/src/model/process.py +++ b/src/model/process.py @@ -19,9 +19,14 @@ class Process: The unique identifier of the process (Process ID). """ - exe: str + binpath: str """ - The name of the executable file associated with the process. + The full path to the executable binary of the process. + """ + + cmdline: str + """ + The command line used to start the process, including all arguments. """ name: str diff --git a/src/service/processes_info_service.py b/src/service/processes_info_service.py index b1b1f8d..e552c5b 100644 --- a/src/service/processes_info_service.py +++ b/src/service/processes_info_service.py @@ -13,11 +13,17 @@ class ProcessesInfoService(ABC): It is an abstract base class (ABC) to be subclassed by specific implementation classes. """ + __prev_pids: Set[int] = [] + @classmethod - def get_list(cls) -> dict[int, Process]: + def get_list(cls, only_new: bool = False) -> dict[int, Process]: """ Get a dictionary of running processes and their information. + Args: + only_new (bool): If True, return only the newly created processes since the last check. + If False, return all running processes. + Returns: dict[int, Process]: A dictionary where keys are process IDs (pids) and values are Process objects representing the running processes. @@ -26,12 +32,18 @@ def get_list(cls) -> dict[int, Process]: current_pids: List[int] = psutil.pids() for pid in current_pids: + if only_new and pid in cls.__prev_pids: + continue + try: process = psutil.Process(pid) - info = process.as_dict(attrs=['name', 'exe', 'nice', 'ionice', 'cpu_affinity']) + info = process.as_dict(attrs=['name', 'exe', 'nice', 'ionice', 'cpu_affinity', 'cmdline']) + cmdline = ' '.join(process for process in info['cmdline'] or [''] if process) + result[pid] = Process( pid, info['exe'], + cmdline, info['name'], int(info['nice']) if info['nice'] else None, int(info['ionice']) if info['ionice'] else None, @@ -43,37 +55,3 @@ def get_list(cls) -> dict[int, Process]: cls.__prev_pids = set(current_pids) return result - - __prev_pids: Set[int] = [] - - @classmethod - def get_new_processes(cls) -> dict[int, Process]: - """ - Get a dictionary of newly created processes since the last check. - - Returns: - dict[int, Process]: A dictionary where keys are process IDs (pids) and values are Process objects - representing the newly created processes. - """ - result: dict[int, Process] = {} - current_pids: List[int] = psutil.pids() - - for pid in current_pids: - if pid not in cls.__prev_pids: - try: - process = psutil.Process(pid) - info = process.as_dict(attrs=['name', 'exe', 'nice', 'ionice', 'cpu_affinity']) - result[pid] = Process( - pid, - info['exe'], - info['name'], - int(info['nice']) if info['nice'] else None, - int(info['ionice']) if info['ionice'] else None, - info['cpu_affinity'], - process - ) - except NoSuchProcess: - pass - - cls.__prev_pids = set(current_pids) - return result diff --git a/src/service/rules_service.py b/src/service/rules_service.py index d0bd593..30297b0 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -9,15 +9,17 @@ from configuration.config import Config from configuration.rule import ProcessRule, ServiceRule from constants.log import LOG -from constants.priority_mappings import iopriority_to_str, priority_to_str +from enums.io_priority import to_iopriority +from enums.priority import to_priority from enums.process import ProcessParameter +from enums.selector import SelectorType from model.process import Process from model.service import Service from service.processes_info_service import ProcessesInfoService from service.services_info_service import ServicesInfoService from util.cpu import format_affinity from util.decorators import cached -from util.utils import fnmatch_cached +from util.utils import path_match class RulesService(ABC): @@ -54,7 +56,7 @@ def apply_rules(cls, config: Config, force=False): LOG.info("Configuration file has been modified. Reloading all rules to apply changes.") processes = ProcessesInfoService.get_list() else: - processes = ProcessesInfoService.get_new_processes() + processes = ProcessesInfoService.get_list(True) cls.__handle_processes(config, processes, services) @@ -65,7 +67,7 @@ def __handle_processes(cls, config: Config, processes: dict[int, Process], servi continue try: - service_info: Service = ServicesInfoService.get_by_pid(pid, services) + service_info: Service = services.get(pid) rule: Optional[ProcessRule | ServiceRule] = cls.__first_rule_by_name(config, service_info, process_info) if not rule: @@ -102,9 +104,9 @@ def __set_ionice(cls, not_success, process_info, rule: ProcessRule | ServiceRule parameter = ProcessParameter.IONICE try: - process_info.process.ionice(rule.ioPriority) - LOG.info( - f"Set {parameter.value} {iopriority_to_str[rule.ioPriority]} for {process_info.name} ({process_info.pid})") + io_priority = to_iopriority[rule.ioPriority] + process_info.process.ionice(io_priority) + LOG.info(f"Set {parameter.value} {rule.ioPriority.value} for {process_info.name} ({process_info.pid})") except AccessDenied: not_success.append(parameter) @@ -116,9 +118,9 @@ def __set_nice(cls, not_success, process_info, rule: ProcessRule | ServiceRule): parameter = ProcessParameter.NICE try: - process_info.process.nice(rule.priority) - LOG.info( - f"Set {parameter.value} {priority_to_str[rule.priority]} for {process_info.name} ({process_info.pid})") + priority = to_priority[rule.priority] + process_info.process.nice(priority) + LOG.info( f"Set {parameter.value} {rule.priority.value} for {process_info.name} ({process_info.pid})") except AccessDenied: not_success.append(parameter) @@ -147,13 +149,27 @@ def __first_rule_by_name( process: Process ) -> Optional[ProcessRule | ServiceRule]: if service: - for rule in config.serviceRules: - if fnmatch_cached(service.name, rule.selector): - return rule + for serviceRule in config.serviceRules: + value = service.name + + if serviceRule.selectorBy == SelectorType.PATH: + value = service.binpath + elif serviceRule.selectorBy == SelectorType.CMDLINE: + value = process.cmdline + + if path_match(serviceRule.selector, value): + return serviceRule + + for processRule in config.processRules: + value = process.name + + if processRule.selectorBy == SelectorType.PATH: + value = process.binpath + elif processRule.selectorBy == SelectorType.CMDLINE: + value = process.cmdline - for rule in config.processRules: - if fnmatch_cached(process.name, rule.selector): - return rule + if path_match(processRule.selector, value): + return processRule return None diff --git a/src/service/services_info_service.py b/src/service/services_info_service.py index e5cb475..358af0a 100644 --- a/src/service/services_info_service.py +++ b/src/service/services_info_service.py @@ -1,5 +1,4 @@ from abc import ABC -from typing import Optional import psutil from psutil import STATUS_STOPPED, NoSuchProcess, ZombieProcess, AccessDenied @@ -58,18 +57,3 @@ def get_list() -> dict[int, Service]: LOG.warning(f"No such service: {service.name}") return result - - @classmethod - def get_by_pid(cls, pid: int, dct: dict[int, Service]) -> Optional[Service]: - """ - Get a Service object by its process ID (pid) from the provided dictionary. - - Args: - pid (int): The process ID (pid) of the service to retrieve. - dct (dict[int, Service]): A dictionary of services where keys are process IDs (pids) and values are - Service objects. - - Returns: - Optional[Service]: The Service object if found, or None if not found. - """ - return dct.get(pid) diff --git a/src/ui/settings.py b/src/ui/settings.py index 5783502..92daede 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -104,8 +104,10 @@ def _create_buttons(self): self._update_buttons_state() def _on_window_closing(self): + has_error = self._tabs.has_error() + if self._tabs.has_unsaved_changes(): - if self._tabs.has_error(): + if has_error: message = ("There are errors in the rules, and they can't be saved. " "Do you want to DISCARD them and exit?") result = messagebox.askyesno(f"{SETTINGS_TITLE} - {APP_NAME_WITH_VERSION}", message) @@ -122,6 +124,15 @@ def _on_window_closing(self): if result and not self._tabs.save_data(): return + else: + if has_error: + message = ( + f"There are errors in the rules, and they must be corrected before the application can work properly. " + f"Do you still want to close the {SETTINGS_TITLE}?") + result = messagebox.askyesno(f"{SETTINGS_TITLE} - {APP_NAME_WITH_VERSION}", message) + + if not result: + return self.destroy() diff --git a/src/ui/widget/common/treeview/editable.py b/src/ui/widget/common/treeview/editable.py index f7ee5f3..b499639 100644 --- a/src/ui/widget/common/treeview/editable.py +++ b/src/ui/widget/common/treeview/editable.py @@ -9,6 +9,11 @@ ColumnType = Literal["text", "list"] +_justify_mapping = { + "w": "left", + "e": "right", + "center": "center" +} @dataclass(frozen=True) class CellInfo: @@ -28,6 +33,7 @@ def __init__( *args, **kwargs ): + self._master = master self._cell = cell_info self._input = self._setup_widgets(master, *args, **kwargs) @@ -38,8 +44,11 @@ def on_change(_): def on_escape(_): self.event_generate(EditableTreeviewEvents.ESCAPE) + column_settings = self._master.column(self._cell.column_id) + justify = _justify_mapping[column_settings.get('anchor', 'center')] + if self._cell.type == "text": - entry_popup = ttk.Entry(master, *args, justify='center', **kwargs) + entry_popup = ttk.Entry(master, *args, justify=justify, **kwargs) entry_popup.insert(0, self._cell.value) entry_popup.select_range(0, tk.END) entry_popup.bind("", on_change, '+') @@ -48,7 +57,7 @@ def on_escape(_): master, *args, values=self._cell.values, - justify='center', + justify=justify, state="readonly", **kwargs ) diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index 39ba483..d7a78a8 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -5,10 +5,8 @@ from tkinter.font import Font from typing import Optional, Any, List -from psutil._pswindows import Priority from pydantic import ValidationError, BaseModel -from constants.priority_mappings import str_to_priority, str_to_iopriority from constants.ui import ERROR_COLOR, ERROR_ROW_COLOR, RulesListEvents, EditableTreeviewEvents, \ ScrollableTreeviewEvents from ui.widget.common.label import Image @@ -60,7 +58,7 @@ def _setup_columns(self): values.append("") if issubclass(typ, enum.Enum): - values += list(str_to_priority.keys() if typ == Priority else str_to_iopriority.keys()) + values += [str(e.value) for e in typ] max_width_value_in_column = max(values + [max_width_value_in_column], key=len) self.column_type(column_name, "list") @@ -73,13 +71,14 @@ def _setup_columns(self): stretch = extra.get('stretchable_column_ui', False) width = extra.get( 'width_ui', - int(self.font.measure(max_width_value_in_column) * 1.5) + int(self.font.measure(max_width_value_in_column) * 1.35) if title else None ) width = width * extra.get('scale_width_ui', 1) if width else None + anchor = {"left": "w", "center": "center", "right": "e"}[extra.get('justify_ui', 'center')] self.heading(column_name, text=title) - self.column(column_name, anchor='center', width=width, minwidth=width, stretch=stretch) + self.column(column_name, anchor=anchor, width=width, minwidth=width, stretch=stretch) def _setup_look(self): self.font = Font(family="TkDefaultFont") diff --git a/src/ui/widget/settings/tooltip.py b/src/ui/widget/settings/tooltip.py index 390652e..472fcc4 100644 --- a/src/ui/widget/settings/tooltip.py +++ b/src/ui/widget/settings/tooltip.py @@ -22,7 +22,7 @@ def __init__(self, master, *args, **kwargs): ) self._image.pack(side=tk.LEFT, fill=tk.Y, padx=(0, UI_PADDING)) - label = RichLabel(self, height=4.25, textvariable=self._text) + label = RichLabel(self, height=5.25, textvariable=self._text) label.pack(expand=True, fill=tk.BOTH) label.pack_propagate(False) diff --git a/src/util/utils.py b/src/util/utils.py index eeb7194..8af2fe6 100644 --- a/src/util/utils.py +++ b/src/util/utils.py @@ -1,27 +1,68 @@ +import re import sys -from fnmatch import fnmatch from functools import lru_cache +from re import Pattern from types import NoneType -from typing import get_origin, get_args, Union, Annotated +from typing import get_origin, get_args, Union, Annotated, Optional + + +@lru_cache(maxsize=None) +def path_pattern_to_regex(pattern: str) -> Optional[Pattern]: + """ + Converts a glob-like path pattern to a regular expression, with partial support for glob syntax. + + Args: + pattern (str): The path pattern to convert. + + Returns: + re.Pattern: The compiled regular expression. + + Supports: + - "*" matches any sequence of characters except the path separator. + - "?" matches any single character except the path separator. + - "**/" matches any number of nested directories. + """ + + pattern = pattern.strip() + + if not pattern: + return None + + pattern = re.escape(pattern.replace('\\', '/')) + pattern = pattern.replace(r'/', '[/]') + pattern = pattern.replace('\\*\\*[/]', '(.*[/])?') + pattern = pattern.replace('\\?', '[^/]') + pattern = pattern.replace('\\*', '[^/]*') + pattern = pattern.replace('/', r'\\/') + + return re.compile(f"^{pattern}$") @lru_cache -def fnmatch_cached(name: str, pattern: str) -> bool: +def path_match(pattern: str, value: str) -> bool: """ - Check if a name matches a pattern using fnmatch, with caching. + Checks if any of the provided values match the given pattern. Args: - name (str): The name to check. - pattern (str): The pattern to match against. + pattern (str): The pattern to match against, supporting wildcards. + *values (str): The values to test against the pattern. Returns: - bool: True if the name matches the pattern, False otherwise. + bool: True if any value matches the pattern, False otherwise. """ - if pattern: - pattern = pattern.strip() + if pattern == value: + return True + + if not pattern: + return False + + regex = path_pattern_to_regex(pattern) + + if not pattern: + return False - return pattern and fnmatch(name, pattern) + return regex.match(value) is not None def is_portable(): From 52c73d7d14df779b268500611ea3234e3e20bdbd Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Tue, 13 Aug 2024 21:58:41 +0800 Subject: [PATCH 12/39] [#10] Implementation of Continuous Rule Application Mode --- src/configuration/migration/all_migration.py | 7 +- ...selectorBy.py => m1_new_fields_in_rule.py} | 3 +- src/configuration/rule.py | 31 +++++-- src/enums/bool.py | 6 ++ src/enums/io_priority.py | 3 +- src/enums/selector.py | 2 +- src/main_loop.py | 6 +- src/model/process.py | 8 ++ src/service/processes_info_service.py | 19 ++-- src/service/rules_service.py | 90 +++++++++---------- .../widget/settings/tabs/rules/rules_list.py | 10 ++- 11 files changed, 116 insertions(+), 69 deletions(-) rename src/configuration/migration/{m1_new_field_selectorBy.py => m1_new_fields_in_rule.py} (87%) create mode 100644 src/enums/bool.py diff --git a/src/configuration/migration/all_migration.py b/src/configuration/migration/all_migration.py index 3e30259..f6fc414 100644 --- a/src/configuration/migration/all_migration.py +++ b/src/configuration/migration/all_migration.py @@ -2,7 +2,7 @@ from configuration.migration.base import BaseMigration from configuration.migration.m0_rules_to_split_rules_config import MigrationRules2SplitRulesConfig -from configuration.migration.m1_new_field_selectorBy import NewFieldSelectorBy +from configuration.migration.m1_new_fields_in_rule import NewFieldsInRule from constants.app_info import APP_NAME_WITH_VERSION from constants.log import LOG from service.config_service import ConfigService @@ -10,7 +10,7 @@ MIGRATIONS: list[type[BaseMigration]] = [ MigrationRules2SplitRulesConfig, - NewFieldSelectorBy + NewFieldsInRule ] """ List of migration classes to be executed in order. @@ -61,3 +61,6 @@ def run_all_migration(): if not has_error: ConfigService.save_config_raw(config) + +if __name__ == '__main__': + run_all_migration() diff --git a/src/configuration/migration/m1_new_field_selectorBy.py b/src/configuration/migration/m1_new_fields_in_rule.py similarity index 87% rename from src/configuration/migration/m1_new_field_selectorBy.py rename to src/configuration/migration/m1_new_fields_in_rule.py index 9a7b9a5..eea94cc 100644 --- a/src/configuration/migration/m1_new_field_selectorBy.py +++ b/src/configuration/migration/m1_new_fields_in_rule.py @@ -3,7 +3,7 @@ from configuration.migration.base import BaseMigration -class NewFieldSelectorBy(BaseMigration): +class NewFieldsInRule(BaseMigration): @staticmethod def get_target_version() -> int: return 2 @@ -16,5 +16,6 @@ def should_migrate(config: dict) -> bool: def migrate(config: dict) -> Optional[dict]: for rule in config.get('processRules', []) + config.get('serviceRules', []): rule['selectorBy'] = 'Name' + rule['force'] = 'N' return config diff --git a/src/configuration/rule.py b/src/configuration/rule.py index dd6e6c6..5f47639 100644 --- a/src/configuration/rule.py +++ b/src/configuration/rule.py @@ -3,6 +3,7 @@ from pydantic import BaseModel, Field from configuration.handler.affinity import Affinity +from enums.bool import BoolStr from enums.io_priority import IOPriorityStr from enums.priority import PriorityStr from enums.selector import SelectorType @@ -10,21 +11,21 @@ class ProcessRule(BaseModel): selectorBy: SelectorType = Field( + default=SelectorType.NAME, title="Selector By", description="Determines how the __Process Selector__ value is interpreted, influencing how the __process__ is matched.\n" "**Options:**\n" " - `Name` - matches by process name (e.g., `notepad.exe`);\n" " - `Path` - matches by the full executable path (e.g., `C:/Windows/System32/notepad.exe`);\n" - " - `Command line` - matches by command line arguments (e.g., `App.exe Document.txt` or `D:/Folder/App.exe Document.txt`).", - default_ui=SelectorType.NAME.value + " - `Command line` - matches by command line arguments (e.g., `App.exe Document.txt` or `D:/Folder/App.exe Document.txt`)." ) selector: str = Field( + default="*", title="Selector", description="Specifies the **name**, **pattern** or **path** of the __process__ to which this rule applies.\n\n" "**Supports wildcard:** `\*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" "**Examples:** `name.exe`, `logioptionsplus_*.exe`, `D:/FolderName/App.exe` or `C:/Program Files/**/app.exe --file Document.txt`.", - default_ui="*", stretchable_column_ui=True, justify_ui="left" ) @@ -52,24 +53,33 @@ class ProcessRule(BaseModel): justify_ui="left" ) + force: BoolStr = Field( + default=BoolStr.NO, + title="Force", + description="**Forces** the settings to be continuously applied to the __process__, even if the application tries to override them.\n\n" + "**Possible values:**\n" + "- `Y` for continuous application;\n" + "- `N` for one-time application.", + ) + class ServiceRule(BaseModel): selectorBy: SelectorType = Field( + default=SelectorType.NAME, title="Selector By", description="Determines how the __Service Selector__ value is interpreted, influencing how the __service__ is matched.\n" "**Options:**\n" " - `Name` - matches by service name (e.g., `Spooler`);\n" " - `Path` - matches by the full executable path (e.g., `C:/Windows/System32/spoolsv.exe`);\n" - " - `Command line` - matches by command line arguments (e.g., `spoolsv.exe -k` or `C:/Windows/System32/spoolsv.exe -k`).", - default_ui=SelectorType.NAME.value + " - `Command line` - matches by command line arguments (e.g., `spoolsv.exe -k` or `C:/Windows/System32/spoolsv.exe -k`)." ) selector: str = Field( + default="*", title="Selector", description="Specifies the **name**, **pattern** or **path** of the __service__ to which this rule applies.\n\n" "**Supports wildcard:** `\*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" "**Examples:** `ServiceName`, `Audio*`, `D:/FolderName/Service.exe` or `C:/Windows/System32/**/service.exe --debug 1`.", - default_ui="*", stretchable_column_ui=True, justify_ui="left" ) @@ -96,3 +106,12 @@ class ServiceRule(BaseModel): scale_width_ui=3, justify_ui="left" ) + + force: BoolStr = Field( + default=BoolStr.NO, + title="Force", + description="**Forces** the settings to be continuously applied to the __service__, even if the application tries to override them.\n\n" + "**Possible values:**\n" + "- `Y` for continuous application;\n" + "- `N` for one-time application.", + ) diff --git a/src/enums/bool.py b/src/enums/bool.py new file mode 100644 index 0000000..23877e4 --- /dev/null +++ b/src/enums/bool.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class BoolStr(Enum): + NO = "N" + YES = "Y" diff --git a/src/enums/io_priority.py b/src/enums/io_priority.py index 4d0f915..0efb0b5 100644 --- a/src/enums/io_priority.py +++ b/src/enums/io_priority.py @@ -15,5 +15,6 @@ class IOPriorityStr(Enum): IOPriorityStr.VERYLOW: IOPriority.IOPRIO_VERYLOW, IOPriorityStr.LOW: IOPriority.IOPRIO_LOW, IOPriorityStr.NORMAL: IOPriority.IOPRIO_NORMAL, - IOPriorityStr.HIGH: IOPriority.IOPRIO_HIGH + IOPriorityStr.HIGH: IOPriority.IOPRIO_HIGH, + None: None } diff --git a/src/enums/selector.py b/src/enums/selector.py index 68b2815..6921c07 100644 --- a/src/enums/selector.py +++ b/src/enums/selector.py @@ -4,4 +4,4 @@ class SelectorType(Enum): NAME = "Name" PATH = "Path" - CMDLINE = "Command line" + CMDLINE = "CommandLine" diff --git a/src/main_loop.py b/src/main_loop.py index 30fa08c..3d187c3 100644 --- a/src/main_loop.py +++ b/src/main_loop.py @@ -55,7 +55,11 @@ def main_loop(tray: Icon): while thread.is_alive(): try: config, is_changed = ConfigService.reload_if_changed(config) - RulesService.apply_rules(config, is_changed) + + if is_changed: + LOG.info("Configuration file has been modified. Reloading all rules to apply changes.") + + RulesService.apply_rules(config, not is_changed) last_error_message = None except KeyboardInterrupt as e: raise e diff --git a/src/model/process.py b/src/model/process.py index 9cd74c8..25eddcc 100644 --- a/src/model/process.py +++ b/src/model/process.py @@ -4,6 +4,8 @@ import psutil from psutil._pswindows import Priority, IOPriority +from model.service import Service + @dataclass class Process: @@ -53,3 +55,9 @@ class Process: """ The psutil.Process object associated with the process, providing access to additional process information and control. """ + + service: Optional[Service] + """ + Contains information about the service if the current process is associated with one. + If the process is not related to a service, this will be None. + """ diff --git a/src/service/processes_info_service.py b/src/service/processes_info_service.py index e552c5b..206672d 100644 --- a/src/service/processes_info_service.py +++ b/src/service/processes_info_service.py @@ -5,6 +5,7 @@ from psutil import NoSuchProcess from model.process import Process +from service.services_info_service import ServicesInfoService class ProcessesInfoService(ABC): @@ -16,23 +17,24 @@ class ProcessesInfoService(ABC): __prev_pids: Set[int] = [] @classmethod - def get_list(cls, only_new: bool = False) -> dict[int, Process]: + def get_list(cls, only_new: bool, return_pids: set[int]) -> dict[int, Process]: """ - Get a dictionary of running processes and their information. + Retrieves a dictionary of running processes and their information. Args: - only_new (bool): If True, return only the newly created processes since the last check. - If False, return all running processes. + only_new (bool): If True, returns only processes that have started since the last call. + If False, returns all currently running processes. + return_pids (list[int]): A list of process IDs to include even if they are not new. Returns: - dict[int, Process]: A dictionary where keys are process IDs (pids) and values are Process objects - representing the running processes. + dict[int, Process]: A dictionary with process IDs as keys and Process objects as values. """ + services = ServicesInfoService.get_list() result: dict[int, Process] = {} current_pids: List[int] = psutil.pids() for pid in current_pids: - if only_new and pid in cls.__prev_pids: + if only_new and pid in cls.__prev_pids and pid not in return_pids: continue try: @@ -48,7 +50,8 @@ def get_list(cls, only_new: bool = False) -> dict[int, Process]: int(info['nice']) if info['nice'] else None, int(info['ionice']) if info['ionice'] else None, info['cpu_affinity'], - process + process, + services.get(pid) ) except NoSuchProcess: pass diff --git a/src/service/rules_service.py b/src/service/rules_service.py index 30297b0..4c1e680 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -9,14 +9,13 @@ from configuration.config import Config from configuration.rule import ProcessRule, ServiceRule from constants.log import LOG +from enums.bool import BoolStr from enums.io_priority import to_iopriority from enums.priority import to_priority from enums.process import ProcessParameter from enums.selector import SelectorType from model.process import Process -from model.service import Service from service.processes_info_service import ProcessesInfoService -from service.services_info_service import ServicesInfoService from util.cpu import format_affinity from util.decorators import cached from util.utils import path_match @@ -30,16 +29,16 @@ class RulesService(ABC): __ignore_pids: set[int] = {0, os.getpid()} __ignored_process_parameters: dict[tuple[int, str], set[ProcessParameter]] = {} + __force_pids: set[int] = set() @classmethod - def apply_rules(cls, config: Config, force=False): + def apply_rules(cls, config: Config, only_new: bool): """ Apply the rules defined in the configuration to handle processes and services. Args: config (Config): The configuration object containing the rules. - force (bool, optional): If set to True, all processes will be fetched, - regardless of their status. Defaults to False. + only_new (bool, optional): If set to True, all processes will be fetched, regardless of their status. Returns: None @@ -48,96 +47,94 @@ def apply_rules(cls, config: Config, force=False): return cls.__light_gc_ignored_process_parameters() - - services: dict[int, Service] = ServicesInfoService.get_list() - processes: dict[int, Process] - - if force: - LOG.info("Configuration file has been modified. Reloading all rules to apply changes.") - processes = ProcessesInfoService.get_list() - else: - processes = ProcessesInfoService.get_list(True) - - cls.__handle_processes(config, processes, services) + cls.__force_pids = cls.__handle_processes( + config, + ProcessesInfoService.get_list(only_new, cls.__force_pids) + ) @classmethod - def __handle_processes(cls, config: Config, processes: dict[int, Process], services: dict[int, Service]): - for pid, process_info in processes.items(): + def __handle_processes(cls, config: Config, processes: dict[int, Process]) -> set[int]: + force_pids: set[int] = set() + + for pid, process in processes.items(): if pid in cls.__ignore_pids: continue try: - service_info: Service = services.get(pid) - rule: Optional[ProcessRule | ServiceRule] = cls.__first_rule_by_name(config, service_info, process_info) + rule: Optional[ProcessRule | ServiceRule] = cls.__first_rule_by_name(config, process) if not rule: continue - tuple_pid_name = (pid, process_info.name) + if rule.force == BoolStr.YES: + force_pids.add(pid) + + tuple_pid_name = (pid, process.name) ignored_process_parameters = cls.__ignored_process_parameters.get(tuple_pid_name, set()) not_success: List[ProcessParameter] = [] if ProcessParameter.AFFINITY not in ignored_process_parameters: - cls.__set_affinity(not_success, process_info, rule) + cls.__set_affinity(not_success, process, rule) if ProcessParameter.NICE not in ignored_process_parameters: - cls.__set_nice(not_success, process_info, rule) + cls.__set_nice(not_success, process, rule) if ProcessParameter.IONICE not in ignored_process_parameters: - cls.__set_ionice(not_success, process_info, rule) + cls.__set_ionice(not_success, process, rule) if not_success: cls.__ignore_process_parameter(tuple_pid_name, set(not_success)) LOG.warning(f"Set failed [{', '.join(map(str, not_success))}] " - f"for {process_info.name} ({process_info.pid}" - f"{', ' + service_info.name + '' if service_info else ''}" + f"for {process.name} ({process.pid}" + f"{', ' + process.service.name + '' if process.service else ''}" f")") except NoSuchProcess: LOG.warning(f"No such process: {pid}") + return force_pids + @classmethod - def __set_ionice(cls, not_success, process_info, rule: ProcessRule | ServiceRule): - if not rule.ioPriority or process_info.ionice == rule.ioPriority: + def __set_ionice(cls, not_success, process: Process, rule: ProcessRule | ServiceRule): + io_priority = to_iopriority[rule.ioPriority] + + if not io_priority or process.ionice == io_priority: return parameter = ProcessParameter.IONICE try: - io_priority = to_iopriority[rule.ioPriority] - process_info.process.ionice(io_priority) - LOG.info(f"Set {parameter.value} {rule.ioPriority.value} for {process_info.name} ({process_info.pid})") + process.process.ionice(io_priority) + LOG.info(f"Set {parameter.value} {rule.ioPriority.value} for {process.name} ({process.pid})") except AccessDenied: not_success.append(parameter) @classmethod - def __set_nice(cls, not_success, process_info, rule: ProcessRule | ServiceRule): - if not rule.priority or process_info.nice == rule.priority: + def __set_nice(cls, not_success, process: Process, rule: ProcessRule | ServiceRule): + priority = to_priority[rule.priority] + + if not priority or process.nice == priority: return parameter = ProcessParameter.NICE try: - priority = to_priority[rule.priority] - process_info.process.nice(priority) - LOG.info( f"Set {parameter.value} {rule.priority.value} for {process_info.name} ({process_info.pid})") + process.process.nice(priority) + LOG.info(f"Set {parameter.value} {rule.priority.value} for {process.name} ({process.pid})") except AccessDenied: not_success.append(parameter) @classmethod - def __set_affinity(cls, not_success, process_info: Process, rule: ProcessRule | ServiceRule): - if not rule.affinity: + def __set_affinity(cls, not_success, process: Process, rule: ProcessRule | ServiceRule): + if not rule.affinity or process.affinity == rule.affinity: return parameter = ProcessParameter.AFFINITY - if process_info.affinity == rule.affinity: - return - try: - process_info.process.cpu_affinity(rule.affinity) - LOG.info( - f"Set {parameter.value} {format_affinity(rule.affinity)} for {process_info.name} ({process_info.pid})") + process.process.cpu_affinity(rule.affinity) + affinity = format_affinity(rule.affinity) + LOG.info(f"Set {parameter.value} {affinity} for {process.name} ({process.pid})") except AccessDenied: not_success.append(parameter) @@ -145,9 +142,10 @@ def __set_affinity(cls, not_success, process_info: Process, rule: ProcessRule | def __first_rule_by_name( cls, config: Config, - service: Service, process: Process ) -> Optional[ProcessRule | ServiceRule]: + service = process.service + if service: for serviceRule in config.serviceRules: value = service.name @@ -191,4 +189,4 @@ def __light_gc_ignored_process_parameters(cls): remove_pids.append(item) for item in remove_pids: - del cls.__ignored_process_parameters[item] + del cls.__ignored_process_parameters[item] \ No newline at end of file diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index d7a78a8..1248f95 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -1,6 +1,7 @@ import enum import json import tkinter as tk +from enum import Enum from tkinter import ttk from tkinter.font import Font from typing import Optional, Any, List @@ -227,9 +228,12 @@ def _get_default_values(self) -> List[Any]: for column_name in self["columns"]: field_info = model_fields.get(column_name) - extra = field_info.json_schema_extra or dict() if field_info else dict() - default_value = extra.get('default_ui', '') - result.append(default_value) + default_value = field_info.default + + if isinstance(default_value, Enum): + default_value = default_value.value + + result.append(default_value or '') return result From d5a30bac3aa24445b7d06ca412c53394dce1fe04 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Thu, 15 Aug 2024 02:56:17 +0800 Subject: [PATCH 13/39] [#9] Added an optional delay in applying rules, as well as refactoring --- .../migration/m1_new_fields_in_rule.py | 3 +- src/configuration/rule.py | 20 +++ src/constants/app_info.py | 2 +- src/constants/log.py | 4 +- src/enums/bool.py | 5 +- src/enums/io_priority.py | 5 +- src/enums/priority.py | 5 +- src/enums/process.py | 8 +- src/enums/selector.py | 5 +- src/model/process.py | 9 ++ src/service/rules_service.py | 150 +++++++----------- .../widget/settings/tabs/rules/rules_list.py | 4 +- src/util/scheduler.py | 74 +++------ src/util/startup.py | 8 +- src/util/windows_scheduler.py | 64 ++++++++ 15 files changed, 208 insertions(+), 158 deletions(-) create mode 100644 src/util/windows_scheduler.py diff --git a/src/configuration/migration/m1_new_fields_in_rule.py b/src/configuration/migration/m1_new_fields_in_rule.py index eea94cc..ec9a29d 100644 --- a/src/configuration/migration/m1_new_fields_in_rule.py +++ b/src/configuration/migration/m1_new_fields_in_rule.py @@ -1,3 +1,4 @@ +import itertools from typing import Optional from configuration.migration.base import BaseMigration @@ -14,7 +15,7 @@ def should_migrate(config: dict) -> bool: @staticmethod def migrate(config: dict) -> Optional[dict]: - for rule in config.get('processRules', []) + config.get('serviceRules', []): + for rule in itertools.chain(config.get('processRules', []), config.get('serviceRules', [])): rule['selectorBy'] = 'Name' rule['force'] = 'N' diff --git a/src/configuration/rule.py b/src/configuration/rule.py index 5f47639..794f45e 100644 --- a/src/configuration/rule.py +++ b/src/configuration/rule.py @@ -62,6 +62,16 @@ class ProcessRule(BaseModel): "- `N` for one-time application.", ) + delay: Optional[int] = Field( + gt=0, + default=0, + title="Delay", + description="Specifies the delay in seconds before the settings are applied to the __process__.\n\n" + "**Possible values:**\n" + "- If not specified, the settings are applied immediately;\n" + "- Positive values set a delay in seconds before applying the settings." + ) + class ServiceRule(BaseModel): selectorBy: SelectorType = Field( @@ -115,3 +125,13 @@ class ServiceRule(BaseModel): "- `Y` for continuous application;\n" "- `N` for one-time application.", ) + + delay: Optional[int] = Field( + gt=0, + default=0, + title="Delay", + description="Specifies the delay in seconds before the settings are applied to the __service__.\n\n" + "**Possible values:**\n" + "- If not specified, the settings are applied immediately;\n" + "- Positive values set a delay in seconds before applying the settings." + ) diff --git a/src/constants/app_info.py b/src/constants/app_info.py index 2ebf018..5bbf414 100644 --- a/src/constants/app_info.py +++ b/src/constants/app_info.py @@ -7,7 +7,7 @@ APP_NAME: Final[str] = "Process Governor" APP_VERSION: Final[str] = "1.2.2" APP_AUTHOR: Final[str] = "System X - Files" -APP_PROCESSES = {"Process Governor.exe", "python.exe"} +APP_PROCESSES = {f"{APP_NAME}.exe", "python.exe"} CURRENT_TAG: Final[str] = f"v{APP_VERSION}" APP_NAME_WITH_VERSION: Final[str] = f"{APP_NAME} {CURRENT_TAG}" diff --git a/src/constants/log.py b/src/constants/log.py index 86cea02..0c28394 100644 --- a/src/constants/log.py +++ b/src/constants/log.py @@ -1,12 +1,14 @@ import logging import sys -from logging import StreamHandler, Logger +from logging import StreamHandler, Logger, WARNING from logging.handlers import RotatingFileHandler from typing import Final from configuration.logs import Logs from constants.files import LOG_FILE_NAME +logging.addLevelName(WARNING, 'WARN') + def __log_setup() -> Logger: """ diff --git a/src/enums/bool.py b/src/enums/bool.py index 23877e4..0dd738c 100644 --- a/src/enums/bool.py +++ b/src/enums/bool.py @@ -1,6 +1,9 @@ from enum import Enum -class BoolStr(Enum): +class BoolStr(str, Enum): NO = "N" YES = "Y" + + def __str__(self): + return str(self.value) \ No newline at end of file diff --git a/src/enums/io_priority.py b/src/enums/io_priority.py index 0efb0b5..7414890 100644 --- a/src/enums/io_priority.py +++ b/src/enums/io_priority.py @@ -4,12 +4,15 @@ from psutil._pswindows import IOPriority -class IOPriorityStr(Enum): +class IOPriorityStr(str, Enum): VERYLOW = 'VeryLow' LOW = 'Low' NORMAL = 'Normal' HIGH = 'High' + def __str__(self): + return str(self.value) + to_iopriority: Final[dict[IOPriorityStr, IOPriority]] = { IOPriorityStr.VERYLOW: IOPriority.IOPRIO_VERYLOW, diff --git a/src/enums/priority.py b/src/enums/priority.py index 7206bc5..797baf5 100644 --- a/src/enums/priority.py +++ b/src/enums/priority.py @@ -4,7 +4,7 @@ from psutil._pswindows import Priority -class PriorityStr(Enum): +class PriorityStr(str, Enum): IDLE = 'Idle' BELOW_NORMAL = 'BelowNormal' NORMAL = 'Normal' @@ -12,6 +12,9 @@ class PriorityStr(Enum): HIGH = 'High' REALTIME = 'Realtime' + def __str__(self): + return str(self.value) + to_priority: Final[dict[PriorityStr, Priority]] = { PriorityStr.IDLE: Priority.IDLE_PRIORITY_CLASS, diff --git a/src/enums/process.py b/src/enums/process.py index 0c37d93..727d491 100644 --- a/src/enums/process.py +++ b/src/enums/process.py @@ -1,10 +1,10 @@ from enum import Enum -class ProcessParameter(Enum): +class ProcessParameter(str, Enum): AFFINITY = "affinity" - NICE = "nice" - IONICE = "ionice" + NICE = "priority" + IONICE = "I/O priority" def __str__(self): - return self.value + return str(self.value) diff --git a/src/enums/selector.py b/src/enums/selector.py index 6921c07..90a2440 100644 --- a/src/enums/selector.py +++ b/src/enums/selector.py @@ -1,7 +1,10 @@ from enum import Enum -class SelectorType(Enum): +class SelectorType(str, Enum): NAME = "Name" PATH = "Path" CMDLINE = "CommandLine" + + def __str__(self): + return str(self.value) diff --git a/src/model/process.py b/src/model/process.py index 25eddcc..c107281 100644 --- a/src/model/process.py +++ b/src/model/process.py @@ -61,3 +61,12 @@ class Process: Contains information about the service if the current process is associated with one. If the process is not related to a service, this will be None. """ + + def __hash__(self): + return hash((self.pid, self.binpath, self.name, self.cmdline)) + + def __eq__(self, other): + if isinstance(other, Process): + return ((self.pid, self.binpath, self.name, self.cmdline) == + (other.pid, other.binpath, other.name, other.cmdline)) + return False diff --git a/src/service/rules_service.py b/src/service/rules_service.py index 4c1e680..6754ac1 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -1,10 +1,9 @@ import os from abc import ABC -from typing import Optional, List +from typing import Optional, Callable import psutil from psutil import AccessDenied, NoSuchProcess -from pyuac import isUserAdmin from configuration.config import Config from configuration.rule import ProcessRule, ServiceRule @@ -18,6 +17,7 @@ from service.processes_info_service import ProcessesInfoService from util.cpu import format_affinity from util.decorators import cached +from util.scheduler import TaskScheduler from util.utils import path_match @@ -28,8 +28,9 @@ class RulesService(ABC): """ __ignore_pids: set[int] = {0, os.getpid()} - __ignored_process_parameters: dict[tuple[int, str], set[ProcessParameter]] = {} + __ignored_process_parameters: dict[Process, set[ProcessParameter]] = {} __force_pids: set[int] = set() + __scheduler = TaskScheduler() @classmethod def apply_rules(cls, config: Config, only_new: bool): @@ -60,133 +61,104 @@ def __handle_processes(cls, config: Config, processes: dict[int, Process]) -> se if pid in cls.__ignore_pids: continue - try: - rule: Optional[ProcessRule | ServiceRule] = cls.__first_rule_by_name(config, process) + rule: Optional[ProcessRule | ServiceRule] = cls.__first_rule_by_process(config, process) - if not rule: - continue + if not rule: + continue - if rule.force == BoolStr.YES: - force_pids.add(pid) + if rule.force == BoolStr.YES: + force_pids.add(pid) - tuple_pid_name = (pid, process.name) - ignored_process_parameters = cls.__ignored_process_parameters.get(tuple_pid_name, set()) - not_success: List[ProcessParameter] = [] + if rule.delay > 0: + cls.__scheduler.schedule_task(process, cls.__handle_process, rule.delay, process, rule) + else: + cls.__handle_process(process, rule) - if ProcessParameter.AFFINITY not in ignored_process_parameters: - cls.__set_affinity(not_success, process, rule) + return force_pids - if ProcessParameter.NICE not in ignored_process_parameters: - cls.__set_nice(not_success, process, rule) + @classmethod + def __handle_process(cls, process: Process, rule: ProcessRule | ServiceRule): + parameter_methods: dict[ProcessParameter, tuple[Callable[[Process, ProcessRule | ServiceRule], bool], str]] = { + ProcessParameter.AFFINITY: (cls.__set_affinity, format_affinity(rule.affinity)), + ProcessParameter.NICE: (cls.__set_nice, rule.priority), + ProcessParameter.IONICE: (cls.__set_ionice, rule.ioPriority) + } - if ProcessParameter.IONICE not in ignored_process_parameters: - cls.__set_ionice(not_success, process, rule) + try: + ignored_parameters = cls.__ignored_process_parameters.setdefault(process, set()) - if not_success: - cls.__ignore_process_parameter(tuple_pid_name, set(not_success)) + for param, (method, logger_value) in parameter_methods.items(): + if param in ignored_parameters: + continue - LOG.warning(f"Set failed [{', '.join(map(str, not_success))}] " - f"for {process.name} ({process.pid}" - f"{', ' + process.service.name + '' if process.service else ''}" - f")") - except NoSuchProcess: - LOG.warning(f"No such process: {pid}") + logger_string = f"{param.value} `{logger_value}` for {process.name} ({process.pid})" - return force_pids + try: + if method(process, rule): + LOG.info(f"Set {logger_string}.") + except AccessDenied: + ignored_parameters.add(param) + LOG.warning(f"Failed to set {logger_string}.") + + except NoSuchProcess: + pass @classmethod - def __set_ionice(cls, not_success, process: Process, rule: ProcessRule | ServiceRule): + def __set_ionice(cls, process: Process, rule: ProcessRule | ServiceRule): io_priority = to_iopriority[rule.ioPriority] - if not io_priority or process.ionice == io_priority: - return - - parameter = ProcessParameter.IONICE - - try: + if io_priority and process.ionice != io_priority: process.process.ionice(io_priority) - LOG.info(f"Set {parameter.value} {rule.ioPriority.value} for {process.name} ({process.pid})") - except AccessDenied: - not_success.append(parameter) + return True @classmethod - def __set_nice(cls, not_success, process: Process, rule: ProcessRule | ServiceRule): + def __set_nice(cls, process: Process, rule: ProcessRule | ServiceRule): priority = to_priority[rule.priority] - if not priority or process.nice == priority: - return - - parameter = ProcessParameter.NICE - - try: + if priority and process.nice != priority: process.process.nice(priority) - LOG.info(f"Set {parameter.value} {rule.priority.value} for {process.name} ({process.pid})") - except AccessDenied: - not_success.append(parameter) + return True @classmethod - def __set_affinity(cls, not_success, process: Process, rule: ProcessRule | ServiceRule): - if not rule.affinity or process.affinity == rule.affinity: - return - - parameter = ProcessParameter.AFFINITY - - try: + def __set_affinity(cls, process: Process, rule: ProcessRule | ServiceRule): + if rule.affinity and process.affinity != rule.affinity: process.process.cpu_affinity(rule.affinity) - affinity = format_affinity(rule.affinity) - LOG.info(f"Set {parameter.value} {affinity} for {process.name} ({process.pid})") - except AccessDenied: - not_success.append(parameter) + return True @classmethod - def __first_rule_by_name( - cls, - config: Config, - process: Process - ) -> Optional[ProcessRule | ServiceRule]: + def __first_rule_by_process(cls, config: Config, process: Process) -> Optional[ProcessRule | ServiceRule]: service = process.service if service: - for serviceRule in config.serviceRules: + for rule in config.serviceRules: value = service.name - if serviceRule.selectorBy == SelectorType.PATH: + if rule.selectorBy == SelectorType.PATH: value = service.binpath - elif serviceRule.selectorBy == SelectorType.CMDLINE: + elif rule.selectorBy == SelectorType.CMDLINE: value = process.cmdline - if path_match(serviceRule.selector, value): - return serviceRule + if path_match(rule.selector, value): + return rule - for processRule in config.processRules: + for rule in config.processRules: value = process.name - if processRule.selectorBy == SelectorType.PATH: + if rule.selectorBy == SelectorType.PATH: value = process.binpath - elif processRule.selectorBy == SelectorType.CMDLINE: + elif rule.selectorBy == SelectorType.CMDLINE: value = process.cmdline - if path_match(processRule.selector, value): - return processRule + if path_match(rule.selector, value): + return rule return None - @classmethod - def __ignore_process_parameter(cls, tuple_pid_name: tuple[int, str], parameters: set[ProcessParameter]): - if isUserAdmin(): - cls.__ignored_process_parameters[tuple_pid_name] = parameters - @classmethod @cached(5) # Workaround to ensure the procedure runs only once every 5 seconds - def __light_gc_ignored_process_parameters(cls): + def __light_gc_ignored_process_parameters(cls) -> None: pids = psutil.pids() - remove_pids: List[tuple[int, str]] = [] - - for item in cls.__ignored_process_parameters.keys(): - pid, _ = item - - if pid not in pids: - remove_pids.append(item) - - for item in remove_pids: - del cls.__ignored_process_parameters[item] \ No newline at end of file + cls._ignored_process_parameters = { + key: value for key, value in cls.__ignored_process_parameters.items() + if key.pid in pids + } diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index 1248f95..331bfc0 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -59,7 +59,7 @@ def _setup_columns(self): values.append("") if issubclass(typ, enum.Enum): - values += [str(e.value) for e in typ] + values += [str(e) for e in typ] max_width_value_in_column = max(values + [max_width_value_in_column], key=len) self.column_type(column_name, "list") @@ -231,7 +231,7 @@ def _get_default_values(self) -> List[Any]: default_value = field_info.default if isinstance(default_value, Enum): - default_value = default_value.value + default_value = str(default_value) result.append(default_value or '') diff --git a/src/util/scheduler.py b/src/util/scheduler.py index d4418f7..20c2b1e 100644 --- a/src/util/scheduler.py +++ b/src/util/scheduler.py @@ -1,64 +1,34 @@ -import subprocess - -from constants.log import LOG +import threading class TaskScheduler: - """ - A class to manage tasks in Windows Task Scheduler using the schtasks utility. - """ - - @staticmethod - def create_startup_task(task_name, exe_path): - """ - Creates a startup task in the Task Scheduler. - - Parameters: - task_name (str): The name of the task to be created. - exe_path (str): The path of the executable to be run as the startup task. - """ - command = f"schtasks /create /tn \"{task_name}\" /tr \"{exe_path}\" /sc onlogon /rl highest" + def __init__(self): + self.tasks = {} + def _execute_task(self, key, callback, *args, **kwargs): try: - subprocess.run(command, check=True, shell=True) - LOG.info(f"Task '{task_name}' created successfully.") - except subprocess.CalledProcessError: - LOG.exception(f"Error creating task '{task_name}'. Command: {command}") - raise + callback(*args, **kwargs) + finally: + del self.tasks[key] - @staticmethod - def check_task(task_name): - """ - Checks for the existence of a task in the Task Scheduler. + def schedule_task(self, key, callback, delay=0, *args, **kwargs): + if key not in self.tasks: + self.tasks[key] = threading.Timer(delay, self._execute_task, args=(key, callback) + args, kwargs=kwargs) + self.tasks[key].start() - Parameters: - task_name (str): Name of the task. - Returns: - bool: True if the task exists, False otherwise. - """ - command = f"schtasks /query /tn \"{task_name}\"" +if __name__ == '__main__': + def my_function(message): + print(f"Function executed with message: {message}") - try: - result = subprocess.run(command, shell=True, capture_output=True, text=True) - return task_name in result.stdout - except subprocess.CalledProcessError: - LOG.exception(f"Error checking task '{task_name}'. Command: {command}") - raise - @staticmethod - def delete_task(task_name): - """ - Deletes a task from the Task Scheduler. + scheduler = TaskScheduler() - Parameters: - task_name (str): Name of the task. - """ - command = f"schtasks /delete /tn \"{task_name}\" /f" + scheduler.schedule_task("task1", my_function, 5, "Hello after 5 seconds") + scheduler.schedule_task("task1", my_function, 2, "Hello after 2 seconds") + scheduler.schedule_task("task2", my_function, 3, "Hello after 3 seconds") + scheduler.schedule_task("task3", my_function, 0, "Immediate execution") - try: - subprocess.run(command, check=True, shell=True) - LOG.info(f"Task '{task_name}' deleted successfully.") - except subprocess.CalledProcessError: - LOG.exception(f"Error deleting task '{task_name}'. Command: {command}") - raise + import time + + time.sleep(10) diff --git a/src/util/startup.py b/src/util/startup.py index 2410487..1d541c4 100644 --- a/src/util/startup.py +++ b/src/util/startup.py @@ -2,8 +2,8 @@ from constants.app_info import STARTUP_TASK_NAME from constants.resources import STARTUP_SCRIPT -from util.scheduler import TaskScheduler from util.utils import is_portable +from util.windows_scheduler import WindowsTaskScheduler def is_in_startup(): @@ -13,7 +13,7 @@ def is_in_startup(): Returns: bool: True if the application is set to run during system startup, False otherwise. """ - return TaskScheduler.check_task(STARTUP_TASK_NAME) + return WindowsTaskScheduler.check_task(STARTUP_TASK_NAME) def add_to_startup(): @@ -23,7 +23,7 @@ def add_to_startup(): if is_in_startup(): return - TaskScheduler.create_startup_task( + WindowsTaskScheduler.create_startup_task( STARTUP_TASK_NAME, f"'{STARTUP_SCRIPT}' '{sys.executable}'" ) @@ -34,7 +34,7 @@ def remove_from_startup(): Remove the current application from the system's startup programs. """ if is_in_startup(): - TaskScheduler.delete_task(STARTUP_TASK_NAME) + WindowsTaskScheduler.delete_task(STARTUP_TASK_NAME) def toggle_startup(): diff --git a/src/util/windows_scheduler.py b/src/util/windows_scheduler.py new file mode 100644 index 0000000..819caed --- /dev/null +++ b/src/util/windows_scheduler.py @@ -0,0 +1,64 @@ +import subprocess + +from constants.log import LOG + + +class WindowsTaskScheduler: + """ + A class to manage tasks in Windows Task Scheduler using the schtasks utility. + """ + + @staticmethod + def create_startup_task(task_name, exe_path): + """ + Creates a startup task in the Task Scheduler. + + Parameters: + task_name (str): The name of the task to be created. + exe_path (str): The path of the executable to be run as the startup task. + """ + command = f"schtasks /create /tn \"{task_name}\" /tr \"{exe_path}\" /sc onlogon /rl highest" + + try: + subprocess.run(command, check=True, shell=True) + LOG.info(f"Task '{task_name}' created successfully.") + except subprocess.CalledProcessError: + LOG.exception(f"Error creating task '{task_name}'. Command: {command}") + raise + + @staticmethod + def check_task(task_name): + """ + Checks for the existence of a task in the Task Scheduler. + + Parameters: + task_name (str): Name of the task. + + Returns: + bool: True if the task exists, False otherwise. + """ + command = f"schtasks /query /tn \"{task_name}\"" + + try: + result = subprocess.run(command, shell=True, capture_output=True, text=True) + return task_name in result.stdout + except subprocess.CalledProcessError: + LOG.exception(f"Error checking task '{task_name}'. Command: {command}") + raise + + @staticmethod + def delete_task(task_name): + """ + Deletes a task from the Task Scheduler. + + Parameters: + task_name (str): Name of the task. + """ + command = f"schtasks /delete /tn \"{task_name}\" /f" + + try: + subprocess.run(command, check=True, shell=True) + LOG.info(f"Task '{task_name}' deleted successfully.") + except subprocess.CalledProcessError: + LOG.exception(f"Error deleting task '{task_name}'. Command: {command}") + raise From 3aaf95334261c39ca8a3ae683c9c7dcfff006f01 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Thu, 15 Aug 2024 03:31:47 +0800 Subject: [PATCH 14/39] [#14] Removed the high I/O priority, because it does not work --- src/configuration/migration/all_migration.py | 4 +++- .../migration/m2_remove_high_io_priority.py | 22 +++++++++++++++++++ src/enums/io_priority.py | 3 --- 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 src/configuration/migration/m2_remove_high_io_priority.py diff --git a/src/configuration/migration/all_migration.py b/src/configuration/migration/all_migration.py index f6fc414..adb1f36 100644 --- a/src/configuration/migration/all_migration.py +++ b/src/configuration/migration/all_migration.py @@ -3,6 +3,7 @@ from configuration.migration.base import BaseMigration from configuration.migration.m0_rules_to_split_rules_config import MigrationRules2SplitRulesConfig from configuration.migration.m1_new_fields_in_rule import NewFieldsInRule +from configuration.migration.m2_remove_high_io_priority import RemoveHighIoPriority from constants.app_info import APP_NAME_WITH_VERSION from constants.log import LOG from service.config_service import ConfigService @@ -10,7 +11,8 @@ MIGRATIONS: list[type[BaseMigration]] = [ MigrationRules2SplitRulesConfig, - NewFieldsInRule + NewFieldsInRule, + RemoveHighIoPriority ] """ List of migration classes to be executed in order. diff --git a/src/configuration/migration/m2_remove_high_io_priority.py b/src/configuration/migration/m2_remove_high_io_priority.py new file mode 100644 index 0000000..0fae0cb --- /dev/null +++ b/src/configuration/migration/m2_remove_high_io_priority.py @@ -0,0 +1,22 @@ +import itertools +from typing import Optional + +from configuration.migration.base import BaseMigration + + +class RemoveHighIoPriority(BaseMigration): + @staticmethod + def get_target_version() -> int: + return 3 + + @staticmethod + def should_migrate(config: dict) -> bool: + return config['version'] == 2 + + @staticmethod + def migrate(config: dict) -> Optional[dict]: + for rule in itertools.chain(config.get('processRules', []), config.get('serviceRules', [])): + if rule.get('ioPriority') == 'High': + del rule['ioPriority'] + + return config diff --git a/src/enums/io_priority.py b/src/enums/io_priority.py index 7414890..81579e7 100644 --- a/src/enums/io_priority.py +++ b/src/enums/io_priority.py @@ -8,8 +8,6 @@ class IOPriorityStr(str, Enum): VERYLOW = 'VeryLow' LOW = 'Low' NORMAL = 'Normal' - HIGH = 'High' - def __str__(self): return str(self.value) @@ -18,6 +16,5 @@ def __str__(self): IOPriorityStr.VERYLOW: IOPriority.IOPRIO_VERYLOW, IOPriorityStr.LOW: IOPriority.IOPRIO_LOW, IOPriorityStr.NORMAL: IOPriority.IOPRIO_NORMAL, - IOPriorityStr.HIGH: IOPriority.IOPRIO_HIGH, None: None } From 9a8dbc29a28f5fcb4e533f50a21fd8d99d7a3db3 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Fri, 16 Aug 2024 00:21:07 +0800 Subject: [PATCH 15/39] Fix selector validation --- src/configuration/rule.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/configuration/rule.py b/src/configuration/rule.py index 794f45e..408e27a 100644 --- a/src/configuration/rule.py +++ b/src/configuration/rule.py @@ -21,10 +21,9 @@ class ProcessRule(BaseModel): ) selector: str = Field( - default="*", title="Selector", description="Specifies the **name**, **pattern** or **path** of the __process__ to which this rule applies.\n\n" - "**Supports wildcard:** `\*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" + "**Supports wildcard:** `*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" "**Examples:** `name.exe`, `logioptionsplus_*.exe`, `D:/FolderName/App.exe` or `C:/Program Files/**/app.exe --file Document.txt`.", stretchable_column_ui=True, justify_ui="left" @@ -85,10 +84,9 @@ class ServiceRule(BaseModel): ) selector: str = Field( - default="*", title="Selector", description="Specifies the **name**, **pattern** or **path** of the __service__ to which this rule applies.\n\n" - "**Supports wildcard:** `\*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" + "**Supports wildcard:** `*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" "**Examples:** `ServiceName`, `Audio*`, `D:/FolderName/Service.exe` or `C:/Windows/System32/**/service.exe --debug 1`.", stretchable_column_ui=True, justify_ui="left" From 4676fc85c344aea669a9de44ac189c8ffc270669 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Fri, 16 Aug 2024 00:23:44 +0800 Subject: [PATCH 16/39] Update requirements.txt --- requirements.txt | Bin 346 -> 304 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/requirements.txt b/requirements.txt index 408ce5ea50d0f94ca521c3b437ced2933a9807b4..0896430341e625f33dd6864758157a6b67163bf8 100644 GIT binary patch delta 70 zcmcb`w1H`Yg}w!Y9)l4BF9R1t0YfE23PU189zzL3CPOkqJP_wI6fvYS*aD#uSe@a- Um+})Ia4;J(7)*TWIk6xN00(0bW&i*H delta 106 zcmdnMbc<<%g}w=c9)l4BF9R1t0YfE23PU189zzL3CPOlVE)eH46fvYS*aD#uP@N%z t!NiO46LXXpjV4a?)F@%dW=I1n0cl8NCoFKG005%16*B+; From 4044e36b0511ee525f9b891a41795a9babe67fb2 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Fri, 16 Aug 2024 00:24:24 +0800 Subject: [PATCH 17/39] Replace tkfontawesome to icons --- src/constants/resources.py | 14 ++++++++++++++ src/constants/ui.py | 2 -- src/ui/settings.py | 10 +++++++--- .../widget/settings/tabs/rules/base_rules_tab.py | 12 ++++++------ src/ui/widget/settings/tabs/rules/rules_list.py | 9 +++++---- src/ui/widget/settings/tabs/rules/rules_tab.py | 6 +++--- src/ui/widget/settings/tooltip.py | 11 +++++------ src/util/ui.py | 2 -- 8 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/constants/resources.py b/src/constants/resources.py index f97d87d..806cfb6 100644 --- a/src/constants/resources.py +++ b/src/constants/resources.py @@ -4,3 +4,17 @@ STARTUP_SCRIPT: Final[str] = f"{APP_PATH}/resources/startup.bat" APP_ICON: Final[str] = f"{APP_PATH}/resources/app.ico" + +UI_PROCESS_RULES: Final[str] = f"{APP_PATH}/resources/UI/process-rules.png" +UI_SERVICE_RULES: Final[str] = f"{APP_PATH}/resources/UI/service-rules.png" + +UI_ADD: Final[str] = f"{APP_PATH}/resources/UI/add.png" +UI_DELETE: Final[str] = f"{APP_PATH}/resources/UI/delete.png" +UI_UP: Final[str] = f"{APP_PATH}/resources/UI/up.png" +UI_DOWN: Final[str] = f"{APP_PATH}/resources/UI/down.png" +UI_SAVE: Final[str] = f"{APP_PATH}/resources/UI/save.png" + +UI_INFO_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/info-tooltip.png" +UI_WARN_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/warn-tooltip.png" + +UI_ERROR: Final[str] = f"{APP_PATH}/resources/UI/error.png" \ No newline at end of file diff --git a/src/constants/ui.py b/src/constants/ui.py index 134d3af..b1ab66d 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -2,9 +2,7 @@ UI_PADDING = 10 BUTTON_SIZE = 7 -ERROR_COLOR = "#e57373" ERROR_ROW_COLOR = "#ffcdd2" -TOOLTIP_ICON_SIZE = 75 RC_WIN_SIZE = (1280, 768) SETTINGS_TITLE = "Settings" diff --git a/src/ui/settings.py b/src/ui/settings.py index 92daede..7d917ba 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -3,17 +3,18 @@ from threading import Thread from tkinter import messagebox, ttk +from PIL.ImageTk import PhotoImage + from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.files import LOG_FILE_NAME from constants.log import LOG -from constants.resources import APP_ICON +from constants.resources import APP_ICON, UI_SAVE from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, SETTINGS_TITLE, RulesListEvents, EditableTreeviewEvents from ui.widget.common.button import IconedButton from ui.widget.settings.settings_tabs import SettingsTabs from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab from ui.widget.settings.tooltip import Tooltip from util.messages import yesno_error_box -from util.ui import icon16px class SettingsButtons(ttk.Frame): @@ -26,7 +27,7 @@ def _setup_btn(self): self, text=" Apply", command=lambda: self.event_generate(ActionEvents.SAVE), - image=icon16px("check", fill="cornflowerblue") + image=PhotoImage(file=UI_SAVE) ) right_btn_pack = dict(side=tk.RIGHT, padx=(UI_PADDING, 0)) save.pack(**right_btn_pack) @@ -150,6 +151,9 @@ def _setup_tooltips(self): tabs.bind("", lambda _: self._tooltip.set(self._DEFAULT_TOOLTIP), "+") for tab in tabs.frames(): + if not isinstance(tab, BaseRulesTab): + continue + btns = tab.buttons self._setup_tooltip(btns.add, "__Adds__ a rule after the current") self._setup_tooltip(btns.delete, "__Deletes__ the selected rules") diff --git a/src/ui/widget/settings/tabs/rules/base_rules_tab.py b/src/ui/widget/settings/tabs/rules/base_rules_tab.py index 5216c5f..f0668ed 100644 --- a/src/ui/widget/settings/tabs/rules/base_rules_tab.py +++ b/src/ui/widget/settings/tabs/rules/base_rules_tab.py @@ -1,14 +1,14 @@ import tkinter as tk from abc import ABC -from tkinter import ttk +from tkinter import ttk, PhotoImage from tkinter.ttk import Notebook +from constants.resources import UI_ADD, UI_DELETE, UI_UP, UI_DOWN from constants.ui import UI_PADDING, RulesListEvents, ActionEvents from enums.rules import RuleType from ui.widget.common.button import IconedButton from ui.widget.settings.tabs.base_tab import BaseTab from ui.widget.settings.tabs.rules.rules_list import RulesList -from util.ui import icon16px class BaseRulesTab(BaseTab, ABC): @@ -91,28 +91,28 @@ def _setup_btn(self): self, text=" Add", command=lambda: self.event_generate(ActionEvents.ADD), - image=icon16px("plus", fill="green") + image=PhotoImage(file=UI_ADD) ) self.delete = delete = IconedButton( self, text=" Del", command=lambda: self.event_generate(ActionEvents.DELETE), - image=icon16px("trash-alt", fill="firebrick") + image=PhotoImage(file=UI_DELETE) ) self.move_up = move_up = IconedButton( self, text=" Up", command=lambda: self.event_generate(ActionEvents.UP), - image=icon16px("arrow-up", fill="#1a1a1a") + image=PhotoImage(file=UI_UP) ) self.move_down = move_down = IconedButton( self, text=" Down", command=lambda: self.event_generate(ActionEvents.DOWN), - image=icon16px("arrow-down", fill="#1a1a1a") + image=PhotoImage(file=UI_DOWN) ) left_btn_pack = dict(side=tk.LEFT, padx=(0, UI_PADDING)) diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index 331bfc0..638e6a8 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -2,17 +2,18 @@ import json import tkinter as tk from enum import Enum -from tkinter import ttk +from tkinter import ttk, PhotoImage from tkinter.font import Font from typing import Optional, Any, List from pydantic import ValidationError, BaseModel -from constants.ui import ERROR_COLOR, ERROR_ROW_COLOR, RulesListEvents, EditableTreeviewEvents, \ +from constants.resources import UI_ERROR +from constants.ui import ERROR_ROW_COLOR, RulesListEvents, EditableTreeviewEvents, \ ScrollableTreeviewEvents from ui.widget.common.label import Image from ui.widget.common.treeview.editable import EditableTreeview -from util.ui import icon16px, full_visible_bbox +from util.ui import full_visible_bbox from util.utils import extract_type, is_optional_type @@ -89,7 +90,7 @@ def _setup_look(self): style = ttk.Style() style.configure('Treeview', rowheight=row_height) - self._error_icon = icon16px("exclamation-triangle", ERROR_COLOR) + self._error_icon = PhotoImage(file=UI_ERROR) def set_data(self, rules_raw: List[dict]): self.delete(*self.get_children()) diff --git a/src/ui/widget/settings/tabs/rules/rules_tab.py b/src/ui/widget/settings/tabs/rules/rules_tab.py index 95a5cbb..fc60e00 100644 --- a/src/ui/widget/settings/tabs/rules/rules_tab.py +++ b/src/ui/widget/settings/tabs/rules/rules_tab.py @@ -1,9 +1,9 @@ from tkinter import PhotoImage from tkinter.ttk import Notebook +from constants.resources import UI_PROCESS_RULES, UI_SERVICE_RULES from enums.rules import RuleType from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab -from util.ui import icon16px class ProcessRulesTab(BaseRulesTab): @@ -12,7 +12,7 @@ def __init__(self, master: Notebook): @staticmethod def icon() -> PhotoImage: - return icon16px("list", fill="#3F888F") + return PhotoImage(file=UI_PROCESS_RULES) @staticmethod def title() -> str: @@ -29,7 +29,7 @@ def __init__(self, master: Notebook): @staticmethod def icon() -> PhotoImage: - return icon16px("cogs", fill="#6495ED") + return PhotoImage(file=UI_SERVICE_RULES) @staticmethod def title() -> str: diff --git a/src/ui/widget/settings/tooltip.py b/src/ui/widget/settings/tooltip.py index 472fcc4..a023775 100644 --- a/src/ui/widget/settings/tooltip.py +++ b/src/ui/widget/settings/tooltip.py @@ -1,9 +1,8 @@ import tkinter as tk -from tkinter import ttk, StringVar +from tkinter import ttk, StringVar, PhotoImage -from tkfontawesome import icon_to_image - -from constants.ui import UI_PADDING, ERROR_COLOR, TOOLTIP_ICON_SIZE +from constants.resources import UI_INFO_TOOLTIP, UI_WARN_TOOLTIP +from constants.ui import UI_PADDING from ui.widget.common.label import RichLabel, Image @@ -13,8 +12,8 @@ def __init__(self, master, *args, **kwargs): super().__init__(master, *args, **kwargs) self._text = StringVar(self, value=text) - self._info_icon = icon_to_image("info-circle", fill="cornflowerblue", scale_to_width=TOOLTIP_ICON_SIZE) - self._error_icon = icon_to_image("exclamation-triangle", fill=ERROR_COLOR, scale_to_width=TOOLTIP_ICON_SIZE) + self._info_icon = PhotoImage(file=UI_INFO_TOOLTIP) + self._error_icon = PhotoImage(file=UI_WARN_TOOLTIP) self._image = Image( self, diff --git a/src/util/ui.py b/src/util/ui.py index d8cbabe..3a3e67f 100644 --- a/src/util/ui.py +++ b/src/util/ui.py @@ -2,8 +2,6 @@ from tkinter import font, Widget, PhotoImage from tkinter.ttk import Treeview -from tkfontawesome import icon_to_image - def state(widget: Widget) -> str: return str(widget["state"]) From 733c232ca6d6e59a076f3aa1438e8a30bb6dd66d Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Fri, 16 Aug 2024 00:28:47 +0800 Subject: [PATCH 18/39] Icons --- resources/UI/add.png | Bin 0 -> 1695 bytes resources/UI/delete.png | Bin 0 -> 1665 bytes resources/UI/down.png | Bin 0 -> 2006 bytes resources/UI/error.png | Bin 0 -> 299 bytes resources/UI/info-tooltip.png | Bin 0 -> 2153 bytes resources/UI/process-rules.png | Bin 0 -> 2123 bytes resources/UI/save.png | Bin 0 -> 1972 bytes resources/UI/service-rules.png | Bin 0 -> 2126 bytes resources/UI/up.png | Bin 0 -> 2008 bytes resources/UI/warn-tooltip.png | Bin 0 -> 2318 bytes 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/UI/add.png create mode 100644 resources/UI/delete.png create mode 100644 resources/UI/down.png create mode 100644 resources/UI/error.png create mode 100644 resources/UI/info-tooltip.png create mode 100644 resources/UI/process-rules.png create mode 100644 resources/UI/save.png create mode 100644 resources/UI/service-rules.png create mode 100644 resources/UI/up.png create mode 100644 resources/UI/warn-tooltip.png diff --git a/resources/UI/add.png b/resources/UI/add.png new file mode 100644 index 0000000000000000000000000000000000000000..d426018bda18e5ca9eb982bcb05f3ab94967a7cb GIT binary patch literal 1695 zcmbVNZEO=|9KW$_8GBLC8IhRmyagD#du_M%E_5%nW2@S^Y>gZ91H0ZmU2kjeIqq(> z9q7ywrs$VN11xh%*DS_JqC|{L95TTyqDY1>As8kQLpI|FHY8C26`$+cW(rE=lDp^a z_x%3v|J&2t)KHYaHXp;VB2S~c1&wRayE-oyeLsta7&NTZ8n+r4R`8(pW?>_v2$A!! z;%hhCy-y1g3{#>E{eX&wHH5~nO*K(XlzM=P`$3nYI*EnJDFRnyC(%~nWxSdT1eL}< z9kli}`J}!ciI<6*YJ5{vKm=i6ig+{}QVk*MB$B)Wnp@j6fhQqmkCUjg1mf-9X50mJ zfLBrsDKShXUd2cAhfu*q=ccBlL(ro zCeU;w5}_hC3hG@n%kwE3MiBlBb>{eQ z0+4UL-i(Yp>JkoTL>OlM4rE5kA$LR@zL*B+7GS_$T>|wxkea2IHJaekfoMYA2Vp23 zsphoGILA?TysS-8Wf(CwF1rBSq6wS?iW-WSgJdgwEH6|z1iS4C#vw4w64VQ2B@nv} z$}s|a8x-Y?ESln7!LlR-pdJ>H!Ae-{0<@-f5qQRpf(wSAjszp^Y|HmOE?2V-14;-T z7%dH(aZkOglI1HaNseNZ>UzC`M>R}Qm4L_XB#?6`MUe$QAlXE~+en@ZRFQt(?jRj< zl^rc*F2Ga(ha@}F_uWwHwNfB`U;dx>pV1XmgJS5Od92E`az|)X3>4K^s&rbx_S7t- z;K_6mM9C@xCm~t!2Qrb`R_@sYOSF+7K&1bX7fUb$2F!@4gSsx{t-IzOjg+UYf?cwM z{-=q_vt`AdhNF&QO*6d;Ei&B>sHny1sF%HTFs}^5vM7(c&gWPyb-p;TXX4NIe~tfs zByi&Ml9~;pH?GIa3%}m^^L+Qv*1{jh7B0^eA1d1N=^t;suwHD(%;&S)A851e`W>w)m}!{Xd*9@fRLEw=-|Lc1`Vja^j8qX9q6Lela+7^uR5AWOytq zr=YH2ZgQdY{ED%;nUlHW*)OkCf4ZS1xo;CwA{1eJr-OAu$+#Wg|7Wo*JI* z*uJi{bJ0FtcHilDigP*+6}eyE_tosK+P8Ba-7pmWt{}p%!myjio;?0>{?%&h7viaJ Ka=*K|bKo!4nMMZy literal 0 HcmV?d00001 diff --git a/resources/UI/delete.png b/resources/UI/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..c031d89b7d5f9454dc50384a4c99af4a84d3415d GIT binary patch literal 1665 zcmbVNU2NM#9CwRa+LgjaVW9CL<4Vv99NYP7Y%OG6lC>F0)@6}e24bA;OJX(l8QW>n ziqUi()dm}y*o5c?T3?u$kU#^e4-C2ukWdj-AJ`CI8c@L#6TEEDhp}+ZmpT|s%+mSJ zcfb4nzyIDl5btYWwQdzb5bcrvPy)|)iv(K1ku)Ej|SrKYZ%dV zmy#T^hGJ1cLaGDENQ91ps$(=ktPd1)APqx{6k%G?{M2tJPf?^I`>8=sjE(6*m{I!2 z47hD9o|MLhC0?cikCN*P0wz$Q1;~P$)l8w_r^>tnUfbIYMV2Afu%GI+1(HLt0WydT zNO~PCEwQYZ?BN|U5P>9$kC0B*$uX>(;oLOK3NBu7yUFT9VR43>5)z?JRblwcPh~7i z7Z@g=&pYxi2QtzO$MZbHIvJ;v#t7OR)htk;HM6tE5Q3&;D7vK}jkFnoh;o*n!m3tm zQ1v>kW>)=#J;oG(&TtOawy6x1r8-W}8QHRMSz=%os!+2`jOFTBJ%cP{X3)P-*N?9f zfPEW_)n!~$7geo`Fs<+iHlym0Yog8Ms1BI~G*QlwV0Z+p*=bv&3qb<{3mHj-vb9JJ z)Kn&&PKTT98dNkH<<0ID7hnij&`;s0;duFI&XeSL!Q&G=o`+eVz_Jx+49QAr^dC?s zD{wx+bu|>{j0`MrU9c<(DP*Vs8?2}x4H;caQ)JzZLJ(zjPJ!Be`G4NuVko!xrN9b2f9M#ck>1>0~R99Jr zET@YAB)bg!lw`*r%2ah*xnU1fX!99}N&h1+DlikJtUNGaZyI~+x_QT7W&#IG##Kb~DI$>6~GgMq=x&&6WHt4%u}8b5YGW!L>0xa4a6xN+u}drrT+;qXMX zcy8a;wyC+M9j`B3KINOfZ~21!`_GeaoqOlo<4Wm|+`__d*?@frS=Z@d@U1Or5Ylv)~{qyFD z9mB6oaxKMAX4YQl{Jt^$#UeXc+CKL~;FinVPu|=8W;C#Me%JFYZN<6eCGpl1r{^zr zHucKyAKgQK^Vlp_Ec$HgrgvYQ?)iFck?87PiXMxn7P{sSJxOeSVdiY(-VXMB+X#OL ZLEOG`;*I9X@P7Lz5edgbZ*P2h*I$PDF&_W` literal 0 HcmV?d00001 diff --git a/resources/UI/down.png b/resources/UI/down.png new file mode 100644 index 0000000000000000000000000000000000000000..71c4358db5e05b899c42f92535e3ec03b545bd5b GIT binary patch literal 2006 zcmb_dTWB0r7#@ozF-?#lgj9r%Q=tuJ?w8Dr*@kpCmjyS5bhW7<^vszvyJP0&%p|)T zU$mM+g7~C@8ckCn7>Z(_YOto@gOZnmee+51p^6j)r4I?#cxG>=HoZ_>n4L4{eCPka z|2y9~XJKM|w6pz*c7h-}vtyY_{O-X|S6d7I|Gw;S`1NQob}}M}{f{TlL&S$m7}0Xs z&QHZtx#x7~y9_XW12JVcz-WRP7%T?>PNSGKP{H<6)bC$krbydNQ77aamkZLUXphZ> z==j`t9?nfe&7=m8k^^NO2XIjg$g=BrkzP(w)wnutC*3SXRw40piW*81l2f?}GVO0{6oskQYH)*Q zSTCyUgcW1UAYgfhOKPeDP1wW*Goe#WZbBA0$VFZpVJzRo21P&iqoRL@(9Pjn5@2m} zxn_<%xwvjKMHCOu;xg)j?1_%@l>o7mDDr1Qh=yk|%|l5wfu0T#i2X3{`%Yt}CK{AU zL0}~E$O+ps{ZiDsYXZuE7^Nt@YIwa=nwRsurpubnDbH}K&T%zp&NpqVavN0ObY9g3 z`4%Ylj0s|JPp}Df%MV?E3$|TQKy2U@D6%P|p7tF-#ECIGad&?V z%nqj&UQ-lWVE8KCTu#q=Q4BnYvY8Zx#bIpQ)FrLo6#Icf8_>{bm6Q5u!%_il0bWMH z(hLErjrkcL&LkE{=GV4^=|ddjUwR@hs0tJNuolF78VUlZP5mgH8fO7gjh$57yBEf-$p%gt)lZ{!?h1Wy)FwZ0xA|F0M}Iaq5BWB+Tu>e#MB7%ybC3!m&svw5fBkLIm}JgifQ z@0>4R`ijE$)i>G9P+skVr(Qq3aPjXyZ!G_{ZhgCXaPaWb_SSM=$JN*V_~n(eC$I19 z>=X!~{`%~eIPbjqL$I^9obBl*UjB)A|KY10<~~y#p?em(-=&XUI2)`tkO9`}D~EE1x@Uo9DM5J9nXSaP^J+Ku2HOmGjqI54`=((9ih`XE!!J z>3#ZQ*tz(~`U@YW)9DY^x-%>D^Gi=v-Wy#xv%J{LTw9%c@~vwxF7Bg$Y&o}fpq2Q| WZQb~8v1=~5d9%agnJLOEgPVoWXJ@nNU!2T#6N#sNu(1)uFbHgjv)O-= zu#?$T41>NnneHduAk+PL4f-15@&DJH8UMeyTA*nB+1332tG6BT2K{KO|NsB>yZ^t} zuYnu(YvEk5*w5}3;tc}Z-ror^Z1aZyzvj&Xvq6TD`nsW(PRJs002ovPDHLkV1l*$hLr#S literal 0 HcmV?d00001 diff --git a/resources/UI/info-tooltip.png b/resources/UI/info-tooltip.png new file mode 100644 index 0000000000000000000000000000000000000000..deb4a91ac15656c4e6ac9cbe5db156bdb4de14e5 GIT binary patch literal 2153 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 literal 0 HcmV?d00001 From 679ab2138afd270dbcd0a4063a8d1dad0abea914 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Fri, 16 Aug 2024 00:35:12 +0800 Subject: [PATCH 19/39] Correct deconstruction of the command line --- src/service/processes_info_service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/service/processes_info_service.py b/src/service/processes_info_service.py index 206672d..e79d7e9 100644 --- a/src/service/processes_info_service.py +++ b/src/service/processes_info_service.py @@ -1,3 +1,4 @@ +import shlex from abc import ABC from typing import List, Set @@ -40,7 +41,7 @@ def get_list(cls, only_new: bool, return_pids: set[int]) -> dict[int, Process]: try: process = psutil.Process(pid) info = process.as_dict(attrs=['name', 'exe', 'nice', 'ionice', 'cpu_affinity', 'cmdline']) - cmdline = ' '.join(process for process in info['cmdline'] or [''] if process) + cmdline = shlex.join(info['cmdline'] or []) result[pid] = Process( pid, From c7b1a6839d8d044cb8704146df77ef1b37a9f38a Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Fri, 16 Aug 2024 00:41:14 +0800 Subject: [PATCH 20/39] Ignore case in pattern of search --- src/util/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/utils.py b/src/util/utils.py index 8af2fe6..b537f23 100644 --- a/src/util/utils.py +++ b/src/util/utils.py @@ -35,7 +35,7 @@ def path_pattern_to_regex(pattern: str) -> Optional[Pattern]: pattern = pattern.replace('\\*', '[^/]*') pattern = pattern.replace('/', r'\\/') - return re.compile(f"^{pattern}$") + return re.compile(f"^{pattern}$", re.IGNORECASE) @lru_cache From e97906367ce38ce4a330e2ddb401c6986ffde282 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 1 Sep 2024 16:16:43 +0800 Subject: [PATCH 21/39] [#6] Added a list of current processes for simplified rule addition --- resources/UI/add.png | Bin 1695 -> 2030 bytes resources/UI/delete.png | Bin 1665 -> 2179 bytes resources/UI/down.png | Bin 2006 -> 2147 bytes resources/UI/error.png | Bin 299 -> 1618 bytes resources/UI/process-list.png | Bin 0 -> 1903 bytes resources/UI/process-rules.png | Bin 2123 -> 2125 bytes resources/UI/refresh.png | Bin 0 -> 1732 bytes resources/UI/save.png | Bin 1972 -> 1959 bytes resources/UI/up.png | Bin 2008 -> 2152 bytes src/configuration/config.py | 6 +- src/configuration/handler/affinity.py | 10 +- .../migration/m1_new_fields_in_rule.py | 11 +- src/configuration/rule.py | 40 +-- src/constants/resources.py | 6 +- src/constants/threads.py | 3 + src/constants/ui.py | 24 +- src/enums/bool.py | 7 +- src/enums/filters.py | 7 + src/enums/io_priority.py | 6 +- src/enums/priority.py | 7 +- src/enums/process.py | 7 +- src/enums/rules.py | 6 +- src/enums/selector.py | 7 +- src/main_loop.py | 12 +- src/model/process.py | 124 ++++--- src/model/service.py | 2 +- src/service/config_service.py | 10 +- src/service/processes_info_service.py | 70 ++-- src/service/rules_service.py | 27 +- src/service/services_info_service.py | 2 +- src/ui/settings.py | 274 +++++++++------ src/ui/tray.py | 18 +- src/ui/widget/common/button.py | 53 ++- src/ui/widget/common/combobox.py | 66 ++++ src/ui/widget/common/entry.py | 43 +++ src/ui/widget/common/label.py | 17 +- src/ui/widget/common/treeview/editable.py | 201 +++++------ src/ui/widget/common/treeview/extended.py | 152 ++++++++ src/ui/widget/common/treeview/pydantic.py | 98 ++++++ src/ui/widget/common/treeview/scrollable.py | 27 +- src/ui/widget/common/treeview/sortable.py | 111 ++++++ src/ui/widget/settings/settings_tabs.py | 25 +- src/ui/widget/settings/tabs/base_tab.py | 9 +- src/ui/widget/settings/tabs/process_list.py | 325 ++++++++++++++++++ .../settings/tabs/rules/base_rules_tab.py | 104 +++--- .../widget/settings/tabs/rules/rules_list.py | 158 ++------- .../widget/settings/tabs/rules/rules_tab.py | 7 +- src/ui/widget/settings/tooltip.py | 16 +- src/util/cpu.py | 12 +- src/util/decorators.py | 47 +-- src/util/files.py | 11 + src/util/scheduler.py | 35 +- src/util/ui.py | 48 ++- src/util/utils.py | 31 +- 54 files changed, 1581 insertions(+), 701 deletions(-) create mode 100644 resources/UI/process-list.png create mode 100644 resources/UI/refresh.png create mode 100644 src/constants/threads.py create mode 100644 src/enums/filters.py create mode 100644 src/ui/widget/common/combobox.py create mode 100644 src/ui/widget/common/entry.py create mode 100644 src/ui/widget/common/treeview/extended.py create mode 100644 src/ui/widget/common/treeview/pydantic.py create mode 100644 src/ui/widget/common/treeview/sortable.py create mode 100644 src/ui/widget/settings/tabs/process_list.py create mode 100644 src/util/files.py diff --git a/resources/UI/add.png b/resources/UI/add.png index d426018bda18e5ca9eb982bcb05f3ab94967a7cb..004a01e6877497d1a95bf6ada7cd3f0514f5cc17 100644 GIT binary patch delta 618 zcmbQw`;LEt1ruAzMyqZnF3S)@3o9c-D-9F%}vcKam-6jEiTC~ zDz;OwDN0GRa!O2xvT`!*Ca-1IF|yGIi352G5EeuQKBFcpvD}($&mziPoLDwFl10vy z822eD6qmS`l~|Q$q~_Tw85tOv=o(n)8X|do4~vZ;R8ew9VqSV`imj6V$mmUa_a{s_y2aEW?CPgxVrm)dVcIK9_NK;*Qg77`1ZY= zo&L8x?m?gI`SNVnjS72KEQ~BZ*8bU{x4yo^&?f(Q=kpV6hZwq4x$o9I5My~BX4di~ z^e_9xBP_fc5gbtl_iN>EiZPhhyO~MII_MPsb_wQg*!Smzz?|@#{6-S8%||}6U1Zw+ zm!&zQ@poL?uU}QmCfqq?sv-6yESHa$H}zQdL7VV+C$Sx8%D=N|^Xck5;W@e5hRgI% zh)S%Ix#ppG&7U@0(p}M z1tyc51B#Qi1lN;U23dcHuLvjr00AyZL_t(I5o2J0f{C~Ov-h9;xn{!2A3rCY`uU$M z4AOh@=W38y4CtWmt1;(?%45sw^n}?3&M*Unrl~||KES& z+aF>Kuh@GC#XuN9v1Fl}58Q&_+{%WKysG~onwX#g1q(q7=DY7B+XA5G&&UR&1BfMV zpJ-|U(3c+>g7Yf-K?b8^kT~8TTHv;yU=S^E-^);6U(XbhTe$|sg50Xjp`oG7crBRc z>PyH1m-+7AV8u+Kg@v3Ud6h?@hM$TlF6JgKnA}=%B~xJVG@~dE&8-v#TCxp9la|rk md_buM94C-?*$a0$5C8!CzDmKp3h_Pw0000i%as0 zitQ9^ic-?7oD$Qatei}{$!nQ)jBNBl;y|7PgauK7{tEVm}xvxqVmCzef)WRY`C zPEAZTwJtiY=ohTk~0$X(o<7xmGqVLC)=<{z-=NXB=Fe;31Xm4f*3YU z{>~CtAN=c%9RmZy3r`ov5DUTNAOHW`GjmAm{W!JG;_YWCg@2q!{+~Reuy?g%n&AP4 zGfWFyxLDa1KUT>RGjULrmN>x@aaLk$!i(q+S8tyA-#z(e<8epF|BgS(vTpsajr}|= zakIkAD^Du6WIn2&aqz{D&6_i|yI3#uY@2nX$1MNf!{-L|hyRt8{yl!|-=myY%-b76 z7`Ug|J1{#wc)uz%frrVy>UM(I8|B+fPagc(o^rBYf+4a=$6b{B-=#xM`hLrP7qVWI z&#+-=&d|RpR#R&9QB~rkUfR7WEP~7$nvZ;z`K6uJI5{PT!K-V*m8K~s-; delta 362 zcmV-w0hRuP5rGYmI06M1u{w(a3N=(RFgh_fIx{ts&jKR~HB>S%Ix#ppGc}X^0(p}M z1tyc51B#Qi1lN-$2U&k1*2(|?009t5L_t(I5o7rO|33o=PrUV?z5nFTH4{$$_&MR! z&;Mj$klvF&SA)!AfB~2VeJ6jWkZmv;?mzW23Bv-Q>l?t5K$?L}fYppq3x>W0U!BeT zzc`s4`0Ql%<%6r$uiL3<|MzvxTZUo5gcCoLNllJNne!*UdVIDUBfAqG(4FBXW#werO zXF|9aT{z@)Zo-~Zivte(9~BWV4z}fUD%N&woR-6U@k$Rf!};_*TeUyZT>Zw$=3;qIM`TFfi=( zba4!^5KK;JXzJYl@AKFBe|DxFIw^0jKIhlZ`8qt8sy{u?S`hi>|NsB#42c#mtbZD} z<}_a{_`h<#r-T?o?0tr5ESGpvm{N@0bR{~)rs&%3Xd_!n)gl#g207-GYt!*Oo)8+OT_KF3EP8yD=`H&0V#dl7FJ z>(0>G&d$y=SBkkTY;B#RSUJ^wVcYyJO}%H!s$^Q8g>^CM-eg;}Qj(qFRWAF!V_kw( QK%X#py85}Sb4q9e08~Vf{Qv*} diff --git a/resources/UI/error.png b/resources/UI/error.png index f1abf876ecb219cad84fd72d2e24efb847880526..0717e9f96e4c01d123df7ae6bfa48cfc232de5b6 100644 GIT binary patch literal 1618 zcmbVMTWB0r7#>p%N$qN*V3PXabSk#R&NaL1&d_n)>~6aYopjkQCPE)_cIM3PnAthg znMroD4`K}j6zlCp4H2OaA_!XOV@nf_px~tsp(H_SZ4rHumTDCZt>c-!k(O$)182_d zJKul*U(Su}4{hGInIMQzHj~QZ`JrI+bmRZC-@Z1Ar(QeroJ$b*KOBsEh`IRzg1E2W zD2#by$^l756$WUi2$@>N#%O}r8?V_woq!%$geAk0sVk=zDALemYBZv7ik*aIBU5+a zq54Qctxu?;M#Y~d_tqp#P=OvGYZcRSrJ77NcqP0Jj#-LqK)eZ=N(2JQF(pSPkpsyn z!_g|oMaic`Mgv8l7K?jGffIO^3$uKf<~V6cl)_=M^-)-yqv=vUwXY=%?_{d%dA7u| z)oPWg4l&3nvAigXEGMvnKw|{$PFo(R(U!ZT&5(kw>KL|XAd3tbK@m-QGKE!b+EB4O zw3gfQ6ZRNe12)SuTwqfJsHq*CJ?WSY;hM@q6IP(*xfsiLuyz@F$StFPq3&GYBmnzX zQ93eit4pQQ5#f62DQrf|A-6@lg=rhIdFY}^M}_Grtmclu8e2*_5O~NbAY`^9m20a^ z3IY=*ca0jBhN|xF4G&-ncu=Nr)Ns6FG#@DloD>O5g7_pClQ^ykRgh-r)3-py0w2RT ziI3d`#W|w^58M%~sgjPI3cv;%6;Oh#ZIvjp<3=foOypp}Si7N(=hK%jLFaIBRVHybG zsIJE%oUTXP?^8&f3{s%|Ui+W#4>|^}L15lBPf(db?noKK#ZjGZmChk}q_r{)vXL$l zP=hj%DK&^c)Tq|6an~Mb(pJk5lm16uG+{2%y((~EqJ+J5$Gl^)@@!DBO*`0IO>Eq4 zDDE~KcZ^`!=~Z~s>2}b}~674fnx|*;Jws>r?;q{rIK`x9MDH{Re&fwY4>K zy?^J)^QlY5W2Sj8zol!?S^47U`0j!7YGKRFnb^CRcb+GgZ`4Bd!M>~h%KV^z<*)VQ zAKdrO;^!}n zyq`LqU_V>({rS~neNV*ap8q=@>fJ8C`sIN)^yLrVNpF07*qo IM6N<$f<`-I^8f$< diff --git a/resources/UI/process-list.png b/resources/UI/process-list.png new file mode 100644 index 0000000000000000000000000000000000000000..f924a0102675a35c63395599bfc73195fe494745 GIT binary patch literal 1903 zcmb_dO>f*p7&fXDl~$1`aHx7Ru8=@rd;GO)TiHh2-H@z=(+#I94 zTyL+hE}pq?Mi7L>)>?A|-cJ|L=>_2$ySlgD zA$!}zq0;gtacSs+gNWr=97g>(bB8r);@5?7F|A7C1d?ypqQZLUFS5*gtfif@@ zo_1BuaU2!ts;JTTYrl6vx36PQ!m+YkdNpMP3)@Kom^9-X_*pg6}zfi2`B?Ex^SVK90qloB`K zX@sFmVT8L(P2%n(n&-K#ILmQNSgTo+AXOy{sawHS-Lid4b{rJQ8Z&(vJEktN6KYzTt;VPQ7BVz+$!`6I>;-UNsHSfgQ-UZ2c7P|S^LMa3q($);4CkOvmY+TN?YYtGo*Se|7>XN&K2+A`wu_<@zb02+h@NUH?%vi-MG8mF?!#A buqwRk|FLrar?=b1mDpNYZ+>?9t^L0MDJEKV literal 0 HcmV?d00001 diff --git a/resources/UI/process-rules.png b/resources/UI/process-rules.png index 3e8ed701bf46aea6078601de65fd16906da98048..f3bff49a40a22d5fb9c3ef427d0be2c981ea165c 100644 GIT binary patch delta 285 zcmX>ta8_W$Q6?_S5JL+qBO@zQ)5+(Vl##iAm?~A$QY_396H_g9O^i|vbyL$!Qgssz zjZAdSlaeegO_B^PlatIh&tx`XCQ9Yxk8I+|HgvJtO!i~XukY%Y`OLt;P~z$07-Auq z95CnGPy3A$91>2SRs|S%@U%#7$edB|N}cQP(VIOs%^W*k*c-VSzBv24pT$s@=g`}& zjYb(RZGsymR%~Qkem#L_#Ui#Dx*jzpJ$Dr*9GkNCe!!gWbI02Qc^0uG8*@C1DY1+5 jsclZ+@iM&1!^E(@*Hch-rGc&k&;bmdu6{1-oD!Mra9Uu)Q6?_45Ca1%Lt`rgv&rX~l##iAm?~8)O$`iE6DwsRZ+?6^v=zLh`c7<{V1|Go-tUFaG>t(B(KKA&2eYobGeSyI1B5 h^f+oRo8`!`K_S**3IFT&H-XkOc)I$ztaD0e0s!V-UU~ok diff --git a/resources/UI/refresh.png b/resources/UI/refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..86318da6b080797d2a4120aae9fedbd4b8c9978e GIT binary patch literal 1732 zcmbVNe{2&~96ul2x9Wpdt2aKYK+3w@ZI0L$poi0O8xU1f~jy#MY z1!ZEOU2pd{(!3lqvx3Y4b26qtG=fxCB^8#B03GE(NR$}t_tR%FR1_Gj&F&}tiU)+n z`jiSFAh$O2J7BgwslmQBS9;d|BXhyie6Ces=K+-jcwdAo%Sk`4NEdL92 z{`fWl(6@enUdCN@iN*3FG`+SPnvr$LUC~;gM*&0&(B!zvgW7JWX1QUFLVHxe>arS; zX!vE z*mDQe9k94)3q{+h+n_LK1XgG72^M%dD626R8Z5@x5FivOgrRvi(jGY~t57i1&boZx z=kYYFa!`!I1Ffa52KCi?92U33fm3EnMqR(3_DPz~N<8p+84NndEQ$hc12)QTcW^lG zqMSIe*(jWK^BhicZl|4c206+R%-#3OeB4NZ+tq9U3}7nw3cuqvnyL2unN z?+B**fD3?${jnJdf*91 zb+ZTiZQCEi#e1!%*H#QXX1$@htXjzyUrD^Rbn~mP|H-aD;F>7;%k#@T9#9T$estaS zi<`deSrr*TFO>cG$;!yrZ(mC9^)+@CT$u^~z4808@xIoJ;`?oU@`tgq;;G$Ria!jA zKlwgq*LzM~xY@bw+ao_e-q8{LwQ#5Da>=LNUBtl9T;r~}f|^^*;lYWiFlv5~OP&2- z;^xYi(;rQaR)74;=rA{U?BLP5&a1u`7NUbA&abA6$_r}VEsD%`m0g`=@a;1V!an=Z zoTM)_TsxCGzgnBSygO~Z68mE8xRYO)jE;^E4qPf-oWEB2P5;nz`s9K4?2ph=`^@2U y8=e`PkN1CvT_?f**~)e4{sL3yt(~)ryT*y*eaxHbQzI$kKjW)y@}8{e+Vc-m6j84L literal 0 HcmV?d00001 diff --git a/resources/UI/save.png b/resources/UI/save.png index 6f98db3624c64161ee790c1e9dc0b81cfd3a924c..b524b748dbeae03491f52bd161838d9048a3496f 100644 GIT binary patch delta 343 zcmdnOznp)=Q6?_S5JL+qV?!$gg{~oz6ZWv! zOm1MyuTPf9Il;idFvruyF~p*G?Zu0nEe1Rd51U-`OR*19omrIBEPB`8TUei=|=tE1G=;80HBJ?DV6dlkw zmcY5TB>K|rKaQ>WvUXKbB`yJi#}w*fGCp$d4L<(mud}5~I{&PeyZT2jsmc9UmNhOr ty(3epMR=|bi;>l{1jPv#*O#2hu6LMq+PBFza}Lm<44$rjF6*2UngGIlef$6b delta 334 zcmZ3^zlDFpQ6?_a5FEG*Itj8n~1Et5<)&ty(xB1+}t*(_3%3s_m1fR^oHv6zR|JyU08iqD}w&4$6{_~yoo9DNS1CAOzXMOj+@yGtpPT!Tfc#3B|&wH}v zz+c@H1{=7)-`?CK<;Hs0DZF))<@xexwl3X8$;JC_CoQl`Tf-$QzGG^GXrstugDDw@ z7wDz1RV8cQkmkN)Z=q9Uy4>Q7+k!SdNAoF*I2bh9GMg&zr|yf^x_Ix%^PuOfdEE=z t{w?>q#86$o@3+$`iMD5#Op5k!GN{(w@wu|+Pd?Dq44$rjF6*2UngBfTfZ+fD diff --git a/resources/UI/up.png b/resources/UI/up.png index fd5c39fb5b4d17e9e8a698761ad50f210cd5477e..137b7ce9e5ea0ee2cc66aa5ed55db0c5cf92ee34 100644 GIT binary patch delta 607 zcma)3J7^R^7~br?AQv@hlq)1b_X?v!_TQPEn_Z5O3#)R4!6KGE=4ld=+i-Ul+C;8W zL=mP62o|;?rmzz%>;x4=eAE`&2wGSf&>XME0$Jd~dt$Uk@-aolwq^770g6k_KXiF@z%q%FQTCLc3X*4kV}~;;Ml(<_txe zaFlRRhzKn?mLP?R?AJoD!HJ9wl^k&l6cJ7^VsWgHFmb{pUrGxRs5~QTcu_ tvCBKAbo}c3`o7=yTz^xyWQX+qt;Bq&h74ISVcH2|s$!_+ zuPleM29y>N8EOF}T@OebOTb-(fk~xfddPLCja4q(X;29TcNhZ<3J6ROTfo5#0>-h$ z5aSS9L_LL#R?~BN#?5#@UDh0}SeeoQ diff --git a/src/configuration/config.py b/src/configuration/config.py index 5d19ebd..2aba3c1 100644 --- a/src/configuration/config.py +++ b/src/configuration/config.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from pydantic import BaseModel, Field @@ -24,12 +24,12 @@ class Config(BaseModel): Default is 1 second. """ - processRules: List[ProcessRule] = Field(default_factory=list) + processRules: list[ProcessRule] = Field(default_factory=list) """ A list of Rule objects that specify how application manages processes based on user-defined rules. """ - serviceRules: List[ServiceRule] = Field(default_factory=list) + serviceRules: list[ServiceRule] = Field(default_factory=list) """ A list of Rule objects that specify how application manages services based on user-defined rules. """ diff --git a/src/configuration/handler/affinity.py b/src/configuration/handler/affinity.py index 3dfd01b..390850e 100644 --- a/src/configuration/handler/affinity.py +++ b/src/configuration/handler/affinity.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from pydantic import PlainSerializer, WithJsonSchema, BeforeValidator from typing_extensions import Annotated @@ -6,8 +6,8 @@ from util.cpu import parse_affinity, format_affinity -def __to_list(value) -> Optional[List[int]]: - if isinstance(value, List): +def __to_list(value) -> Optional[list[int]]: + if isinstance(value, list): return value if not value.strip(): @@ -20,14 +20,14 @@ def __to_str(value) -> Optional[str]: if not value: return None - if isinstance(value, List): + if isinstance(value, list): return format_affinity(value) return value Affinity = Annotated[ - Optional[List[int]], + Optional[list[int]], BeforeValidator(__to_list), PlainSerializer(__to_str, return_type=str), WithJsonSchema({'type': 'string'}, mode='serialization'), diff --git a/src/configuration/migration/m1_new_fields_in_rule.py b/src/configuration/migration/m1_new_fields_in_rule.py index ec9a29d..8e6ddae 100644 --- a/src/configuration/migration/m1_new_fields_in_rule.py +++ b/src/configuration/migration/m1_new_fields_in_rule.py @@ -2,6 +2,8 @@ from typing import Optional from configuration.migration.base import BaseMigration +from enums.bool import BoolStr +from enums.selector import SelectorType class NewFieldsInRule(BaseMigration): @@ -15,8 +17,11 @@ def should_migrate(config: dict) -> bool: @staticmethod def migrate(config: dict) -> Optional[dict]: - for rule in itertools.chain(config.get('processRules', []), config.get('serviceRules', [])): - rule['selectorBy'] = 'Name' - rule['force'] = 'N' + for rule in config.get('processRules', []): + rule['selectorBy'] = SelectorType.NAME.value + rule['force'] = BoolStr.NO.value + + for rule in config.get('serviceRules', []): + rule['force'] = BoolStr.NO.value return config diff --git a/src/configuration/rule.py b/src/configuration/rule.py index 408e27a..8cd19af 100644 --- a/src/configuration/rule.py +++ b/src/configuration/rule.py @@ -15,18 +15,18 @@ class ProcessRule(BaseModel): title="Selector By", description="Determines how the __Process Selector__ value is interpreted, influencing how the __process__ is matched.\n" "**Options:**\n" - " - `Name` - matches by process name (e.g., `notepad.exe`);\n" - " - `Path` - matches by the full executable path (e.g., `C:/Windows/System32/notepad.exe`);\n" - " - `Command line` - matches by command line arguments (e.g., `App.exe Document.txt` or `D:/Folder/App.exe Document.txt`)." + "- `Name` - matches by process name (e.g., `notepad.exe`);\n" + "- `Path` - matches by the full executable path (e.g., `C:/Windows/System32/notepad.exe`);\n" + "- `Command line` - matches by command line arguments (e.g., `App.exe Document.txt` or `D:/Folder/App.exe Document.txt`)." ) selector: str = Field( - title="Selector", + title="Process Selector", description="Specifies the **name**, **pattern** or **path** of the __process__ to which this rule applies.\n\n" "**Supports wildcard:** `*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" "**Examples:** `name.exe`, `logioptionsplus_*.exe`, `D:/FolderName/App.exe` or `C:/Program Files/**/app.exe --file Document.txt`.", stretchable_column_ui=True, - justify_ui="left" + # justify_ui="left" ) priority: Optional[PriorityStr] = Field( @@ -48,8 +48,8 @@ class ProcessRule(BaseModel): title="Affinity", description="Sets the **CPU core affinity** for the __process__, defining which CPU cores are allowed for execution.\n\n" "**Format:** range `0-3`, specific cores `0;2;4`, combination `1;3-5`.", - scale_width_ui=3, - justify_ui="left" + justify_ui="left", + width_ui=200 ) force: BoolStr = Field( @@ -65,7 +65,7 @@ class ProcessRule(BaseModel): gt=0, default=0, title="Delay", - description="Specifies the delay in seconds before the settings are applied to the __process__.\n\n" + description="Specifies the **delay** in __seconds__ before the settings are applied to the __process__.\n\n" "**Possible values:**\n" "- If not specified, the settings are applied immediately;\n" "- Positive values set a delay in seconds before applying the settings." @@ -73,21 +73,11 @@ class ProcessRule(BaseModel): class ServiceRule(BaseModel): - selectorBy: SelectorType = Field( - default=SelectorType.NAME, - title="Selector By", - description="Determines how the __Service Selector__ value is interpreted, influencing how the __service__ is matched.\n" - "**Options:**\n" - " - `Name` - matches by service name (e.g., `Spooler`);\n" - " - `Path` - matches by the full executable path (e.g., `C:/Windows/System32/spoolsv.exe`);\n" - " - `Command line` - matches by command line arguments (e.g., `spoolsv.exe -k` or `C:/Windows/System32/spoolsv.exe -k`)." - ) - selector: str = Field( - title="Selector", - description="Specifies the **name**, **pattern** or **path** of the __service__ to which this rule applies.\n\n" - "**Supports wildcard:** `*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" - "**Examples:** `ServiceName`, `Audio*`, `D:/FolderName/Service.exe` or `C:/Windows/System32/**/service.exe --debug 1`.", + title="Service Selector", + description="Specifies the **name** of the __service__ to which this rule applies.\n\n" + "**Supports wildcard:** `*` (matches any characters) and `?` (matches any single character)\n" + "**Examples:** `ServiceName` or `Audio*`.", stretchable_column_ui=True, justify_ui="left" ) @@ -111,8 +101,8 @@ class ServiceRule(BaseModel): title="Affinity", description="Sets the **CPU core affinity** for the __service__, defining which CPU cores are allowed for execution.\n\n" "**Format:** range `0-3`, specific cores `0;2;4`, combination `1;3-5`.", - scale_width_ui=3, - justify_ui="left" + justify_ui="left", + width_ui=200 ) force: BoolStr = Field( @@ -128,7 +118,7 @@ class ServiceRule(BaseModel): gt=0, default=0, title="Delay", - description="Specifies the delay in seconds before the settings are applied to the __service__.\n\n" + description="Specifies the **delay** in __seconds__ before the settings are applied to the __service__.\n\n" "**Possible values:**\n" "- If not specified, the settings are applied immediately;\n" "- Positive values set a delay in seconds before applying the settings." diff --git a/src/constants/resources.py b/src/constants/resources.py index 806cfb6..6ec1553 100644 --- a/src/constants/resources.py +++ b/src/constants/resources.py @@ -7,14 +7,18 @@ UI_PROCESS_RULES: Final[str] = f"{APP_PATH}/resources/UI/process-rules.png" UI_SERVICE_RULES: Final[str] = f"{APP_PATH}/resources/UI/service-rules.png" +UI_PROCESS_LIST: Final[str] = f"{APP_PATH}/resources/UI/process-list.png" UI_ADD: Final[str] = f"{APP_PATH}/resources/UI/add.png" UI_DELETE: Final[str] = f"{APP_PATH}/resources/UI/delete.png" UI_UP: Final[str] = f"{APP_PATH}/resources/UI/up.png" UI_DOWN: Final[str] = f"{APP_PATH}/resources/UI/down.png" UI_SAVE: Final[str] = f"{APP_PATH}/resources/UI/save.png" +UI_REFRESH: Final[str] = f"{APP_PATH}/resources/UI/refresh.png" +UI_CONFIG: Final[str] = f"{APP_PATH}/resources/UI/config.png" +UI_LOG: Final[str] = f"{APP_PATH}/resources/UI/log.png" UI_INFO_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/info-tooltip.png" UI_WARN_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/warn-tooltip.png" -UI_ERROR: Final[str] = f"{APP_PATH}/resources/UI/error.png" \ No newline at end of file +UI_ERROR: Final[str] = f"{APP_PATH}/resources/UI/error.png" diff --git a/src/constants/threads.py b/src/constants/threads.py new file mode 100644 index 0000000..3d037f5 --- /dev/null +++ b/src/constants/threads.py @@ -0,0 +1,3 @@ +THREAD_SETTINGS = "settings" +THREAD_TRAY = "tray" +THREAD_PROCESS_LIST = "process_list" diff --git a/src/constants/ui.py b/src/constants/ui.py index b1ab66d..5ba4b35 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -1,10 +1,22 @@ +from tkinter import LEFT, RIGHT from typing import Final UI_PADDING = 10 -BUTTON_SIZE = 7 -ERROR_ROW_COLOR = "#ffcdd2" RC_WIN_SIZE = (1280, 768) + +LEFT_PACK = dict(side=LEFT, padx=(0, UI_PADDING)) +RIGHT_PACK = dict(side=RIGHT, padx=(UI_PADDING, 0)) + +COLUMN_TITLE_PADDING = 30 +ERROR_ROW_COLOR = "#ffcdd2" +CHANGED_ROW_COLOR = "#b8e6bb" + SETTINGS_TITLE = "Settings" +OPEN_CONFIG_LABEL = "Open config file" +OPEN_LOG_LABEL = "Open log file" + +ADD_PROCESS_RULE_LABEL = " Add Process Rule" +ADD_SERVICE_RULE_LABEL = " Add Service Rule" class ActionEvents: @@ -13,7 +25,13 @@ class ActionEvents: UP: Final[str] = "<>" DOWN: Final[str] = "<>" CANCEL: Final[str] = "<>" - SAVE: Final[str] = "<>" + APPLY: Final[str] = "<>" + APPLY_N_CLOSE: Final[str] = "<>" + REFRESH: Final[str] = "<>" + CONFIG: Final[str] = "<>" + LOG: Final[str] = "<>" + FILTER_BY_TYPE: Final[str] = "<>" + SEARCH_CHANGE: Final[str] = "<>" class RulesListEvents: diff --git a/src/enums/bool.py b/src/enums/bool.py index 0dd738c..9cd645d 100644 --- a/src/enums/bool.py +++ b/src/enums/bool.py @@ -1,9 +1,6 @@ -from enum import Enum +from enum import StrEnum -class BoolStr(str, Enum): +class BoolStr(StrEnum): NO = "N" YES = "Y" - - def __str__(self): - return str(self.value) \ No newline at end of file diff --git a/src/enums/filters.py b/src/enums/filters.py new file mode 100644 index 0000000..80fbdc8 --- /dev/null +++ b/src/enums/filters.py @@ -0,0 +1,7 @@ +from enum import StrEnum + + +class FilterByProcessType(StrEnum): + ALL = 'Show All' + PROCESSES = 'Show Processes' + SERVICES = 'Show Services' diff --git a/src/enums/io_priority.py b/src/enums/io_priority.py index 81579e7..5421346 100644 --- a/src/enums/io_priority.py +++ b/src/enums/io_priority.py @@ -1,15 +1,13 @@ -from enum import Enum +from enum import StrEnum from typing import Final from psutil._pswindows import IOPriority -class IOPriorityStr(str, Enum): +class IOPriorityStr(StrEnum): VERYLOW = 'VeryLow' LOW = 'Low' NORMAL = 'Normal' - def __str__(self): - return str(self.value) to_iopriority: Final[dict[IOPriorityStr, IOPriority]] = { diff --git a/src/enums/priority.py b/src/enums/priority.py index 797baf5..49a120c 100644 --- a/src/enums/priority.py +++ b/src/enums/priority.py @@ -1,10 +1,10 @@ -from enum import Enum +from enum import StrEnum from typing import Final from psutil._pswindows import Priority -class PriorityStr(str, Enum): +class PriorityStr(StrEnum): IDLE = 'Idle' BELOW_NORMAL = 'BelowNormal' NORMAL = 'Normal' @@ -12,9 +12,6 @@ class PriorityStr(str, Enum): HIGH = 'High' REALTIME = 'Realtime' - def __str__(self): - return str(self.value) - to_priority: Final[dict[PriorityStr, Priority]] = { PriorityStr.IDLE: Priority.IDLE_PRIORITY_CLASS, diff --git a/src/enums/process.py b/src/enums/process.py index 727d491..7a33e5f 100644 --- a/src/enums/process.py +++ b/src/enums/process.py @@ -1,10 +1,7 @@ -from enum import Enum +from enum import StrEnum -class ProcessParameter(str, Enum): +class ProcessParameter(StrEnum): AFFINITY = "affinity" NICE = "priority" IONICE = "I/O priority" - - def __str__(self): - return str(self.value) diff --git a/src/enums/rules.py b/src/enums/rules.py index d4ebdec..d0b43cc 100644 --- a/src/enums/rules.py +++ b/src/enums/rules.py @@ -1,5 +1,7 @@ from enum import Enum +from pydantic import BaseModel + from configuration.rule import ProcessRule, ServiceRule @@ -8,5 +10,5 @@ class RuleType(Enum): SERVICE = (ServiceRule, "serviceRules") def __init__(self, clazz, field_in_config): - self.clazz = clazz - self.field_in_config = field_in_config + self.clazz: type[BaseModel] = clazz + self.field_in_config: str = field_in_config diff --git a/src/enums/selector.py b/src/enums/selector.py index 90a2440..308e1d3 100644 --- a/src/enums/selector.py +++ b/src/enums/selector.py @@ -1,10 +1,7 @@ -from enum import Enum +from enum import StrEnum -class SelectorType(str, Enum): +class SelectorType(StrEnum): NAME = "Name" PATH = "Path" CMDLINE = "CommandLine" - - def __str__(self): - return str(self.value) diff --git a/src/main_loop.py b/src/main_loop.py index 3d187c3..e141d50 100644 --- a/src/main_loop.py +++ b/src/main_loop.py @@ -1,5 +1,4 @@ import os -from threading import Thread from time import sleep from typing import Optional @@ -12,12 +11,14 @@ from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.files import LOG_FILE_NAME from constants.log import LOG +from constants.threads import THREAD_SETTINGS, THREAD_TRAY from constants.ui import SETTINGS_TITLE from service.config_service import ConfigService from service.rules_service import RulesService -from ui.settings import open_settings, is_settings_open +from ui.settings import open_settings from ui.tray import init_tray from util.messages import yesno_error_box, show_error +from util.scheduler import TaskScheduler from util.startup import update_startup @@ -43,8 +44,7 @@ def main_loop(tray: Icon): tray (Icon): The system tray icon instance to be managed within the loop. It will be stopped gracefully when the loop exits. """ - thread = Thread(target=tray.run) - thread.start() + TaskScheduler.schedule_task(THREAD_TRAY, tray.run) LOG.info('Application started') @@ -52,7 +52,7 @@ def main_loop(tray: Icon): is_changed: bool last_error_message = None - while thread.is_alive(): + while TaskScheduler.check_task(THREAD_TRAY): try: config, is_changed = ConfigService.reload_if_changed(config) @@ -113,7 +113,7 @@ def show_rules_error_message(): title = f"Error Detected - {APP_NAME_WITH_VERSION}" message = "An error has occurred while loading or applying the rules.\n" - if is_settings_open: + if TaskScheduler.check_task(THREAD_SETTINGS): message += "Please check the correctness of the rules." show_error(title, message) else: diff --git a/src/model/process.py b/src/model/process.py index c107281..f96933b 100644 --- a/src/model/process.py +++ b/src/model/process.py @@ -1,14 +1,15 @@ -from dataclasses import dataclass -from typing import List, Optional +from typing import Optional import psutil from psutil._pswindows import Priority, IOPriority +from pydantic import BaseModel, Field, ConfigDict from model.service import Service -@dataclass -class Process: +class Process(BaseModel): + model_config = ConfigDict(arbitrary_types_allowed=True, populate_by_name=True) + """ The Process class represents information about a running process. @@ -16,57 +17,76 @@ class Process: (ionice), CPU core affinity, and the associated psutil.Process object. """ - pid: int - """ - The unique identifier of the process (Process ID). - """ - - binpath: str - """ - The full path to the executable binary of the process. - """ - - cmdline: str - """ - The command line used to start the process, including all arguments. - """ - - name: str - """ - The name of the process. - """ - - nice: Optional[Priority] - """ - The priority level of the process (nice). Default is None (no priority specified). - """ - - ionice: Optional[IOPriority] - """ - The I/O priority of the process (ionice). Default is None (no I/O priority specified). - """ - - affinity: List[int] - """ - A list of integers representing the CPU cores to which the process is bound (CPU core affinity). - """ - - process: psutil.Process - """ - The psutil.Process object associated with the process, providing access to additional process information and control. - """ - - service: Optional[Service] - """ - Contains information about the service if the current process is associated with one. - If the process is not related to a service, this will be None. - """ + pid: int = Field( + title="PID", + description="The unique identifier of the __process__ (**Process ID**).", + default_sort_column_ui=True, + width_ui=75 + ) + + process_name: Optional[str] = Field( + title="Process Name", + description="The **name** of the __process__.", + justify_ui="left", + width_ui=200 + ) + + service_name: Optional[str] = Field( + title="Service Name", + description="The **name** of the __service__ associated with this __process__.\n" + "This field may be absent if the process is not a service.", + justify_ui="left", + width_ui=250 + ) + + bin_path: Optional[str] = Field( + title="Executable Path", + description="The **full path** to the executable binary of the __process__.", + stretchable_column_ui=True, + justify_ui="left" + ) + + cmd_line: Optional[str] = Field( + title="Command Line", + description="The **command line** used to start the __process__, including all arguments.", + stretchable_column_ui=True, + justify_ui="left" + ) + + priority: Optional[Priority] = Field( + title="Priority", + description="The **priority level** of the __process__.", + exclude=True + ) + + io_priority: Optional[IOPriority] = Field( + title="I/O Priority", + description="The **I/O priority** of the __process__.", + exclude=True + ) + + affinity: Optional[list[int]] = Field( + title="CPU Core Affinity", + description="A list of integers representing the CPU cores to which the __process__ is bound (**CPU core affinity**).", + exclude=True + ) + + process: psutil.Process = Field( + description="The psutil.Process object associated with the __process__, providing access to additional control.", + exclude=True + ) + + service: Optional[Service] = Field( + description="Contains information about the service if the current __process__ is associated with one.\n" + "If the __process__ is not related to a service, this will be None.", + exclude=True + ) def __hash__(self): - return hash((self.pid, self.binpath, self.name, self.cmdline)) + return hash((self.pid, self.bin_path, self.process_name, self.cmd_line)) def __eq__(self, other): if isinstance(other, Process): - return ((self.pid, self.binpath, self.name, self.cmdline) == - (other.pid, other.binpath, other.name, other.cmdline)) + return ((self.pid, self.bin_path, self.process_name, self.cmd_line) == + (other.pid, other.bin_path, other.process_name, other.cmd_line)) return False diff --git a/src/model/service.py b/src/model/service.py index c8c2a85..e680ce9 100644 --- a/src/model/service.py +++ b/src/model/service.py @@ -36,7 +36,7 @@ class Service: The current status of the Windows service. """ - binpath: str + bin_path: str """ The binary path of the Windows service, specifying the location of the service executable. """ diff --git a/src/service/config_service.py b/src/service/config_service.py index aa63427..4af543b 100644 --- a/src/service/config_service.py +++ b/src/service/config_service.py @@ -3,7 +3,9 @@ from abc import ABC from datetime import datetime from os.path import exists -from typing import Optional, List, Any +from typing import Optional, Any + +from pydantic.config import JsonDict from configuration.config import Config from constants.files import CONFIG_FILE_NAME, CONFIG_FILE_ENCODING @@ -90,7 +92,7 @@ def rules_has_error(cls) -> bool: """ try: for rule_type in RuleType: - rules: List[Any] = cls.load_config_raw().get(rule_type.field_in_config, []) + rules: list[Any] = cls.load_config_raw().get(rule_type.field_in_config, []) try: for rule in rules: @@ -103,7 +105,7 @@ def rules_has_error(cls) -> bool: return False @classmethod - def load_config_raw(cls) -> dict: + def load_config_raw(cls) -> JsonDict: """ Loads the raw configuration as a dictionary from the configuration file. @@ -117,7 +119,7 @@ def load_config_raw(cls) -> dict: return json.load(file) @classmethod - def save_config_raw(cls, config: dict): + def save_config_raw(cls, config: JsonDict): """ Saves the raw configuration dictionary to the configuration file. diff --git a/src/service/processes_info_service.py b/src/service/processes_info_service.py index e79d7e9..5961b38 100644 --- a/src/service/processes_info_service.py +++ b/src/service/processes_info_service.py @@ -1,12 +1,12 @@ -import shlex +import subprocess from abc import ABC -from typing import List, Set import psutil from psutil import NoSuchProcess from model.process import Process from service.services_info_service import ServicesInfoService +from util.utils import none_int class ProcessesInfoService(ABC): @@ -15,47 +15,71 @@ class ProcessesInfoService(ABC): It is an abstract base class (ABC) to be subclassed by specific implementation classes. """ - __prev_pids: Set[int] = [] + __prev_pids: set[int] = [] @classmethod - def get_list(cls, only_new: bool, return_pids: set[int]) -> dict[int, Process]: + def get_processes( + cls, + only_new: bool, + force_return_pids: set[int] = None + ) -> dict[int, Process]: """ Retrieves a dictionary of running processes and their information. Args: only_new (bool): If True, returns only processes that have started since the last call. If False, returns all currently running processes. - return_pids (list[int]): A list of process IDs to include even if they are not new. - + force_return_pids (set[int], optional): A set of process IDs that should be included in the result + even if they are not new. Defaults to an empty set if not provided. Returns: - dict[int, Process]: A dictionary with process IDs as keys and Process objects as values. + dict[int, Process]: A dictionary where keys are process IDs and values are Process objects, + containing detailed information about each running process. """ - services = ServicesInfoService.get_list() + services = ServicesInfoService.get_services() result: dict[int, Process] = {} - current_pids: List[int] = psutil.pids() + current_pids: list[int] = psutil.pids() + force_return_pids = force_return_pids or set() for pid in current_pids: - if only_new and pid in cls.__prev_pids and pid not in return_pids: + if only_new and pid in cls.__prev_pids and pid not in force_return_pids: continue try: process = psutil.Process(pid) + service = services.get(pid) + info = process.as_dict(attrs=['name', 'exe', 'nice', 'ionice', 'cpu_affinity', 'cmdline']) - cmdline = shlex.join(info['cmdline'] or []) - - result[pid] = Process( - pid, - info['exe'], - cmdline, - info['name'], - int(info['nice']) if info['nice'] else None, - int(info['ionice']) if info['ionice'] else None, - info['cpu_affinity'], - process, - services.get(pid) + result[pid] = Process.model_construct( + pid=pid, + process_name=info['name'], + service_name=getattr(service, 'name', None), + bin_path=info['exe'], + cmd_line=cls._get_command_line(pid, info), + priority=none_int(info['nice']), + io_priority=none_int(info['ionice']), + affinity=info['cpu_affinity'], + process=process, + service=service ) except NoSuchProcess: pass - cls.__prev_pids = set(current_pids) + if only_new: + cls.__prev_pids = set(current_pids) + return result + + @staticmethod + def _get_command_line(pid, info): + if pid == 0: + return '' + + cmdline = info['cmdline'] or [''] + + if not cmdline[0]: + cmdline[0] = info['exe'] or info['name'] + + if not cmdline[0]: + return '' + + return subprocess.list2cmdline(cmdline) diff --git a/src/service/rules_service.py b/src/service/rules_service.py index 6754ac1..58bc128 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -30,7 +30,6 @@ class RulesService(ABC): __ignore_pids: set[int] = {0, os.getpid()} __ignored_process_parameters: dict[Process, set[ProcessParameter]] = {} __force_pids: set[int] = set() - __scheduler = TaskScheduler() @classmethod def apply_rules(cls, config: Config, only_new: bool): @@ -50,7 +49,7 @@ def apply_rules(cls, config: Config, only_new: bool): cls.__light_gc_ignored_process_parameters() cls.__force_pids = cls.__handle_processes( config, - ProcessesInfoService.get_list(only_new, cls.__force_pids) + ProcessesInfoService.get_processes(only_new, cls.__force_pids) ) @classmethod @@ -70,7 +69,7 @@ def __handle_processes(cls, config: Config, processes: dict[int, Process]) -> se force_pids.add(pid) if rule.delay > 0: - cls.__scheduler.schedule_task(process, cls.__handle_process, rule.delay, process, rule) + TaskScheduler.schedule_task(process, cls.__handle_process, rule.delay, process, rule) else: cls.__handle_process(process, rule) @@ -91,7 +90,7 @@ def __handle_process(cls, process: Process, rule: ProcessRule | ServiceRule): if param in ignored_parameters: continue - logger_string = f"{param.value} `{logger_value}` for {process.name} ({process.pid})" + logger_string = f"{param.value} `{logger_value}` for {process.process_name} ({process.pid})" try: if method(process, rule): @@ -107,7 +106,7 @@ def __handle_process(cls, process: Process, rule: ProcessRule | ServiceRule): def __set_ionice(cls, process: Process, rule: ProcessRule | ServiceRule): io_priority = to_iopriority[rule.ioPriority] - if io_priority and process.ionice != io_priority: + if io_priority and process.io_priority != io_priority: process.process.ionice(io_priority) return True @@ -115,7 +114,7 @@ def __set_ionice(cls, process: Process, rule: ProcessRule | ServiceRule): def __set_nice(cls, process: Process, rule: ProcessRule | ServiceRule): priority = to_priority[rule.priority] - if priority and process.nice != priority: + if priority and process.priority != priority: process.process.nice(priority) return True @@ -127,27 +126,25 @@ def __set_affinity(cls, process: Process, rule: ProcessRule | ServiceRule): @classmethod def __first_rule_by_process(cls, config: Config, process: Process) -> Optional[ProcessRule | ServiceRule]: - service = process.service - - if service: + if process.service: for rule in config.serviceRules: - value = service.name + value = process.service_name if rule.selectorBy == SelectorType.PATH: - value = service.binpath + value = process.bin_path elif rule.selectorBy == SelectorType.CMDLINE: - value = process.cmdline + value = process.cmd_line if path_match(rule.selector, value): return rule for rule in config.processRules: - value = process.name + value = process.process_name if rule.selectorBy == SelectorType.PATH: - value = process.binpath + value = process.bin_path elif rule.selectorBy == SelectorType.CMDLINE: - value = process.cmdline + value = process.cmd_line if path_match(rule.selector, value): return rule diff --git a/src/service/services_info_service.py b/src/service/services_info_service.py index 358af0a..3e27551 100644 --- a/src/service/services_info_service.py +++ b/src/service/services_info_service.py @@ -28,7 +28,7 @@ class ServicesInfoService(ABC): """ @staticmethod - def get_list() -> dict[int, Service]: + def get_services() -> dict[int, Service]: """ Get a dictionary of running services and their information. diff --git a/src/ui/settings.py b/src/ui/settings.py index 7d917ba..6bd0de5 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -1,52 +1,36 @@ import os -import tkinter as tk -from threading import Thread -from tkinter import messagebox, ttk - -from PIL.ImageTk import PhotoImage +from tkinter import messagebox, ttk, Tk, X, TOP, BOTH, NORMAL, DISABLED from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.files import LOG_FILE_NAME from constants.log import LOG -from constants.resources import APP_ICON, UI_SAVE -from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, SETTINGS_TITLE, RulesListEvents, EditableTreeviewEvents -from ui.widget.common.button import IconedButton +from constants.resources import APP_ICON, UI_SAVE, UI_LOG, UI_CONFIG +from constants.threads import THREAD_SETTINGS +from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, SETTINGS_TITLE, RulesListEvents, EditableTreeviewEvents, \ + RIGHT_PACK, LEFT_PACK, OPEN_CONFIG_LABEL, OPEN_LOG_LABEL +from ui.widget.common.button import ExtendedButton from ui.widget.settings.settings_tabs import SettingsTabs +from ui.widget.settings.tabs.base_tab import BaseTab +from ui.widget.settings.tabs.process_list import ProcessListTab from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab from ui.widget.settings.tooltip import Tooltip +from util.files import open_config_file, open_log_file from util.messages import yesno_error_box +from util.scheduler import TaskScheduler +from util.ui import load_img -class SettingsButtons(ttk.Frame): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._setup_btn() - - def _setup_btn(self): - self.save = save = IconedButton( - self, - text=" Apply", - command=lambda: self.event_generate(ActionEvents.SAVE), - image=PhotoImage(file=UI_SAVE) - ) - right_btn_pack = dict(side=tk.RIGHT, padx=(UI_PADDING, 0)) - save.pack(**right_btn_pack) - - -class Settings(tk.Tk): - _DEFAULT_TOOLTIP = ( - "To add a new rule, click the **Add** button.\n" - "To edit a rule, **double-click** on the corresponding cell." - ) - - _tabs = None - _tooltip = None - _buttons = None - +class Settings(Tk): def __init__(self): super().__init__() + + self._tabs: SettingsTabs + self._tooltip: Tooltip + self._actions: SettingsActions + self._setup_window() self._create_widgets() + self._pack() self._setup_tooltips() def _setup_window(self): @@ -54,26 +38,31 @@ def _setup_window(self): self.protocol("WM_DELETE_WINDOW", self._on_window_closing) self.iconbitmap(APP_ICON) - self.title(f"{SETTINGS_TITLE} - {APP_NAME_WITH_VERSION}") + self.title(APP_NAME_WITH_VERSION) self.minsize(*RC_WIN_SIZE) self.bind_all("", self._on_key_release, "+") - @staticmethod - def _on_key_release(event): + def _on_key_release(self, event): ctrl = (event.state & 0x4) != 0 + shift = (event.state & 0x1) != 0 - if event.keycode == ord('X') and ctrl and event.keysym.lower() != "x": - event.widget.event_generate("<>") - - if event.keycode == ord('V') and ctrl and event.keysym.lower() != "v": - event.widget.event_generate("<>") + keycode = event.keycode + widget = event.widget + keysym = event.keysym.upper() - if event.keycode == ord('C') and ctrl and event.keysym.lower() != "c": - event.widget.event_generate("<>") + key_actions = { + ord('X'): "<>", + ord('V'): "<>", + ord('C'): "<>", + ord('A'): "<>", + # ord('Z'): "<>" if not shift else "<>", + # ord('Y'): "<>", + } - if event.keycode == ord('A') and ctrl and event.keysym.lower() != "c": - event.widget.event_generate("<>") + if ctrl and keycode in key_actions and keysym == '??': + self.after(0, lambda: widget.event_generate(key_actions[keycode])) + # return 'break' def _center_window(self): x = (self.winfo_screenwidth() // 2) - (RC_WIN_SIZE[0] // 2) @@ -82,27 +71,31 @@ def _center_window(self): self.geometry(f"{RC_WIN_SIZE[0]}x{RC_WIN_SIZE[1]}+{x}+{y}") def _create_widgets(self): - self._create_tooltips() self._create_tabs() - self._create_buttons() + self._create_tooltips() + self._create_actions() def _create_tooltips(self): - self._tooltip = Tooltip(self, text=self._DEFAULT_TOOLTIP) - self._tooltip.pack(fill=tk.X, expand=False, side=tk.TOP, padx=UI_PADDING, pady=(UI_PADDING, 0)) + self._tooltip = Tooltip(self, text=self._tabs.get_default_tooltip()) def _create_tabs(self): self._tabs = tabs = SettingsTabs(self) tabs.load_data() - tabs.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_buttons_state(), "+") - tabs.pack(fill=tk.BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) + tabs.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_actions_state(), "+") - def _create_buttons(self): - self._buttons = buttons = SettingsButtons(self) + def _create_actions(self): + self._actions = actions = SettingsActions(self) - buttons.pack(fill=tk.X, padx=UI_PADDING, pady=(0, UI_PADDING)) - buttons.bind(ActionEvents.SAVE, lambda _: self._tabs.save_data(), "+") + actions.bind(ActionEvents.APPLY, lambda _: self._tabs.save_data(), "+") + actions.bind(ActionEvents.APPLY_N_CLOSE, lambda _: self._apply_and_save(), "+") + actions.bind(ActionEvents.CONFIG, lambda _: open_config_file(), "+") + actions.bind(ActionEvents.LOG, lambda _: open_log_file(), "+") - self._update_buttons_state() + self._update_actions_state() + + def _apply_and_save(self): + self._tabs.save_data() + self._on_window_closing() def _on_window_closing(self): has_error = self._tabs.has_error() @@ -111,14 +104,14 @@ def _on_window_closing(self): if has_error: message = ("There are errors in the rules, and they can't be saved. " "Do you want to DISCARD them and exit?") - result = messagebox.askyesno(f"{SETTINGS_TITLE} - {APP_NAME_WITH_VERSION}", message) + result = messagebox.askyesno(f"{APP_NAME_WITH_VERSION}", message) if not result: return else: message = ("There are unsaved changes. " "Do you want to save them before exiting?") - result = messagebox.askyesnocancel(f"{SETTINGS_TITLE} - {APP_NAME_WITH_VERSION}", message) + result = messagebox.askyesnocancel(f"{APP_NAME_WITH_VERSION}", message) if result is None: return @@ -130,76 +123,112 @@ def _on_window_closing(self): message = ( f"There are errors in the rules, and they must be corrected before the application can work properly. " f"Do you still want to close the {SETTINGS_TITLE}?") - result = messagebox.askyesno(f"{SETTINGS_TITLE} - {APP_NAME_WITH_VERSION}", message) + result = messagebox.askyesno(f"{APP_NAME_WITH_VERSION}", message) if not result: return self.destroy() - def _update_buttons_state(self, _=None): + def _update_actions_state(self, _=None): tabs = self._tabs - buttons = self._buttons + actions = self._actions - buttons.save["state"] = tk.NORMAL if tabs.has_unsaved_changes() and not tabs.has_error() else tk.DISABLED + actions.apply["state"] = NORMAL if tabs.has_unsaved_changes() and not tabs.has_error() else DISABLED + actions.apply_n_close["state"] = actions.apply["state"] def _setup_tooltips(self): - self._setup_tooltip(self._buttons.save, "__Adds__ a rule after the current") + self._setup_tooltip(self._actions.open_config) + self._setup_tooltip(self._actions.open_log) + self._setup_tooltip(self._actions.apply) + self._setup_tooltip(self._actions.apply_n_close) tabs = self._tabs tabs.bind("", self._set_tooltip_by_tab, "+") - tabs.bind("", lambda _: self._tooltip.set(self._DEFAULT_TOOLTIP), "+") + tabs.bind("", lambda _: self._tooltip.set(self._tabs.get_default_tooltip()), "+") for tab in tabs.frames(): - if not isinstance(tab, BaseRulesTab): - continue - - btns = tab.buttons - self._setup_tooltip(btns.add, "__Adds__ a rule after the current") - self._setup_tooltip(btns.delete, "__Deletes__ the selected rules") - self._setup_tooltip(btns.move_up, "__Moves__ the current rule __up__") - self._setup_tooltip(btns.move_down, "__Moves__ the current rule __down__") - - rules_list = tab.rules_list - rules_list.bind("", self._set_tooltip_by_tree, "+") - rules_list.bind(EditableTreeviewEvents.START_EDIT_CELL, self._setup_tooltip_cell_editor, "+") - rules_list.error_icon_created = lambda icon, tooltip: self._setup_tooltip(icon, tooltip, True, False) - self._setup_tooltip(rules_list, "", enter=False) - - def _setup_tooltip(self, widget, text: str, error: bool = False, leave: bool = True, enter: bool = True): + tab: BaseRulesTab | ProcessListTab + actions = tab.actions + + if isinstance(tab, BaseRulesTab): + self._setup_tooltip(actions.add) + self._setup_tooltip(actions.delete) + self._setup_tooltip(actions.move_up) + self._setup_tooltip(actions.move_down) + + rules_list = tab.rules_list + rules_list.bind("", self._set_tooltip_by_tree, "+") + rules_list.bind(EditableTreeviewEvents.START_EDIT_CELL, self._setup_tooltip_cell_editor, "+") + rules_list.error_icon_created = lambda icon, tooltip: self._setup_tooltip(icon, tooltip, True, False) + self._setup_tooltip(rules_list, "", enter=False) + + if isinstance(tab, ProcessListTab): + self._setup_tooltip(actions.refresh) + self._setup_tooltip(actions.filterByType) + self._setup_tooltip(actions.search) + + process_list = tab.process_list + process_list.bind("", self._set_tooltip_by_tree, "+") + self._setup_tooltip(process_list, "", enter=False) + + def _setup_tooltip(self, widget, text: str = None, error: bool = False, leave: bool = True, enter: bool = True): + if hasattr(widget, 'description') and text is None: + text = widget.description + + if text is None: + raise ValueError("text is None") + if enter: def on_enter(_): self._tooltip.set(text, error) - widget.bind("", on_enter) + widget.bind("", on_enter, '+') if leave: def on_leave(_): - self._tooltip.set(self._DEFAULT_TOOLTIP) + self._tooltip.set(self._tabs.get_default_tooltip()) - widget.bind("", on_leave) + widget.bind("", on_leave, '+') def _set_tooltip_by_tree(self, event): if not event or not isinstance(event.widget, ttk.Treeview): return - tab = self._tabs.current_tab() - cell = tab.rules_list.get_cell_info(event) + tab: BaseTab = self._tabs.current_tab() + treeview = None + + if isinstance(tab, BaseRulesTab): + treeview = tab.rules_list - if cell: - self._tooltip.set(tab.rule_type.clazz.model_fields[cell.column_name].description) + if isinstance(tab, ProcessListTab): + treeview = tab.process_list + + if treeview is None: + raise ValueError(type(tab)) + + cell = treeview.get_cell_info_by_event(event) + + if cell.region == 'heading': + self._tooltip.set(tab.model.model_fields[cell.column_name].description) + else: + self._tooltip.set(self._tabs.get_default_tooltip()) def _setup_tooltip_cell_editor(self, _=None): tab = self._tabs.current_tab() + + if not isinstance(tab, BaseRulesTab): + return + rules_list = tab.rules_list - cell = rules_list.current_cell() + editor = rules_list.editor() - if not cell: + if not editor: return self._setup_tooltip( - rules_list.popup(), - tab.rule_type.clazz.model_fields[cell.column_name].description, + rules_list.editor(), + tab.rule_type.clazz.model_fields[editor.cell.column_name].description, leave=False ) @@ -207,36 +236,73 @@ def _set_tooltip_by_tab(self, event): try: tab_index = event.widget.index("@%d,%d" % (event.x, event.y)) except: - self._tooltip.set(self._DEFAULT_TOOLTIP) + self._tooltip.set(self._tabs.get_default_tooltip()) return tabs = self._tabs tab: BaseRulesTab = tabs.nametowidget(tabs.tabs()[tab_index]) self._tooltip.set(tab.description()) + def _pack(self): + self._tooltip.pack(fill=X, expand=False, side=TOP, padx=UI_PADDING, pady=(UI_PADDING, 0)) + self._tabs.pack(fill=BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) + self._actions.pack(fill=X, padx=UI_PADDING, pady=(0, UI_PADDING)) -is_settings_open = False +class SettingsActions(ttk.Frame): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._setup_btn() -def open_settings(): - global is_settings_open + def _setup_btn(self): + self.open_config = open_config = ExtendedButton( + self, + text=f"{OPEN_CONFIG_LABEL}", + event=ActionEvents.CONFIG, + image=load_img(file=UI_CONFIG), + description="**Opens** the __config file__." + ) + self.open_log = open_log = ExtendedButton( + self, + text=f"{OPEN_LOG_LABEL}", + event=ActionEvents.LOG, + image=load_img(file=UI_LOG), + description="**Opens** the __log file__." + ) + + self.apply = apply = ExtendedButton( + self, + text="Apply", + event=ActionEvents.APPLY, + image=load_img(file=UI_SAVE), + description="**Applies** the __settings__." + ) + + self.apply_n_close = apply_n_close = ExtendedButton( + self, + text="Apply & Close", + event=ActionEvents.APPLY_N_CLOSE, + image=load_img(file=UI_SAVE), + description="**Applies and Сloses** the __settings__." + ) + + open_config.pack(**LEFT_PACK) + open_log.pack(**LEFT_PACK) + apply_n_close.pack(**RIGHT_PACK) + apply.pack(**RIGHT_PACK) + + +def open_settings(): def settings(): - global is_settings_open try: - is_settings_open = True - app = Settings() app.mainloop() except: LOG.exception(f"An unexpected error occurred in the {SETTINGS_TITLE} of {APP_NAME}.") show_settings_error_message() - finally: - is_settings_open = False - if not is_settings_open: - thread = Thread(target=settings) - thread.start() + TaskScheduler.schedule_task(THREAD_SETTINGS, settings) def show_settings_error_message(): diff --git a/src/ui/tray.py b/src/ui/tray.py index 488938b..9d938db 100644 --- a/src/ui/tray.py +++ b/src/ui/tray.py @@ -1,4 +1,3 @@ -import os import webbrowser import pystray @@ -7,11 +6,11 @@ from pystray._win32 import Icon from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME -from constants.files import CONFIG_FILE_NAME, LOG_FILE_NAME from constants.resources import APP_ICON -from constants.ui import SETTINGS_TITLE +from constants.ui import OPEN_LOG_LABEL, OPEN_CONFIG_LABEL from constants.updates import UPDATE_URL from ui.settings import open_settings +from util.files import open_log_file, open_config_file from util.messages import yesno_error_box, show_error, show_info from util.startup import toggle_startup, is_in_startup from util.updates import check_latest_version @@ -57,18 +56,11 @@ def init_tray() -> Icon: image: Image = Image.open(APP_ICON) menu: tuple[MenuItem, ...] = ( - MenuItem(APP_NAME_WITH_VERSION, None, enabled=False), + MenuItem(APP_NAME_WITH_VERSION, lambda item: open_settings(), default=True), Menu.SEPARATOR, - MenuItem(SETTINGS_TITLE, lambda item: open_settings(), default=True), - Menu.SEPARATOR, - - MenuItem('Open config file', lambda item: os.startfile(CONFIG_FILE_NAME)), - MenuItem( - 'Open log file', - lambda item: os.startfile(LOG_FILE_NAME), - visible=lambda item: os.path.isfile(LOG_FILE_NAME) - ), + MenuItem(OPEN_CONFIG_LABEL, lambda _: open_config_file()), + MenuItem(OPEN_LOG_LABEL, lambda _: open_log_file()), Menu.SEPARATOR, MenuItem( diff --git a/src/ui/widget/common/button.py b/src/ui/widget/common/button.py index c6ecdb5..418435a 100644 --- a/src/ui/widget/common/button.py +++ b/src/ui/widget/common/button.py @@ -1,19 +1,48 @@ -from tkinter import ttk, LEFT +from tkinter import ttk, LEFT, PhotoImage +from typing import Optional -from constants.ui import BUTTON_SIZE +from constants.ui import UI_PADDING +from util.ui import get_button_font, single_font_width -class IconedButton(ttk.Button): - def __init__(self, *args, image=None, compound=LEFT, width=BUTTON_SIZE, **kwargs): - self._image = image - super().__init__(*args, image=image, compound=compound, width=width, **kwargs) +class ExtendedButton(ttk.Button): - def config(self, *args, **kwargs): - image = kwargs.get('image') + def __init__( + self, + master, + *args, + event: str, + text: Optional[str] = None, + width: Optional[int] = None, + image=None, + description=None, + compound=None, + **kwargs + ): + self._font = get_button_font() + self.description = description - if image is not None: - self._image = image + if compound is None: + compound = LEFT if text else None - super().config(*args, **kwargs) + super().__init__( + master, + *args, + text=f" {text}" if image and text else text, + command=lambda: master.event_generate(event), + image=image, + compound=compound, + width=self._calc_width(text, image, width), + **kwargs + ) - configure = config + def _calc_width(self, text: Optional[str], image: Optional[PhotoImage], width: Optional[int]) -> Optional[int]: + if width: + return width + + width_image = getattr(image, 'width', lambda: 0)() + + if not text: + return None + + return int((self._font.measure(text) + width_image + UI_PADDING) / single_font_width()) + 1 diff --git a/src/ui/widget/common/combobox.py b/src/ui/widget/common/combobox.py new file mode 100644 index 0000000..f9a76cc --- /dev/null +++ b/src/ui/widget/common/combobox.py @@ -0,0 +1,66 @@ +from enum import Enum +from tkinter import ttk, Tk +from typing import Optional + +from util.ui import get_default_font, single_font_width +from util.utils import extract_type, get_values_from_enum + + +class EnumCombobox(ttk.Combobox): + def __init__( + self, + master, + annotation: type[Enum] | Optional[type[Enum]], + description=None, + auto_width=True, + *args, + **kwargs + ): + self.description = description + self._font = get_default_font() if auto_width else None + self._enum_type = extract_type(annotation) + self._values = get_values_from_enum(annotation) + + super().__init__( + master, + values=self._values, + width=self._calculate_max_width() if auto_width else None, + *args, + **kwargs + ) + + def get_enum_value(self) -> Optional[Enum]: + selected_value = self.get() + + if selected_value: + return self._enum_type(selected_value) + + return None + + def _calculate_max_width(self): + return max(map(self._font.measure, self._values)) // single_font_width() + 1 + + +if __name__ == "__main__": + # Пример использования + + class MyEnum(str, Enum): + OPTION1 = "Option 1" + OPTION2 = "Option 2" + OPTION3 = "Option 3" + + + root = Tk() + + combobox = EnumCombobox(root, MyEnum, state="readonly") + combobox.pack(padx=10, pady=10) + + + def on_select(event): + enum_value = combobox.get_enum_value() + print(f"Selected Enum: {enum_value}") + + + combobox.bind("<>", on_select, '+') + + root.mainloop() diff --git a/src/ui/widget/common/entry.py b/src/ui/widget/common/entry.py new file mode 100644 index 0000000..fb9f3ee --- /dev/null +++ b/src/ui/widget/common/entry.py @@ -0,0 +1,43 @@ +from tkinter import END, Entry + + +class ExtendedEntry(Entry): + def __init__(self, master=None, placeholder=None, color='grey', description=None, *args, **kwargs): + super().__init__( + master, + *args, + **kwargs + ) + + self.description = description + self._placeholder = placeholder + + if placeholder is not None: + self._placeholder_color = color + self._default_fg_color = self['fg'] + + self.bind("", self._focus_in, '+') + self.bind("", self._focus_out, '+') + + self._focus_out() + + def _set_placeholder(self): + self.insert(0, self._placeholder) + self['fg'] = self._placeholder_color + + def _focus_in(self, *args): + if super().get() == self._placeholder: + self.delete(0, END) + self['fg'] = self._default_fg_color + + def _focus_out(self, *args): + if not self.get(): + self._set_placeholder() + + def get(self): + current_text = super().get() + + if self._placeholder is not None and current_text == self._placeholder: + return "" + else: + return current_text diff --git a/src/ui/widget/common/label.py b/src/ui/widget/common/label.py index 91aea47..70ce738 100644 --- a/src/ui/widget/common/label.py +++ b/src/ui/widget/common/label.py @@ -1,18 +1,16 @@ import re -import tkinter as tk -from tkinter import font -from tkinter.ttk import Label +from tkinter import font, END, Text, ttk, Label from util.ui import get_parent_with_bg, get_label_font -class WrappingLabel(tk.Label): +class WrappingLabel(Label): def __init__(self, master=None, **kwargs): - tk.Label.__init__(self, master, **kwargs) + Label.__init__(self, master, **kwargs) self.bind('', lambda e: self.config(wraplength=self.winfo_width()), '+') -class RichLabel(tk.Text): +class RichLabel(Text): def __init__(self, *args, text="", textvariable=None, **kwargs): kwargs.setdefault("borderwidth", 0) kwargs.setdefault("relief", "flat") @@ -84,7 +82,7 @@ def _on_var_changed(self, *args): def _on_text_changed(self, event): if self._textvariable: - self._textvariable.set(self.get("1.0", tk.END)) + self._textvariable.set(self.get("1.0", END)) def config(self, **kwargs): text = kwargs.pop('text', None) @@ -96,7 +94,7 @@ def config(self, **kwargs): super().config(**kwargs) def _set_text(self, text): - self.delete("1.0", tk.END) + self.delete("1.0", END) tokens = self._tokenize(text) pos = "1.0" @@ -156,9 +154,8 @@ def configure(self, **kwargs): return self.config(**kwargs) -class Image(Label): +class Image(ttk.Label): def __init__(self, *args, image=None, **kwargs): - self._image = image super().__init__(*args, image=image, **kwargs) def config(self, *args, **kwargs): diff --git a/src/ui/widget/common/treeview/editable.py b/src/ui/widget/common/treeview/editable.py index b499639..4650d42 100644 --- a/src/ui/widget/common/treeview/editable.py +++ b/src/ui/widget/common/treeview/editable.py @@ -1,11 +1,14 @@ -import tkinter as tk -from dataclasses import dataclass -from tkinter import ttk -from typing import Optional, Literal, List +from enum import Enum +from tkinter import END, BOTH, Widget +from typing import Optional, Literal from constants.ui import EditableTreeviewEvents, ScrollableTreeviewEvents +from ui.widget.common.combobox import EnumCombobox +from ui.widget.common.entry import ExtendedEntry +from ui.widget.common.treeview.extended import CellInfo, ExtendedTreeview, RegionType from ui.widget.common.treeview.scrollable import ScrollableTreeview from util.ui import full_visible_bbox +from util.utils import extract_type ColumnType = Literal["text", "list"] @@ -15,82 +18,67 @@ "center": "center" } -@dataclass(frozen=True) -class CellInfo: - column_id: str - row_id: str - column_name: str - value: str - values: List[str] - type: ColumnType - class CellEditor: def __init__( self, - master, - cell_info: CellInfo, - *args, - **kwargs + master: ExtendedTreeview, + cell_info: CellInfo ): - self._master = master - self._cell = cell_info - self._input = self._setup_widgets(master, *args, **kwargs) + self.cell = cell_info + self.widget = self._setup_widgets(master) - def _setup_widgets(self, master, *args, **kwargs): + def _setup_widgets(self, master): def on_change(_): self.event_generate(EditableTreeviewEvents.SAVE_CELL) def on_escape(_): self.event_generate(EditableTreeviewEvents.ESCAPE) - column_settings = self._master.column(self._cell.column_id) + cell = self.cell + column_settings = master.column(cell.column_id) + annotation = column_settings.get('type') justify = _justify_mapping[column_settings.get('anchor', 'center')] - if self._cell.type == "text": - entry_popup = ttk.Entry(master, *args, justify=justify, **kwargs) - entry_popup.insert(0, self._cell.value) - entry_popup.select_range(0, tk.END) - entry_popup.bind("", on_change, '+') - else: - entry_popup = ttk.Combobox( + if issubclass(extract_type(annotation), Enum): + editor = EnumCombobox( master, - *args, - values=self._cell.values, + annotation, justify=justify, state="readonly", - **kwargs + auto_width=False ) - entry_popup.set(self._cell.value) - entry_popup.bind("<>", on_change, '+') + editor.set(cell.value) + editor.bind("<>", on_change, '+') + else: + editor = ExtendedEntry(master, justify=justify) + editor.insert(0, cell.value) + editor.select_range(0, END) + editor.bind("", on_change, '+') - entry_popup.bind("", on_change, '+') - entry_popup.bind("", on_escape, '+') - entry_popup.pack(fill=tk.BOTH) - entry_popup.focus_force() + editor.bind("", on_change, '+') + editor.bind("", on_escape, '+') + editor.pack(fill=BOTH) - return entry_popup + return editor def get(self): - return self._input.get().strip() + return self.widget.get().strip() def __getattr__(self, name): - return getattr(self._input, name) + return getattr(self.widget, name) class EditableTreeview(ScrollableTreeview): - _types: dict[str, ColumnType] = {} - _values: dict[str, List[str]] = {} - _popup: Optional[CellEditor] = None - _cell: Optional[CellInfo] = None - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.bind("", self._save_and_destroy_popup, '+') + self._editor: Optional[Widget | CellEditor] = None + + self.bind("", self._save_and_destroy_editor, '+') self.bind("", self._on_dbl_click, '+') - self.bind(ScrollableTreeviewEvents.SCROLL, self._place_popup, '+') - self.bind("", lambda _: self.after(1, self._place_popup), '+') + self.bind(ScrollableTreeviewEvents.SCROLL, self._place_editor, '+') + self.bind("", lambda _: self.after(1, self._place_editor), '+') def insert(self, parent, index, iid=None, **kw): result = super().insert(parent, index, iid, **kw) @@ -115,92 +103,71 @@ def move(self, item, parent, index): self.event_generate(EditableTreeviewEvents.CHANGE) return result - def column_type(self, column: str, ctype: ColumnType): - self._types[column] = ctype - - def column_values(self, column: str, values: List[str]): - self._values[column] = values - - def get_cell_info(self, event): - row_id, column_id = self.identify_row(event.y), self.identify_column(event.x) - return self._get_cell_info(row_id, column_id) - - def _get_cell_info(self, row_id, column_id): - try: - column_name = self.column(column_id)["id"] - cell_value = self.set(row_id, column_id) - values = self._values.get(column_name, []) - cell_type = self._types.get(column_name, "text") - - return CellInfo( - column_id, - row_id, - column_name, - cell_value, - values, - cell_type - ) - except: - return None - - def current_cell(self): - return self._cell - - def popup(self): - return self._popup + def editor(self) -> CellEditor: + return self._editor def _on_dbl_click(self, event): - row_id, column_id = self.identify_row(event.y), self.identify_column(event.x) - self.edit_cell(row_id, column_id) - - def _create_editor(self): - if not self._cell or not self._cell.row_id or not self._cell.column_id or self._cell.column_id == "#0": + self.edit_cell( + self.identify_column(event.x), + self.identify_row(event.y), + self.identify_region(event.x, event.y) + ) + + def _create_editor(self, cell): + if cell.region != 'cell': return - self._popup = entry_popup = CellEditor(self, self._cell) + self._editor = editor = CellEditor(self, cell) - entry_popup.bind(EditableTreeviewEvents.SAVE_CELL, self._save_and_destroy_popup, '+') - entry_popup.bind(EditableTreeviewEvents.ESCAPE, self._destroy_editor, '+') - entry_popup.bind("", self._on_popup_destroy, '+') + editor.bind(EditableTreeviewEvents.SAVE_CELL, self._save_and_destroy_editor, '+') + editor.bind(EditableTreeviewEvents.ESCAPE, self._destroy_editor, '+') + editor.bind("", self._on_editor_destroy, '+') - self._place_popup() + self._place_editor() self.event_generate(EditableTreeviewEvents.START_EDIT_CELL) - def _place_popup(self, _=None): - if not self._popup: + def _place_editor(self, _=None): + editor = self._editor + + if not editor: return - bbox = full_visible_bbox(self, self._cell.row_id, self._cell.column_id) + cell = editor.cell + bbox = full_visible_bbox(self, cell.row_id, cell.column_id) if bbox: x, y, width, height = bbox - self._popup.place(x=x, y=y, width=width, height=height) + editor.place(x=x, y=y, width=width, height=height) + editor.after(0, lambda: editor.focus_force()) # fixing focus_force not working from time to time else: - self._popup.place_forget() + editor.place_forget() - def _save_and_destroy_popup(self, _=None): - if self._popup: - self._save_cell_changes() - self._destroy_editor() + def _save_and_destroy_editor(self, _=None): + self._save_cell_changes() + self._destroy_editor() def _destroy_editor(self, _=None): - if self._popup: - self._popup.destroy() + if self._editor: + self._editor.destroy() def _save_cell_changes(self): - new_value = self._popup.get() + editor = self._editor + + if not editor: + return + + new_value = editor.get() + cell = editor.cell - if self._cell.value != new_value: - self.set(self._cell.row_id, self._cell.column_id, new_value) + if cell.value != new_value: + self.set(cell.row_id, cell.column_id, new_value) - def _on_popup_destroy(self, _=None): - self._popup = None - self._cell = None + def _on_editor_destroy(self, _=None): + self._editor = None - def edit_cell(self, row_id, column_id): + def edit_cell(self, column_id, row_id, region: RegionType): self._destroy_editor() - self._cell = self._get_cell_info(row_id, column_id) - self._create_editor() + self._create_editor(self.get_cell_info_by_ids(column_id, row_id, region)) def select_all_rows(self): items = self.get_children() @@ -239,17 +206,17 @@ def move_rows_down(self): self.selection_set(selected_items) - def add_row(self, values=[]): + def add_row(self, values=None): selected_items = self.selection() if selected_items: - selected_item = selected_items[-1] + selected_item = selected_items[0] index = self.index(selected_item) - self.insert('', index + 1, values=values) - self.selection_set(self.get_children()[index + 1]) + self.insert('', index, values=values or []) + self.selection_set(self.get_children()[index]) else: - self.insert('', tk.END, values=values) + self.insert('', 0, values=values or []) def delete_selected_rows(self): selected_items = self.selection() diff --git a/src/ui/widget/common/treeview/extended.py b/src/ui/widget/common/treeview/extended.py new file mode 100644 index 0000000..a8199e8 --- /dev/null +++ b/src/ui/widget/common/treeview/extended.py @@ -0,0 +1,152 @@ +from dataclasses import dataclass +from functools import lru_cache +from tkinter import ttk +from typing import Optional, Literal, Any + +from pydantic.config import JsonDict + +from constants.ui import COLUMN_TITLE_PADDING +from util.ui import get_default_font +from util.utils import get_values_from_enum + +type RegionType = Literal['heading', 'separator', 'tree', 'cell', 'nothing'] + + +@dataclass(frozen=True) +class CellInfo: + column_id: Optional[str] + row_id: Optional[str] + column_name: Optional[str] + value: str + region: RegionType + + +class ExtendedTreeview(ttk.Treeview): + def __init__(self, *args, hand_on_title: bool = False, **kwargs): + super().__init__(*args, **kwargs) + + self._font = get_default_font() + self._types: dict[str, type] = {} + self._width_set: dict[str, bool] = {} + + self._setup_font() + self.bind('', self._calculate_columns_width, '+') + self.bind('', lambda _: self.clear_selection()) + + if hand_on_title: + self.bind("", self._on_motion, '+') + + def _setup_font(self): + ttk.Style().configure('Treeview', rowheight=self._font.metrics("linespace") + 8) + + def _on_motion(self, event): + region = self.identify_region(event.x, event.y) + if region == "heading": + self.configure(cursor="hand2") + else: + self.configure(cursor="") + + def clear(self): + self.delete(*self.get_children()) + + def clear_selection(self): + self.selection_remove(self.selection()) + + def get_cell_info_by_event(self, event) -> Optional[CellInfo]: + # noinspection PyTypeChecker + return self.get_cell_info_by_ids( + self.identify_column(event.x), + self.identify_row(event.y), + self.identify_region(event.x, event.y) + ) + + def get_cell_info_by_ids(self, column_id, row_id, region: RegionType) -> Optional[CellInfo]: + if column_id == '': + column_id = None + + if row_id == '': + row_id = None + + # noinspection PyTypeChecker + column_name: Optional[str] = self.column(column_id, 'id') if column_id else None + cell_value: str = self.set(row_id, column_id) if column_id and row_id else '' + + if column_name == '': + column_name = None + + if cell_value is None: + cell_value = '' + + return CellInfo( + column_id, + row_id, + column_name, + cell_value, + region + ) + + def column(self, column_id, option=None, **kw): + column_name = super().column(column_id, 'id') + type_field = 'type' + + self._width_set[column_name] = 'width' in kw or 'minwidth' in kw or self._width_set.get(column_name, False) + + if option == type_field: + return self._types.get(column_name) + + if type_field in kw: + self._types[column_name] = kw.pop(type_field) + + if not kw: + return + + result = super().column(column_id, option, **kw) + + if isinstance(result, dict): + column_type = self._types.get(column_name) + + if column_type: + result[type_field] = column_type + + return result + + def _calculate_columns_width(self, _=None): + for column_name in self["columns"]: + if self._width_set.get(column_name, False): + continue + + width = self._calculate_max_width(column_name) + self.column(column_name, width=width, minwidth=width) + + @lru_cache + def _calculate_max_width(self, column_name): + column_name = super().column(column_name, 'id') + + values = get_values_from_enum(self._types.get(column_name)) + values.append(self.heading(column_name)['text']) + + return max(map(self._font.measure, values)) + COLUMN_TITLE_PADDING + + def force_update_columns_width(self): + for column in self["columns"]: + self.column(column, width=self.column(column, 'width')) + + def configure(self, dct: dict[str, Any] | None = None, *args, **kwargs): + result = super().configure(dct, *args, **kwargs) + + if dct and 'displaycolumns' in dct: + self.force_update_columns_width() + + return result + + def as_dict(self, row_id) -> JsonDict: + column_names = self["columns"] + values = self.item(row_id, 'values') + + return { + key: value for key, value in zip(column_names, values) + if value and value.strip() + } + + def as_list_of_dict(self) -> list[JsonDict]: + return [self.as_dict(row_id) for row_id in self.get_children()] diff --git a/src/ui/widget/common/treeview/pydantic.py b/src/ui/widget/common/treeview/pydantic.py new file mode 100644 index 0000000..935f1de --- /dev/null +++ b/src/ui/widget/common/treeview/pydantic.py @@ -0,0 +1,98 @@ +import json +from collections import OrderedDict +from tkinter import END +from typing import Any, Optional, Iterable + +from pydantic import BaseModel, ValidationError +from pydantic.config import JsonDict +from pydantic_core import PydanticUndefined + +from ui.widget.common.treeview.extended import ExtendedTreeview + +_anchor_mapping = { + "left": "w", + "center": "center", + "right": "e" +} + + +class PydanticTreeviewLoader: + def \ + __init__(self, treeview: ExtendedTreeview, model: type[BaseModel]): + self._treeview = treeview + self._model = model + self._setup_columns() + + def _setup_columns(self): + treeview = self._treeview + model_fields = self._model.model_fields + + for column_name in treeview["columns"]: + field_info = model_fields.get(column_name) + + if field_info: + title = field_info.title or column_name + else: + raise RuntimeError("field_info is None") + + extra = field_info.json_schema_extra or dict() if field_info else dict() + + if extra.get('default_sort_column_ui', False) and hasattr(treeview, 'sort_column_name'): + treeview.sort_column_name(column_name) + + kw = { + 'anchor': _anchor_mapping[extra.get('justify_ui', 'center')], + 'stretch': extra.get('stretchable_column_ui', False), + 'type': field_info.annotation + } + + width = extra.get('width_ui', None) + if width: + kw['minwidth'] = kw['width'] = width + + treeview.heading(column_name, text=title) + treeview.column(column_name, **kw) + + def set_data(self, rules: Iterable[JsonDict | BaseModel]): + treeview = self._treeview + treeview.clear() + column_names = treeview["columns"] + + for rule in rules: + values = [ + getattr(rule, column_name, '') + if isinstance(rule, BaseModel) + else rule.get(column_name, '') + for column_name in column_names + ] + values = list(map(lambda value: '' if value is None or str(value) == '' else str(value), values)) + treeview.insert('', END, values=values) + + if hasattr(treeview, 'sort_column'): + treeview.sort_column() + + def has_changes(self): + pass + + def get_data(self) -> list[JsonDict]: + return self._treeview.as_list_of_dict() + + def get_error_if_available(self, row_id) -> Optional[tuple[Any, Any]]: + try: + # noinspection PyCallingNonCallable + self._model(**self._treeview.as_dict(row_id)) + return None + except ValidationError as e: + return row_id, json.loads(e.json()) + + def get_default_row(self) -> JsonDict: + treeview = self._treeview + result = OrderedDict() + model_fields = self._model.model_fields + + for column_name in treeview["columns"]: + field_info = model_fields.get(column_name) or '' + default_value = '' if field_info.default == PydanticUndefined else field_info.default or '' + result[column_name] = str(default_value) + + return result diff --git a/src/ui/widget/common/treeview/scrollable.py b/src/ui/widget/common/treeview/scrollable.py index 894c36e..6338db8 100644 --- a/src/ui/widget/common/treeview/scrollable.py +++ b/src/ui/widget/common/treeview/scrollable.py @@ -1,10 +1,10 @@ -import tkinter as tk -from tkinter import ttk +from tkinter import ttk, LEFT, BOTH, RIGHT, Y from constants.ui import ScrollableTreeviewEvents +from ui.widget.common.treeview.extended import ExtendedTreeview -class ScrollableTreeview(ttk.Treeview): +class ScrollableTreeview(ExtendedTreeview): def __init__(self, master=None, *args, **kwargs): self._frame = ttk.Frame(master) self._scrollbar = ttk.Scrollbar( @@ -17,16 +17,27 @@ def __init__(self, master=None, *args, **kwargs): self._scrollbar.configure(command=self._on_scrollbar) super().configure(yscrollcommand=self._on_scrollbar_mouse) - self._scrollbar.pack(side=tk.RIGHT, fill=tk.Y) - super().pack(fill=tk.BOTH, expand=True, side=tk.LEFT) + self._scrollbar.pack(side=RIGHT, fill=Y) + super().pack(fill=BOTH, expand=True, side=LEFT) - self.bind("<>", self.__on_select) + self.bind("<>", self.__on_select, '+') def on_scroll(self): pass + def _forward_geometry_options(self, method, *args, **kwargs): + geometry_options = ['anchor', 'expand', 'fill', 'in_', 'ipadx', 'ipady', 'padx', 'pady', 'side'] + frame_kwargs = {key: value for key, value in kwargs.items() if key in geometry_options} + other_kwargs = {key: value for key, value in kwargs.items() if key not in geometry_options} + + if frame_kwargs: + getattr(self._frame, method)(*args, **frame_kwargs) + + if other_kwargs: + getattr(super(ScrollableTreeview, self), method)(*args, **other_kwargs) + def pack_configure(self, *args, **kwargs): - self._frame.pack_configure(*args, **kwargs) + return self._forward_geometry_options('pack_configure', *args, **kwargs) def pack_forget(self): self._frame.pack_forget() @@ -43,7 +54,7 @@ def place_forget(self): def place_info(self): return self._frame.place_info() - pack = configure = config = pack_configure + pack = pack_configure forget = pack_forget info = pack_info diff --git a/src/ui/widget/common/treeview/sortable.py b/src/ui/widget/common/treeview/sortable.py new file mode 100644 index 0000000..ea4d7fc --- /dev/null +++ b/src/ui/widget/common/treeview/sortable.py @@ -0,0 +1,111 @@ +from tkinter import Tk, BOTH + +from ui.widget.common.treeview.scrollable import ScrollableTreeview + + +class SortableTreeview(ScrollableTreeview): + def __init__(self, master=None, *args, **kwargs): + super().__init__(master, *args, **kwargs, hand_on_title=True) + self._sort_column_name = None + self._sort_reverse = False + self._setup_sorting() + + def _setup_sorting(self): + for column_name in self["columns"]: + self.heading(column_name, command=lambda c=column_name: self._on_heading_click(c)) + + def _on_heading_click(self, column): + if self._sort_column_name == column: + self._sort_reverse = not self._sort_reverse + else: + self._sort_column_name = column + self._sort_reverse = False + + self.sort_column() + + def sort_column(self): + if not self._sort_column_name: + return + + column = self._sort_column_name + reverse = self._sort_reverse + + items = [(self._get_value_as_type(self.set(k, column)), k) for k in self.get_children()] + items.sort(key=lambda x: (isinstance(x[0], str), x[0]), reverse=reverse) + + for index, (_, k) in enumerate(items): + self.move(k, '', index) + + self._update_heading_text() + + @staticmethod + def _get_value_as_type(value): + if value.replace('.', '', 1).isdigit(): + return float(value) if '.' in value else int(value) + return value + + def _update_heading_text(self): + up = '⭡' + down = '⭣' + sort_symbol = up if self._sort_reverse else down + + for column_name in self["columns"]: + title = self.heading(column_name, 'text') + title = (title + .replace(up, '') + .replace(down, '') + .strip()) + + if column_name == self._sort_column_name: + title = f" {title} {sort_symbol}" + + self.heading(column_name, text=title) + + def sort_column_name(self, column_name): + self._sort_column_name = column_name + + +if __name__ == "__main__": + root = Tk() + treeview = SortableTreeview(root, columns=('Column1', 'Column2', 'Column3'), show='headings') + + data = [ + ('Apple', 3, 50), + ('1', 3, 50), + ('2', 3, 50), + ('Banana', 1, 30), + ('Cherry', 2, 40), + ('Date', 5, 25), + ('Elderberry', 10, 100), + ('Fig', 7, 45), + ('Grape', 12, 20), + ('Honeydew', 4, 60), + ('Indian Fig', 8, 70), + ('Jackfruit', 6, 150), + ('Kiwi', 9, 85), + ('Lemon', 13, 10), + ('Mango', 14, 200), + ('Nectarine', 11, 90), + ('Orange', 2, 40), + ('Papaya', 16, 120), + ('Quince', 15, 110), + ('Raspberry', 18, 35), + ('Strawberry', 19, 95), + ('Tangerine', 17, 55), + ('Ugli Fruit', 21, 130), + ('Vanilla', 22, 300), + ('Watermelon', 20, 40), + ('Xigua', 23, 80), + ('Yellow Passion Fruit', 24, 75), + ('Zucchini', 25, 15) + ] + + for item in data: + treeview.insert('', 'end', values=item) + + treeview.heading('Column1', text='Fruit Name') + treeview.heading('Column2', text='Quantity') + treeview.heading('Column3', text='Price') + + treeview.pack(fill=BOTH, expand=True) + root.mainloop() diff --git a/src/ui/widget/settings/settings_tabs.py b/src/ui/widget/settings/settings_tabs.py index d1eaca5..afd4574 100644 --- a/src/ui/widget/settings/settings_tabs.py +++ b/src/ui/widget/settings/settings_tabs.py @@ -4,11 +4,18 @@ from constants.app_info import APP_NAME_WITH_VERSION from constants.log import LOG from service.config_service import ConfigService -from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab +from ui.widget.settings.tabs.base_tab import BaseTab +from ui.widget.settings.tabs.process_list import ProcessListTab from ui.widget.settings.tabs.rules.rules_tab import ServiceRulesTab, ProcessRulesTab class SettingsTabs(ttk.Notebook): + _DEFAULT_TOOLTIP = ( + "To add a new rule, click the **Add** button.\n" + "To edit a rule, **double-click** on the corresponding cell.\n" + "Use the **context menu** for additional actions." + ) + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -16,10 +23,15 @@ def __init__(self, *args, **kwargs): self._create_tabs() def _create_tabs(self): - ProcessRulesTab(self) - ServiceRulesTab(self) + process_rules_tab = ProcessRulesTab(self) + service_rules_tab = ServiceRulesTab(self) + process_list_tab = ProcessListTab(self, process_rules_tab.rules_list, service_rules_tab.rules_list) + + process_list_tab.add_tab_to_master() + process_rules_tab.add_tab_to_master() + service_rules_tab.add_tab_to_master() - def current_tab(self) -> BaseRulesTab: + def current_tab(self) -> BaseTab: current_index = self.index(self.select()) tab_id = self.tabs()[current_index] return self.nametowidget(tab_id) @@ -65,5 +77,8 @@ def save_data(self) -> bool: messagebox.showerror(f"Error Detected - {APP_NAME_WITH_VERSION}", "An error occurred while saving.") return False - def frames(self) -> list[BaseRulesTab]: + def frames(self) -> list[BaseTab]: return [self.nametowidget(tab_id) for tab_id in self.tabs()] + + def get_default_tooltip(self): + return self.current_tab().default_tooltip() diff --git a/src/ui/widget/settings/tabs/base_tab.py b/src/ui/widget/settings/tabs/base_tab.py index c6697c7..a271a60 100644 --- a/src/ui/widget/settings/tabs/base_tab.py +++ b/src/ui/widget/settings/tabs/base_tab.py @@ -8,9 +8,9 @@ def __init__(self, master: Notebook): super().__init__(master) self.master: Notebook = master - self.__icon_tab: PhotoImage = self.icon() - master.add(self, text=f" {self.title()} ", image=self.__icon_tab, compound=LEFT) + def add_tab_to_master(self): + self.master.add(self, text=f" {self.title()} ", image=self.icon(), compound=LEFT) @staticmethod @abstractmethod @@ -27,6 +27,11 @@ def title() -> str: def description() -> str: pass + @staticmethod + @abstractmethod + def default_tooltip() -> str: + pass + @abstractmethod def load_from_config(self, config: dict): pass diff --git a/src/ui/widget/settings/tabs/process_list.py b/src/ui/widget/settings/tabs/process_list.py new file mode 100644 index 0000000..177d7f2 --- /dev/null +++ b/src/ui/widget/settings/tabs/process_list.py @@ -0,0 +1,325 @@ +import textwrap +from tkinter import PhotoImage, ttk, X, BOTH, NORMAL, DISABLED, CENTER, Menu, LEFT, END +from tkinter.ttk import Notebook +from typing import Optional + +from constants.log import LOG +from constants.resources import UI_PROCESS_LIST, UI_REFRESH +from constants.threads import THREAD_PROCESS_LIST +from constants.ui import UI_PADDING, ActionEvents, LEFT_PACK, ADD_PROCESS_RULE_LABEL, ADD_SERVICE_RULE_LABEL +from enums.filters import FilterByProcessType +from enums.rules import RuleType +from enums.selector import SelectorType +from model.process import Process +from service.processes_info_service import ProcessesInfoService +from ui.widget.common.button import ExtendedButton +from ui.widget.common.combobox import EnumCombobox +from ui.widget.common.entry import ExtendedEntry +from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader +from ui.widget.common.treeview.sortable import SortableTreeview +from ui.widget.settings.tabs.base_tab import BaseTab +from ui.widget.settings.tabs.rules.rules_list import RulesList +from util.scheduler import TaskScheduler +from util.ui import load_img + + +class ProcessListTab(BaseTab): + @staticmethod + def default_tooltip() -> str: + return "Use the **context menu** to add a __process__ or __service__ as a rule." + + @staticmethod + def icon() -> PhotoImage: + return load_img(file=UI_PROCESS_LIST) + + @staticmethod + def title() -> str: + return 'Process List' + + @staticmethod + def description() -> str: + return ("Interface for **browsing** the list of active __processes__ and __services__ with the option to " + "**add** selected items to the rules configuration.") + + def __init__(self, master: Notebook, process_rules_list: RulesList, service_rules_list: RulesList): + self.model = Process + self.process_rules_list = process_rules_list + self.service_rules_list = service_rules_list + self._data: dict[int, Process] = {} + + super().__init__(master) + + self._setup_widgets() + self._loader = PydanticTreeviewLoader(self.process_list, self.model) + self._pack() + self._setup_context_menu() + + def _create_process_list(self): + columns = [key for key, field_info in self.model.model_fields.items() if not field_info.exclude] + + return SortableTreeview( + self, + show='headings', + columns=columns, + selectmode="browse" + ) + + def _create_progress_bar(self): + progress_bar = ttk.Progressbar(self.process_list, mode='indeterminate') + progress_bar.start() + return progress_bar + + def _create_actions(self): + actions = ProcessListTabActions(self) + actions.bind(ActionEvents.REFRESH, lambda _: self._refresh(), "+") + actions.bind(ActionEvents.FILTER_BY_TYPE, lambda _: self._update_process_list(), "+") + actions.bind(ActionEvents.SEARCH_CHANGE, lambda _: self._update_process_list(), "+") + + return actions + + def _pack(self): + self.actions.pack(fill=X, padx=UI_PADDING, pady=(UI_PADDING, 0)) + self.process_list.pack(fill=BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) + + def load_from_config(self, config: dict): + self._refresh() + + def _update_process_list(self): + filter_by_type = self.actions.filterByType.get_enum_value() + search_query = self.actions.search.get().strip().lower() + + data = [] + + for row in self._data.values(): + by_type = (filter_by_type == FilterByProcessType.ALL + or filter_by_type == FilterByProcessType.PROCESSES and row.service is None + or filter_by_type == FilterByProcessType.SERVICES and row.service is not None) + + by_search = not search_query or any( + value is not None and search_query in str(value).lower() + for value in row.model_dump().values() + ) + + if by_type and by_search: + data.append(row) + + self._set_display_columns(filter_by_type) + self._loader.set_data(data) + + def _set_display_columns(self, filter_by_type): + process_list = self.process_list + display_columns = list(process_list['columns']) + + if filter_by_type == FilterByProcessType.PROCESSES: + display_columns.remove('service_name') + + process_list['displaycolumns'] = display_columns + + def _refresh(self): + try: + self._refresh_state(True) + self.process_list.clear() + + def load(): + try: + def set_data(data): + try: + self._data = data + self._update_process_list() + except: + LOG.exception("Refresh error") + finally: + self._refresh_state(False) + + values = ProcessesInfoService.get_processes(False) + self.after(0, set_data, values) + except: + self._refresh_state(False) + LOG.exception("Refresh error") + + TaskScheduler.schedule_task(THREAD_PROCESS_LIST, load) + except: + self._refresh_state(False) + LOG.exception("Refresh error") + + def _refresh_state(self, lock: bool): + try: + actions = self.actions + actions.refresh['state'] = DISABLED if lock else NORMAL + actions.filterByType['state'] = DISABLED if lock else "readonly" + + progress_bar = self._progress_bar + if lock: + progress_bar.place(relx=0.5, rely=0.5, anchor=CENTER) + else: + progress_bar.place_forget() + except: + # When the window was closed while getting the process list + pass + + def save_to_config(self, config: dict): + pass + + def has_unsaved_changes(self) -> bool: + return False + + def has_error(self) -> bool: + return False + + def _setup_widgets(self): + self.process_list = self._create_process_list() + self._progress_bar = self._create_progress_bar() + self.actions = self._create_actions() + + def as_model(self, row_id) -> Process: + pid = int(self.process_list.as_dict(row_id)['pid']) + return self._data[pid] + + def _setup_context_menu(self): + process_list = self.process_list + + self._context_menu = context_menu = Menu(process_list, tearoff=0) + self._process_menu = Menu(context_menu, tearoff=0) + + context_menu.add_cascade( + label=ADD_PROCESS_RULE_LABEL, + menu=self._process_menu, + compound=LEFT + ) + + context_menu.add_command( + label=ADD_SERVICE_RULE_LABEL, + compound=LEFT, + command=lambda: self._add_rule(RuleType.SERVICE) + ) + + process_list.bind("", self._show_context_menu) + + def _show_context_menu(self, event): + context_menu = self._context_menu + menu = self._process_menu + process_list = self.process_list + row_id = process_list.identify_row(event.y) + + if row_id: + process_list.selection_set(row_id) + row = self.as_model(row_id) + exists = False + + menu.delete(0, END) + if row.process_name: + exists = True + menu.add_command( + label=f"By {SelectorType.NAME.value}: {row.process_name}", + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.NAME) + ) + + if row.bin_path: + exists = True + menu.add_command( + label=textwrap.shorten( + f"By {SelectorType.PATH.value}: {row.bin_path}", + width=128, + placeholder="..." + ), + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.PATH) + ) + + if row.cmd_line: + exists = True + menu.add_command( + label=textwrap.shorten( + f"By {SelectorType.CMDLINE.value}: {row.cmd_line}", + width=128, + placeholder="..." + ), + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.CMDLINE) + ) + + self._context_menu.entryconfig(ADD_PROCESS_RULE_LABEL, state=NORMAL if exists else DISABLED) + self._context_menu.entryconfig(ADD_SERVICE_RULE_LABEL, state=NORMAL if row.service else DISABLED) + + context_menu.post(event.x_root, event.y_root) + + def _add_rule(self, rule_type: RuleType, selector_type: Optional[SelectorType] = None): + if rule_type == RuleType.SERVICE and selector_type is not None: + raise ValueError("rule_type == RuleType.SERVICE and selector_type is not None") + + process_list = self.process_list + row_id = process_list.selection() + row = process_list.as_dict(row_id) + rules_list = None + + if rule_type == RuleType.PROCESS: + rules_list = self.process_rules_list + elif rule_type == RuleType.SERVICE: + rules_list = self.service_rules_list + + if rules_list is None: + raise ValueError("rules_list is None") + + rule_row = rules_list._loader.get_default_row() + + if selector_type is None: + rule_row['selector'] = row['service_name'] + else: + rule_row['selectorBy'] = str(selector_type) + + if selector_type == SelectorType.NAME: + rule_row['selector'] = row['process_name'] + elif selector_type == SelectorType.PATH: + rule_row['selector'] = row['bin_path'] + elif selector_type == SelectorType.CMDLINE: + rule_row['selector'] = row['cmd_line'] + + rules_list.add_row([*rule_row.values()]) + + +class ProcessListTabActions(ttk.Frame): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self._search_delay_timer = None + self._setup_btn() + + def _setup_btn(self): + self.refresh = refresh = ExtendedButton( + self, + # text="Refresh", + event=ActionEvents.REFRESH, + image=load_img(file=UI_REFRESH), + description="**Refreshes** the list of __processes__." + ) + + self.filterByType = filterByType = EnumCombobox( + self, + FilterByProcessType, + description="**Filters** processes by __type__.", + state="readonly" + ) + + self.search = search = ExtendedEntry( + self, + description="**Searches** processes by __name__ or __attribute__.", + placeholder="Search", + width=30 + ) + + search.bind('', self._on_search_key_release, '+') + + filterByType.set(FilterByProcessType.ALL) + filterByType.bind('<>', lambda _: self.event_generate(ActionEvents.FILTER_BY_TYPE), '+') + + search.pack(**LEFT_PACK) + filterByType.pack(**LEFT_PACK) + refresh.pack(**LEFT_PACK) + + def _on_search_key_release(self, _): + if self._search_delay_timer: + self.after_cancel(self._search_delay_timer) + + self._search_delay_timer = self.after(250, self._trigger_search_change_event) + + def _trigger_search_change_event(self): + self.event_generate(ActionEvents.SEARCH_CHANGE) + self._search_delay_timer = None diff --git a/src/ui/widget/settings/tabs/rules/base_rules_tab.py b/src/ui/widget/settings/tabs/rules/base_rules_tab.py index f0668ed..58f1637 100644 --- a/src/ui/widget/settings/tabs/rules/base_rules_tab.py +++ b/src/ui/widget/settings/tabs/rules/base_rules_tab.py @@ -1,52 +1,61 @@ -import tkinter as tk from abc import ABC -from tkinter import ttk, PhotoImage +from tkinter import ttk, X, BOTH, NORMAL, DISABLED from tkinter.ttk import Notebook from constants.resources import UI_ADD, UI_DELETE, UI_UP, UI_DOWN -from constants.ui import UI_PADDING, RulesListEvents, ActionEvents +from constants.ui import UI_PADDING, RulesListEvents, ActionEvents, LEFT_PACK from enums.rules import RuleType -from ui.widget.common.button import IconedButton +from ui.widget.common.button import ExtendedButton from ui.widget.settings.tabs.base_tab import BaseTab from ui.widget.settings.tabs.rules.rules_list import RulesList +from util.ui import load_img class BaseRulesTab(BaseTab, ABC): + @staticmethod + def default_tooltip() -> str: + return ( + "To add a new rule, click the **Add** button.\n" + "To edit a rule, **double-click** on the corresponding cell.\n" + "Use the **context menu** for additional actions." + ) + def __init__(self, master: Notebook, rule_type: RuleType): super().__init__(master) self.rule_type: RuleType = rule_type + self.model = rule_type.clazz self.rules_list = self._create_rules_list() - self.buttons = self._create_buttons() + self.actions = self._create_actions() - self._update_buttons_state() + self._update_actions_state() self._pack() def _pack(self): - self.buttons.pack(fill=tk.X, padx=UI_PADDING, pady=(UI_PADDING, 0)) - self.rules_list.pack(fill=tk.BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) + self.actions.pack(fill=X, padx=UI_PADDING, pady=(UI_PADDING, 0)) + self.rules_list.pack(fill=BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) def _create_rules_list(self): rules_list = RulesList(self.rule_type.clazz, self) - rules_list.bind("<>", lambda _: self._update_buttons_state(), "+") - rules_list.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_buttons_state(), "+") + rules_list.bind("<>", lambda _: self._update_actions_state(), "+") + rules_list.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_actions_state(), "+") return rules_list - def _create_buttons(self): - buttons = RulesTabButtons(self) + def _create_actions(self): + actions = RulesTabActions(self) - buttons.bind(ActionEvents.ADD, lambda _: self.rules_list.add_row(), "+") - buttons.bind(ActionEvents.DELETE, lambda _: self.rules_list.delete_selected_rows(), "+") - buttons.bind(ActionEvents.UP, lambda _: self.rules_list.move_rows_up(), "+") - buttons.bind(ActionEvents.DOWN, lambda _: self.rules_list.move_rows_down(), "+") + actions.bind(ActionEvents.ADD, lambda _: self.rules_list.add_row(), "+") + actions.bind(ActionEvents.DELETE, lambda _: self.rules_list.delete_selected_rows(), "+") + actions.bind(ActionEvents.UP, lambda _: self.rules_list.move_rows_up(), "+") + actions.bind(ActionEvents.DOWN, lambda _: self.rules_list.move_rows_down(), "+") - return buttons + return actions - def _update_buttons_state(self): + def _update_actions_state(self): rules_list = self.rules_list - buttons = self.buttons + actions = self.actions selected_items = rules_list.selection() if selected_items: @@ -56,13 +65,13 @@ def _update_buttons_state(self): last_index = rules_list.index(last_selected_item) total_items = len(rules_list.get_children()) - buttons.move_up["state"] = tk.NORMAL if first_index > 0 else tk.DISABLED - buttons.move_down["state"] = tk.NORMAL if last_index < total_items - 1 else tk.DISABLED + actions.move_up["state"] = NORMAL if first_index > 0 else DISABLED + actions.move_down["state"] = NORMAL if last_index < total_items - 1 else DISABLED else: - buttons.move_up["state"] = tk.DISABLED - buttons.move_down["state"] = tk.DISABLED + actions.move_up["state"] = DISABLED + actions.move_down["state"] = DISABLED - buttons.delete["state"] = tk.NORMAL if selected_items else tk.DISABLED + actions.delete["state"] = NORMAL if selected_items else DISABLED self.master.event_generate(RulesListEvents.UNSAVED_CHANGES_STATE) @@ -81,42 +90,45 @@ def has_error(self) -> bool: return self.rules_list.has_error() -class RulesTabButtons(ttk.Frame): +class RulesTabActions(ttk.Frame): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._setup_btn() def _setup_btn(self): - self.add = add = IconedButton( + self.add = add = ExtendedButton( self, - text=" Add", - command=lambda: self.event_generate(ActionEvents.ADD), - image=PhotoImage(file=UI_ADD) + text="Add", + event=ActionEvents.ADD, + image=load_img(file=UI_ADD), + description="**Adds** a rule before the current." ) - self.delete = delete = IconedButton( + self.delete = delete = ExtendedButton( self, - text=" Del", - command=lambda: self.event_generate(ActionEvents.DELETE), - image=PhotoImage(file=UI_DELETE) + text="Del", + event=ActionEvents.DELETE, + image=load_img(file=UI_DELETE), + description="**Deletes** the selected rules." ) - self.move_up = move_up = IconedButton( + self.move_up = move_up = ExtendedButton( self, - text=" Up", - command=lambda: self.event_generate(ActionEvents.UP), - image=PhotoImage(file=UI_UP) + text="Up", + event=ActionEvents.UP, + image=load_img(file=UI_UP), + description="**Moves** the current rule __up__." ) - self.move_down = move_down = IconedButton( + self.move_down = move_down = ExtendedButton( self, - text=" Down", - command=lambda: self.event_generate(ActionEvents.DOWN), - image=PhotoImage(file=UI_DOWN) + text="Down", + event=ActionEvents.DOWN, + image=load_img(file=UI_DOWN), + description="**Moves** the current rule __down__." ) - left_btn_pack = dict(side=tk.LEFT, padx=(0, UI_PADDING)) - add.pack(**left_btn_pack) - delete.pack(**left_btn_pack) - move_up.pack(**left_btn_pack) - move_down.pack(**left_btn_pack) + add.pack(**LEFT_PACK) + delete.pack(**LEFT_PACK) + move_up.pack(**LEFT_PACK) + move_down.pack(**LEFT_PACK) diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index 638e6a8..3850cfd 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -1,129 +1,42 @@ -import enum -import json -import tkinter as tk -from enum import Enum -from tkinter import ttk, PhotoImage -from tkinter.font import Font -from typing import Optional, Any, List +from typing import Any -from pydantic import ValidationError, BaseModel +from pydantic import BaseModel +from pydantic.config import JsonDict from constants.resources import UI_ERROR from constants.ui import ERROR_ROW_COLOR, RulesListEvents, EditableTreeviewEvents, \ - ScrollableTreeviewEvents + ScrollableTreeviewEvents, CHANGED_ROW_COLOR from ui.widget.common.label import Image from ui.widget.common.treeview.editable import EditableTreeview -from util.ui import full_visible_bbox -from util.utils import extract_type, is_optional_type +from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader +from util.ui import full_visible_bbox, load_img class RulesList(EditableTreeview): - def __init__(self, model: BaseModel, *args, **kwargs): - self.has_unsaved_changes = False - - self._model = model + def __init__(self, model: type[BaseModel], *args, **kwargs): + super().__init__( + *args, + **kwargs, + show='headings', + columns=list(model.model_fields.keys()), + hand_on_title=True + ) + self._loader = PydanticTreeviewLoader(self, model) + + self.has_unsaved_changes = False # dfgsdf Надо сделать иначе, хранить оригинал и сравнивать. Еще думаю стоит добавить подсветку измененных строк до сохранения и вкладки self._error_icons: dict[tuple[str, str], Image] = {} - - super().__init__(*args, columns=list(self._model.model_fields.keys()), **kwargs, show='headings') - self._setup_look() + self.tag_configure("error", background=ERROR_ROW_COLOR) + self.tag_configure("changed", background=CHANGED_ROW_COLOR) self.bind(EditableTreeviewEvents.CHANGE, lambda _: self._changed(), '+') self.bind(ScrollableTreeviewEvents.SCROLL, self._place_icons, '+') - self.bind("", self._handle_click, '+') - self.bind("", self._handle_click, '+') self.bind("", lambda _: self.after(1, self._place_icons), '+') self.bind("", self._on_key_press_tree, "+") self.bind("", lambda _: self.delete_selected_rows(), "+") - self._setup_columns() - - def _handle_click(self, event): - row_id = self.identify_row(event.y) - region = self.identify_region(event.x, event.y) - - if region == "separator" and not row_id: - return "break" - - def _setup_columns(self): - model_fields = self._model.model_fields - - for column_name in self["columns"]: - field_info = model_fields.get(column_name) - - if field_info: - title = field_info.title - max_width_value_in_column = title - typ = extract_type(field_info.annotation) - values = [] - - if is_optional_type(field_info.annotation): - values.append("") - - if issubclass(typ, enum.Enum): - values += [str(e) for e in typ] - max_width_value_in_column = max(values + [max_width_value_in_column], key=len) - - self.column_type(column_name, "list") - self.column_values(column_name, values) - else: - title = "?" - max_width_value_in_column = title - - extra = field_info.json_schema_extra or dict() if field_info else dict() - stretch = extra.get('stretchable_column_ui', False) - width = extra.get( - 'width_ui', - int(self.font.measure(max_width_value_in_column) * 1.35) - if title else None - ) - width = width * extra.get('scale_width_ui', 1) if width else None - anchor = {"left": "w", "center": "center", "right": "e"}[extra.get('justify_ui', 'center')] - - self.heading(column_name, text=title) - self.column(column_name, anchor=anchor, width=width, minwidth=width, stretch=stretch) - - def _setup_look(self): - self.font = Font(family="TkDefaultFont") - self.tag_configure("error", background=ERROR_ROW_COLOR) - - row_height = self.font.metrics("linespace") + 10 - style = ttk.Style() - style.configure('Treeview', rowheight=row_height) - - self._error_icon = PhotoImage(file=UI_ERROR) - - def set_data(self, rules_raw: List[dict]): - self.delete(*self.get_children()) - fields = self["columns"] - - for rule in rules_raw: - values = [rule.get(field_name, '') or '' for field_name in fields] - self.insert('', tk.END, values=values) - - self.set_unsaved_changes(False) - - def get_data(self) -> List[dict]: - return [self._to_rule_raw(row_id) for row_id in self.get_children()] - - def _to_rule_raw(self, row_id): - keys = self["columns"] - values = self.item(row_id, 'values') - return { - key: value for key, value in zip(keys, values) - if value and value.strip() - } - - def get_error_if_available(self, row_id) -> Optional[tuple[Any, Any]]: - try: - # noinspection PyCallingNonCallable - self._model(**self._to_rule_raw(row_id)) - return None - except ValidationError as e: - return row_id, json.loads(e.json()) - def _errors(self) -> dict[Any, Any]: errors = [ - self.get_error_if_available(row_id) + self._loader.get_error_if_available(row_id) for row_id in self.get_children() ] @@ -178,11 +91,11 @@ def _place_icon(self, row_id, column_id, column_error=None): if not icon: self._error_icons[key] = icon = Image( self, - image=self._error_icon, + image=load_img(file=UI_ERROR), background=ERROR_ROW_COLOR, cursor="hand2" ) - icon.bind("", lambda _: self.edit_cell(row_id, column_id), "+") + icon.bind("", lambda _: self.edit_cell(column_id, row_id, 'cell'), "+") icon.bind("", lambda _: self.selection_set(row_id), '+') user_input = "" @@ -208,7 +121,6 @@ def _highlights_error(self, row_id, has_error: bool): if has_error: kwargs["tags"] = ("error",) - kwargs["image"] = self._error_icon else: kwargs["tags"] = ("",) @@ -223,22 +135,14 @@ def _on_key_press_tree(self, event): if ctrl and event.keycode == ord('A'): self.select_all_rows() - def _get_default_values(self) -> List[Any]: - result = [] - model_fields = self._model.model_fields - - for column_name in self["columns"]: - field_info = model_fields.get(column_name) - default_value = field_info.default - - if isinstance(default_value, Enum): - default_value = str(default_value) - - result.append(default_value or '') - - return result - - def add_row(self, values=[]): + def add_row(self, values=None): if not values: - values = self._get_default_values() + values = [*self._loader.get_default_row().values()] super().add_row(values) + + def set_data(self, rules_raw: list[JsonDict]): + self._loader.set_data(rules_raw) + self.set_unsaved_changes(False) + + def get_data(self) -> list[JsonDict]: + return self._loader.get_data() diff --git a/src/ui/widget/settings/tabs/rules/rules_tab.py b/src/ui/widget/settings/tabs/rules/rules_tab.py index fc60e00..51f2587 100644 --- a/src/ui/widget/settings/tabs/rules/rules_tab.py +++ b/src/ui/widget/settings/tabs/rules/rules_tab.py @@ -4,6 +4,7 @@ from constants.resources import UI_PROCESS_RULES, UI_SERVICE_RULES from enums.rules import RuleType from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab +from util.ui import load_img class ProcessRulesTab(BaseRulesTab): @@ -12,7 +13,7 @@ def __init__(self, master: Notebook): @staticmethod def icon() -> PhotoImage: - return PhotoImage(file=UI_PROCESS_RULES) + return load_img(file=UI_PROCESS_RULES) @staticmethod def title() -> str: @@ -29,7 +30,7 @@ def __init__(self, master: Notebook): @staticmethod def icon() -> PhotoImage: - return PhotoImage(file=UI_SERVICE_RULES) + return load_img(file=UI_SERVICE_RULES) @staticmethod def title() -> str: @@ -38,5 +39,3 @@ def title() -> str: @staticmethod def description() -> str: return "Settings for defining **priority**, **I/O priority**, and **core affinity** for __services__." - - diff --git a/src/ui/widget/settings/tooltip.py b/src/ui/widget/settings/tooltip.py index a023775..7cf5ef4 100644 --- a/src/ui/widget/settings/tooltip.py +++ b/src/ui/widget/settings/tooltip.py @@ -1,9 +1,9 @@ -import tkinter as tk -from tkinter import ttk, StringVar, PhotoImage +from tkinter import ttk, StringVar, LEFT, Y, BOTH from constants.resources import UI_INFO_TOOLTIP, UI_WARN_TOOLTIP from constants.ui import UI_PADDING from ui.widget.common.label import RichLabel, Image +from util.ui import load_img class Tooltip(ttk.Frame): @@ -12,22 +12,20 @@ def __init__(self, master, *args, **kwargs): super().__init__(master, *args, **kwargs) self._text = StringVar(self, value=text) - self._info_icon = PhotoImage(file=UI_INFO_TOOLTIP) - self._error_icon = PhotoImage(file=UI_WARN_TOOLTIP) self._image = Image( self, - image=self._info_icon + image=load_img(file=UI_INFO_TOOLTIP) ) - self._image.pack(side=tk.LEFT, fill=tk.Y, padx=(0, UI_PADDING)) + self._image.pack(side=LEFT, fill=Y, padx=(0, UI_PADDING)) label = RichLabel(self, height=5.25, textvariable=self._text) - label.pack(expand=True, fill=tk.BOTH) + label.pack(expand=True, fill=BOTH) label.pack_propagate(False) def set(self, text: str, error: bool = False): if error: - self._image.configure(image=self._error_icon) + self._image.configure(image=load_img(file=UI_WARN_TOOLTIP)) else: - self._image.configure(image=self._info_icon) + self._image.configure(image=load_img(file=UI_INFO_TOOLTIP)) self._text.set(text) diff --git a/src/util/cpu.py b/src/util/cpu.py index f54b618..d5cae6b 100644 --- a/src/util/cpu.py +++ b/src/util/cpu.py @@ -1,11 +1,11 @@ from functools import lru_cache -from typing import Optional, List +from typing import Optional from psutil import cpu_count @lru_cache -def parse_affinity(in_affinity: str) -> List[int]: +def parse_affinity(in_affinity: str) -> list[int]: """ Parse a CPU core affinity string and return a list of core numbers. @@ -13,7 +13,7 @@ def parse_affinity(in_affinity: str) -> List[int]: in_affinity (str): The CPU core affinity string to parse. Returns: - Optional[List[int]]: A list of CPU core numbers specified in the affinity string. + Optional[list[int]]: A list of CPU core numbers specified in the affinity string. """ if in_affinity is None: raise ValueError("empty value") @@ -24,7 +24,7 @@ def parse_affinity(in_affinity: str) -> List[int]: raise ValueError("empty string") affinity = affinity.split(";") - cores: List[int] = [] + cores: list[int] = [] try: for el in affinity: @@ -43,12 +43,12 @@ def parse_affinity(in_affinity: str) -> List[int]: return cores -def format_affinity(cores: List[int]) -> Optional[str]: +def format_affinity(cores: list[int]) -> Optional[str]: """ Format a list of CPU core numbers into an affinity string. Args: - cores (List[int]): A list of CPU core numbers. + cores (list[int]): A list of CPU core numbers. Returns: Optional[str]: An affinity string. diff --git a/src/util/decorators.py b/src/util/decorators.py index 3a6778c..d939779 100644 --- a/src/util/decorators.py +++ b/src/util/decorators.py @@ -1,53 +1,9 @@ import logging -import threading from contextlib import suppress from functools import wraps from time import time from typing import Callable, Optional, TypeVar -from constants.log import LOG - - -def run_in_thread(non_reentrant=True): - """ - Decorator to run a function in a separate thread. Prevents re-entry of the function while it is still running. - Includes a method to check if the function is currently running. - - Args: - non_reentrant (bool): If True, prevents re-invocation of the function while it is already running. - """ - - def decorator(func): - func._is_running = False - - @wraps(func) - def wrapper(*args, **kwargs): - nonlocal func - if non_reentrant and func._is_running: - LOG.debug(f"Function {func.__name__} is already running.") - return - - def run(): - nonlocal func - try: - func._is_running = True - func(*args, **kwargs) - finally: - func._is_running = False - - thread = threading.Thread(target=run) - thread.start() - - def is_running(): - """Returns True if the function is currently running.""" - return func._is_running - - wrapper.is_running = is_running - return wrapper - - return decorator - - T = TypeVar('T') @@ -101,7 +57,8 @@ def decorated_function(*args, **kwargs) -> T: return decorator -def suppress_exception(function: Callable[..., T], exceptions: tuple = (BaseException,), default_value_function: Callable[[], T] = lambda: None) -> Callable[..., T]: +def suppress_exception(function: Callable[..., T], exceptions: tuple = (BaseException,), + default_value_function: Callable[[], T] = lambda: None) -> Callable[..., T]: """ Decorator that suppresses specified exceptions raised by a function. diff --git a/src/util/files.py b/src/util/files.py new file mode 100644 index 0000000..b58fd8f --- /dev/null +++ b/src/util/files.py @@ -0,0 +1,11 @@ +import os + +from constants.files import LOG_FILE_NAME, CONFIG_FILE_NAME + + +def open_log_file(): + return os.startfile(LOG_FILE_NAME) + + +def open_config_file(): + os.startfile(CONFIG_FILE_NAME) diff --git a/src/util/scheduler.py b/src/util/scheduler.py index 20c2b1e..dd99a3b 100644 --- a/src/util/scheduler.py +++ b/src/util/scheduler.py @@ -2,19 +2,28 @@ class TaskScheduler: - def __init__(self): - self.tasks = {} + _tasks = {} - def _execute_task(self, key, callback, *args, **kwargs): + @classmethod + def _execute_task(cls, key, callback, *args, **kwargs): try: callback(*args, **kwargs) finally: - del self.tasks[key] + del cls._tasks[key] - def schedule_task(self, key, callback, delay=0, *args, **kwargs): - if key not in self.tasks: - self.tasks[key] = threading.Timer(delay, self._execute_task, args=(key, callback) + args, kwargs=kwargs) - self.tasks[key].start() + @classmethod + def schedule_task(cls, key, callback, delay=0, *args, **kwargs): + if key not in cls._tasks: + if delay: + cls._tasks[key] = threading.Timer(delay, cls._execute_task, args=(key, callback) + args, kwargs=kwargs) + else: + cls._tasks[key] = threading.Thread(target=cls._execute_task, args=(key, callback) + args, kwargs=kwargs) + + cls._tasks[key].start() + + @classmethod + def check_task(cls, key) -> bool: + return key in cls._tasks if __name__ == '__main__': @@ -22,12 +31,10 @@ def my_function(message): print(f"Function executed with message: {message}") - scheduler = TaskScheduler() - - scheduler.schedule_task("task1", my_function, 5, "Hello after 5 seconds") - scheduler.schedule_task("task1", my_function, 2, "Hello after 2 seconds") - scheduler.schedule_task("task2", my_function, 3, "Hello after 3 seconds") - scheduler.schedule_task("task3", my_function, 0, "Immediate execution") + TaskScheduler.schedule_task("task1", my_function, 5, "Hello after 5 seconds") + TaskScheduler.schedule_task("task1", my_function, 2, "Hello after 2 seconds") + TaskScheduler.schedule_task("task2", my_function, 3, "Hello after 3 seconds") + TaskScheduler.schedule_task("task3", my_function, 0, "Immediate execution") import time diff --git a/src/util/ui.py b/src/util/ui.py index 3a3e67f..d57b9d7 100644 --- a/src/util/ui.py +++ b/src/util/ui.py @@ -1,5 +1,7 @@ import tkinter -from tkinter import font, Widget, PhotoImage +from functools import cache +from tkinter import font, Widget, Entry, PhotoImage +from tkinter.font import Font from tkinter.ttk import Treeview @@ -32,13 +34,47 @@ def get_parent_with_bg(widget: Widget): return None +@cache def get_label_font(): - temp_label = tkinter.Label() - default_font = font.nametofont(temp_label.cget("font")) - temp_label.destroy() + temp_widget = tkinter.Label() + default_font = font.nametofont(temp_widget.cget("font")) + temp_widget.destroy() + return default_font + + +@cache +def get_default_font(): + return Font(family="TkDefaultFont") + + +@cache +def single_font_width(): + return get_default_font().measure('0') + +@cache +def get_button_font(): + temp_widget = tkinter.Button() + default_font = font.nametofont(temp_widget.cget("font")) + temp_widget.destroy() return default_font -def icon16px(name: str, fill: str = None) -> PhotoImage: - return icon_to_image(name, fill=fill, scale_to_width=16) +@cache +def get_combobox_font(): + temp_widget = tkinter.Button() + default_font = font.nametofont(temp_widget.cget("font")) + temp_widget.destroy() + return default_font + + +@cache +def get_entry_font(): + temp_entry = Entry() + default_font = temp_entry.cget("font") + temp_entry.destroy() + return default_font + +@cache +def load_img(file) -> PhotoImage: + return PhotoImage(file=file) \ No newline at end of file diff --git a/src/util/utils.py b/src/util/utils.py index b537f23..0999063 100644 --- a/src/util/utils.py +++ b/src/util/utils.py @@ -1,12 +1,13 @@ import re import sys -from functools import lru_cache +from enum import Enum +from functools import lru_cache, cache from re import Pattern from types import NoneType from typing import get_origin, get_args, Union, Annotated, Optional -@lru_cache(maxsize=None) +@cache def path_pattern_to_regex(pattern: str) -> Optional[Pattern]: """ Converts a glob-like path pattern to a regular expression, with partial support for glob syntax. @@ -51,12 +52,12 @@ def path_match(pattern: str, value: str) -> bool: bool: True if any value matches the pattern, False otherwise. """ - if pattern == value: - return True - if not pattern: return False + if pattern == value: + return True + regex = path_pattern_to_regex(pattern) if not pattern: @@ -132,3 +133,23 @@ def is_optional_type(annotation): if arg == NoneType or is_optional_type(arg): return True return False + + +def none_int(value: str) -> Optional[int]: + return int(value) if value else None + + +def get_values_from_enum(annotation): + origin_type = extract_type(annotation) + values = [] + + if not issubclass(origin_type, Enum): + return values + + if is_optional_type(annotation): + values.append('') + + for e in origin_type: + values.append(str(e.value)) + + return values From 765a86b4e688c4b4c0b1fe6b76ebbe508cf36aa5 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 1 Sep 2024 16:17:48 +0800 Subject: [PATCH 22/39] [#6] Forgot to add a few icons --- resources/UI/config.png | Bin 0 -> 1751 bytes resources/UI/log.png | Bin 0 -> 1661 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/UI/config.png create mode 100644 resources/UI/log.png diff --git a/resources/UI/config.png b/resources/UI/config.png new file mode 100644 index 0000000000000000000000000000000000000000..63112c680da7918d72f32c07cbb108f43389b238 GIT binary patch literal 1751 zcmbVNO>Epm6n0sNXviYbLKRUJ4Q@do>YwrMde@^aNxHivi@G67S4w*8cxHCjitTZ2 zC%eh1$l*B6@%W5-WkqwGxLg-an-!X{%bYJ)ZgI zd+&Yk&GUtY`PuaNi{p|crK@x0Me%+P>L0g9L%cVhlQ->qn?llzY5LjFV|i20ci;Qj}*BgJ8L~07^V$ zz*KdG=(-8=mP)aWiESSRhHgMj&uTEM=sL<+D4PX?OBUur+CYotw+6<o3F-2S-9Gd!3##T zel*ZYD5iCApg~nnV(I}Y8R3G}(CrzgL}M=Vm>)+13rEH}j_T_H(-v98S3|-oYr@ULNi+c}g$&0$taI)TGqo^u85o9| z1+OhRKIQG`^=%ti8ON+Bi>!%!6%=UIVF6__2pVtb1*GeJXpK{+vHpLkg&;&m<{qf1 z8H!{4P%tH^!9x#=fE^DvnHKm>8H{8^CGPT27#7}Tw$E2frG=0;99Jwvi?hc;wNf&n zWtxhi!k)Xe8mjtHjD5nY<)SRaQ5}b(oJAmHmI$(878HWBrefvuStX-q8WuA##LOD* zFLSb*l)!L575hmJW^~KQDJ*B@6|<4G6>QV2Vl$Y}Hy{=CeYu4FcS1*;LF_&@PjWJo z+Cg(pB(l0bI65cUnZd|)K(Aa7Cdn}<$|T7@qw-+d*+GFvi=a>2ZZSdnfV$|zBHoDG zIAk+Tq1Hp|PTS4-2(LZZ^+!wIZm!=~r;p?MKvvSiev^r&s>w+(TGD;`Nzv}lS8r`w zry9aV`%8wS#w$KXt(*CRIuwoBxd}qi)IYD5XX=IL$la~2sZ1pGLC<=^h!&1Y|XdrklJNNUNyoid-Klg5`v zQ+Vub>$AV6UAna21DA1Et>ibqKG!{e@!(ni<*NGgfwk^|eTUBfa^*dL^2YZQZ_7Vi x`{?iZ{mnbKKAAW*w(p7SSEoaLK6UBbo^QG@d~j>bm`;8@)yjPNyW^+d{SRb*E2jVe literal 0 HcmV?d00001 diff --git a/resources/UI/log.png b/resources/UI/log.png new file mode 100644 index 0000000000000000000000000000000000000000..2cd6cef579f7bd75441b20271b10e9d78fcf7944 GIT binary patch literal 1661 zcmbVNYitxn9A5~}*2W@;#spori4aYJhZNYPAl!kdt8PoU+s-W%%Ra68D{AX zX1txW$F>0-rv+%>1QN1oo1z(Jb8Xg!dKV&W0(F>{#$A|rpJPo!<8}mMQp^scPP4J! zL2dobalOAwR}HSVhTWV6lpu`=WV7j%<$|on<#_>Jd)p$%<{_j@KyL}dcS>AH1iVP9t>W*m>6I-mu2ot!6XdG2_-iEYY zqP5(DpQy*gEVM;gkUX36KtnI#>>ekT7jEbxN})8eh)c0@32S#^g56I1FVv;uO9W8g z#$qKIm(?YmE{SkSLoYR>;E>Cr-FTmk#8%|u9!EzFy;RLA&l($q9Rvw>;uxojk!mTb z%qoiDXRCLZmVq4jg@7c@Lu1%5lYRe$sz8!K zK)nP?bH;!KUJ-2QAc>tcqz0R5*nvdb>fqRt8$lSSutNn??R*ROqv3FigOg^89=NSr z>)B{SI4G;ZAg>5=Ufoy>L@k#X9I zwxGC+aN04vWvN%uk5aco7Hx43?PcpvUH>}6EV?Edsf&k(59i)2o02MbU%Y)+#Vs%X zv3LLgRYg6O%O~r|s?je`O@3ZCdM|lm#X#4@_vE{#@t5SG18ZxZdgt43KD+PS5@!Ex zYu<`iZ#jFuuWDp%6Q66IJ)bLIYKN>3t6Se#{X(vGYF5}ob}}=MOr0G=IRnK|~vxBjfcC4EzNZ?kTna literal 0 HcmV?d00001 From 0f72a7522d666cb0bae06c7915207a0a8fd583f5 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 1 Sep 2024 21:44:11 +0800 Subject: [PATCH 23/39] Refactoring, optimization, QoL changes --- src/constants/ui.py | 9 ++- src/ui/settings.py | 6 +- src/ui/widget/common/treeview/editable.py | 29 +-------- src/ui/widget/common/treeview/extended.py | 64 ++++++++++++++++++- src/ui/widget/common/treeview/pydantic.py | 57 +++++++++++------ src/ui/widget/settings/settings_tabs.py | 35 ++++++++-- src/ui/widget/settings/tabs/base_tab.py | 7 +- src/ui/widget/settings/tabs/process_list.py | 20 +++--- .../settings/tabs/rules/base_rules_tab.py | 14 ++-- .../widget/settings/tabs/rules/rules_list.py | 31 ++++----- 10 files changed, 171 insertions(+), 101 deletions(-) diff --git a/src/constants/ui.py b/src/constants/ui.py index 5ba4b35..019f104 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -15,8 +15,8 @@ OPEN_CONFIG_LABEL = "Open config file" OPEN_LOG_LABEL = "Open log file" -ADD_PROCESS_RULE_LABEL = " Add Process Rule" -ADD_SERVICE_RULE_LABEL = " Add Service Rule" +CMENU_ADD_PROCESS_RULE_LABEL = " Add Process Rule" +CMENU_ADD_SERVICE_RULE_LABEL = " Add Service Rule" class ActionEvents: @@ -34,12 +34,11 @@ class ActionEvents: SEARCH_CHANGE: Final[str] = "<>" -class RulesListEvents: - UNSAVED_CHANGES_STATE: Final[str] = "<>" +class ExtendedTreeviewEvents: + CHANGE: Final[str] = "<>" class EditableTreeviewEvents: - CHANGE: Final[str] = "<>" ESCAPE: Final[str] = "<>" START_EDIT_CELL: Final[str] = "<>" SAVE_CELL: Final[str] = "<>" diff --git a/src/ui/settings.py b/src/ui/settings.py index 6bd0de5..142d79a 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -6,8 +6,8 @@ from constants.log import LOG from constants.resources import APP_ICON, UI_SAVE, UI_LOG, UI_CONFIG from constants.threads import THREAD_SETTINGS -from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, SETTINGS_TITLE, RulesListEvents, EditableTreeviewEvents, \ - RIGHT_PACK, LEFT_PACK, OPEN_CONFIG_LABEL, OPEN_LOG_LABEL +from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, SETTINGS_TITLE, EditableTreeviewEvents, \ + RIGHT_PACK, LEFT_PACK, OPEN_CONFIG_LABEL, OPEN_LOG_LABEL, ExtendedTreeviewEvents from ui.widget.common.button import ExtendedButton from ui.widget.settings.settings_tabs import SettingsTabs from ui.widget.settings.tabs.base_tab import BaseTab @@ -81,7 +81,7 @@ def _create_tooltips(self): def _create_tabs(self): self._tabs = tabs = SettingsTabs(self) tabs.load_data() - tabs.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_actions_state(), "+") + tabs.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._update_actions_state(), "+") def _create_actions(self): self._actions = actions = SettingsActions(self) diff --git a/src/ui/widget/common/treeview/editable.py b/src/ui/widget/common/treeview/editable.py index 4650d42..c87064c 100644 --- a/src/ui/widget/common/treeview/editable.py +++ b/src/ui/widget/common/treeview/editable.py @@ -80,29 +80,6 @@ def __init__(self, *args, **kwargs): self.bind(ScrollableTreeviewEvents.SCROLL, self._place_editor, '+') self.bind("", lambda _: self.after(1, self._place_editor), '+') - def insert(self, parent, index, iid=None, **kw): - result = super().insert(parent, index, iid, **kw) - self.event_generate(EditableTreeviewEvents.CHANGE) - return result - - def delete(self, *args): - result = super().delete(*args) - self.event_generate(EditableTreeviewEvents.CHANGE) - return result - - def set(self, item, column=None, value=None): - result = super().set(item, column, value) - - if value is not None: - self.event_generate(EditableTreeviewEvents.CHANGE) - - return result - - def move(self, item, parent, index): - result = super().move(item, parent, index) - self.event_generate(EditableTreeviewEvents.CHANGE) - return result - def editor(self) -> CellEditor: return self._editor @@ -206,17 +183,17 @@ def move_rows_down(self): self.selection_set(selected_items) - def add_row(self, values=None): + def add_row(self, values=None, index=None): selected_items = self.selection() - if selected_items: + if selected_items and index is None: selected_item = selected_items[0] index = self.index(selected_item) self.insert('', index, values=values or []) self.selection_set(self.get_children()[index]) else: - self.insert('', 0, values=values or []) + self.insert('', index or 0, values=values or []) def delete_selected_rows(self): selected_items = self.selection() diff --git a/src/ui/widget/common/treeview/extended.py b/src/ui/widget/common/treeview/extended.py index a8199e8..31228f9 100644 --- a/src/ui/widget/common/treeview/extended.py +++ b/src/ui/widget/common/treeview/extended.py @@ -1,11 +1,11 @@ from dataclasses import dataclass from functools import lru_cache -from tkinter import ttk +from tkinter import ttk, END from typing import Optional, Literal, Any from pydantic.config import JsonDict -from constants.ui import COLUMN_TITLE_PADDING +from constants.ui import COLUMN_TITLE_PADDING, ExtendedTreeviewEvents from util.ui import get_default_font from util.utils import get_values_from_enum @@ -29,6 +29,9 @@ def __init__(self, *args, hand_on_title: bool = False, **kwargs): self._types: dict[str, type] = {} self._width_set: dict[str, bool] = {} + self._generate_event_change: bool = True + self._changed: tuple = tuple() + self._setup_font() self.bind('', self._calculate_columns_width, '+') self.bind('', lambda _: self.clear_selection()) @@ -139,9 +142,15 @@ def configure(self, dct: dict[str, Any] | None = None, *args, **kwargs): return result + def as_list(self, row_id): + return self.item(row_id, 'values') + + def as_list_of_list(self) -> list[list[str]]: + return [self.as_list(row_id) for row_id in self.get_children()] + def as_dict(self, row_id) -> JsonDict: column_names = self["columns"] - values = self.item(row_id, 'values') + values = self.as_list(row_id) return { key: value for key, value in zip(column_names, values) @@ -150,3 +159,52 @@ def as_dict(self, row_id) -> JsonDict: def as_list_of_dict(self) -> list[JsonDict]: return [self.as_dict(row_id) for row_id in self.get_children()] + + def begin_changes(self): + if not self._generate_event_change: + raise RuntimeError("Has already been called begin_changes") + + self._changed = [] + self._generate_event_change = False + + def end_changes(self): + if self._generate_event_change: + raise RuntimeError("begin_changes must be called before end_changes") + + self._generate_event_change = True + + if self._changed: + sequence, args, kwargs = self._changed + self._changed = [] + + super().event_generate(sequence, *args, **kwargs) + + def event_generate(self, sequence, *args, **kwargs): + if not self._generate_event_change and sequence == ExtendedTreeviewEvents.CHANGE: + self._changed = (sequence, args, kwargs) + return + + super().event_generate(sequence, *args, **kwargs) + + def insert(self, parent, index, iid=None, **kw): + result = super().insert(parent, index, iid, **kw) + self.event_generate(ExtendedTreeviewEvents.CHANGE) + return result + + def delete(self, *args): + result = super().delete(*args) + self.event_generate(ExtendedTreeviewEvents.CHANGE) + return result + + def set(self, item, column=None, value=None): + result = super().set(item, column, value) + + if value is not None: + self.event_generate(ExtendedTreeviewEvents.CHANGE) + + return result + + def move(self, item, parent, index): + result = super().move(item, parent, index) + self.event_generate(ExtendedTreeviewEvents.CHANGE) + return result diff --git a/src/ui/widget/common/treeview/pydantic.py b/src/ui/widget/common/treeview/pydantic.py index 935f1de..69ad7c0 100644 --- a/src/ui/widget/common/treeview/pydantic.py +++ b/src/ui/widget/common/treeview/pydantic.py @@ -21,6 +21,7 @@ def \ __init__(self, treeview: ExtendedTreeview, model: type[BaseModel]): self._treeview = treeview self._model = model + self._original_data = [] self._setup_columns() def _setup_columns(self): @@ -55,24 +56,44 @@ def _setup_columns(self): def set_data(self, rules: Iterable[JsonDict | BaseModel]): treeview = self._treeview - treeview.clear() - column_names = treeview["columns"] - - for rule in rules: - values = [ - getattr(rule, column_name, '') - if isinstance(rule, BaseModel) - else rule.get(column_name, '') - for column_name in column_names - ] - values = list(map(lambda value: '' if value is None or str(value) == '' else str(value), values)) - treeview.insert('', END, values=values) - - if hasattr(treeview, 'sort_column'): - treeview.sort_column() - - def has_changes(self): - pass + + try: + self._original_data = [] + + treeview.begin_changes() + treeview.clear() + + column_names = treeview["columns"] + + for rule in rules: + values = [ + getattr(rule, column_name, '') + if isinstance(rule, BaseModel) + else rule.get(column_name, '') + for column_name in column_names + ] + values = tuple(map(self._to_str, values)) + + self._original_data.append(values) + self._treeview.insert('', END, values=values) + + if hasattr(treeview, 'sort_column'): + treeview.sort_column() + finally: + treeview.end_changes() + + @staticmethod + def _to_str(value) -> str: + if value is None or str(value) == '': + return '' + + return str(value) + + def has_changes(self) -> bool: + return self._original_data != self._treeview.as_list_of_list() + + def commit_changes(self): + self._original_data = self._treeview.as_list_of_list() def get_data(self) -> list[JsonDict]: return self._treeview.as_list_of_dict() diff --git a/src/ui/widget/settings/settings_tabs.py b/src/ui/widget/settings/settings_tabs.py index afd4574..dd723cc 100644 --- a/src/ui/widget/settings/settings_tabs.py +++ b/src/ui/widget/settings/settings_tabs.py @@ -1,8 +1,9 @@ -from tkinter import ttk, messagebox +from tkinter import ttk, messagebox, LEFT from typing import Optional from constants.app_info import APP_NAME_WITH_VERSION from constants.log import LOG +from constants.ui import ExtendedTreeviewEvents from service.config_service import ConfigService from ui.widget.settings.tabs.base_tab import BaseTab from ui.widget.settings.tabs.process_list import ProcessListTab @@ -22,14 +23,20 @@ def __init__(self, *args, **kwargs): self._config: Optional[dict] = None self._create_tabs() + self.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._update_tabs_state(), "+") + def _create_tabs(self): process_rules_tab = ProcessRulesTab(self) service_rules_tab = ServiceRulesTab(self) - process_list_tab = ProcessListTab(self, process_rules_tab.rules_list, service_rules_tab.rules_list) + process_list_tab = ProcessListTab( + self, + process_rules_tab.rules_list, + service_rules_tab.rules_list + ) - process_list_tab.add_tab_to_master() - process_rules_tab.add_tab_to_master() - service_rules_tab.add_tab_to_master() + self._add_tab(process_list_tab) + self._add_tab(process_rules_tab) + self._add_tab(service_rules_tab) def current_tab(self) -> BaseTab: current_index = self.index(self.select()) @@ -38,7 +45,7 @@ def current_tab(self) -> BaseTab: def has_unsaved_changes(self) -> bool: for tab in self.frames(): - if tab.has_unsaved_changes(): + if tab.has_changes(): return True return False @@ -80,5 +87,21 @@ def save_data(self) -> bool: def frames(self) -> list[BaseTab]: return [self.nametowidget(tab_id) for tab_id in self.tabs()] + def frames_by_tab(self) -> dict[str, BaseTab]: + return { + tab_id: self.nametowidget(tab_id) + for tab_id in self.tabs() + } + def get_default_tooltip(self): return self.current_tab().default_tooltip() + + def _add_tab(self, tab: BaseTab): + self.add(tab, text=f" {tab.title()}", image=tab.icon(), compound=LEFT) + + def _update_tabs_state(self): + tabs = self.frames_by_tab() + + for id, tab in tabs.items(): + star = "*" if tab.has_changes() or tab.has_error() else "" + self.tab(id, text=f" {tab.title()} {star}") diff --git a/src/ui/widget/settings/tabs/base_tab.py b/src/ui/widget/settings/tabs/base_tab.py index a271a60..26e8a83 100644 --- a/src/ui/widget/settings/tabs/base_tab.py +++ b/src/ui/widget/settings/tabs/base_tab.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from tkinter import PhotoImage, ttk, LEFT +from tkinter import PhotoImage, ttk from tkinter.ttk import Notebook @@ -9,9 +9,6 @@ def __init__(self, master: Notebook): self.master: Notebook = master - def add_tab_to_master(self): - self.master.add(self, text=f" {self.title()} ", image=self.icon(), compound=LEFT) - @staticmethod @abstractmethod def icon() -> PhotoImage: @@ -41,7 +38,7 @@ def save_to_config(self, config: dict): pass @abstractmethod - def has_unsaved_changes(self) -> bool: + def has_changes(self) -> bool: pass @abstractmethod diff --git a/src/ui/widget/settings/tabs/process_list.py b/src/ui/widget/settings/tabs/process_list.py index 177d7f2..ee2649a 100644 --- a/src/ui/widget/settings/tabs/process_list.py +++ b/src/ui/widget/settings/tabs/process_list.py @@ -6,7 +6,8 @@ from constants.log import LOG from constants.resources import UI_PROCESS_LIST, UI_REFRESH from constants.threads import THREAD_PROCESS_LIST -from constants.ui import UI_PADDING, ActionEvents, LEFT_PACK, ADD_PROCESS_RULE_LABEL, ADD_SERVICE_RULE_LABEL +from constants.ui import UI_PADDING, ActionEvents, LEFT_PACK, CMENU_ADD_PROCESS_RULE_LABEL, \ + CMENU_ADD_SERVICE_RULE_LABEL from enums.filters import FilterByProcessType from enums.rules import RuleType from enums.selector import SelectorType @@ -146,7 +147,6 @@ def _refresh_state(self, lock: bool): try: actions = self.actions actions.refresh['state'] = DISABLED if lock else NORMAL - actions.filterByType['state'] = DISABLED if lock else "readonly" progress_bar = self._progress_bar if lock: @@ -160,7 +160,7 @@ def _refresh_state(self, lock: bool): def save_to_config(self, config: dict): pass - def has_unsaved_changes(self) -> bool: + def has_changes(self) -> bool: return False def has_error(self) -> bool: @@ -182,14 +182,12 @@ def _setup_context_menu(self): self._process_menu = Menu(context_menu, tearoff=0) context_menu.add_cascade( - label=ADD_PROCESS_RULE_LABEL, - menu=self._process_menu, - compound=LEFT + label=CMENU_ADD_PROCESS_RULE_LABEL, + menu=self._process_menu ) context_menu.add_command( - label=ADD_SERVICE_RULE_LABEL, - compound=LEFT, + label=CMENU_ADD_SERVICE_RULE_LABEL, command=lambda: self._add_rule(RuleType.SERVICE) ) @@ -236,8 +234,8 @@ def _show_context_menu(self, event): command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.CMDLINE) ) - self._context_menu.entryconfig(ADD_PROCESS_RULE_LABEL, state=NORMAL if exists else DISABLED) - self._context_menu.entryconfig(ADD_SERVICE_RULE_LABEL, state=NORMAL if row.service else DISABLED) + self._context_menu.entryconfig(CMENU_ADD_PROCESS_RULE_LABEL, state=NORMAL if exists else DISABLED) + self._context_menu.entryconfig(CMENU_ADD_SERVICE_RULE_LABEL, state=NORMAL if row.service else DISABLED) context_menu.post(event.x_root, event.y_root) @@ -272,7 +270,7 @@ def _add_rule(self, rule_type: RuleType, selector_type: Optional[SelectorType] = elif selector_type == SelectorType.CMDLINE: rule_row['selector'] = row['cmd_line'] - rules_list.add_row([*rule_row.values()]) + rules_list.add_row([*rule_row.values()], index=0) class ProcessListTabActions(ttk.Frame): diff --git a/src/ui/widget/settings/tabs/rules/base_rules_tab.py b/src/ui/widget/settings/tabs/rules/base_rules_tab.py index 58f1637..fa0c351 100644 --- a/src/ui/widget/settings/tabs/rules/base_rules_tab.py +++ b/src/ui/widget/settings/tabs/rules/base_rules_tab.py @@ -3,7 +3,7 @@ from tkinter.ttk import Notebook from constants.resources import UI_ADD, UI_DELETE, UI_UP, UI_DOWN -from constants.ui import UI_PADDING, RulesListEvents, ActionEvents, LEFT_PACK +from constants.ui import UI_PADDING, ActionEvents, LEFT_PACK, ExtendedTreeviewEvents from enums.rules import RuleType from ui.widget.common.button import ExtendedButton from ui.widget.settings.tabs.base_tab import BaseTab @@ -39,7 +39,9 @@ def _create_rules_list(self): rules_list = RulesList(self.rule_type.clazz, self) rules_list.bind("<>", lambda _: self._update_actions_state(), "+") - rules_list.bind(RulesListEvents.UNSAVED_CHANGES_STATE, lambda _: self._update_actions_state(), "+") + rules_list.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._update_actions_state(), "+") + rules_list.bind(ExtendedTreeviewEvents.CHANGE, + lambda _: self.master.event_generate(ExtendedTreeviewEvents.CHANGE), "+") return rules_list @@ -73,18 +75,16 @@ def _update_actions_state(self): actions.delete["state"] = NORMAL if selected_items else DISABLED - self.master.event_generate(RulesListEvents.UNSAVED_CHANGES_STATE) - def load_from_config(self, config: dict): self.rules_list.set_data(config.get(self.rule_type.field_in_config, [])) def save_to_config(self, config: dict): rules_list = self.rules_list config[self.rule_type.field_in_config] = rules_list.get_data() - rules_list.set_unsaved_changes(False) + self.rules_list.commit_changes() - def has_unsaved_changes(self) -> bool: - return self.rules_list.has_unsaved_changes + def has_changes(self) -> bool: + return self.rules_list.has_changes() def has_error(self) -> bool: return self.rules_list.has_error() diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index 3850cfd..203236c 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -4,8 +4,8 @@ from pydantic.config import JsonDict from constants.resources import UI_ERROR -from constants.ui import ERROR_ROW_COLOR, RulesListEvents, EditableTreeviewEvents, \ - ScrollableTreeviewEvents, CHANGED_ROW_COLOR +from constants.ui import ERROR_ROW_COLOR, \ + ScrollableTreeviewEvents, CHANGED_ROW_COLOR, ExtendedTreeviewEvents from ui.widget.common.label import Image from ui.widget.common.treeview.editable import EditableTreeview from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader @@ -21,14 +21,14 @@ def __init__(self, model: type[BaseModel], *args, **kwargs): columns=list(model.model_fields.keys()), hand_on_title=True ) - self._loader = PydanticTreeviewLoader(self, model) - self.has_unsaved_changes = False # dfgsdf Надо сделать иначе, хранить оригинал и сравнивать. Еще думаю стоит добавить подсветку измененных строк до сохранения и вкладки + self._loader = PydanticTreeviewLoader(self, model) self._error_icons: dict[tuple[str, str], Image] = {} + self.tag_configure("error", background=ERROR_ROW_COLOR) self.tag_configure("changed", background=CHANGED_ROW_COLOR) - self.bind(EditableTreeviewEvents.CHANGE, lambda _: self._changed(), '+') + self.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._check_errors(), '+') self.bind(ScrollableTreeviewEvents.SCROLL, self._place_icons, '+') self.bind("", lambda _: self.after(1, self._place_icons), '+') self.bind("", self._on_key_press_tree, "+") @@ -49,15 +49,7 @@ def _errors(self) -> dict[Any, Any]: def has_error(self): return len(self._errors()) > 0 - def set_unsaved_changes(self, state: bool): - self.has_unsaved_changes = state - self.event_generate(RulesListEvents.UNSAVED_CHANGES_STATE) - - def _changed(self): - self.set_unsaved_changes(True) - self._handle_errors() - - def _handle_errors(self): + def _check_errors(self): self._destroy_error_icons() errors = self._errors() @@ -135,14 +127,19 @@ def _on_key_press_tree(self, event): if ctrl and event.keycode == ord('A'): self.select_all_rows() - def add_row(self, values=None): + def add_row(self, values=None, index=None): if not values: values = [*self._loader.get_default_row().values()] - super().add_row(values) + super().add_row(values, index) def set_data(self, rules_raw: list[JsonDict]): self._loader.set_data(rules_raw) - self.set_unsaved_changes(False) def get_data(self) -> list[JsonDict]: return self._loader.get_data() + + def has_changes(self) -> bool: + return self._loader.has_changes() + + def commit_changes(self): + self._loader.commit_changes() From 71d972a748b460b2a2181b523a18619a08ee77d4 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 1 Sep 2024 22:14:41 +0800 Subject: [PATCH 24/39] Bug fixes --- src/configuration/rule.py | 2 +- src/ui/settings.py | 11 ++++++++--- src/ui/widget/settings/settings_tabs.py | 6 +++++- src/ui/widget/settings/tabs/base_tab.py | 4 ++++ src/ui/widget/settings/tabs/process_list.py | 3 +++ src/ui/widget/settings/tabs/rules/base_rules_tab.py | 4 +++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/configuration/rule.py b/src/configuration/rule.py index 8cd19af..fb1adb9 100644 --- a/src/configuration/rule.py +++ b/src/configuration/rule.py @@ -26,7 +26,7 @@ class ProcessRule(BaseModel): "**Supports wildcard:** `*` (matches any characters), `?` (matches any single character) and `**` (matches any sequence of directories).\n" "**Examples:** `name.exe`, `logioptionsplus_*.exe`, `D:/FolderName/App.exe` or `C:/Program Files/**/app.exe --file Document.txt`.", stretchable_column_ui=True, - # justify_ui="left" + justify_ui="left" ) priority: Optional[PriorityStr] = Field( diff --git a/src/ui/settings.py b/src/ui/settings.py index 142d79a..869a867 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -86,7 +86,7 @@ def _create_tabs(self): def _create_actions(self): self._actions = actions = SettingsActions(self) - actions.bind(ActionEvents.APPLY, lambda _: self._tabs.save_data(), "+") + actions.bind(ActionEvents.APPLY, lambda _: self._apply(), "+") actions.bind(ActionEvents.APPLY_N_CLOSE, lambda _: self._apply_and_save(), "+") actions.bind(ActionEvents.CONFIG, lambda _: open_config_file(), "+") actions.bind(ActionEvents.LOG, lambda _: open_log_file(), "+") @@ -94,9 +94,14 @@ def _create_actions(self): self._update_actions_state() def _apply_and_save(self): - self._tabs.save_data() + self._apply() self._on_window_closing() + def _apply(self): + result = self._tabs.save_data() + self._update_actions_state() + return result + def _on_window_closing(self): has_error = self._tabs.has_error() @@ -116,7 +121,7 @@ def _on_window_closing(self): if result is None: return - if result and not self._tabs.save_data(): + if result and not self._apply(): return else: if has_error: diff --git a/src/ui/widget/settings/settings_tabs.py b/src/ui/widget/settings/settings_tabs.py index dd723cc..6dd73a5 100644 --- a/src/ui/widget/settings/settings_tabs.py +++ b/src/ui/widget/settings/settings_tabs.py @@ -75,9 +75,13 @@ def save_data(self) -> bool: return False for tab in self.frames(): + if not tab.has_changes(): + continue + tab.save_to_config(self._config) + ConfigService.save_config_raw(self._config) + tab.commit_changes() - ConfigService.save_config_raw(self._config) return True except: LOG.exception("Error when saving file.") diff --git a/src/ui/widget/settings/tabs/base_tab.py b/src/ui/widget/settings/tabs/base_tab.py index 26e8a83..ed1e5ae 100644 --- a/src/ui/widget/settings/tabs/base_tab.py +++ b/src/ui/widget/settings/tabs/base_tab.py @@ -41,6 +41,10 @@ def save_to_config(self, config: dict): def has_changes(self) -> bool: pass + @abstractmethod + def commit_changes(self): + pass + @abstractmethod def has_error(self) -> bool: pass diff --git a/src/ui/widget/settings/tabs/process_list.py b/src/ui/widget/settings/tabs/process_list.py index ee2649a..40204c3 100644 --- a/src/ui/widget/settings/tabs/process_list.py +++ b/src/ui/widget/settings/tabs/process_list.py @@ -166,6 +166,9 @@ def has_changes(self) -> bool: def has_error(self) -> bool: return False + def commit_changes(self): + pass + def _setup_widgets(self): self.process_list = self._create_process_list() self._progress_bar = self._create_progress_bar() diff --git a/src/ui/widget/settings/tabs/rules/base_rules_tab.py b/src/ui/widget/settings/tabs/rules/base_rules_tab.py index fa0c351..7a241d9 100644 --- a/src/ui/widget/settings/tabs/rules/base_rules_tab.py +++ b/src/ui/widget/settings/tabs/rules/base_rules_tab.py @@ -81,11 +81,13 @@ def load_from_config(self, config: dict): def save_to_config(self, config: dict): rules_list = self.rules_list config[self.rule_type.field_in_config] = rules_list.get_data() - self.rules_list.commit_changes() def has_changes(self) -> bool: return self.rules_list.has_changes() + def commit_changes(self): + self.rules_list.commit_changes() + def has_error(self) -> bool: return self.rules_list.has_error() From df393d9ae1b0b3bebba04d103fa687149bed5d3c Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 1 Sep 2024 22:42:05 +0800 Subject: [PATCH 25/39] Fix double saving when click button Apply & Close --- src/ui/settings.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ui/settings.py b/src/ui/settings.py index 869a867..a7f3a5d 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -87,22 +87,21 @@ def _create_actions(self): self._actions = actions = SettingsActions(self) actions.bind(ActionEvents.APPLY, lambda _: self._apply(), "+") - actions.bind(ActionEvents.APPLY_N_CLOSE, lambda _: self._apply_and_save(), "+") + actions.bind(ActionEvents.APPLY_N_CLOSE, lambda _: self._apply_and_close(), "+") actions.bind(ActionEvents.CONFIG, lambda _: open_config_file(), "+") actions.bind(ActionEvents.LOG, lambda _: open_log_file(), "+") self._update_actions_state() - def _apply_and_save(self): - self._apply() - self._on_window_closing() + def _apply_and_close(self): + self._on_window_closing(False) def _apply(self): result = self._tabs.save_data() self._update_actions_state() return result - def _on_window_closing(self): + def _on_window_closing(self, ask_about_changes=True): has_error = self._tabs.has_error() if self._tabs.has_unsaved_changes(): @@ -114,9 +113,12 @@ def _on_window_closing(self): if not result: return else: - message = ("There are unsaved changes. " - "Do you want to save them before exiting?") - result = messagebox.askyesnocancel(f"{APP_NAME_WITH_VERSION}", message) + if ask_about_changes: + message = ("There are unsaved changes. " + "Do you want to save them before exiting?") + result = messagebox.askyesnocancel(f"{APP_NAME_WITH_VERSION}", message) + else: + result = True if result is None: return From 3d978c1c02e0d7b0112040f5c6f0ecf9cddb1019 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 1 Sep 2024 23:00:18 +0800 Subject: [PATCH 26/39] Fix binds --- src/ui/widget/common/treeview/extended.py | 2 +- src/ui/widget/settings/tabs/process_list.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/widget/common/treeview/extended.py b/src/ui/widget/common/treeview/extended.py index 31228f9..783af0f 100644 --- a/src/ui/widget/common/treeview/extended.py +++ b/src/ui/widget/common/treeview/extended.py @@ -34,7 +34,7 @@ def __init__(self, *args, hand_on_title: bool = False, **kwargs): self._setup_font() self.bind('', self._calculate_columns_width, '+') - self.bind('', lambda _: self.clear_selection()) + self.bind('', lambda _: self.clear_selection(), '+') if hand_on_title: self.bind("", self._on_motion, '+') diff --git a/src/ui/widget/settings/tabs/process_list.py b/src/ui/widget/settings/tabs/process_list.py index 40204c3..297746f 100644 --- a/src/ui/widget/settings/tabs/process_list.py +++ b/src/ui/widget/settings/tabs/process_list.py @@ -194,7 +194,7 @@ def _setup_context_menu(self): command=lambda: self._add_rule(RuleType.SERVICE) ) - process_list.bind("", self._show_context_menu) + process_list.bind("", self._show_context_menu, '+') def _show_context_menu(self, event): context_menu = self._context_menu From a3f3c5c15bb10f90e62986d0b88c053ec04278ca Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Mon, 9 Sep 2024 00:35:03 +0800 Subject: [PATCH 27/39] Added support for undo/redo, hotkeys, and bug fixes --- resources/UI/add-process-rule.png | Bin 0 -> 2321 bytes resources/UI/add-service-rule.png | Bin 0 -> 2387 bytes resources/UI/redo.png | Bin 0 -> 1643 bytes resources/UI/select-all.png | Bin 0 -> 2099 bytes resources/UI/undo.png | Bin 0 -> 1778 bytes .../migration/m1_new_fields_in_rule.py | 1 - src/constants/resources.py | 5 + src/constants/ui.py | 7 +- src/service/rules_service.py | 19 +-- src/ui/settings.py | 160 +++++++++++++----- src/ui/widget/common/button.py | 1 + src/ui/widget/common/entry.py | 31 +++- src/ui/widget/common/label.py | 2 +- src/ui/widget/common/treeview/editable.py | 112 +++++------- src/ui/widget/common/treeview/extended.py | 143 ++++++++++++++-- src/ui/widget/common/treeview/scrollable.py | 3 +- src/ui/widget/settings/settings_tabs.py | 21 ++- src/ui/widget/settings/tabs/base_tab.py | 6 +- src/ui/widget/settings/tabs/process_list.py | 113 ++++++++----- .../settings/tabs/rules/base_rules_tab.py | 14 +- .../widget/settings/tabs/rules/rules_list.py | 64 ++++++- src/util/history.py | 32 ++++ src/util/ui.py | 11 +- 23 files changed, 520 insertions(+), 225 deletions(-) create mode 100644 resources/UI/add-process-rule.png create mode 100644 resources/UI/add-service-rule.png create mode 100644 resources/UI/redo.png create mode 100644 resources/UI/select-all.png create mode 100644 resources/UI/undo.png create mode 100644 src/util/history.py diff --git a/resources/UI/add-process-rule.png b/resources/UI/add-process-rule.png new file mode 100644 index 0000000000000000000000000000000000000000..80a4dbd7f37c314744b811ba73ad601c34cea18a GIT binary patch literal 2321 zcmb_eZHN?Q93Rp2d^xf=x%xDXNEbCb&%Ex;cP!>Gl0Fz=5L92p#G*)$@;HeiG3-O2(FZBWixh1q!CgLal4EV0;5MmQkoA(J zWDkw|WaIdTJR0AM49xYfVf$((HBccTWNVeO6PUFGSGQ}@b+j#TY+WSWn&1W^hwSET zj!n8gVYL|G5daz+H)0rC5LwoftOO)c0E!?gJOHL_n2N$Se;jq^E;YS0tJ7>Hu33u4rk^G5x0-8n`ADU%9u!hp((ZCS76hHg-D=P=zq zzR3a2Z8qEXF)NlzrR^dJ)7xnn&4kP<9puM6B8-s09rY1OZ>KOfiz&d0*gfOoFd1z(`Y8$vg=dF6rJ3;pGhWj zzFV-%^dJ~nKged%Nli2~jhA9#9d0&jW}F~|4kDRUf}_ca*)}#6wSYvWP~de-(|Hvs z5)Vb9@mL0!V2#8vP+Iya7mY?O5a~DQfL%mw+<<54SOIce;dNCl@N^;bmK>LO%R(55 zx@-Z}XjyyOw<#lGxzlQd3R8qvyWq)C!Yps0(0L~Vb=bIZyA zjW3`T51OVKiKg&k+>ql0Ss2P>4(M8*zM=soyU}9s-9T@q6_ub< zBy`*e+}#IrXB=&y?5xAAucQAjn0jkAI!yR)^VQEf1`;h~eTz=HXxW~x^r1bWi9_?` z)A@Vx(}maQ?7oyq4dnIvQ0~x`tNkDJboC7WemDn)mhF7_nEi$~^VpJqK0m*&Z=&n? zbicGtoIZ2y)deEIZ0eVfUzAF(?L08^$F=Kk{d7V#&s0zT_~GQw@Z8J~-=5!c@H;Tc zJUa3G{NKLXyZ-uW!TVzW#S_M-(4CG?;DsLI=<(~;uY`p?zntq!4&+6 znNfEvyyu~V%at$5XREnm+u(90Egqd-G=6&Vkym;qCU?zyr{}@d7r?~MEs1lhatxDu XIlXtwGnWoWA1#^mhSbr)7hd`owZZg% literal 0 HcmV?d00001 diff --git a/resources/UI/add-service-rule.png b/resources/UI/add-service-rule.png new file mode 100644 index 0000000000000000000000000000000000000000..c31d86b18673984bf055598a3f784a6fcc4261ea GIT binary patch literal 2387 zcmb_ed2AF_7+(tIDx{@YAgE-Rf?S=QbB`I=mbP2kg>I>3Q(6+CbG&IM-Q8JdrtP+d zLnvMif+;outAYmzM*V{t&?1d7jRz@$6y?yA0Gb*FIYbD7=$pMLT8+mAMzh$Y9Tf z))+>J!|{fO25SRtRkdoIWLXv`D4e1&Xo2aCL4yxtK|M2$;0C&=DIr5qgNTX93u>L= zLZQ^C4}nkuHmJwq1S5ur`4CQ83Dc*Dp(G~kLUo!yLN19o@Phyd8alKk6Skom)ll^s z^)Aqf={pEuY`xwD$DmpQfdqwa6x2gEVgVV{TK6@E0A2=kwN4X3K|Pe2X?hdl@-@I4 zs^(Kwe|)D(13Ra^?B8*(V>Q^;L z4As#C$36M^rJ5=$emJ3*73LwHf_yv4+U*!+B_ndZUd|KL4L&FWkK2X9;8+z!;s8yv z1P~k;!AeeyaWEt%02_g^c3z|o+(i!}vSB<~-HYO0bTBEw4#K_*y?5qKLWF^mHf91aq* z(@xsyVC_JlC^PMEGsjVKp?^BuaXnU6d3<%OzrDTZAGEU4XIT+ZL zD4DPUrzkn+;bslNMM$(21;X#m2nk@Eixg8qV~lqRcsii~i6k?}i)N9!P|?gzAfd5g zWsv=Oph(2lH`D+KdXKD)vg@jBH1Hb8t%iGf->SgxCSK?3?=78muz;j#CuRc#g-JX^ zVFD@Bm@LbpWVZ>jD2j2{|0A8EImQl;$#@k#jPzJo#2P+W4d9WFqYv-QgVjk?Vcp>aKit~?jA!9;Z)^9uvp+BITX}6!#=DDp(>r??K6Y{c#S51C{blu6 zHa2yQ+H&&wsoa+vtAOIiQyurYEQI%(T+^RvfOP~!eDuWIc-%WW)G literal 0 HcmV?d00001 diff --git a/resources/UI/redo.png b/resources/UI/redo.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe652482333d32de07327d354f22f6516c73c75 GIT binary patch literal 1643 zcmbVNTWB0r7@kHWHk(*VOX}rimfsKn4%+-(E!RorexX}O%O-IC0o-cp+{z5&ahPKm-pVMNCT+UXm^53*b$gFVlxgL znHfs!Gn2XusPLoYk&=Q5Oz3H3$t+l|Qc|fZuY%|PHcOFJh&QQHeZD|)ERiH5$bqE9 zaJ0^G64@g&K+9-)CUck+IDuz5k>y32M4_uYhV2>1B7H_JgQh%{!m8G6FzqI- z<<|X#J;s(ao8=kKx2XyQdJ|_)IfbflptG<5O=x*8#_~<9okt#W^XOlwo5wc^z`ji+ znlg6O#Wb5DTyNkMHlyy49no%j+JYTZuSO^N^E9sL+U1vY|35 z2#iQRG-_A?72SuoU4T)|gDQoihT|pETrkZEiV#$S+#xQca9j`I)N+uutsF%*-Ka!R0XbMO)-JexKOTuB9h5Z+_`ppa?I+^{ z5s8;2i53{Xs%|2o#4Xp;EFH$9DutcH7zR)v$4l7^=%z)Gm1$lVd+1P)mZiB6;3N$M zMJXgU?njY6<)=X7KKP&ahaCggpjNnT9=|gE+)-kNi=#SSFP#y1vOX&qWHntBP4~+{ zrF1|35K#4PTMO*_qC7-Z=Aa=fveR`M{0b>^0)a@s~qCt&EUcdzO>lJlOqs=hfk@{e-ywz<7kG zH{t>!Zes~bzJUshgA zzujy7a3DT$W43?pYG&y;(eZuem4)Bp+09V{ui82%9vmNB|8C_@yjWfCI${63xcN@s o>|dwvSvo<{9 literal 0 HcmV?d00001 diff --git a/resources/UI/select-all.png b/resources/UI/select-all.png new file mode 100644 index 0000000000000000000000000000000000000000..a23a9ee40a39a9049a619331ffc0d1965e191e23 GIT binary patch literal 2099 zcmb_d%WvF77&j@TG*N`AqN;$9jLWm&_4v8#Q8usL(5%EJAz75=P^shbc-P9V$JkDG z6LEnH&kJy?kf_=d2qB?@gv5cOic%yvaN-XDA#tLQ3*yl7d0*W^npP1jc|G?0=J)-+ zm%q1`7mrVjJv=4|!bEAIxB~Yha2>pV6#l<&HxS$ogbOdnf-rt4z3vfCeF%vCC;Un^ zsg_^Bls7ZP<)wO(gji8ptyZR` zXLwXoRNJ-{q$!#v1453sf`qi?AU@h>D6*JFewg??5K~6t@Qoxdfz+-K&2T^)#JxB{ z#FRD(6*YrWpE^L74shW{)aV#@slpnp$$}&XtUADkb)N9J&Tm6K*uKR8#I{@>*w|4^ zvpFykC-a-&MlT>cqT|X|$dnZp^NonI`Av{{H1#ILg@}=aM-|Q+{Y)+QC5xJtF~q0W z{J`a{_?e*ttVj};mmq79ubix!71hS3jgj>%%3*}M&@y*@Z)+H8%Sf*v9iuGP>|3Bv zGcHNU9l#?9QK=}#*{FqN#Y=kxWF4c0>hwAAAVmd6qY0I`3=~JSB}q#rTK!T z+Lk428MPy~T*jp!PDnsmshF1_I2qq}an7=Ao9M2LOz_mu3{Q5lIa8(%&AJFN2bos? ze38?Qv;@-g-F9#}1&*8YbXCh)RQF`VbS;@OgUAj+5JXqCJ<3eeF<75%De|EsNn@Bb zRpkOBF{tTTl*mL^E!iN3F6T_sl^xHtb5zxHs^_I;f75cGWfuI4A>(nct>#Frw`%xP zdlx;aq#XqmVt3W0Rd%=EsdK#Gr+T(}DpuJm13hA=v@xM+%jPAT)+%$Q-fMq{Y~58{ zdgohp2Bf>xaMyawy`)7VHd}+t-myoN+li0K=I+uh6;Z>`Em`*w-g)%G$m!zPeWPc8eY|nln0exnBbV;I{L7UwG literal 0 HcmV?d00001 diff --git a/resources/UI/undo.png b/resources/UI/undo.png new file mode 100644 index 0000000000000000000000000000000000000000..c2d8b9b4f3aed0f739003d400d4d5d4351e62b63 GIT binary patch literal 1778 zcmbVNU5Fb+9M7G`)}DncMJ)aW7D4bqp@?XG@B;*`h%Z*KLZMF$6?{+xAEaRLoXr>4de@dN?C$K$ zZ+`#Z|6~69a%tw^_H7Ssi$o&Zi-la7y?3#D$JTq;^ZQmqVy}DM!kiz8jO`5Xk;vO; z7$SPrs>}wn`qLVwwt!4(5TRwe3>}F~O}AWx=SctzQnQ>C_ve>ibHFlF+>uFL(%men zTZLth9A2KO;N^L&n%wjgV5+4t0-FQ~wCslCYpoR5<<;0YoEACIg#_~{E)yCAvw8_+ zsYie!NIaG#1te6#LpBOOYh>tzX4J_(_kP#VlAxLpdYR?DT z9nv~}KTa%SVhg!qOprpKx0L1G@yQ+ZbCg=zRm!P zt*#GkY^cSyhbH_WzsTI^2V_IEUs-aASSCJQ@G!|QGMN*hH?EfT2nwiIp|ml`RB0d? zKq$n)o+FlH(x$(6-3F3F0ZDNzYb;+XFUb`NYEahX0e1`ae|G7zirY zL0Qe1C_uLan^>z-&qmB)%SJUKx=xJ)!!T-D+MpgY%+$&2=Zo2F$)i=P!4~}T!Tq3^ z&nhuhQFtiCx^i`0D>{CF988M26vu)iSeB`&ScOJXGI(4y2|uaEA)myO!plijB_@;& zoKy$&coeV3cu9$?Jc3x|%@{P|gvbQS%3%K?&thi~HSU-v zJegtbXa&n>SzYQMox|j4f7Gx*w_G%Y!())*aF~B$a{Xy*g9zN72R+(moiNgy)I|^G z(`wK}9?8^Lv~F2<;%4G~w0Lvrx0k%lq~B1dcOtzXR$NC;jj*OFa-lO~*nN6Q5pT>_ zcWqs#8o*im3x~tT%RYv!n>dWxV~u(0a`rT9>gS5NOeMJkm(KkC*7I+k-j&a!J7X(r zKYuf7e*2*_^2L?PXOVZV{C4fp@#$zgnm&8rM6{jmym5?8Jv{!;srFqI{F`}k_jB)` zA5orq{nxo;mmXN5kNt3AV)Fj?o;j|+%CB~IdVh_4vis82&rj~VHuGBag^wRxjV3;@ zNA^4-aC1LBX^)*adEeUI=T|SDOOLKhgSk@9K`)IRO2ZBu|FnF0Q~^J3Xb fx4zOowI%Y$#m>8HU;Xl3_*W|CXL29yfA;u)`@cSd literal 0 HcmV?d00001 diff --git a/src/configuration/migration/m1_new_fields_in_rule.py b/src/configuration/migration/m1_new_fields_in_rule.py index 8e6ddae..4e964ec 100644 --- a/src/configuration/migration/m1_new_fields_in_rule.py +++ b/src/configuration/migration/m1_new_fields_in_rule.py @@ -1,4 +1,3 @@ -import itertools from typing import Optional from configuration.migration.base import BaseMigration diff --git a/src/constants/resources.py b/src/constants/resources.py index 6ec1553..2563dd7 100644 --- a/src/constants/resources.py +++ b/src/constants/resources.py @@ -10,6 +10,8 @@ UI_PROCESS_LIST: Final[str] = f"{APP_PATH}/resources/UI/process-list.png" UI_ADD: Final[str] = f"{APP_PATH}/resources/UI/add.png" +UI_ADD_PROCESS_RULE: Final[str] = f"{APP_PATH}/resources/UI/add-process-rule.png" +UI_ADD_SERVICE_RULE: Final[str] = f"{APP_PATH}/resources/UI/add-service-rule.png" UI_DELETE: Final[str] = f"{APP_PATH}/resources/UI/delete.png" UI_UP: Final[str] = f"{APP_PATH}/resources/UI/up.png" UI_DOWN: Final[str] = f"{APP_PATH}/resources/UI/down.png" @@ -17,6 +19,9 @@ UI_REFRESH: Final[str] = f"{APP_PATH}/resources/UI/refresh.png" UI_CONFIG: Final[str] = f"{APP_PATH}/resources/UI/config.png" UI_LOG: Final[str] = f"{APP_PATH}/resources/UI/log.png" +UI_REDO: Final[str] = f"{APP_PATH}/resources/UI/redo.png" +UI_UNDO: Final[str] = f"{APP_PATH}/resources/UI/undo.png" +UI_SELECT_ALL: Final[str] = f"{APP_PATH}/resources/UI/select-all.png" UI_INFO_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/info-tooltip.png" UI_WARN_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/warn-tooltip.png" diff --git a/src/constants/ui.py b/src/constants/ui.py index 019f104..bdadf64 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -15,8 +15,8 @@ OPEN_CONFIG_LABEL = "Open config file" OPEN_LOG_LABEL = "Open log file" -CMENU_ADD_PROCESS_RULE_LABEL = " Add Process Rule" -CMENU_ADD_SERVICE_RULE_LABEL = " Add Service Rule" +CMENU_ADD_PROCESS_RULE_LABEL = " Add Process Rule" +CMENU_ADD_SERVICE_RULE_LABEL = " Add Service Rule" class ActionEvents: @@ -25,7 +25,7 @@ class ActionEvents: UP: Final[str] = "<>" DOWN: Final[str] = "<>" CANCEL: Final[str] = "<>" - APPLY: Final[str] = "<>" + SAVE: Final[str] = "<>" APPLY_N_CLOSE: Final[str] = "<>" REFRESH: Final[str] = "<>" CONFIG: Final[str] = "<>" @@ -36,6 +36,7 @@ class ActionEvents: class ExtendedTreeviewEvents: CHANGE: Final[str] = "<>" + BEFORE_CHANGE: Final[str] = "<>" class EditableTreeviewEvents: diff --git a/src/service/rules_service.py b/src/service/rules_service.py index 58bc128..c7188c3 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -128,23 +128,20 @@ def __set_affinity(cls, process: Process, rule: ProcessRule | ServiceRule): def __first_rule_by_process(cls, config: Config, process: Process) -> Optional[ProcessRule | ServiceRule]: if process.service: for rule in config.serviceRules: - value = process.service_name - - if rule.selectorBy == SelectorType.PATH: - value = process.bin_path - elif rule.selectorBy == SelectorType.CMDLINE: - value = process.cmd_line - - if path_match(rule.selector, value): + if path_match(rule.selector, process.service_name): return rule for rule in config.processRules: - value = process.process_name - - if rule.selectorBy == SelectorType.PATH: + if rule.selectorBy == SelectorType.NAME: + value = process.process_name + elif rule.selectorBy == SelectorType.PATH: value = process.bin_path elif rule.selectorBy == SelectorType.CMDLINE: value = process.cmd_line + else: + message = f"Unknown selector type: {rule.selectorBy}" + LOG.error(message) + raise ValueError(message) if path_match(rule.selector, value): return rule diff --git a/src/ui/settings.py b/src/ui/settings.py index a7f3a5d..47e4286 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -1,6 +1,8 @@ import os from tkinter import messagebox, ttk, Tk, X, TOP, BOTH, NORMAL, DISABLED +from typing import Optional +from configuration.migration.all_migration import run_all_migration from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.files import LOG_FILE_NAME from constants.log import LOG @@ -9,12 +11,15 @@ from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, SETTINGS_TITLE, EditableTreeviewEvents, \ RIGHT_PACK, LEFT_PACK, OPEN_CONFIG_LABEL, OPEN_LOG_LABEL, ExtendedTreeviewEvents from ui.widget.common.button import ExtendedButton +from ui.widget.common.entry import ExtendedEntry from ui.widget.settings.settings_tabs import SettingsTabs from ui.widget.settings.tabs.base_tab import BaseTab from ui.widget.settings.tabs.process_list import ProcessListTab from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab +from ui.widget.settings.tabs.rules.rules_list import RulesList from ui.widget.settings.tooltip import Tooltip from util.files import open_config_file, open_log_file +from util.history import HistoryManager from util.messages import yesno_error_box from util.scheduler import TaskScheduler from util.ui import load_img @@ -28,10 +33,10 @@ def __init__(self): self._tooltip: Tooltip self._actions: SettingsActions - self._setup_window() self._create_widgets() self._pack() self._setup_tooltips() + self._setup_window() def _setup_window(self): self._center_window() @@ -41,28 +46,70 @@ def _setup_window(self): self.title(APP_NAME_WITH_VERSION) self.minsize(*RC_WIN_SIZE) - self.bind_all("", self._on_key_release, "+") + self.bind("", lambda _: self._tabs.next_tab(), "+") + self.bind("", lambda _: self._tabs.prev_tab(), "+") - def _on_key_release(self, event): + self.bind("", self._fix_cyrillic_binds, "+") + self.bind("", self._global_actions, "+") + + def _fix_cyrillic_binds(self, event): + ctrl = (event.state & 0x4) != 0 + + if not ctrl: + return + + keycode = event.keycode + keysym = event.keysym.upper() + + if keysym != "??": + return + + keysym = chr(keycode) + key_to_event = { + "X": "<>", + "V": "<>", + "C": "<>", + "A": "<>" + } + + if keysym not in key_to_event: + return + + self.focus_get().event_generate(key_to_event[keysym]) + + def _global_actions(self, event): ctrl = (event.state & 0x4) != 0 shift = (event.state & 0x1) != 0 + if not ctrl: + return + keycode = event.keycode - widget = event.widget keysym = event.keysym.upper() - key_actions = { - ord('X'): "<>", - ord('V'): "<>", - ord('C'): "<>", - ord('A'): "<>", - # ord('Z'): "<>" if not shift else "<>", - # ord('Y'): "<>", + if keysym == "??": + keysym = chr(keycode) + + if shift: + key = ("Shift", keysym) + else: + key = (keysym,) + + key_to_callback = { + ("D",): lambda: self._add_row(), + ("F",): lambda: self._search_focus(), + + ("S",): lambda: self._save(), + ("Z",): lambda: self._history_shift(event, False), + + ("Shift", "Z"): lambda: self._history_shift(event, True), + ("Y",): lambda: self._history_shift(event, True) } - if ctrl and keycode in key_actions and keysym == '??': - self.after(0, lambda: widget.event_generate(key_actions[keycode])) - # return 'break' + if key not in key_to_callback: + return + + key_to_callback[key]() def _center_window(self): x = (self.winfo_screenwidth() // 2) - (RC_WIN_SIZE[0] // 2) @@ -86,22 +133,19 @@ def _create_tabs(self): def _create_actions(self): self._actions = actions = SettingsActions(self) - actions.bind(ActionEvents.APPLY, lambda _: self._apply(), "+") - actions.bind(ActionEvents.APPLY_N_CLOSE, lambda _: self._apply_and_close(), "+") + actions.bind(ActionEvents.SAVE, lambda _: self._save(), "+") actions.bind(ActionEvents.CONFIG, lambda _: open_config_file(), "+") actions.bind(ActionEvents.LOG, lambda _: open_log_file(), "+") self._update_actions_state() - def _apply_and_close(self): - self._on_window_closing(False) - - def _apply(self): + def _save(self): result = self._tabs.save_data() + self._tabs._update_tabs_state() self._update_actions_state() return result - def _on_window_closing(self, ask_about_changes=True): + def _on_window_closing(self): has_error = self._tabs.has_error() if self._tabs.has_unsaved_changes(): @@ -113,17 +157,14 @@ def _on_window_closing(self, ask_about_changes=True): if not result: return else: - if ask_about_changes: - message = ("There are unsaved changes. " - "Do you want to save them before exiting?") - result = messagebox.askyesnocancel(f"{APP_NAME_WITH_VERSION}", message) - else: - result = True + message = ("There are unsaved changes. " + "Do you want to save them before exiting?") + result = messagebox.askyesnocancel(f"{APP_NAME_WITH_VERSION}", message) if result is None: return - if result and not self._apply(): + if result and not self._save(): return else: if has_error: @@ -141,14 +182,12 @@ def _update_actions_state(self, _=None): tabs = self._tabs actions = self._actions - actions.apply["state"] = NORMAL if tabs.has_unsaved_changes() and not tabs.has_error() else DISABLED - actions.apply_n_close["state"] = actions.apply["state"] + actions.save["state"] = NORMAL if tabs.has_unsaved_changes() and not tabs.has_error() else DISABLED def _setup_tooltips(self): self._setup_tooltip(self._actions.open_config) self._setup_tooltip(self._actions.open_log) - self._setup_tooltip(self._actions.apply) - self._setup_tooltip(self._actions.apply_n_close) + self._setup_tooltip(self._actions.save) tabs = self._tabs tabs.bind("", self._set_tooltip_by_tab, "+") @@ -255,6 +294,43 @@ def _pack(self): self._tabs.pack(fill=BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) self._actions.pack(fill=X, padx=UI_PADDING, pady=(0, UI_PADDING)) + def _history_shift(self, event, is_redo): + widget = event.widget + tab = self._tabs.current_tab() + history: Optional[HistoryManager] = None + + if isinstance(widget, ExtendedEntry): + history = widget.history + elif isinstance(tab, BaseRulesTab): + history = tab.rules_list.history + + if history is None: + return + + if is_redo: + history.redo() + else: + history.undo() + + def _add_row(self): + tab = self._tabs.current_tab() + + if not isinstance(tab, BaseRulesTab): + return + + if not isinstance(self.focus_get(), RulesList): + return + + tab.rules_list.add_row() + + def _search_focus(self): + tab = self._tabs.current_tab() + + if not isinstance(tab, ProcessListTab): + return + + tab.actions.search.focus_set() + class SettingsActions(ttk.Frame): def __init__(self, *args, **kwargs): @@ -278,26 +354,17 @@ def _setup_btn(self): description="**Opens** the __log file__." ) - self.apply = apply = ExtendedButton( - self, - text="Apply", - event=ActionEvents.APPLY, - image=load_img(file=UI_SAVE), - description="**Applies** the __settings__." - ) - - self.apply_n_close = apply_n_close = ExtendedButton( + self.save = save = ExtendedButton( self, - text="Apply & Close", - event=ActionEvents.APPLY_N_CLOSE, + text="Save", + event=ActionEvents.SAVE, image=load_img(file=UI_SAVE), - description="**Applies and Сloses** the __settings__." + description="**Saves** the __settings__. \n**Hotkey:** __Ctrl+S__." ) open_config.pack(**LEFT_PACK) open_log.pack(**LEFT_PACK) - apply_n_close.pack(**RIGHT_PACK) - apply.pack(**RIGHT_PACK) + save.pack(**RIGHT_PACK) def open_settings(): @@ -325,5 +392,6 @@ def show_settings_error_message(): if __name__ == "__main__": + run_all_migration() test_app = Settings() test_app.mainloop() diff --git a/src/ui/widget/common/button.py b/src/ui/widget/common/button.py index 418435a..e79c3a5 100644 --- a/src/ui/widget/common/button.py +++ b/src/ui/widget/common/button.py @@ -19,6 +19,7 @@ def __init__( compound=None, **kwargs ): + self._image = image self._font = get_button_font() self.description = description diff --git a/src/ui/widget/common/entry.py b/src/ui/widget/common/entry.py index fb9f3ee..18f8178 100644 --- a/src/ui/widget/common/entry.py +++ b/src/ui/widget/common/entry.py @@ -1,5 +1,7 @@ from tkinter import END, Entry +from util.history import HistoryManager + class ExtendedEntry(Entry): def __init__(self, master=None, placeholder=None, color='grey', description=None, *args, **kwargs): @@ -9,7 +11,12 @@ def __init__(self, master=None, placeholder=None, color='grey', description=None **kwargs ) + self._commit_history = True self.description = description + self._setup_placeholder(color, placeholder) + self._setup_history() + + def _setup_placeholder(self, color, placeholder): self._placeholder = placeholder if placeholder is not None: @@ -21,8 +28,22 @@ def __init__(self, master=None, placeholder=None, color='grey', description=None self._focus_out() + def _setup_history(self): + self.history = history = HistoryManager(self.get, self.set) + + # Doesn't work globally + # self.bind("<>", lambda _: history.redo() or print('redo'), '+') + # self.bind("<>", lambda _: history.undo() or print('undo'), '+') + + self.config(validate="key", validatecommand=(self.register(self._text_changed))) + + def _text_changed(self): + if self._commit_history: + self.history.commit() + return True + def _set_placeholder(self): - self.insert(0, self._placeholder) + self.set(self._placeholder) self['fg'] = self._placeholder_color def _focus_in(self, *args): @@ -41,3 +62,11 @@ def get(self): return "" else: return current_text + + def set(self, value): + try: + self._commit_history = False + self.delete(0, END) + self.insert(0, value) + finally: + self._commit_history = True diff --git a/src/ui/widget/common/label.py b/src/ui/widget/common/label.py index 70ce738..d91a695 100644 --- a/src/ui/widget/common/label.py +++ b/src/ui/widget/common/label.py @@ -54,7 +54,6 @@ def _set_bg(event): if text: self.configure(text=text) - self.bind("", lambda e: self.focus_set(), '+') self.bind("<1>", lambda event: "break", '+') self.bind("", lambda event: "break", '+') self.bind("", lambda event: "break", '+') @@ -156,6 +155,7 @@ def configure(self, **kwargs): class Image(ttk.Label): def __init__(self, *args, image=None, **kwargs): + self._image = image super().__init__(*args, image=image, **kwargs) def config(self, *args, **kwargs): diff --git a/src/ui/widget/common/treeview/editable.py b/src/ui/widget/common/treeview/editable.py index c87064c..b1932b9 100644 --- a/src/ui/widget/common/treeview/editable.py +++ b/src/ui/widget/common/treeview/editable.py @@ -2,11 +2,12 @@ from tkinter import END, BOTH, Widget from typing import Optional, Literal -from constants.ui import EditableTreeviewEvents, ScrollableTreeviewEvents +from constants.ui import EditableTreeviewEvents, ScrollableTreeviewEvents, ExtendedTreeviewEvents from ui.widget.common.combobox import EnumCombobox from ui.widget.common.entry import ExtendedEntry from ui.widget.common.treeview.extended import CellInfo, ExtendedTreeview, RegionType from ui.widget.common.treeview.scrollable import ScrollableTreeview +from util.history import HistoryManager from util.ui import full_visible_bbox from util.utils import extract_type @@ -26,14 +27,16 @@ def __init__( cell_info: CellInfo ): self.cell = cell_info - self.widget = self._setup_widgets(master) + self._setup_widgets(master) def _setup_widgets(self, master): def on_change(_): self.event_generate(EditableTreeviewEvents.SAVE_CELL) + master.focus_set() def on_escape(_): self.event_generate(EditableTreeviewEvents.ESCAPE) + master.focus_set() cell = self.cell column_settings = master.column(cell.column_id) @@ -52,7 +55,8 @@ def on_escape(_): editor.bind("<>", on_change, '+') else: editor = ExtendedEntry(master, justify=justify) - editor.insert(0, cell.value) + editor.set(cell.value) + editor.history.clear() editor.select_range(0, END) editor.bind("", on_change, '+') @@ -60,7 +64,7 @@ def on_escape(_): editor.bind("", on_escape, '+') editor.pack(fill=BOTH) - return editor + self.widget = editor def get(self): return self.widget.get().strip() @@ -79,6 +83,38 @@ def __init__(self, *args, **kwargs): self.bind("", self._on_dbl_click, '+') self.bind(ScrollableTreeviewEvents.SCROLL, self._place_editor, '+') self.bind("", lambda _: self.after(1, self._place_editor), '+') + self.bind("<>", lambda _: self.select_all_rows(), "+") + self.bind("", lambda _: self.delete_selected_rows(), "+") + + self._setup_history() + + def _setup_history(self): + self.history = history = HistoryManager( + self._get_historical_data, + self._set_historical_data, + 50 + ) + + self.bind(ExtendedTreeviewEvents.BEFORE_CHANGE, lambda _: history.commit(), "+") + + def _get_historical_data(self): + return self.selection_indices(), self.as_list_of_list() + + def _set_historical_data(self, indices_values): + try: + self.begin_changes(True) + self.clear() + + indices, values = indices_values + + for value in values: + self.insert('', 'end', values=value) + + self.selection_indices_set(indices) + finally: + self.end_changes() + + self.update_focus() def editor(self) -> CellEditor: return self._editor @@ -115,7 +151,7 @@ def _place_editor(self, _=None): if bbox: x, y, width, height = bbox editor.place(x=x, y=y, width=width, height=height) - editor.after(0, lambda: editor.focus_force()) # fixing focus_force not working from time to time + editor.after(0, lambda: editor.focus_set()) # fixing focus_force not working from time to time else: editor.place_forget() @@ -145,69 +181,3 @@ def _on_editor_destroy(self, _=None): def edit_cell(self, column_id, row_id, region: RegionType): self._destroy_editor() self._create_editor(self.get_cell_info_by_ids(column_id, row_id, region)) - - def select_all_rows(self): - items = self.get_children() - - if items: - self.selection_set(items) - - def move_rows_up(self): - selected_items = self.selection() - - if selected_items: - for selected_item in selected_items: - index = self.index(selected_item) - next_index = index - 1 - - if index <= 0: - break - - self.move(selected_item, '', next_index) - - self.selection_set(selected_items) - - def move_rows_down(self): - selected_items = self.selection() - count_items = len(self.get_children()) - - if selected_items: - for selected_item in reversed(selected_items): - index = self.index(selected_item) - next_index = index + 1 - - if next_index >= count_items: - break - - self.move(selected_item, '', next_index) - - self.selection_set(selected_items) - - def add_row(self, values=None, index=None): - selected_items = self.selection() - - if selected_items and index is None: - selected_item = selected_items[0] - index = self.index(selected_item) - - self.insert('', index, values=values or []) - self.selection_set(self.get_children()[index]) - else: - self.insert('', index or 0, values=values or []) - - def delete_selected_rows(self): - selected_items = self.selection() - - if selected_items: - index = self.index(selected_items[0]) - - for item in selected_items: - self.delete(item) - - children = self.get_children() - - if len(children) <= index: - index -= 1 - - if children and len(children) > index: - self.selection_set(children[index]) diff --git a/src/ui/widget/common/treeview/extended.py b/src/ui/widget/common/treeview/extended.py index 783af0f..6c9052d 100644 --- a/src/ui/widget/common/treeview/extended.py +++ b/src/ui/widget/common/treeview/extended.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from functools import lru_cache -from tkinter import ttk, END +from tkinter import ttk from typing import Optional, Literal, Any from pydantic.config import JsonDict @@ -29,12 +29,14 @@ def __init__(self, *args, hand_on_title: bool = False, **kwargs): self._types: dict[str, type] = {} self._width_set: dict[str, bool] = {} - self._generate_event_change: bool = True + self._stop_event_broadcast: bool = False self._changed: tuple = tuple() + self._before_change_sent: bool = False self._setup_font() self.bind('', self._calculate_columns_width, '+') self.bind('', lambda _: self.clear_selection(), '+') + self.bind("", lambda _: self._focus_in(), '+') if hand_on_title: self.bind("", self._on_motion, '+') @@ -160,43 +162,56 @@ def as_dict(self, row_id) -> JsonDict: def as_list_of_dict(self) -> list[JsonDict]: return [self.as_dict(row_id) for row_id in self.get_children()] - def begin_changes(self): - if not self._generate_event_change: + def begin_changes(self, disable_before_change_event=False): + if self._stop_event_broadcast: raise RuntimeError("Has already been called begin_changes") - self._changed = [] - self._generate_event_change = False + self._stop_event_broadcast = True + self._before_change_sent = disable_before_change_event + self._changed = tuple() def end_changes(self): - if self._generate_event_change: + if not self._stop_event_broadcast: raise RuntimeError("begin_changes must be called before end_changes") - self._generate_event_change = True + self._stop_event_broadcast = False + self._before_change_sent = False if self._changed: sequence, args, kwargs = self._changed - self._changed = [] + self._changed = tuple() super().event_generate(sequence, *args, **kwargs) def event_generate(self, sequence, *args, **kwargs): - if not self._generate_event_change and sequence == ExtendedTreeviewEvents.CHANGE: - self._changed = (sequence, args, kwargs) + if self._stop_event_broadcast: + if sequence == ExtendedTreeviewEvents.BEFORE_CHANGE and not self._before_change_sent: + self._before_change_sent = True + return super().event_generate(sequence, *args, **kwargs) + + if sequence == ExtendedTreeviewEvents.CHANGE: + self._changed = (sequence, args, kwargs) + return super().event_generate(sequence, *args, **kwargs) def insert(self, parent, index, iid=None, **kw): + self.event_generate(ExtendedTreeviewEvents.BEFORE_CHANGE) result = super().insert(parent, index, iid, **kw) self.event_generate(ExtendedTreeviewEvents.CHANGE) return result def delete(self, *args): + self.event_generate(ExtendedTreeviewEvents.BEFORE_CHANGE) result = super().delete(*args) self.event_generate(ExtendedTreeviewEvents.CHANGE) return result def set(self, item, column=None, value=None): + if value is not None: + self.event_generate(ExtendedTreeviewEvents.BEFORE_CHANGE) + result = super().set(item, column, value) if value is not None: @@ -205,6 +220,112 @@ def set(self, item, column=None, value=None): return result def move(self, item, parent, index): + self.event_generate(ExtendedTreeviewEvents.BEFORE_CHANGE) result = super().move(item, parent, index) self.event_generate(ExtendedTreeviewEvents.CHANGE) return result + + def _focus_in(self): + items = self.get_children() + + if not items: + return + + selected_items = self.selection() + + if selected_items: + items = selected_items + + item = items[0] + + if not selected_items: + self.selection_set(item) + + self.focus(item) + + def focus_set(self): + super().focus_set() + self._focus_in() + + def selection_indices(self): + return [self.index(item) for item in self.selection()] + + def selection_indices_set(self, indices): + items = self.get_children() + self.selection_set([items[index] for index in indices]) + + def select_all_rows(self): + items = self.get_children() + + if items: + self.selection_set(items) + + self.update_focus() + + def move_rows_up(self): + selected_items = self.selection() + + if selected_items: + for selected_item in selected_items: + index = self.index(selected_item) + next_index = index - 1 + + if index <= 0: + break + + self.move(selected_item, '', next_index) + + self.update_focus() + + def move_rows_down(self): + selected_items = self.selection() + count_items = len(self.get_children()) + + if selected_items: + for selected_item in reversed(selected_items): + index = self.index(selected_item) + next_index = index + 1 + + if next_index >= count_items: + break + + self.move(selected_item, '', next_index) + + self.update_focus() + + def add_row(self, values=None, index=None): + selected_items = self.selection() + + if selected_items and index is None: + selected_item = selected_items[0] + index = self.index(selected_item) + + self.insert('', index, values=values or []) + self.selection_set(self.get_children()[index]) + else: + self.insert('', index or 0, values=values or []) + + self.update_focus() + + def delete_selected_rows(self): + selected_items = self.selection() + + if selected_items: + index = self.index(selected_items[0]) + + self.delete(*selected_items) + children = self.get_children() + + if len(children) <= index: + index -= 1 + + if children and len(children) > index: + self.selection_set(children[index]) + + self.update_focus() + + def update_focus(self): + if self.focus_get() != self: + return + + self.focus_set() diff --git a/src/ui/widget/common/treeview/scrollable.py b/src/ui/widget/common/treeview/scrollable.py index 6338db8..100a862 100644 --- a/src/ui/widget/common/treeview/scrollable.py +++ b/src/ui/widget/common/treeview/scrollable.py @@ -9,7 +9,8 @@ def __init__(self, master=None, *args, **kwargs): self._frame = ttk.Frame(master) self._scrollbar = ttk.Scrollbar( self._frame, - orient="vertical" + orient="vertical", + takefocus=0 ) super().__init__(self._frame, *args, **kwargs) diff --git a/src/ui/widget/settings/settings_tabs.py b/src/ui/widget/settings/settings_tabs.py index 6dd73a5..cee483a 100644 --- a/src/ui/widget/settings/settings_tabs.py +++ b/src/ui/widget/settings/settings_tabs.py @@ -1,4 +1,4 @@ -from tkinter import ttk, messagebox, LEFT +from tkinter import ttk, messagebox from typing import Optional from constants.app_info import APP_NAME_WITH_VERSION @@ -34,9 +34,9 @@ def _create_tabs(self): service_rules_tab.rules_list ) - self._add_tab(process_list_tab) - self._add_tab(process_rules_tab) - self._add_tab(service_rules_tab) + process_list_tab.place() + process_rules_tab.place() + service_rules_tab.place() def current_tab(self) -> BaseTab: current_index = self.index(self.select()) @@ -100,12 +100,19 @@ def frames_by_tab(self) -> dict[str, BaseTab]: def get_default_tooltip(self): return self.current_tab().default_tooltip() - def _add_tab(self, tab: BaseTab): - self.add(tab, text=f" {tab.title()}", image=tab.icon(), compound=LEFT) - def _update_tabs_state(self): tabs = self.frames_by_tab() for id, tab in tabs.items(): star = "*" if tab.has_changes() or tab.has_error() else "" self.tab(id, text=f" {tab.title()} {star}") + + def next_tab(self): + current_tab = self.index(self.select()) + next_tab = (current_tab + 1) % self.index("end") + self.select(next_tab) + + def prev_tab(self): + current_tab = self.index(self.select()) + next_tab = (current_tab - 1) % self.index("end") + self.select(next_tab) \ No newline at end of file diff --git a/src/ui/widget/settings/tabs/base_tab.py b/src/ui/widget/settings/tabs/base_tab.py index ed1e5ae..17c763d 100644 --- a/src/ui/widget/settings/tabs/base_tab.py +++ b/src/ui/widget/settings/tabs/base_tab.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from tkinter import PhotoImage, ttk +from tkinter import PhotoImage, ttk, LEFT from tkinter.ttk import Notebook @@ -49,4 +49,6 @@ def commit_changes(self): def has_error(self) -> bool: pass - + def place(self): + self._icon = self.icon() + self.master.add(self, text=f" {self.title()}", image=self._icon, compound=LEFT) diff --git a/src/ui/widget/settings/tabs/process_list.py b/src/ui/widget/settings/tabs/process_list.py index 297746f..b1e38fc 100644 --- a/src/ui/widget/settings/tabs/process_list.py +++ b/src/ui/widget/settings/tabs/process_list.py @@ -1,10 +1,10 @@ import textwrap -from tkinter import PhotoImage, ttk, X, BOTH, NORMAL, DISABLED, CENTER, Menu, LEFT, END +from tkinter import PhotoImage, ttk, X, BOTH, NORMAL, DISABLED, CENTER, Menu, END, LEFT from tkinter.ttk import Notebook from typing import Optional from constants.log import LOG -from constants.resources import UI_PROCESS_LIST, UI_REFRESH +from constants.resources import UI_PROCESS_LIST, UI_REFRESH, UI_ADD_PROCESS_RULE, UI_ADD_SERVICE_RULE from constants.threads import THREAD_PROCESS_LIST from constants.ui import UI_PADDING, ActionEvents, LEFT_PACK, CMENU_ADD_PROCESS_RULE_LABEL, \ CMENU_ADD_SERVICE_RULE_LABEL @@ -50,6 +50,9 @@ def __init__(self, master: Notebook, process_rules_list: RulesList, service_rule super().__init__(master) + self._is_close = False + self.bind("", self._on_close) + self._setup_widgets() self._loader = PydanticTreeviewLoader(self.process_list, self.model) self._pack() @@ -57,13 +60,11 @@ def __init__(self, master: Notebook, process_rules_list: RulesList, service_rule def _create_process_list(self): columns = [key for key, field_info in self.model.model_fields.items() if not field_info.exclude] + treeview = SortableTreeview(self, show='headings', columns=columns, selectmode="browse") - return SortableTreeview( - self, - show='headings', - columns=columns, - selectmode="browse" - ) + treeview.bind("", lambda _: self._refresh(), "+") + + return treeview def _create_progress_bar(self): progress_bar = ttk.Progressbar(self.process_list, mode='indeterminate') @@ -116,46 +117,58 @@ def _set_display_columns(self, filter_by_type): process_list['displaycolumns'] = display_columns + def _on_close(self, _=None): + self._is_close = True + def _refresh(self): + main_thread_not_in_mainloop_message = 'main thread is not in main loop' + try: self._refresh_state(True) self.process_list.clear() def load(): try: - def set_data(data): - try: - self._data = data - self._update_process_list() - except: - LOG.exception("Refresh error") - finally: - self._refresh_state(False) - - values = ProcessesInfoService.get_processes(False) - self.after(0, set_data, values) - except: - self._refresh_state(False) - LOG.exception("Refresh error") + try: + self._data = ProcessesInfoService.get_processes(False) + + def do_ui_update(): + if self._is_close: + return + + try: + try: + self._update_process_list() + finally: + self._refresh_state() + except BaseException as e: + if str(e) != main_thread_not_in_mainloop_message: + LOG.exception("Refresh error") + + if self._is_close: + return + + self.after(0, do_ui_update) + finally: + self._refresh_state() + except BaseException as e: + if str(e) != main_thread_not_in_mainloop_message: + LOG.exception("Refresh error") TaskScheduler.schedule_task(THREAD_PROCESS_LIST, load) except: - self._refresh_state(False) + self._refresh_state() LOG.exception("Refresh error") - def _refresh_state(self, lock: bool): - try: - actions = self.actions - actions.refresh['state'] = DISABLED if lock else NORMAL - - progress_bar = self._progress_bar - if lock: - progress_bar.place(relx=0.5, rely=0.5, anchor=CENTER) - else: - progress_bar.place_forget() - except: - # When the window was closed while getting the process list - pass + def _refresh_state(self, lock: bool = False): + actions = self.actions + actions.refresh['state'] = DISABLED if lock else NORMAL + + progress_bar = self._progress_bar + if lock: + progress_bar.place(relx=0.5, rely=0.5, anchor=CENTER) + else: + progress_bar.place_forget() def save_to_config(self, config: dict): pass @@ -181,17 +194,25 @@ def as_model(self, row_id) -> Process: def _setup_context_menu(self): process_list = self.process_list - self._context_menu = context_menu = Menu(process_list, tearoff=0) - self._process_menu = Menu(context_menu, tearoff=0) + self._context_menu_icons = icons = { + CMENU_ADD_PROCESS_RULE_LABEL: load_img(UI_ADD_PROCESS_RULE), + CMENU_ADD_SERVICE_RULE_LABEL: load_img(UI_ADD_SERVICE_RULE), + } + self._context_menu = menu = Menu(process_list, tearoff=0) + self._process_menu = Menu(menu, tearoff=0) - context_menu.add_cascade( + menu.add_cascade( label=CMENU_ADD_PROCESS_RULE_LABEL, - menu=self._process_menu + menu=self._process_menu, + image=icons[CMENU_ADD_PROCESS_RULE_LABEL], + compound=LEFT ) - context_menu.add_command( + menu.add_command( label=CMENU_ADD_SERVICE_RULE_LABEL, - command=lambda: self._add_rule(RuleType.SERVICE) + command=lambda: self._add_rule(RuleType.SERVICE), + image=icons[CMENU_ADD_SERVICE_RULE_LABEL], + compound=LEFT ) process_list.bind("", self._show_context_menu, '+') @@ -244,7 +265,7 @@ def _show_context_menu(self, event): def _add_rule(self, rule_type: RuleType, selector_type: Optional[SelectorType] = None): if rule_type == RuleType.SERVICE and selector_type is not None: - raise ValueError("rule_type == RuleType.SERVICE and selector_type is not None") + raise ValueError("selector_type must be None when rule_type is SERVICE") process_list = self.process_list row_id = process_list.selection() @@ -286,10 +307,10 @@ def __init__(self, *args, **kwargs): def _setup_btn(self): self.refresh = refresh = ExtendedButton( self, - # text="Refresh", + text="Refresh", event=ActionEvents.REFRESH, image=load_img(file=UI_REFRESH), - description="**Refreshes** the list of __processes__." + description="**Refreshes** the list of __processes__. \n**Hotkey:** __F5__." ) self.filterByType = filterByType = EnumCombobox( @@ -319,7 +340,7 @@ def _on_search_key_release(self, _): if self._search_delay_timer: self.after_cancel(self._search_delay_timer) - self._search_delay_timer = self.after(250, self._trigger_search_change_event) + self._search_delay_timer = self.after(125, self._trigger_search_change_event) def _trigger_search_change_event(self): self.event_generate(ActionEvents.SEARCH_CHANGE) diff --git a/src/ui/widget/settings/tabs/rules/base_rules_tab.py b/src/ui/widget/settings/tabs/rules/base_rules_tab.py index 7a241d9..9882030 100644 --- a/src/ui/widget/settings/tabs/rules/base_rules_tab.py +++ b/src/ui/widget/settings/tabs/rules/base_rules_tab.py @@ -47,11 +47,12 @@ def _create_rules_list(self): def _create_actions(self): actions = RulesTabActions(self) + rules_list = self.rules_list - actions.bind(ActionEvents.ADD, lambda _: self.rules_list.add_row(), "+") - actions.bind(ActionEvents.DELETE, lambda _: self.rules_list.delete_selected_rows(), "+") - actions.bind(ActionEvents.UP, lambda _: self.rules_list.move_rows_up(), "+") - actions.bind(ActionEvents.DOWN, lambda _: self.rules_list.move_rows_down(), "+") + actions.bind(ActionEvents.ADD, lambda _: rules_list.add_row(), "+") + actions.bind(ActionEvents.DELETE, lambda _: rules_list.delete_selected_rows(), "+") + actions.bind(ActionEvents.UP, lambda _: rules_list.move_rows_up(), "+") + actions.bind(ActionEvents.DOWN, lambda _: rules_list.move_rows_down(), "+") return actions @@ -77,6 +78,7 @@ def _update_actions_state(self): def load_from_config(self, config: dict): self.rules_list.set_data(config.get(self.rule_type.field_in_config, [])) + self.rules_list.history.clear() def save_to_config(self, config: dict): rules_list = self.rules_list @@ -103,7 +105,7 @@ def _setup_btn(self): text="Add", event=ActionEvents.ADD, image=load_img(file=UI_ADD), - description="**Adds** a rule before the current." + description="**Adds** a rule before the current. \n**Hotkey:** __Ctrl+D__." ) self.delete = delete = ExtendedButton( @@ -111,7 +113,7 @@ def _setup_btn(self): text="Del", event=ActionEvents.DELETE, image=load_img(file=UI_DELETE), - description="**Deletes** the selected rules." + description="**Deletes** the selected rules. \n**Hotkey:** __Del__." ) self.move_up = move_up = ExtendedButton( diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index 203236c..c94676e 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -1,9 +1,10 @@ +from tkinter import Menu, LEFT from typing import Any from pydantic import BaseModel from pydantic.config import JsonDict -from constants.resources import UI_ERROR +from constants.resources import UI_ERROR, UI_DELETE, UI_REDO, UI_UNDO, UI_SELECT_ALL, UI_ADD from constants.ui import ERROR_ROW_COLOR, \ ScrollableTreeviewEvents, CHANGED_ROW_COLOR, ExtendedTreeviewEvents from ui.widget.common.label import Image @@ -31,8 +32,59 @@ def __init__(self, model: type[BaseModel], *args, **kwargs): self.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._check_errors(), '+') self.bind(ScrollableTreeviewEvents.SCROLL, self._place_icons, '+') self.bind("", lambda _: self.after(1, self._place_icons), '+') - self.bind("", self._on_key_press_tree, "+") - self.bind("", lambda _: self.delete_selected_rows(), "+") + + self._setup_context_menu() + + def _setup_context_menu(self): + history = self.history + + self._context_menu_icons = icons = { + 'del': load_img(UI_DELETE), + 'undo': load_img(UI_UNDO), + 'redo': load_img(UI_REDO), + 'select_all': load_img(UI_SELECT_ALL), + 'add': load_img(UI_ADD), + } + self._context_menu = menu = Menu(self, tearoff=0) + + menu.add_command( + label=" Undo", + command=history.undo, + image=icons['undo'], + compound=LEFT, + accelerator="Ctrl+Z" + ) + menu.add_command( + label=" Redo", + command=history.redo, + image=icons['redo'], + compound=LEFT, + accelerator="Ctrl+Shift+Z" + ) + menu.add_separator() + menu.add_command( + label=" Add", + command=self.add_row, + image=icons['add'], + compound=LEFT, + accelerator="Ctrl+D" + ) + menu.add_command( + label=" Select all", + command=self.select_all_rows, + image=icons['select_all'], + compound=LEFT, + accelerator="Ctrl+A" + ) + menu.add_command( + label=" Delete", + command=self.delete_selected_rows, + image=icons['del'], + compound=LEFT, + accelerator="Del" + ) + + self.bind("", lambda event: menu.post(event.x_root, event.y_root), '+') def _errors(self) -> dict[Any, Any]: errors = [ @@ -121,12 +173,6 @@ def _highlights_error(self, row_id, has_error: bool): def error_icon_created(self, icon, tooltip): pass - def _on_key_press_tree(self, event): - ctrl = (event.state & 0x4) != 0 - - if ctrl and event.keycode == ord('A'): - self.select_all_rows() - def add_row(self, values=None, index=None): if not values: values = [*self._loader.get_default_row().values()] diff --git a/src/util/history.py b/src/util/history.py new file mode 100644 index 0000000..38fc5d3 --- /dev/null +++ b/src/util/history.py @@ -0,0 +1,32 @@ +class HistoryManager: + def __init__(self, getter, setter, max_depth=20): + self.getter = getter + self.setter = setter + self.history = [] + self.redo_stack = [] + self.max_depth = max_depth + self.commit() + + def commit(self): + self.add(self.getter()) + + def undo(self): + if len(self.history) > 0: + self.redo_stack.append(self.getter()) + self.setter(self.history.pop()) + + def redo(self): + if self.redo_stack: + self.history.append(self.getter()) + self.setter(self.redo_stack.pop()) + + def clear(self): + self.history.clear() + self.redo_stack.clear() + + def add(self, value): + if not self.history or self.history[-1] != value: + if len(self.history) >= self.max_depth: + self.history.pop(0) + self.history.append(value) + self.redo_stack.clear() diff --git a/src/util/ui.py b/src/util/ui.py index d57b9d7..e73a7ac 100644 --- a/src/util/ui.py +++ b/src/util/ui.py @@ -1,5 +1,4 @@ import tkinter -from functools import cache from tkinter import font, Widget, Entry, PhotoImage from tkinter.font import Font from tkinter.ttk import Treeview @@ -34,7 +33,6 @@ def get_parent_with_bg(widget: Widget): return None -@cache def get_label_font(): temp_widget = tkinter.Label() default_font = font.nametofont(temp_widget.cget("font")) @@ -42,17 +40,14 @@ def get_label_font(): return default_font -@cache def get_default_font(): return Font(family="TkDefaultFont") -@cache def single_font_width(): return get_default_font().measure('0') -@cache def get_button_font(): temp_widget = tkinter.Button() default_font = font.nametofont(temp_widget.cget("font")) @@ -60,7 +55,6 @@ def get_button_font(): return default_font -@cache def get_combobox_font(): temp_widget = tkinter.Button() default_font = font.nametofont(temp_widget.cget("font")) @@ -68,13 +62,12 @@ def get_combobox_font(): return default_font -@cache def get_entry_font(): temp_entry = Entry() default_font = temp_entry.cget("font") temp_entry.destroy() return default_font -@cache + def load_img(file) -> PhotoImage: - return PhotoImage(file=file) \ No newline at end of file + return PhotoImage(file=file) From d7b241ee211c917c5138fcfe2adec649b4e14a8b Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Fri, 13 Sep 2024 02:48:13 +0800 Subject: [PATCH 28/39] Refactoring --- src/ui/settings.py | 10 +- src/ui/widget/settings/settings_tabs.py | 8 +- src/ui/widget/settings/tabs/process_list.py | 347 ------------------ .../settings/tabs/processes/process_list.py | 151 ++++++++ .../tabs/processes/process_list_actions.py | 59 +++ .../settings/tabs/processes/process_tab.py | 179 +++++++++ .../settings/tabs/rules/base_rules_tab.py | 54 +-- .../settings/tabs/rules/rules_list_actions.py | 50 +++ .../rules/{rules_tab.py => rules_tabs.py} | 0 9 files changed, 452 insertions(+), 406 deletions(-) delete mode 100644 src/ui/widget/settings/tabs/process_list.py create mode 100644 src/ui/widget/settings/tabs/processes/process_list.py create mode 100644 src/ui/widget/settings/tabs/processes/process_list_actions.py create mode 100644 src/ui/widget/settings/tabs/processes/process_tab.py create mode 100644 src/ui/widget/settings/tabs/rules/rules_list_actions.py rename src/ui/widget/settings/tabs/rules/{rules_tab.py => rules_tabs.py} (100%) diff --git a/src/ui/settings.py b/src/ui/settings.py index 47e4286..cd4ee7a 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -14,7 +14,7 @@ from ui.widget.common.entry import ExtendedEntry from ui.widget.settings.settings_tabs import SettingsTabs from ui.widget.settings.tabs.base_tab import BaseTab -from ui.widget.settings.tabs.process_list import ProcessListTab +from ui.widget.settings.tabs.processes.process_tab import ProcessesTab from ui.widget.settings.tabs.rules.base_rules_tab import BaseRulesTab from ui.widget.settings.tabs.rules.rules_list import RulesList from ui.widget.settings.tooltip import Tooltip @@ -194,7 +194,7 @@ def _setup_tooltips(self): tabs.bind("", lambda _: self._tooltip.set(self._tabs.get_default_tooltip()), "+") for tab in tabs.frames(): - tab: BaseRulesTab | ProcessListTab + tab: BaseRulesTab | ProcessesTab actions = tab.actions if isinstance(tab, BaseRulesTab): @@ -209,7 +209,7 @@ def _setup_tooltips(self): rules_list.error_icon_created = lambda icon, tooltip: self._setup_tooltip(icon, tooltip, True, False) self._setup_tooltip(rules_list, "", enter=False) - if isinstance(tab, ProcessListTab): + if isinstance(tab, ProcessesTab): self._setup_tooltip(actions.refresh) self._setup_tooltip(actions.filterByType) self._setup_tooltip(actions.search) @@ -247,7 +247,7 @@ def _set_tooltip_by_tree(self, event): if isinstance(tab, BaseRulesTab): treeview = tab.rules_list - if isinstance(tab, ProcessListTab): + if isinstance(tab, ProcessesTab): treeview = tab.process_list if treeview is None: @@ -326,7 +326,7 @@ def _add_row(self): def _search_focus(self): tab = self._tabs.current_tab() - if not isinstance(tab, ProcessListTab): + if not isinstance(tab, ProcessesTab): return tab.actions.search.focus_set() diff --git a/src/ui/widget/settings/settings_tabs.py b/src/ui/widget/settings/settings_tabs.py index cee483a..aa1ca40 100644 --- a/src/ui/widget/settings/settings_tabs.py +++ b/src/ui/widget/settings/settings_tabs.py @@ -6,8 +6,8 @@ from constants.ui import ExtendedTreeviewEvents from service.config_service import ConfigService from ui.widget.settings.tabs.base_tab import BaseTab -from ui.widget.settings.tabs.process_list import ProcessListTab -from ui.widget.settings.tabs.rules.rules_tab import ServiceRulesTab, ProcessRulesTab +from ui.widget.settings.tabs.processes.process_tab import ProcessesTab +from ui.widget.settings.tabs.rules.rules_tabs import ServiceRulesTab, ProcessRulesTab class SettingsTabs(ttk.Notebook): @@ -28,7 +28,7 @@ def __init__(self, *args, **kwargs): def _create_tabs(self): process_rules_tab = ProcessRulesTab(self) service_rules_tab = ServiceRulesTab(self) - process_list_tab = ProcessListTab( + process_list_tab = ProcessesTab( self, process_rules_tab.rules_list, service_rules_tab.rules_list @@ -115,4 +115,4 @@ def next_tab(self): def prev_tab(self): current_tab = self.index(self.select()) next_tab = (current_tab - 1) % self.index("end") - self.select(next_tab) \ No newline at end of file + self.select(next_tab) diff --git a/src/ui/widget/settings/tabs/process_list.py b/src/ui/widget/settings/tabs/process_list.py deleted file mode 100644 index b1e38fc..0000000 --- a/src/ui/widget/settings/tabs/process_list.py +++ /dev/null @@ -1,347 +0,0 @@ -import textwrap -from tkinter import PhotoImage, ttk, X, BOTH, NORMAL, DISABLED, CENTER, Menu, END, LEFT -from tkinter.ttk import Notebook -from typing import Optional - -from constants.log import LOG -from constants.resources import UI_PROCESS_LIST, UI_REFRESH, UI_ADD_PROCESS_RULE, UI_ADD_SERVICE_RULE -from constants.threads import THREAD_PROCESS_LIST -from constants.ui import UI_PADDING, ActionEvents, LEFT_PACK, CMENU_ADD_PROCESS_RULE_LABEL, \ - CMENU_ADD_SERVICE_RULE_LABEL -from enums.filters import FilterByProcessType -from enums.rules import RuleType -from enums.selector import SelectorType -from model.process import Process -from service.processes_info_service import ProcessesInfoService -from ui.widget.common.button import ExtendedButton -from ui.widget.common.combobox import EnumCombobox -from ui.widget.common.entry import ExtendedEntry -from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader -from ui.widget.common.treeview.sortable import SortableTreeview -from ui.widget.settings.tabs.base_tab import BaseTab -from ui.widget.settings.tabs.rules.rules_list import RulesList -from util.scheduler import TaskScheduler -from util.ui import load_img - - -class ProcessListTab(BaseTab): - @staticmethod - def default_tooltip() -> str: - return "Use the **context menu** to add a __process__ or __service__ as a rule." - - @staticmethod - def icon() -> PhotoImage: - return load_img(file=UI_PROCESS_LIST) - - @staticmethod - def title() -> str: - return 'Process List' - - @staticmethod - def description() -> str: - return ("Interface for **browsing** the list of active __processes__ and __services__ with the option to " - "**add** selected items to the rules configuration.") - - def __init__(self, master: Notebook, process_rules_list: RulesList, service_rules_list: RulesList): - self.model = Process - self.process_rules_list = process_rules_list - self.service_rules_list = service_rules_list - self._data: dict[int, Process] = {} - - super().__init__(master) - - self._is_close = False - self.bind("", self._on_close) - - self._setup_widgets() - self._loader = PydanticTreeviewLoader(self.process_list, self.model) - self._pack() - self._setup_context_menu() - - def _create_process_list(self): - columns = [key for key, field_info in self.model.model_fields.items() if not field_info.exclude] - treeview = SortableTreeview(self, show='headings', columns=columns, selectmode="browse") - - treeview.bind("", lambda _: self._refresh(), "+") - - return treeview - - def _create_progress_bar(self): - progress_bar = ttk.Progressbar(self.process_list, mode='indeterminate') - progress_bar.start() - return progress_bar - - def _create_actions(self): - actions = ProcessListTabActions(self) - actions.bind(ActionEvents.REFRESH, lambda _: self._refresh(), "+") - actions.bind(ActionEvents.FILTER_BY_TYPE, lambda _: self._update_process_list(), "+") - actions.bind(ActionEvents.SEARCH_CHANGE, lambda _: self._update_process_list(), "+") - - return actions - - def _pack(self): - self.actions.pack(fill=X, padx=UI_PADDING, pady=(UI_PADDING, 0)) - self.process_list.pack(fill=BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) - - def load_from_config(self, config: dict): - self._refresh() - - def _update_process_list(self): - filter_by_type = self.actions.filterByType.get_enum_value() - search_query = self.actions.search.get().strip().lower() - - data = [] - - for row in self._data.values(): - by_type = (filter_by_type == FilterByProcessType.ALL - or filter_by_type == FilterByProcessType.PROCESSES and row.service is None - or filter_by_type == FilterByProcessType.SERVICES and row.service is not None) - - by_search = not search_query or any( - value is not None and search_query in str(value).lower() - for value in row.model_dump().values() - ) - - if by_type and by_search: - data.append(row) - - self._set_display_columns(filter_by_type) - self._loader.set_data(data) - - def _set_display_columns(self, filter_by_type): - process_list = self.process_list - display_columns = list(process_list['columns']) - - if filter_by_type == FilterByProcessType.PROCESSES: - display_columns.remove('service_name') - - process_list['displaycolumns'] = display_columns - - def _on_close(self, _=None): - self._is_close = True - - def _refresh(self): - main_thread_not_in_mainloop_message = 'main thread is not in main loop' - - try: - self._refresh_state(True) - self.process_list.clear() - - def load(): - try: - try: - self._data = ProcessesInfoService.get_processes(False) - - def do_ui_update(): - if self._is_close: - return - - try: - try: - self._update_process_list() - finally: - self._refresh_state() - except BaseException as e: - if str(e) != main_thread_not_in_mainloop_message: - LOG.exception("Refresh error") - - if self._is_close: - return - - self.after(0, do_ui_update) - finally: - self._refresh_state() - except BaseException as e: - if str(e) != main_thread_not_in_mainloop_message: - LOG.exception("Refresh error") - - TaskScheduler.schedule_task(THREAD_PROCESS_LIST, load) - except: - self._refresh_state() - LOG.exception("Refresh error") - - def _refresh_state(self, lock: bool = False): - actions = self.actions - actions.refresh['state'] = DISABLED if lock else NORMAL - - progress_bar = self._progress_bar - if lock: - progress_bar.place(relx=0.5, rely=0.5, anchor=CENTER) - else: - progress_bar.place_forget() - - def save_to_config(self, config: dict): - pass - - def has_changes(self) -> bool: - return False - - def has_error(self) -> bool: - return False - - def commit_changes(self): - pass - - def _setup_widgets(self): - self.process_list = self._create_process_list() - self._progress_bar = self._create_progress_bar() - self.actions = self._create_actions() - - def as_model(self, row_id) -> Process: - pid = int(self.process_list.as_dict(row_id)['pid']) - return self._data[pid] - - def _setup_context_menu(self): - process_list = self.process_list - - self._context_menu_icons = icons = { - CMENU_ADD_PROCESS_RULE_LABEL: load_img(UI_ADD_PROCESS_RULE), - CMENU_ADD_SERVICE_RULE_LABEL: load_img(UI_ADD_SERVICE_RULE), - } - self._context_menu = menu = Menu(process_list, tearoff=0) - self._process_menu = Menu(menu, tearoff=0) - - menu.add_cascade( - label=CMENU_ADD_PROCESS_RULE_LABEL, - menu=self._process_menu, - image=icons[CMENU_ADD_PROCESS_RULE_LABEL], - compound=LEFT - ) - - menu.add_command( - label=CMENU_ADD_SERVICE_RULE_LABEL, - command=lambda: self._add_rule(RuleType.SERVICE), - image=icons[CMENU_ADD_SERVICE_RULE_LABEL], - compound=LEFT - ) - - process_list.bind("", self._show_context_menu, '+') - - def _show_context_menu(self, event): - context_menu = self._context_menu - menu = self._process_menu - process_list = self.process_list - row_id = process_list.identify_row(event.y) - - if row_id: - process_list.selection_set(row_id) - row = self.as_model(row_id) - exists = False - - menu.delete(0, END) - if row.process_name: - exists = True - menu.add_command( - label=f"By {SelectorType.NAME.value}: {row.process_name}", - command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.NAME) - ) - - if row.bin_path: - exists = True - menu.add_command( - label=textwrap.shorten( - f"By {SelectorType.PATH.value}: {row.bin_path}", - width=128, - placeholder="..." - ), - command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.PATH) - ) - - if row.cmd_line: - exists = True - menu.add_command( - label=textwrap.shorten( - f"By {SelectorType.CMDLINE.value}: {row.cmd_line}", - width=128, - placeholder="..." - ), - command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.CMDLINE) - ) - - self._context_menu.entryconfig(CMENU_ADD_PROCESS_RULE_LABEL, state=NORMAL if exists else DISABLED) - self._context_menu.entryconfig(CMENU_ADD_SERVICE_RULE_LABEL, state=NORMAL if row.service else DISABLED) - - context_menu.post(event.x_root, event.y_root) - - def _add_rule(self, rule_type: RuleType, selector_type: Optional[SelectorType] = None): - if rule_type == RuleType.SERVICE and selector_type is not None: - raise ValueError("selector_type must be None when rule_type is SERVICE") - - process_list = self.process_list - row_id = process_list.selection() - row = process_list.as_dict(row_id) - rules_list = None - - if rule_type == RuleType.PROCESS: - rules_list = self.process_rules_list - elif rule_type == RuleType.SERVICE: - rules_list = self.service_rules_list - - if rules_list is None: - raise ValueError("rules_list is None") - - rule_row = rules_list._loader.get_default_row() - - if selector_type is None: - rule_row['selector'] = row['service_name'] - else: - rule_row['selectorBy'] = str(selector_type) - - if selector_type == SelectorType.NAME: - rule_row['selector'] = row['process_name'] - elif selector_type == SelectorType.PATH: - rule_row['selector'] = row['bin_path'] - elif selector_type == SelectorType.CMDLINE: - rule_row['selector'] = row['cmd_line'] - - rules_list.add_row([*rule_row.values()], index=0) - - -class ProcessListTabActions(ttk.Frame): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self._search_delay_timer = None - self._setup_btn() - - def _setup_btn(self): - self.refresh = refresh = ExtendedButton( - self, - text="Refresh", - event=ActionEvents.REFRESH, - image=load_img(file=UI_REFRESH), - description="**Refreshes** the list of __processes__. \n**Hotkey:** __F5__." - ) - - self.filterByType = filterByType = EnumCombobox( - self, - FilterByProcessType, - description="**Filters** processes by __type__.", - state="readonly" - ) - - self.search = search = ExtendedEntry( - self, - description="**Searches** processes by __name__ or __attribute__.", - placeholder="Search", - width=30 - ) - - search.bind('', self._on_search_key_release, '+') - - filterByType.set(FilterByProcessType.ALL) - filterByType.bind('<>', lambda _: self.event_generate(ActionEvents.FILTER_BY_TYPE), '+') - - search.pack(**LEFT_PACK) - filterByType.pack(**LEFT_PACK) - refresh.pack(**LEFT_PACK) - - def _on_search_key_release(self, _): - if self._search_delay_timer: - self.after_cancel(self._search_delay_timer) - - self._search_delay_timer = self.after(125, self._trigger_search_change_event) - - def _trigger_search_change_event(self): - self.event_generate(ActionEvents.SEARCH_CHANGE) - self._search_delay_timer = None diff --git a/src/ui/widget/settings/tabs/processes/process_list.py b/src/ui/widget/settings/tabs/processes/process_list.py new file mode 100644 index 0000000..894e4df --- /dev/null +++ b/src/ui/widget/settings/tabs/processes/process_list.py @@ -0,0 +1,151 @@ +import textwrap +from tkinter import Menu, LEFT, END, NORMAL, DISABLED +from typing import Callable, Optional + +from pydantic import BaseModel + +from constants.resources import UI_ADD_PROCESS_RULE, UI_ADD_SERVICE_RULE +from constants.ui import CMENU_ADD_PROCESS_RULE_LABEL, CMENU_ADD_SERVICE_RULE_LABEL +from enums.filters import FilterByProcessType +from enums.rules import RuleType +from enums.selector import SelectorType +from model.process import Process +from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader +from ui.widget.common.treeview.sortable import SortableTreeview +from util.ui import load_img + + +class ProcessList(SortableTreeview): + def __init__( + self, + model: type[BaseModel], + add_rule_command: Callable[[RuleType, Optional[SelectorType]], None], + *args, **kwargs + ): + self._filter_by_type: FilterByProcessType = FilterByProcessType.ALL + self._filter_by_search_query: Optional[str] = None + + columns = [key for key, field_info in model.model_fields.items() if not field_info.exclude] + + super().__init__( + *args, + **kwargs, + show='headings', + columns=columns, + selectmode="browse" + ) + + self._add_rule: Callable[[RuleType, Optional[SelectorType]], None] = add_rule_command + self._data: dict[int, Process] = {} + self._loader = PydanticTreeviewLoader(self, model) + self._setup_context_menu() + + def set_data(self, values: dict[int, Process]): + self._data = values + + def _setup_context_menu(self): + self._context_menu_icons = icons = { + CMENU_ADD_PROCESS_RULE_LABEL: load_img(UI_ADD_PROCESS_RULE), + CMENU_ADD_SERVICE_RULE_LABEL: load_img(UI_ADD_SERVICE_RULE), + } + self._context_menu = menu = Menu(self, tearoff=0) + self._process_menu = Menu(menu, tearoff=0) + + menu.add_cascade( + label=CMENU_ADD_PROCESS_RULE_LABEL, + menu=self._process_menu, + image=icons[CMENU_ADD_PROCESS_RULE_LABEL], + compound=LEFT + ) + + menu.add_command( + label=CMENU_ADD_SERVICE_RULE_LABEL, + command=lambda: self._add_rule(RuleType.SERVICE, None), + image=icons[CMENU_ADD_SERVICE_RULE_LABEL], + compound=LEFT + ) + + self.bind("", self._show_context_menu, '+') + + def _show_context_menu(self, event): + context_menu = self._context_menu + menu = self._process_menu + process_list = self + row_id = process_list.identify_row(event.y) + + if row_id: + process_list.selection_set(row_id) + row = self.as_model(row_id) + exists = False + + menu.delete(0, END) + if row.process_name: + exists = True + menu.add_command( + label=f"By {SelectorType.NAME.value}: {row.process_name}", + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.NAME) + ) + + if row.bin_path: + exists = True + menu.add_command( + label=textwrap.shorten( + f"By {SelectorType.PATH.value}: {row.bin_path}", + width=128, + placeholder="..." + ), + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.PATH) + ) + + if row.cmd_line: + exists = True + menu.add_command( + label=textwrap.shorten( + f"By {SelectorType.CMDLINE.value}: {row.cmd_line}", + width=128, + placeholder="..." + ), + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.CMDLINE) + ) + + self._context_menu.entryconfig(CMENU_ADD_PROCESS_RULE_LABEL, state=NORMAL if exists else DISABLED) + self._context_menu.entryconfig(CMENU_ADD_SERVICE_RULE_LABEL, state=NORMAL if row.service else DISABLED) + + context_menu.post(event.x_root, event.y_root) + + def set_display_columns(self, filter_by_type): + display_columns = list(self['columns']) + + if filter_by_type == FilterByProcessType.PROCESSES: + display_columns.remove('service_name') + + self['displaycolumns'] = display_columns + + def set_filter(self, by_type: FilterByProcessType, by_search_query: str): + self._filter_by_type = by_type + self._filter_by_search_query = by_search_query + + def update_ui(self): + filter_by_type = self._filter_by_type + search_query = self._filter_by_search_query + data = [] + + for row in self._data.values(): + by_type = (filter_by_type == FilterByProcessType.ALL + or filter_by_type == FilterByProcessType.PROCESSES and row.service is None + or filter_by_type == FilterByProcessType.SERVICES and row.service is not None) + + by_search = not search_query or any( + value is not None and search_query in str(value).lower() + for value in row.model_dump().values() + ) + + if by_type and by_search: + data.append(row) + + self.set_display_columns(filter_by_type) + self._loader.set_data(data) + + def as_model(self, row_id) -> Process: + pid = int(self.as_dict(row_id)['pid']) + return self._data[pid] diff --git a/src/ui/widget/settings/tabs/processes/process_list_actions.py b/src/ui/widget/settings/tabs/processes/process_list_actions.py new file mode 100644 index 0000000..69ee80b --- /dev/null +++ b/src/ui/widget/settings/tabs/processes/process_list_actions.py @@ -0,0 +1,59 @@ +from tkinter import ttk + +from constants.resources import UI_REFRESH +from constants.ui import ActionEvents, LEFT_PACK +from enums.filters import FilterByProcessType +from ui.widget.common.button import ExtendedButton +from ui.widget.common.combobox import EnumCombobox +from ui.widget.common.entry import ExtendedEntry +from util.ui import load_img + + +class ProcessListActions(ttk.Frame): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self._search_delay_timer = None + self._setup_btn() + + def _setup_btn(self): + self.refresh = refresh = ExtendedButton( + self, + text="Refresh", + event=ActionEvents.REFRESH, + image=load_img(file=UI_REFRESH), + description="**Refreshes** the list of __processes__. \n**Hotkey:** __F5__." + ) + + self.filterByType = filterByType = EnumCombobox( + self, + FilterByProcessType, + description="**Filters** processes by __type__.", + state="readonly" + ) + + self.search = search = ExtendedEntry( + self, + description="**Searches** processes by __name__ or __attribute__.", + placeholder="Search", + width=30 + ) + + search.bind('', self._on_search_key_release, '+') + + filterByType.set(FilterByProcessType.ALL) + filterByType.bind('<>', lambda _: self.event_generate(ActionEvents.FILTER_BY_TYPE), '+') + + search.pack(**LEFT_PACK) + filterByType.pack(**LEFT_PACK) + refresh.pack(**LEFT_PACK) + + def _on_search_key_release(self, _): + if self._search_delay_timer: + self.after_cancel(self._search_delay_timer) + + self._search_delay_timer = self.after(125, self._trigger_search_change_event) + + def _trigger_search_change_event(self): + self.event_generate(ActionEvents.SEARCH_CHANGE) + self._search_delay_timer = None diff --git a/src/ui/widget/settings/tabs/processes/process_tab.py b/src/ui/widget/settings/tabs/processes/process_tab.py new file mode 100644 index 0000000..e5d72d3 --- /dev/null +++ b/src/ui/widget/settings/tabs/processes/process_tab.py @@ -0,0 +1,179 @@ +from tkinter import PhotoImage, ttk, X, BOTH, NORMAL, DISABLED, CENTER +from tkinter.ttk import Notebook +from typing import Optional + +from constants.log import LOG +from constants.resources import UI_PROCESS_LIST +from constants.threads import THREAD_PROCESS_LIST +from constants.ui import UI_PADDING, ActionEvents +from enums.rules import RuleType +from enums.selector import SelectorType +from model.process import Process +from service.processes_info_service import ProcessesInfoService +from ui.widget.settings.tabs.base_tab import BaseTab +from ui.widget.settings.tabs.processes.process_list import ProcessList +from ui.widget.settings.tabs.processes.process_list_actions import ProcessListActions +from ui.widget.settings.tabs.rules.rules_list import RulesList +from util.scheduler import TaskScheduler +from util.ui import load_img + + +class ProcessesTab(BaseTab): + @staticmethod + def default_tooltip() -> str: + return "Use the **context menu** to add a __process__ or __service__ as a rule." + + @staticmethod + def icon() -> PhotoImage: + return load_img(file=UI_PROCESS_LIST) + + @staticmethod + def title() -> str: + return 'Process List' + + @staticmethod + def description() -> str: + return ("Interface for **browsing** the list of active __processes__ and __services__ with the option to " + "**add** selected items to the rules configuration.") + + def __init__(self, master: Notebook, process_rules_list: RulesList, service_rules_list: RulesList): + self.model = Process + self.process_rules_list = process_rules_list + self.service_rules_list = service_rules_list + + super().__init__(master) + + self._is_close = False + self.bind("", self._on_close) + + self._create_process_list() + self._create_progress_bar() + self._create_actions() + + self._pack() + + def _create_process_list(self): + self.process_list = process_list = ProcessList(self.model, self._add_rule, self) + process_list.bind("", lambda _: self._refresh(), "+") + + def _create_progress_bar(self): + self._progress_bar = progress_bar = ttk.Progressbar(self.process_list, mode='indeterminate') + progress_bar.start() + + def _create_actions(self): + self.actions = actions = ProcessListActions(self) + actions.bind(ActionEvents.REFRESH, lambda _: self._refresh(), "+") + actions.bind(ActionEvents.FILTER_BY_TYPE, lambda _: self._update_process_list(), "+") + actions.bind(ActionEvents.SEARCH_CHANGE, lambda _: self._update_process_list(), "+") + + def _pack(self): + self.actions.pack(fill=X, padx=UI_PADDING, pady=(UI_PADDING, 0)) + self.process_list.pack(fill=BOTH, expand=True, padx=UI_PADDING, pady=UI_PADDING) + + def load_from_config(self, config: dict): + self._refresh() + + def _update_process_list(self): + filter_by_type = self.actions.filterByType.get_enum_value() + search_query = self.actions.search.get().strip().lower() + + self.process_list.set_filter(filter_by_type, search_query) + self.process_list.update_ui() + + def _on_close(self, _=None): + self._is_close = True + + def _refresh(self): + main_thread_not_in_mainloop_message = 'main thread is not in main loop' + + try: + self._refresh_state(True) + self.process_list.clear() + + def load(): + try: + try: + self.process_list.set_data(ProcessesInfoService.get_processes(False)) + + def do_ui_update(): + if self._is_close: + return + + try: + try: + self._update_process_list() + finally: + self._refresh_state() + except BaseException as e: + if str(e) != main_thread_not_in_mainloop_message: + LOG.exception("Refresh error") + + if self._is_close: + return + + self.after(0, do_ui_update) + finally: + self._refresh_state() + except BaseException as e: + if str(e) != main_thread_not_in_mainloop_message: + LOG.exception("Refresh error") + + TaskScheduler.schedule_task(THREAD_PROCESS_LIST, load) + except: + self._refresh_state() + LOG.exception("Refresh error") + + def _refresh_state(self, lock: bool = False): + actions = self.actions + actions.refresh['state'] = DISABLED if lock else NORMAL + + progress_bar = self._progress_bar + if lock: + progress_bar.place(relx=0.5, rely=0.5, anchor=CENTER) + else: + progress_bar.place_forget() + + def save_to_config(self, config: dict): + pass + + def has_changes(self) -> bool: + return False + + def has_error(self) -> bool: + return False + + def commit_changes(self): + pass + + def _add_rule(self, rule_type: RuleType, selector_type: Optional[SelectorType] = None): + if rule_type == RuleType.SERVICE and selector_type is not None: + raise ValueError("selector_type must be None when rule_type is SERVICE") + + process_list = self.process_list + row_id = process_list.selection() + row = process_list.as_dict(row_id) + rules_list = None + + if rule_type == RuleType.PROCESS: + rules_list = self.process_rules_list + elif rule_type == RuleType.SERVICE: + rules_list = self.service_rules_list + + if rules_list is None: + raise ValueError("rules_list is None") + + rule_row = rules_list._loader.get_default_row() + + if selector_type is None: + rule_row['selector'] = row['service_name'] + else: + rule_row['selectorBy'] = str(selector_type) + + if selector_type == SelectorType.NAME: + rule_row['selector'] = row['process_name'] + elif selector_type == SelectorType.PATH: + rule_row['selector'] = row['bin_path'] + elif selector_type == SelectorType.CMDLINE: + rule_row['selector'] = row['cmd_line'] + + rules_list.add_row([*rule_row.values()], index=0) diff --git a/src/ui/widget/settings/tabs/rules/base_rules_tab.py b/src/ui/widget/settings/tabs/rules/base_rules_tab.py index 9882030..5e49154 100644 --- a/src/ui/widget/settings/tabs/rules/base_rules_tab.py +++ b/src/ui/widget/settings/tabs/rules/base_rules_tab.py @@ -1,14 +1,12 @@ from abc import ABC -from tkinter import ttk, X, BOTH, NORMAL, DISABLED +from tkinter import X, BOTH, NORMAL, DISABLED from tkinter.ttk import Notebook -from constants.resources import UI_ADD, UI_DELETE, UI_UP, UI_DOWN -from constants.ui import UI_PADDING, ActionEvents, LEFT_PACK, ExtendedTreeviewEvents +from constants.ui import UI_PADDING, ActionEvents, ExtendedTreeviewEvents from enums.rules import RuleType -from ui.widget.common.button import ExtendedButton from ui.widget.settings.tabs.base_tab import BaseTab from ui.widget.settings.tabs.rules.rules_list import RulesList -from util.ui import load_img +from ui.widget.settings.tabs.rules.rules_list_actions import RulesListActions class BaseRulesTab(BaseTab, ABC): @@ -46,7 +44,7 @@ def _create_rules_list(self): return rules_list def _create_actions(self): - actions = RulesTabActions(self) + actions = RulesListActions(self) rules_list = self.rules_list actions.bind(ActionEvents.ADD, lambda _: rules_list.add_row(), "+") @@ -92,47 +90,3 @@ def commit_changes(self): def has_error(self) -> bool: return self.rules_list.has_error() - - -class RulesTabActions(ttk.Frame): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._setup_btn() - - def _setup_btn(self): - self.add = add = ExtendedButton( - self, - text="Add", - event=ActionEvents.ADD, - image=load_img(file=UI_ADD), - description="**Adds** a rule before the current. \n**Hotkey:** __Ctrl+D__." - ) - - self.delete = delete = ExtendedButton( - self, - text="Del", - event=ActionEvents.DELETE, - image=load_img(file=UI_DELETE), - description="**Deletes** the selected rules. \n**Hotkey:** __Del__." - ) - - self.move_up = move_up = ExtendedButton( - self, - text="Up", - event=ActionEvents.UP, - image=load_img(file=UI_UP), - description="**Moves** the current rule __up__." - ) - - self.move_down = move_down = ExtendedButton( - self, - text="Down", - event=ActionEvents.DOWN, - image=load_img(file=UI_DOWN), - description="**Moves** the current rule __down__." - ) - - add.pack(**LEFT_PACK) - delete.pack(**LEFT_PACK) - move_up.pack(**LEFT_PACK) - move_down.pack(**LEFT_PACK) diff --git a/src/ui/widget/settings/tabs/rules/rules_list_actions.py b/src/ui/widget/settings/tabs/rules/rules_list_actions.py new file mode 100644 index 0000000..3fc98d7 --- /dev/null +++ b/src/ui/widget/settings/tabs/rules/rules_list_actions.py @@ -0,0 +1,50 @@ +from tkinter import ttk + +from constants.resources import UI_ADD, UI_DELETE, UI_UP, UI_DOWN +from constants.ui import ActionEvents, LEFT_PACK +from ui.widget.common.button import ExtendedButton +from util.ui import load_img + + +class RulesListActions(ttk.Frame): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._setup_btn() + + def _setup_btn(self): + self.add = add = ExtendedButton( + self, + text="Add", + event=ActionEvents.ADD, + image=load_img(file=UI_ADD), + description="**Adds** a rule before the current. \n**Hotkey:** __Ctrl+D__." + ) + + self.delete = delete = ExtendedButton( + self, + text="Del", + event=ActionEvents.DELETE, + image=load_img(file=UI_DELETE), + description="**Deletes** the selected rules. \n**Hotkey:** __Del__." + ) + + self.move_up = move_up = ExtendedButton( + self, + text="Up", + event=ActionEvents.UP, + image=load_img(file=UI_UP), + description="**Moves** the current rule __up__." + ) + + self.move_down = move_down = ExtendedButton( + self, + text="Down", + event=ActionEvents.DOWN, + image=load_img(file=UI_DOWN), + description="**Moves** the current rule __down__." + ) + + add.pack(**LEFT_PACK) + delete.pack(**LEFT_PACK) + move_up.pack(**LEFT_PACK) + move_down.pack(**LEFT_PACK) diff --git a/src/ui/widget/settings/tabs/rules/rules_tab.py b/src/ui/widget/settings/tabs/rules/rules_tabs.py similarity index 100% rename from src/ui/widget/settings/tabs/rules/rules_tab.py rename to src/ui/widget/settings/tabs/rules/rules_tabs.py From 8a6e5224ec2cd881ba7b1f463070a16f2cce9950 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 15 Sep 2024 01:11:50 +0800 Subject: [PATCH 29/39] Added the display of application icons on the processes tab, as well as refactoring and bug fixes --- resources/UI/copy.png | Bin 0 -> 2070 bytes resources/UI/process.png | Bin 0 -> 2042 bytes resources/UI/service.png | Bin 0 -> 1595 bytes resources/UI/sort-down.png | Bin 0 -> 1553 bytes resources/UI/sort-empty.png | Bin 0 -> 223 bytes resources/UI/sort-up.png | Bin 0 -> 1549 bytes src/constants/resources.py | 7 + src/constants/ui.py | 4 +- src/ui/settings.py | 4 +- src/ui/widget/common/treeview/extended.py | 8 +- src/ui/widget/common/treeview/pydantic.py | 3 +- src/ui/widget/common/treeview/sortable.py | 31 ++-- .../settings/tabs/processes/process_list.py | 173 +++++++++++++----- .../widget/settings/tabs/rules/rules_list.py | 4 +- src/util/ui.py | 7 + src/util/utils.py | 80 ++++++++ 16 files changed, 255 insertions(+), 66 deletions(-) create mode 100644 resources/UI/copy.png create mode 100644 resources/UI/process.png create mode 100644 resources/UI/service.png create mode 100644 resources/UI/sort-down.png create mode 100644 resources/UI/sort-empty.png create mode 100644 resources/UI/sort-up.png diff --git a/resources/UI/copy.png b/resources/UI/copy.png new file mode 100644 index 0000000000000000000000000000000000000000..1a230229848150ac99e1d5f64e3f78e061d42ed7 GIT binary patch literal 2070 zcmb_dU2oe|81__Yz-SR-l{SGUS>6qUo!G~A65BK@ZBo{trH#74$_?!JoRh>f_A$2G zq(wrMD|#`B3#6fegt(bNApQWAkU+cOj{OCS5O-)onkH__>wI__blsSUGk+g_`kAqY6@;ogo|&)lJw;9^g1G4`|PA7J+|yM zR+H7*1&0bhN0@MVuIGn_lac~b2R`^=MjOP# zI6=hJ9tl;P(^8-MKt?lMxE^)-#u-(4hxHCn&oKP09q5wYi^E1ZG?>mwjHcF*tiD@ zHN!|k9tdXCX^O}v;IQYD7FWZdrN~(rowDeN2n>TdWBh%!T&_o=>2+WuUO7K6R~O0! zY!?bh&*8q@TFt2jaY6#htCf-h!O3|Zb67#QaGo$^x|pJ7-ZYS9+7>d2trdx(6-{o9 z&Q}CoPfH*@KWGOgC~(}Bhh4yHE<=STGY~OMhAh|6kZIUWm$=2EWo2y3kp~?~I^(RV zDh7-+j}6V%^N8o|B9NIbA}%wL%W<*T#LT8xOUwSQjTOPE6~;by@?l$Zr%7mFq`G^1(r z0>OmaBiH{e9l8iRde%jcB7GPZ+9pAZ!zW)=9^ILT>yv@Xac2(vB>aEQ^ow**Vd_7N zufI1o6h@T{lO|neGY%fIDaiwfQv@^co2qvk=BHn+%r&el^v?eN>_i^FK6k_WeE<0N zyYGL}o4B>@ci-DHKR!EgbLxgC<2U`%UlTvpcaJ`^_W~=Q(VzbGi|OY+{Oz@0CMSRT z`iGsHyRV))@zn12o!!YlZ-069tG)S?*RNl_b>b}(e>8pJ=a=8UEL~eZ^6N|8-&fPg OU0qnJd^>;ngTDdb^^oNN literal 0 HcmV?d00001 diff --git a/resources/UI/process.png b/resources/UI/process.png new file mode 100644 index 0000000000000000000000000000000000000000..8789713cc1c1d1244a61d7ea38c442cc63c504fc GIT binary patch literal 2042 zcmb_dTWs4@7;c#S%hgz?)$t{c6Pt#vO+p)KDQTK+odAhr`y?@qeO%jZ z(mt$=Ndq>hC=ZB@3JJCsco?D@LgG>;RSYI3F>Qz;Aw+k17$8)tfhIAa9H&Xtp{|=M zEMJb#`Obg&{{KJ!i^=ZJhV}QaCkUb;-W5&ZZ=?6DtHbYyt}X!lskgdzI|Om(J>FA8 z9G<+FAnM-N)BSFLVu!3E!v{2^Kwr_YFq$A*+lm%Y2cSzTFsqwkYVPCDC{owL)UH5+ zO;{0_)4N7(*gM*tR!0X^Nu$~xC0mO!7GOXZkVPYJI&v{gmE_8J>`gNiS%SC&VXECz zNcJa^WCYoe6n!kMvaCo3C7%WqpejlW$+JAiumZygG|S3Kju4~B*Qz#UC1-}p3S%#A&iD7w$=V^?foe|RoMcQ+LKbRCT4s#q(BT;$}? zO+;6hZ%}}_O(d#1mbJw&swx~eHjLdU6S6GYNsm~NNkIn<*(!_;V>6pPZ!9@tL*ODi zjZnT4sbs}ulIMK_*}O|PHB@l6F4+L1z=dH7M-9hIqPalYiyFT9ZEQ$p*+pmqX?kX4 zS!hV+*c+fYXEfk~TY@!J&LGA1jDVLTe9FgZS5*JLH5h?x-2(F)*LTH^$b24XNn zi>wGFzXpPt5LQ%*m>fmwke33L{TklSiXjOEL*D*?M)RToX~1Jik_0kA02Cz%0+s!b z+d8g6kYBYNuQI*dk-KyUM|GrJI=yhPJj&~2DP3fsdSwu%R4@Keqsr6zG7Q|F2a940 zIf#X>kQa+E2W8v>uwi=^vvte7V{T@=1BO>NU4#Lsh@zk7Bu=8CA_z1H`UAA8iJYLo zK!{V6itEdoF34;(rB`EmnN~Fi%q+x*DnqT_ncK_672>e8=>9)v81E=u%rNG^$yZui za_r(jmZtDo?hUJ51pid~5HvAQHtsSH|5o=d?oe~_XnQ*J@(-_a=DzKXu@4WT_}=Zc zUp#TV@GK{?yhwAL981cgNH#tSi}Q?vJf0qI2*W#tDg}WnvuveO zVJa~Oc}12_CX*~Du!2Bi1nti{0jScB-_vABLtpnyH!zVyhKxW%B*G6eGuVuVL$*Zw`B@jTEV`wnoD%yD(7iVU+byA?DRlLhH6D9#xJ z1mK=vLzfH4vjH~Pv_TQFu2ZDQ$c=IeS;)hJv39Y|=ebmB%tHm!!WaJd$Pk&!q!N5G zk)Q>Juc@o5a?bGs;OH=yRw(Qo#xxDNPtv&ph(lTfQk>TN#25`gAwi2!6M!VeV^RV( z-=~pY4pX4{-uR#Ik9j7pL15iCPgt2@?#Nlw$5EYal+FY^-dI^CSxXlg=wTTslpe+( z8dT%hyl)TGX)7g&N&h1+>M$P_f(r29U=e%ko_WV&<=L=c>vpjJG_iKKskobP+%dvs z)T{6&>UPk0h~U^mu_faHy5|8hw5;xb*6GVSCSIM$;=pFD?8HEJ_F@ literal 0 HcmV?d00001 diff --git a/resources/UI/sort-down.png b/resources/UI/sort-down.png new file mode 100644 index 0000000000000000000000000000000000000000..22d7dcd976f1c10c0e8b00e9d5fb042a356e4ac0 GIT binary patch literal 1553 zcmbVMU5MO79M4vJw3Wp#uu`=RDT1XG3crr4=yO*C7gzdY% z+B}=Lry-`kf?VnlrR#?rEeJ;@x*@^~gozGmc!4GT{^eJa=((13`mhb`utb{P)KWxF zEzQ*M(gHSJX<}SF(uJJBCk%;QzZJx=Ye{`x$k)lSDv5mvTd<_bM4&it&x$1)5izd- z83T|P3#Q^C2VuuKBvGZ0ZADoZ`ZE)ana&u}WIRCjpB&R!gyAlQJ4N>Az5?*LMlvzP0UC#+JJH zekvknm2=#Tp+mMr$F;?fsBq}Mp&XP8gao~J7e>CwN#poXx(e^i+JwDF|k@H)XCOa4xWq@?YF^ziNDda})%M`bh z6d1jC|L6OYk;iKgweFiIsmvsI;FK5hs4fmm=M;H)xN3P~KV2ZgNf}rYPU25oX?X12 zw+9BaohIR=|B)91SWN4zgCa87;NH4t-l<%9H7VGE9qK<#?B8uF?h%}KjAWViD!xg( z9SL}gi+C@)TFNZ(KDb&fPu7Z$;+wtR!~@T+pzF(sEdTYky7$es@i!iOb@Hs1UAeXX zJo@p&eMh(V{y?vN{N5`Erf>iJ77})Rd-C?v?-y^Zy?A+S`p%yZe`N0c;E5|4QK+q4 z`f2(53TPLzLT1%C53)C}U;1S1v&_-V@zr?u*LSQNYx?WAdeh%LB|Lb|=zYE|yPjd+ voq6YCZ~cc~cJ2|j{T83uxB&9z%DAxc#o1?mJ#_wB(zL6UnewN{Ub^r%LF)C$ literal 0 HcmV?d00001 diff --git a/resources/UI/sort-empty.png b/resources/UI/sort-empty.png new file mode 100644 index 0000000000000000000000000000000000000000..d72a0630a59665933fc3424e4f618ab3c507fe7b GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP;jEB zi(^Q|oU@bnavd^|aQ)2E6i@&Hg$19!8b6t*;>PgaJ7-SLCq6eniMRacfZvA?T$ z@Z0p+^osZWv1%s|#9flD@UW^;^}fXv{@|wTCErVVIXAN(%z2_Cp71$v+qEzUV}<2j zw*(Gl1@sx}HT;@8=joF<(X;+5pS#$kEBQz#+r-wjeTs(F(=~Hno;R5$UbpX`>7L1J RE&?6L;OXk;vd$@?2>_#FRzCm$ literal 0 HcmV?d00001 diff --git a/resources/UI/sort-up.png b/resources/UI/sort-up.png new file mode 100644 index 0000000000000000000000000000000000000000..2ee014e7aed9acd0c9ab8dcd6e641531978ed596 GIT binary patch literal 1549 zcmbVMO=uid9G_TS(j?Vlk%l5TPA(BMGjC>gCp)j1F6nM;Rx-(wEF^+h-@JLdJIT(x zac0t;p5zyJ6D zoyzis6Juw_IF36}UM#J$`D8jqGwlD&eh0DXc(C|V#Bt-N(lNqaX-{(8W2fEfM!aDy zK}ixIespIjKCu?;uEjwM=&vkE-z&3^jH@7E+pPEh51wb9h(AEwP%AD3~BwS?ku5bs-q)9yD#}UISLu}BXF^wAZU#N%I_X%LWwXC6xBX#k-p@=A6 zxWvrpJLE`oRNV=PyhL@aqCUbR#U%CJmWjrk!^9yj(0+LRxd1>>^sdaGozO6m`YWby1a+uDX^5 z%YGCiACq#)6qs`)*LC2minAJ-HN?D56cLlGAtJ-p#2To9yl$&n&Q=HSOB8RXDKL2N z{Ll9*q04FzH6NNMt;{rc;G!F`sP6PjXN|npUo~C6n=TOHv zR)a9o|Hz9TETXlzg+el4XWn{X-pNdPIW5?p9r8a-?A{$J?g5;2jC48dRctftcEo2b zE@ZuI{lNN&^}%+zG+)iXi~s0!3dctAv0tKB_Adk7_~P8lnaRDodmrb2|KaiL?gzK8 zF5TT*zB1D3XpiLNO8fRfVRGf(XYCLFDxCU0Gre@@#`upD*T>ch*0bMoZ(hCl;&-{J zpY3azY3tzWaB$^?J Optiona # noinspection PyTypeChecker column_name: Optional[str] = self.column(column_id, 'id') if column_id else None - cell_value: str = self.set(row_id, column_id) if column_id and row_id else '' + cell_value: str = '' + + if column_id and row_id: + if column_id == '#0': + cell_value = self.item(row_id, 'text') + else: + cell_value = self.set(row_id, column_id) if column_name == '': column_name = None diff --git a/src/ui/widget/common/treeview/pydantic.py b/src/ui/widget/common/treeview/pydantic.py index 69ad7c0..47ea0d1 100644 --- a/src/ui/widget/common/treeview/pydantic.py +++ b/src/ui/widget/common/treeview/pydantic.py @@ -17,8 +17,7 @@ class PydanticTreeviewLoader: - def \ - __init__(self, treeview: ExtendedTreeview, model: type[BaseModel]): + def __init__(self, treeview: ExtendedTreeview, model: type[BaseModel]): self._treeview = treeview self._model = model self._original_data = [] diff --git a/src/ui/widget/common/treeview/sortable.py b/src/ui/widget/common/treeview/sortable.py index ea4d7fc..1174a12 100644 --- a/src/ui/widget/common/treeview/sortable.py +++ b/src/ui/widget/common/treeview/sortable.py @@ -1,6 +1,8 @@ from tkinter import Tk, BOTH +from constants.resources import UI_SORT_UP, UI_SORT_DOWN, UI_SORT_EMPTY from ui.widget.common.treeview.scrollable import ScrollableTreeview +from util.ui import load_img class SortableTreeview(ScrollableTreeview): @@ -8,12 +10,19 @@ def __init__(self, master=None, *args, **kwargs): super().__init__(master, *args, **kwargs, hand_on_title=True) self._sort_column_name = None self._sort_reverse = False + + self._sort_up_icon = load_img(UI_SORT_UP) + self._sort_down_icon = load_img(UI_SORT_DOWN) + self._sort_empty_icon = load_img(UI_SORT_EMPTY) + self._setup_sorting() def _setup_sorting(self): for column_name in self["columns"]: self.heading(column_name, command=lambda c=column_name: self._on_heading_click(c)) + self._update_heading_text() + def _on_heading_click(self, column): if self._sort_column_name == column: self._sort_reverse = not self._sort_reverse @@ -40,26 +49,22 @@ def sort_column(self): @staticmethod def _get_value_as_type(value): + if not value: + return value + if value.replace('.', '', 1).isdigit(): return float(value) if '.' in value else int(value) - return value + + return str.lower(value) def _update_heading_text(self): - up = '⭡' - down = '⭣' - sort_symbol = up if self._sort_reverse else down + sort_icon = self._sort_up_icon if self._sort_reverse else self._sort_down_icon for column_name in self["columns"]: - title = self.heading(column_name, 'text') - title = (title - .replace(up, '') - .replace(down, '') - .strip()) - if column_name == self._sort_column_name: - title = f" {title} {sort_symbol}" - - self.heading(column_name, text=title) + self.heading(column_name, image=sort_icon) + else: + self.heading(column_name, image=self._sort_empty_icon) def sort_column_name(self, column_name): self._sort_column_name = column_name diff --git a/src/ui/widget/settings/tabs/processes/process_list.py b/src/ui/widget/settings/tabs/processes/process_list.py index 894e4df..1efcd0b 100644 --- a/src/ui/widget/settings/tabs/processes/process_list.py +++ b/src/ui/widget/settings/tabs/processes/process_list.py @@ -1,18 +1,22 @@ -import textwrap +import os.path from tkinter import Menu, LEFT, END, NORMAL, DISABLED from typing import Callable, Optional +from PIL import ImageTk from pydantic import BaseModel -from constants.resources import UI_ADD_PROCESS_RULE, UI_ADD_SERVICE_RULE -from constants.ui import CMENU_ADD_PROCESS_RULE_LABEL, CMENU_ADD_SERVICE_RULE_LABEL +from constants.resources import UI_ADD_PROCESS_RULE, UI_ADD_SERVICE_RULE, UI_COPY, UI_SERVICE, \ + UI_PROCESS +from constants.ui import CMENU_ADD_PROCESS_RULE_LABEL, CMENU_ADD_SERVICE_RULE_LABEL, COLUMN_WIDTH_WITH_ICON, \ + CMENU_COPY_LABEL from enums.filters import FilterByProcessType from enums.rules import RuleType from enums.selector import SelectorType from model.process import Process from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader from ui.widget.common.treeview.sortable import SortableTreeview -from util.ui import load_img +from util.ui import load_img, trim_cmenu_label +from util.utils import get_icon_from_exe class ProcessList(SortableTreeview): @@ -22,19 +26,26 @@ def __init__( add_rule_command: Callable[[RuleType, Optional[SelectorType]], None], *args, **kwargs ): - self._filter_by_type: FilterByProcessType = FilterByProcessType.ALL - self._filter_by_search_query: Optional[str] = None - columns = [key for key, field_info in model.model_fields.items() if not field_info.exclude] super().__init__( *args, **kwargs, - show='headings', + show='tree headings', columns=columns, selectmode="browse" ) + self.heading("#0", text="") + self.column("#0", width=COLUMN_WIDTH_WITH_ICON, stretch=False) + + self._filter_by_type: FilterByProcessType = FilterByProcessType.ALL + self._filter_by_search_query: Optional[str] = None + + self._process_icon = load_img(UI_PROCESS) + self._service_icon = load_img(UI_SERVICE) + self._icons = {} + self._add_rule: Callable[[RuleType, Optional[SelectorType]], None] = add_rule_command self._data: dict[int, Process] = {} self._loader = PydanticTreeviewLoader(self, model) @@ -47,9 +58,11 @@ def _setup_context_menu(self): self._context_menu_icons = icons = { CMENU_ADD_PROCESS_RULE_LABEL: load_img(UI_ADD_PROCESS_RULE), CMENU_ADD_SERVICE_RULE_LABEL: load_img(UI_ADD_SERVICE_RULE), + CMENU_COPY_LABEL: load_img(UI_COPY), } self._context_menu = menu = Menu(self, tearoff=0) self._process_menu = Menu(menu, tearoff=0) + self._copy_menu = Menu(menu, tearoff=0) menu.add_cascade( label=CMENU_ADD_PROCESS_RULE_LABEL, @@ -65,54 +78,62 @@ def _setup_context_menu(self): compound=LEFT ) + menu.add_separator() + + menu.add_cascade( + label=CMENU_COPY_LABEL, + menu=self._copy_menu, + image=icons[CMENU_COPY_LABEL], + compound=LEFT + ) + self.bind("", self._show_context_menu, '+') def _show_context_menu(self, event): context_menu = self._context_menu - menu = self._process_menu process_list = self row_id = process_list.identify_row(event.y) if row_id: process_list.selection_set(row_id) row = self.as_model(row_id) - exists = False - - menu.delete(0, END) - if row.process_name: - exists = True - menu.add_command( - label=f"By {SelectorType.NAME.value}: {row.process_name}", - command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.NAME) - ) - - if row.bin_path: - exists = True - menu.add_command( - label=textwrap.shorten( - f"By {SelectorType.PATH.value}: {row.bin_path}", - width=128, - placeholder="..." - ), - command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.PATH) - ) - - if row.cmd_line: - exists = True - menu.add_command( - label=textwrap.shorten( - f"By {SelectorType.CMDLINE.value}: {row.cmd_line}", - width=128, - placeholder="..." - ), - command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.CMDLINE) - ) - - self._context_menu.entryconfig(CMENU_ADD_PROCESS_RULE_LABEL, state=NORMAL if exists else DISABLED) + process_exists = self._update_process_menu(row) + self._update_copy_menu(row) + + self._context_menu.entryconfig(CMENU_ADD_PROCESS_RULE_LABEL, state=NORMAL if process_exists else DISABLED) self._context_menu.entryconfig(CMENU_ADD_SERVICE_RULE_LABEL, state=NORMAL if row.service else DISABLED) context_menu.post(event.x_root, event.y_root) + def _update_process_menu(self, row): + process_menu = self._process_menu + exists = False + + process_menu.delete(0, END) + + if row.process_name: + exists = True + process_menu.add_command( + label=f"By {SelectorType.NAME.value}: {row.process_name}", + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.NAME) + ) + + if row.bin_path: + exists = True + process_menu.add_command( + label=trim_cmenu_label(f"By {SelectorType.PATH.value}: {row.bin_path}"), + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.PATH) + ) + + if row.cmd_line: + exists = True + process_menu.add_command( + label=trim_cmenu_label(f"By {SelectorType.CMDLINE.value}: {row.cmd_line}"), + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.CMDLINE) + ) + + return exists + def set_display_columns(self, filter_by_type): display_columns = list(self['columns']) @@ -128,6 +149,20 @@ def set_filter(self, by_type: FilterByProcessType, by_search_query: str): def update_ui(self): filter_by_type = self._filter_by_type search_query = self._filter_by_search_query + data = self._get_filtered_data(filter_by_type, search_query) + + self.set_display_columns(filter_by_type) + self._loader.set_data(data) + + self._update_process_icons() + + def _update_process_icons(self): + for row_id in self.get_children(): + model = self.as_model(row_id) + icon = self.get_process_icon(model) + self.item(row_id, image=icon) + + def _get_filtered_data(self, filter_by_type, search_query): data = [] for row in self._data.values(): @@ -143,9 +178,59 @@ def update_ui(self): if by_type and by_search: data.append(row) - self.set_display_columns(filter_by_type) - self._loader.set_data(data) + return data def as_model(self, row_id) -> Process: pid = int(self.as_dict(row_id)['pid']) return self._data[pid] + + def _update_copy_menu(self, row): + copy_menu = self._copy_menu + copy_menu.delete(0, END) + + values = [ + row.pid, + row.process_name, + row.service_name, + row.bin_path, + row.cmd_line + ] + + values = map(lambda o: str(o) if o else '', values) + values = filter(lambda o: o, values) + values = [*dict.fromkeys(values)] + + for value in values: + copy_menu.add_command(label=trim_cmenu_label(value), command=lambda v=value: self._copy_to_clipboard(v)) + + def _copy_to_clipboard(self, text): + self.clipboard_clear() + self.clipboard_append(text) + self.update() + + def get_process_icon(self, process: Process): + bin_path = process.bin_path + + if bin_path in self._icons: + return self._icons[bin_path] + + image = None + + if bin_path: + path = os.path.abspath(bin_path) + + if os.path.exists(path): + try: + pil_image = get_icon_from_exe(path) + image = ImageTk.PhotoImage(pil_image) if pil_image else None + except: + pass + + if image is None: + if process.service: + image = self._service_icon + else: + image = self._process_icon + + self._icons[bin_path] = image + return image diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index c94676e..c904851 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -5,8 +5,7 @@ from pydantic.config import JsonDict from constants.resources import UI_ERROR, UI_DELETE, UI_REDO, UI_UNDO, UI_SELECT_ALL, UI_ADD -from constants.ui import ERROR_ROW_COLOR, \ - ScrollableTreeviewEvents, CHANGED_ROW_COLOR, ExtendedTreeviewEvents +from constants.ui import ERROR_ROW_COLOR, ScrollableTreeviewEvents, ExtendedTreeviewEvents from ui.widget.common.label import Image from ui.widget.common.treeview.editable import EditableTreeview from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader @@ -27,7 +26,6 @@ def __init__(self, model: type[BaseModel], *args, **kwargs): self._error_icons: dict[tuple[str, str], Image] = {} self.tag_configure("error", background=ERROR_ROW_COLOR) - self.tag_configure("changed", background=CHANGED_ROW_COLOR) self.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._check_errors(), '+') self.bind(ScrollableTreeviewEvents.SCROLL, self._place_icons, '+') diff --git a/src/util/ui.py b/src/util/ui.py index e73a7ac..30f4b66 100644 --- a/src/util/ui.py +++ b/src/util/ui.py @@ -1,8 +1,11 @@ +import textwrap import tkinter from tkinter import font, Widget, Entry, PhotoImage from tkinter.font import Font from tkinter.ttk import Treeview +from constants.ui import TRIM_LENGTH_OF_ITEM_IN_CONTEXT_MENU + def state(widget: Widget) -> str: return str(widget["state"]) @@ -71,3 +74,7 @@ def get_entry_font(): def load_img(file) -> PhotoImage: return PhotoImage(file=file) + + +def trim_cmenu_label(text: str) -> str: + return textwrap.shorten(text, width=TRIM_LENGTH_OF_ITEM_IN_CONTEXT_MENU, placeholder="...") diff --git a/src/util/utils.py b/src/util/utils.py index 0999063..4550f9e 100644 --- a/src/util/utils.py +++ b/src/util/utils.py @@ -6,6 +6,12 @@ from types import NoneType from typing import get_origin, get_args, Union, Annotated, Optional +import win32api +import win32con +import win32gui +import win32ui +from PIL import Image + @cache def path_pattern_to_regex(pattern: str) -> Optional[Pattern]: @@ -153,3 +159,77 @@ def get_values_from_enum(annotation): values.append(str(e.value)) return values + + +def get_icon_from_exe(exe_path, icon_index=0, large=False, try_load_another_if_absent=True): + if large: + icon_size = ( + win32api.GetSystemMetrics(win32con.SM_CXICON), + win32api.GetSystemMetrics(win32con.SM_CYICON) + ) + else: + icon_size = ( + win32api.GetSystemMetrics(win32con.SM_CXSMICON), + win32api.GetSystemMetrics(win32con.SM_CYSMICON) + ) + + hdc = None + hdc_mem = None + bmp = None + list_of_large_hicon = [] + list_of_small_hicon = [] + + try: + list_of_large_hicon, list_of_small_hicon = win32gui.ExtractIconEx(exe_path, icon_index) + list_of_hicon = list_of_large_hicon if large else list_of_small_hicon + + if not list_of_hicon: + return + + hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0)) + hdc_mem = hdc.CreateCompatibleDC() + + bmp = win32ui.CreateBitmap() + bmp.CreateCompatibleBitmap(hdc, icon_size[0], icon_size[1]) + + hdc_mem.SelectObject(bmp) + + win32gui.DrawIconEx( + hdc_mem.GetSafeHdc(), + 0, + 0, + list_of_hicon[0], + icon_size[0], + icon_size[1], + 0, + None, + win32con.DI_NORMAL + ) + + bmp_info = bmp.GetInfo() + bmp_bits = bmp.GetBitmapBits(True) + + return Image.frombuffer( + 'RGBA', + (bmp_info['bmWidth'], bmp_info['bmHeight']), + bmp_bits, 'raw', 'BGRA', 0, 1 + ) + finally: + if bmp: + handle = bmp.GetHandle() + + if handle: + win32gui.DeleteObject(handle) + + if hdc_mem: + hdc_mem.DeleteDC() + + if hdc: + hdc.DeleteDC() + win32gui.ReleaseDC(0, hdc.GetSafeHdc()) + + for hicon in list_of_large_hicon: + win32gui.DestroyIcon(hicon) + + for hicon in list_of_small_hicon: + win32gui.DestroyIcon(hicon) From 9a8990063d887b27594eac955fff4ea60c18ed16 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Sun, 15 Sep 2024 01:42:34 +0800 Subject: [PATCH 30/39] Fix incorrect build configuration --- build_portable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_portable.py b/build_portable.py index a662229..4ac05b1 100644 --- a/build_portable.py +++ b/build_portable.py @@ -41,7 +41,7 @@ '--onedir', # Build the app in one directory '--uac-admin', # Request admin rights on launch '--hide-console', 'hide-early', # Hide the console on startup - '--add-data', './resources/*;./resources', # Add additional resources + '--add-data', './resources/;./resources', # Add additional resources '--contents-directory', 'scripts', # Directory for Python and app scripts in the built package '--icon', 'resources/app.ico', # Application icon '--debug', 'noarchive', # Disables bundling of application scripts inside the exe From 864b845f303ea1a0fe6dedb031acac40905b8e34 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Tue, 17 Sep 2024 01:24:48 +0800 Subject: [PATCH 31/39] Trying to fix process list update stuck --- src/constants/threads.py | 3 +- src/constants/ui.py | 3 + src/ui/tray.py | 12 ++- .../settings/tabs/processes/process_list.py | 26 ++++- .../settings/tabs/processes/process_tab.py | 101 +++++++++--------- 5 files changed, 86 insertions(+), 59 deletions(-) diff --git a/src/constants/threads.py b/src/constants/threads.py index 3d037f5..1e128bf 100644 --- a/src/constants/threads.py +++ b/src/constants/threads.py @@ -1,3 +1,4 @@ THREAD_SETTINGS = "settings" THREAD_TRAY = "tray" -THREAD_PROCESS_LIST = "process_list" +THREAD_PROCESS_LIST_DATA = "process_list_data" +THREAD_PROCESS_LIST_ICONS = "process_list_icons" diff --git a/src/constants/ui.py b/src/constants/ui.py index 2a2eb5c..5bf4eaf 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -49,3 +49,6 @@ class EditableTreeviewEvents: class ScrollableTreeviewEvents: SCROLL: Final[str] = "<>" + + +ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE = 'main thread is not in main loop' diff --git a/src/ui/tray.py b/src/ui/tray.py index 9d938db..460bbb2 100644 --- a/src/ui/tray.py +++ b/src/ui/tray.py @@ -7,11 +7,13 @@ from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.resources import APP_ICON +from constants.threads import THREAD_SETTINGS from constants.ui import OPEN_LOG_LABEL, OPEN_CONFIG_LABEL from constants.updates import UPDATE_URL from ui.settings import open_settings from util.files import open_log_file, open_config_file from util.messages import yesno_error_box, show_error, show_info +from util.scheduler import TaskScheduler from util.startup import toggle_startup, is_in_startup from util.updates import check_latest_version from util.utils import is_portable @@ -46,6 +48,14 @@ def check_updates(): webbrowser.open(UPDATE_URL, new=0, autoraise=True) +def close_app(item): + if TaskScheduler.check_task(THREAD_SETTINGS): + show_info(APP_NAME_WITH_VERSION, "Please close the settings window before closing the application.") + return + + return item.stop() + + def init_tray() -> Icon: """ Initializes and returns a system tray icon. @@ -75,7 +85,7 @@ def init_tray() -> Icon: ), Menu.SEPARATOR, - MenuItem('Quit', lambda item: item.stop()), + MenuItem('Quit', close_app), ) return pystray.Icon("tray_icon", image, APP_NAME, menu) diff --git a/src/ui/widget/settings/tabs/processes/process_list.py b/src/ui/widget/settings/tabs/processes/process_list.py index 1efcd0b..21d8733 100644 --- a/src/ui/widget/settings/tabs/processes/process_list.py +++ b/src/ui/widget/settings/tabs/processes/process_list.py @@ -5,16 +5,19 @@ from PIL import ImageTk from pydantic import BaseModel +from constants.log import LOG from constants.resources import UI_ADD_PROCESS_RULE, UI_ADD_SERVICE_RULE, UI_COPY, UI_SERVICE, \ UI_PROCESS +from constants.threads import THREAD_PROCESS_LIST_ICONS from constants.ui import CMENU_ADD_PROCESS_RULE_LABEL, CMENU_ADD_SERVICE_RULE_LABEL, COLUMN_WIDTH_WITH_ICON, \ - CMENU_COPY_LABEL + CMENU_COPY_LABEL, ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE from enums.filters import FilterByProcessType from enums.rules import RuleType from enums.selector import SelectorType from model.process import Process from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader from ui.widget.common.treeview.sortable import SortableTreeview +from util.scheduler import TaskScheduler from util.ui import load_img, trim_cmenu_label from util.utils import get_icon_from_exe @@ -157,10 +160,23 @@ def update_ui(self): self._update_process_icons() def _update_process_icons(self): - for row_id in self.get_children(): - model = self.as_model(row_id) - icon = self.get_process_icon(model) - self.item(row_id, image=icon) + def set_icons(icons): + try: + for row_id, icon in icons: + self.item(row_id, image=icon) + except BaseException as e: + if ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE not in str(e): + LOG.exception("Update process icons error") + + def get_icons(): + try: + icons = {row_id: self.get_process_icon(self.as_model(row_id)) for row_id in self.get_children()} + self.after(0, lambda: set_icons(icons.items())) + except BaseException as e: + if ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE not in str(e): + LOG.exception("Get process icons error") + + TaskScheduler.schedule_task(THREAD_PROCESS_LIST_ICONS, get_icons) def _get_filtered_data(self, filter_by_type, search_query): data = [] diff --git a/src/ui/widget/settings/tabs/processes/process_tab.py b/src/ui/widget/settings/tabs/processes/process_tab.py index e5d72d3..9fbe71b 100644 --- a/src/ui/widget/settings/tabs/processes/process_tab.py +++ b/src/ui/widget/settings/tabs/processes/process_tab.py @@ -4,8 +4,8 @@ from constants.log import LOG from constants.resources import UI_PROCESS_LIST -from constants.threads import THREAD_PROCESS_LIST -from constants.ui import UI_PADDING, ActionEvents +from constants.threads import THREAD_PROCESS_LIST_DATA +from constants.ui import UI_PADDING, ActionEvents, ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE from enums.rules import RuleType from enums.selector import SelectorType from model.process import Process @@ -43,9 +43,6 @@ def __init__(self, master: Notebook, process_rules_list: RulesList, service_rule super().__init__(master) - self._is_close = False - self.bind("", self._on_close) - self._create_process_list() self._create_progress_bar() self._create_actions() @@ -74,64 +71,64 @@ def load_from_config(self, config: dict): self._refresh() def _update_process_list(self): - filter_by_type = self.actions.filterByType.get_enum_value() - search_query = self.actions.search.get().strip().lower() - - self.process_list.set_filter(filter_by_type, search_query) - self.process_list.update_ui() + try: + filter_by_type = self.actions.filterByType.get_enum_value() + search_query = self.actions.search.get().strip().lower() - def _on_close(self, _=None): - self._is_close = True + self.process_list.set_filter(filter_by_type, search_query) + self.process_list.update_ui() + except BaseException as e: + if ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE not in str(e): + LOG.exception("Update process list error") def _refresh(self): - main_thread_not_in_mainloop_message = 'main thread is not in main loop' + LOG.info("Refreshing process list...") + + def update_process_list(): + LOG.info("Updating process list...") + + try: + self._update_process_list() + finally: + self._refresh_state() + + def load_data(): + LOG.info("Loading data...") + + try: + self.process_list.set_data(ProcessesInfoService.get_processes(False)) + self.after(0, update_process_list) + except BaseException as e: + if ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE not in str(e): + LOG.exception("Load data error") + + self._refresh_state() try: self._refresh_state(True) self.process_list.clear() - def load(): - try: - try: - self.process_list.set_data(ProcessesInfoService.get_processes(False)) - - def do_ui_update(): - if self._is_close: - return - - try: - try: - self._update_process_list() - finally: - self._refresh_state() - except BaseException as e: - if str(e) != main_thread_not_in_mainloop_message: - LOG.exception("Refresh error") - - if self._is_close: - return - - self.after(0, do_ui_update) - finally: - self._refresh_state() - except BaseException as e: - if str(e) != main_thread_not_in_mainloop_message: - LOG.exception("Refresh error") - - TaskScheduler.schedule_task(THREAD_PROCESS_LIST, load) - except: + TaskScheduler.schedule_task(THREAD_PROCESS_LIST_DATA, load_data) + except BaseException as e: + if ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE not in str(e): + LOG.exception("Refresh error") + self._refresh_state() - LOG.exception("Refresh error") def _refresh_state(self, lock: bool = False): - actions = self.actions - actions.refresh['state'] = DISABLED if lock else NORMAL - - progress_bar = self._progress_bar - if lock: - progress_bar.place(relx=0.5, rely=0.5, anchor=CENTER) - else: - progress_bar.place_forget() + try: + actions = self.actions + actions.refresh['state'] = DISABLED if lock else NORMAL + + progress_bar = self._progress_bar + + if lock: + progress_bar.place(relx=0.5, rely=0.5, anchor=CENTER) + else: + progress_bar.place_forget() + except BaseException as e: + if ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE not in str(e): + LOG.exception("Refresh state error") def save_to_config(self, config: dict): pass From 7a30ca8627c0085c29599c1a760feabc138cbe5d Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Tue, 17 Sep 2024 02:00:21 +0800 Subject: [PATCH 32/39] Added the ability to open the folder where the process executable file is located --- resources/UI/open-folder.png | Bin 0 -> 1502 bytes src/constants/resources.py | 1 + src/constants/ui.py | 1 + .../settings/tabs/processes/process_list.py | 24 ++++++++++++++++-- src/util/files.py | 13 ++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 resources/UI/open-folder.png diff --git a/resources/UI/open-folder.png b/resources/UI/open-folder.png new file mode 100644 index 0000000000000000000000000000000000000000..d72fa23ee8811418ddd8866a142094bea164f651 GIT binary patch literal 1502 zcmbVMO=uid9G?&yH6LK5G$_85AK0 z%)2Hdbwca)mw}CJ3!(zF3I;-W&c%fS7(TiZm#_w2tGqfCrdFQbk}}2+b~+uiGiQpV z2`$%kA+n)u8wz2h+mR$)BT7$?7%DuaNf66GL?B}%b+IKqU8y>-A&hg{C>{Dqc?@<* z3@sC7HuZsw=D2t(Y4?RQ3VEA{Jd&xxS~)gu2`SQ+_!sK@_#pwxx4xgtI8v7|%tfSf z>AEsw=#V4PX>B{^aE+&8E1`Vpx>ECWW=)LC2`5q{H6hxgNUe@k2DWV$z?tvT)JC$a)EtFhT>UFIdpnJ`y^Qi|#{El{1V;@<=eFxFM2| zD1(ELG&zi;rVes9;<9LqLa`80VKt0Wqd<*%ah@2ih3vUfoic}&M)xa%Ze=Mjy3hXS z{nwH})gWmg0QXXanJFo-()5QMSq2eCFRmaGtd9PB7yxZ|ewYWs} zGX3uFU#UJARx69O(s8=q>n)5w|NhShPu%~$b1?bCo`37=&3E=L-hvEFeDmQaf6ktK z<43r6?%lEdnf3i~dH?dAv5zlL9Q3{{zWvri7zi{K!=TCn2-kZCBOl#+Un-Vwq@!6~cSC>{QU!1>o;{gH5-fI8= literal 0 HcmV?d00001 diff --git a/src/constants/resources.py b/src/constants/resources.py index 99f458a..f1574bf 100644 --- a/src/constants/resources.py +++ b/src/constants/resources.py @@ -25,6 +25,7 @@ UI_COPY: Final[str] = f"{APP_PATH}/resources/UI/copy.png" UI_SERVICE: Final[str] = f"{APP_PATH}/resources/UI/service.png" UI_PROCESS: Final[str] = f"{APP_PATH}/resources/UI/process.png" +UI_OPEN_FOLDER: Final[str] = f"{APP_PATH}/resources/UI/open-folder.png" UI_INFO_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/info-tooltip.png" UI_WARN_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/warn-tooltip.png" diff --git a/src/constants/ui.py b/src/constants/ui.py index 5bf4eaf..3650c86 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -19,6 +19,7 @@ CMENU_ADD_PROCESS_RULE_LABEL = " Add Process Rule" CMENU_ADD_SERVICE_RULE_LABEL = " Add Service Rule" CMENU_COPY_LABEL = " Copy Special" +CMENU_OPEN_PROCESS_FOLDER = " Open process folder" class ActionEvents: diff --git a/src/ui/widget/settings/tabs/processes/process_list.py b/src/ui/widget/settings/tabs/processes/process_list.py index 21d8733..2ffd86b 100644 --- a/src/ui/widget/settings/tabs/processes/process_list.py +++ b/src/ui/widget/settings/tabs/processes/process_list.py @@ -7,16 +7,17 @@ from constants.log import LOG from constants.resources import UI_ADD_PROCESS_RULE, UI_ADD_SERVICE_RULE, UI_COPY, UI_SERVICE, \ - UI_PROCESS + UI_PROCESS, UI_OPEN_FOLDER from constants.threads import THREAD_PROCESS_LIST_ICONS from constants.ui import CMENU_ADD_PROCESS_RULE_LABEL, CMENU_ADD_SERVICE_RULE_LABEL, COLUMN_WIDTH_WITH_ICON, \ - CMENU_COPY_LABEL, ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE + CMENU_COPY_LABEL, ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE, CMENU_OPEN_PROCESS_FOLDER from enums.filters import FilterByProcessType from enums.rules import RuleType from enums.selector import SelectorType from model.process import Process from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader from ui.widget.common.treeview.sortable import SortableTreeview +from util.files import explore from util.scheduler import TaskScheduler from util.ui import load_img, trim_cmenu_label from util.utils import get_icon_from_exe @@ -62,6 +63,7 @@ def _setup_context_menu(self): CMENU_ADD_PROCESS_RULE_LABEL: load_img(UI_ADD_PROCESS_RULE), CMENU_ADD_SERVICE_RULE_LABEL: load_img(UI_ADD_SERVICE_RULE), CMENU_COPY_LABEL: load_img(UI_COPY), + CMENU_OPEN_PROCESS_FOLDER: load_img(UI_OPEN_FOLDER), } self._context_menu = menu = Menu(self, tearoff=0) self._process_menu = Menu(menu, tearoff=0) @@ -90,8 +92,24 @@ def _setup_context_menu(self): compound=LEFT ) + menu.add_command( + label=CMENU_OPEN_PROCESS_FOLDER, + command=self._open_process_folder, + image=icons[CMENU_OPEN_PROCESS_FOLDER], + compound=LEFT + ) + self.bind("", self._show_context_menu, '+') + def _open_process_folder(self): + selected_item = self.selection() + + if not selected_item: + return + + row = self.as_model(selected_item[0]) + explore(row.bin_path) + def _show_context_menu(self, event): context_menu = self._context_menu process_list = self @@ -105,6 +123,8 @@ def _show_context_menu(self, event): self._context_menu.entryconfig(CMENU_ADD_PROCESS_RULE_LABEL, state=NORMAL if process_exists else DISABLED) self._context_menu.entryconfig(CMENU_ADD_SERVICE_RULE_LABEL, state=NORMAL if row.service else DISABLED) + self._context_menu.entryconfig(CMENU_OPEN_PROCESS_FOLDER, + state=NORMAL if os.path.isfile(row.bin_path or '') else DISABLED) context_menu.post(event.x_root, event.y_root) diff --git a/src/util/files.py b/src/util/files.py index b58fd8f..ab71be1 100644 --- a/src/util/files.py +++ b/src/util/files.py @@ -1,4 +1,5 @@ import os +import subprocess from constants.files import LOG_FILE_NAME, CONFIG_FILE_NAME @@ -9,3 +10,15 @@ def open_log_file(): def open_config_file(): os.startfile(CONFIG_FILE_NAME) + + +FILEBROWSER_PATH = os.path.join(os.getenv('WINDIR'), 'explorer.exe') + + +def explore(path): + path = os.path.normpath(path) + + if os.path.isdir(path): + subprocess.run([FILEBROWSER_PATH, path]) + elif os.path.isfile(path): + subprocess.run([FILEBROWSER_PATH, '/select,', path]) From a58c1b337487f0284e82608e882efb0a1b836680 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Tue, 17 Sep 2024 22:02:10 +0800 Subject: [PATCH 33/39] Optimizations, QoL improvements --- process-governor.py | 4 +- src/configuration/migration/all_migration.py | 7 +- src/constants/app_info.py | 1 + src/main_loop.py | 12 ++-- src/model/process.py | 2 + src/service/processes_info_service.py | 66 +++++++++++-------- src/service/rules_service.py | 16 ++--- src/ui/settings.py | 64 ++++++++++++++---- src/ui/tray.py | 50 +++----------- src/ui/widget/settings/settings_tabs.py | 12 ++-- .../settings/tabs/processes/process_tab.py | 2 +- src/util/lock_instance.py | 4 +- src/util/messages.py | 39 ++++------- src/util/updates.py | 24 ++++++- 14 files changed, 159 insertions(+), 144 deletions(-) diff --git a/process-governor.py b/process-governor.py index 31493a0..f1c9ff3 100644 --- a/process-governor.py +++ b/process-governor.py @@ -3,7 +3,7 @@ import pyuac -from constants.app_info import APP_NAME, APP_NAME_WITH_VERSION +from constants.app_info import APP_NAME from constants.log import LOG from main_loop import start_app from util.lock_instance import create_lock_file, remove_lock_file @@ -19,7 +19,7 @@ "Please run the program as an administrator to ensure proper functionality.") LOG.error(message) - show_error(f"Error Detected - {APP_NAME_WITH_VERSION}", message) + show_error(message) sys.exit(1) create_lock_file() diff --git a/src/configuration/migration/all_migration.py b/src/configuration/migration/all_migration.py index adb1f36..12c8981 100644 --- a/src/configuration/migration/all_migration.py +++ b/src/configuration/migration/all_migration.py @@ -4,7 +4,6 @@ from configuration.migration.m0_rules_to_split_rules_config import MigrationRules2SplitRulesConfig from configuration.migration.m1_new_fields_in_rule import NewFieldsInRule from configuration.migration.m2_remove_high_io_priority import RemoveHighIoPriority -from constants.app_info import APP_NAME_WITH_VERSION from constants.log import LOG from service.config_service import ConfigService from util.messages import show_error @@ -55,14 +54,12 @@ def run_all_migration(): except Exception as e: has_error = True LOG.exception(f"[{migration_name}] Migration failed.") - show_error( - f"Error Detected - {APP_NAME_WITH_VERSION}", - f"Migration `{migration_name}` failed: \n{str(e)}" - ) + show_error(f"Migration `{migration_name}` failed: \n{str(e)}") break if not has_error: ConfigService.save_config_raw(config) + if __name__ == '__main__': run_all_migration() diff --git a/src/constants/app_info.py b/src/constants/app_info.py index 5bbf414..12c150a 100644 --- a/src/constants/app_info.py +++ b/src/constants/app_info.py @@ -11,6 +11,7 @@ CURRENT_TAG: Final[str] = f"v{APP_VERSION}" APP_NAME_WITH_VERSION: Final[str] = f"{APP_NAME} {CURRENT_TAG}" +TITLE_ERROR: Final[str] = f"Error Detected - {APP_NAME_WITH_VERSION}" if is_portable(): APP_PATH: Final[str] = sys._MEIPASS diff --git a/src/main_loop.py b/src/main_loop.py index e141d50..2f3ab27 100644 --- a/src/main_loop.py +++ b/src/main_loop.py @@ -8,7 +8,7 @@ from configuration.config import Config from configuration.migration.all_migration import run_all_migration -from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME +from constants.app_info import APP_NAME from constants.files import LOG_FILE_NAME from constants.log import LOG from constants.threads import THREAD_SETTINGS, THREAD_TRAY @@ -20,6 +20,7 @@ from util.messages import yesno_error_box, show_error from util.scheduler import TaskScheduler from util.startup import update_startup +from util.updates import check_updates def priority_setup(): @@ -96,6 +97,7 @@ def start_app(): run_all_migration() update_startup() priority_setup() + check_updates(True) tray: Icon = init_tray() main_loop(tray) @@ -110,20 +112,18 @@ def start_app(): def show_rules_error_message(): - title = f"Error Detected - {APP_NAME_WITH_VERSION}" message = "An error has occurred while loading or applying the rules.\n" if TaskScheduler.check_task(THREAD_SETTINGS): message += "Please check the correctness of the rules." - show_error(title, message) + show_error(message) else: message += f"Would you like to open the {SETTINGS_TITLE} to review and correct the rules?" - if yesno_error_box(title, message): + if yesno_error_box(message): open_settings() def show_abstract_error_message(will_closed: bool): - title = f"Error Detected - {APP_NAME_WITH_VERSION}" will_closed_text = 'The application will now close.' if will_closed else '' message = ( f"An error has occurred in the {APP_NAME} application. {will_closed_text}\n" @@ -131,5 +131,5 @@ def show_abstract_error_message(will_closed: bool): f"Would you like to open the log file?" ) - if yesno_error_box(title, message): + if yesno_error_box(message): os.startfile(LOG_FILE_NAME) diff --git a/src/model/process.py b/src/model/process.py index f96933b..320db80 100644 --- a/src/model/process.py +++ b/src/model/process.py @@ -82,6 +82,8 @@ class Process(BaseModel): exclude=True ) + is_new: bool = Field(exclude=True) + def __hash__(self): return hash((self.pid, self.bin_path, self.process_name, self.cmd_line)) diff --git a/src/service/processes_info_service.py b/src/service/processes_info_service.py index 5961b38..54aad3e 100644 --- a/src/service/processes_info_service.py +++ b/src/service/processes_info_service.py @@ -15,41 +15,46 @@ class ProcessesInfoService(ABC): It is an abstract base class (ABC) to be subclassed by specific implementation classes. """ - __prev_pids: set[int] = [] + _cache: dict[int, Process] = {} @classmethod - def get_processes( - cls, - only_new: bool, - force_return_pids: set[int] = None - ) -> dict[int, Process]: + def get_processes(cls) -> dict[int, Process]: """ - Retrieves a dictionary of running processes and their information. + Returns a dictionary with information about running processes. - Args: - only_new (bool): If True, returns only processes that have started since the last call. - If False, returns all currently running processes. - force_return_pids (set[int], optional): A set of process IDs that should be included in the result - even if they are not new. Defaults to an empty set if not provided. Returns: - dict[int, Process]: A dictionary where keys are process IDs and values are Process objects, - containing detailed information about each running process. + dict[int, Process]: A dictionary with information about running processes. """ - services = ServicesInfoService.get_services() - result: dict[int, Process] = {} - current_pids: list[int] = psutil.pids() - force_return_pids = force_return_pids or set() - for pid in current_pids: - if only_new and pid in cls.__prev_pids and pid not in force_return_pids: - continue + cache = cls._cache + services = ServicesInfoService.get_services() + pids = set(psutil.pids()) + for pid in pids: try: - process = psutil.Process(pid) + process_info = psutil.Process(pid) + info = process_info.as_dict(attrs=[ + 'exe', + 'nice', 'ionice', 'cpu_affinity' + ]) + + if pid in cache: + process = cache[pid] + + if process.bin_path == info['exe']: + process.priority = none_int(info['nice']) + process.io_priority = none_int(info['ionice']) + process.affinity = info['cpu_affinity'] + process.is_new = False + continue + service = services.get(pid) + info = process_info.as_dict(attrs=[ + 'name', 'exe', 'cmdline', + 'nice', 'ionice', 'cpu_affinity' + ]) - info = process.as_dict(attrs=['name', 'exe', 'nice', 'ionice', 'cpu_affinity', 'cmdline']) - result[pid] = Process.model_construct( + cache[pid] = Process.model_construct( pid=pid, process_name=info['name'], service_name=getattr(service, 'name', None), @@ -58,16 +63,19 @@ def get_processes( priority=none_int(info['nice']), io_priority=none_int(info['ionice']), affinity=info['cpu_affinity'], - process=process, - service=service + process=process_info, + service=service, + is_new=True ) except NoSuchProcess: pass - if only_new: - cls.__prev_pids = set(current_pids) + deleted_pids = cache.keys() - pids + + for pid in deleted_pids: + del cache[pid] - return result + return cache.copy() @staticmethod def _get_command_line(pid, info): diff --git a/src/service/rules_service.py b/src/service/rules_service.py index c7188c3..b87e7e6 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -29,7 +29,6 @@ class RulesService(ABC): __ignore_pids: set[int] = {0, os.getpid()} __ignored_process_parameters: dict[Process, set[ProcessParameter]] = {} - __force_pids: set[int] = set() @classmethod def apply_rules(cls, config: Config, only_new: bool): @@ -47,15 +46,14 @@ def apply_rules(cls, config: Config, only_new: bool): return cls.__light_gc_ignored_process_parameters() - cls.__force_pids = cls.__handle_processes( + cls.__handle_processes( config, - ProcessesInfoService.get_processes(only_new, cls.__force_pids) + ProcessesInfoService.get_processes(), + only_new ) @classmethod - def __handle_processes(cls, config: Config, processes: dict[int, Process]) -> set[int]: - force_pids: set[int] = set() - + def __handle_processes(cls, config: Config, processes: dict[int, Process], only_new: bool): for pid, process in processes.items(): if pid in cls.__ignore_pids: continue @@ -65,16 +63,14 @@ def __handle_processes(cls, config: Config, processes: dict[int, Process]) -> se if not rule: continue - if rule.force == BoolStr.YES: - force_pids.add(pid) + if rule.force == BoolStr.NO and only_new and not process.is_new: + continue if rule.delay > 0: TaskScheduler.schedule_task(process, cls.__handle_process, rule.delay, process, rule) else: cls.__handle_process(process, rule) - return force_pids - @classmethod def __handle_process(cls, process: Process, rule: ProcessRule | ServiceRule): parameter_methods: dict[ProcessParameter, tuple[Callable[[Process, ProcessRule | ServiceRule], bool], str]] = { diff --git a/src/ui/settings.py b/src/ui/settings.py index 360305a..71fa303 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -3,7 +3,7 @@ from typing import Optional from configuration.migration.all_migration import run_all_migration -from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME +from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME, TITLE_ERROR from constants.files import LOG_FILE_NAME from constants.log import LOG from constants.resources import APP_ICON, UI_SAVE, UI_LOG, UI_CONFIG @@ -41,7 +41,7 @@ def __init__(self): def _setup_window(self): self._center_window() - self.protocol("WM_DELETE_WINDOW", self._on_window_closing) + self.protocol("WM_DELETE_WINDOW", self.close) self.iconbitmap(APP_ICON) self.title(APP_NAME_WITH_VERSION) self.minsize(*RC_WIN_SIZE) @@ -145,38 +145,45 @@ def _save(self): self._update_actions_state() return result - def _on_window_closing(self): + def close(self): has_error = self._tabs.has_error() if self._tabs.has_unsaved_changes(): if has_error: + self.to_front() + message = ("There are errors in the rules, and they can't be saved. " "Do you want to DISCARD them and exit?") - result = messagebox.askyesno(f"{APP_NAME_WITH_VERSION}", message) + result = messagebox.askyesno(TITLE_ERROR, message) if not result: - return + return False else: + self.to_front() + message = ("There are unsaved changes. " "Do you want to save them before exiting?") - result = messagebox.askyesnocancel(f"{APP_NAME_WITH_VERSION}", message) + result = messagebox.askyesnocancel(APP_NAME_WITH_VERSION, message) if result is None: - return + return False if result and not self._save(): - return + return False else: if has_error: + self.to_front() + message = ( f"There are errors in the rules, and they must be corrected before the application can work properly. " f"Do you still want to close the {SETTINGS_TITLE}?") - result = messagebox.askyesno(f"{APP_NAME_WITH_VERSION}", message) + result = messagebox.askyesno(APP_NAME_WITH_VERSION, message) if not result: - return + return False self.destroy() + return True def _update_actions_state(self, _=None): tabs = self._tabs @@ -331,6 +338,12 @@ def _search_focus(self): tab.actions.search.focus_set() + def to_front(self): + self.deiconify() + self.lift() + self.attributes('-topmost', True) + self.after_idle(self.attributes, '-topmost', False) + class SettingsActions(ttk.Frame): def __init__(self, *args, **kwargs): @@ -367,11 +380,25 @@ def _setup_btn(self): save.pack(**RIGHT_PACK) +__app: Optional[Settings] = None + + def open_settings(): + global __app + + if __app is not None: + __app.after_idle(__app.to_front) + return + def settings(): try: - app = Settings() - app.mainloop() + global __app + + try: + __app = Settings() + __app.mainloop() + finally: + __app = None except: LOG.exception(f"An unexpected error occurred in the {SETTINGS_TITLE} of {APP_NAME}.") show_settings_error_message() @@ -379,15 +406,24 @@ def settings(): TaskScheduler.schedule_task(THREAD_SETTINGS, settings) +def is_opened_settings() -> bool: + global __app + return __app is not None + + +def get_settings() -> Settings: + global __app + return __app + + def show_settings_error_message(): - title = f"Error Detected - {APP_NAME_WITH_VERSION}" message = ( f"An error has occurred in the {SETTINGS_TITLE} of {APP_NAME}.\n" f"To troubleshoot, please check the log file `{LOG_FILE_NAME}` for details.\n\n" f"Would you like to open the log file?" ) - if yesno_error_box(title, message): + if yesno_error_box(message): os.startfile(LOG_FILE_NAME) diff --git a/src/ui/tray.py b/src/ui/tray.py index 460bbb2..8235dc5 100644 --- a/src/ui/tray.py +++ b/src/ui/tray.py @@ -1,5 +1,3 @@ -import webbrowser - import pystray from PIL import Image from pystray import MenuItem, Menu @@ -7,53 +5,25 @@ from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME from constants.resources import APP_ICON -from constants.threads import THREAD_SETTINGS from constants.ui import OPEN_LOG_LABEL, OPEN_CONFIG_LABEL -from constants.updates import UPDATE_URL -from ui.settings import open_settings +from ui.settings import open_settings, is_opened_settings, get_settings from util.files import open_log_file, open_config_file -from util.messages import yesno_error_box, show_error, show_info -from util.scheduler import TaskScheduler from util.startup import toggle_startup, is_in_startup -from util.updates import check_latest_version +from util.updates import check_updates from util.utils import is_portable -def check_updates(): - """ - Check for updates and display appropriate messages depending on the result. - - Returns: - None - """ - - latest_version = check_latest_version() - - if latest_version is None: - show_error( - f"Error Detected - {APP_NAME_WITH_VERSION}", - "Failed to check for updates. Please check your internet connection." - ) - elif not latest_version: - show_info( - APP_NAME_WITH_VERSION, - "You are using the latest version." - ) - else: - message = ( - f"A new version {latest_version} is available. Would you like to update {APP_NAME} now?" - ) - - if yesno_error_box(APP_NAME_WITH_VERSION, message): - webbrowser.open(UPDATE_URL, new=0, autoraise=True) +def close_app(item): + if not is_opened_settings(): + return item.stop() + settings = get_settings() -def close_app(item): - if TaskScheduler.check_task(THREAD_SETTINGS): - show_info(APP_NAME_WITH_VERSION, "Please close the settings window before closing the application.") - return + def close(): + if settings.close(): + item.stop() - return item.stop() + settings.after_idle(close) def init_tray() -> Icon: diff --git a/src/ui/widget/settings/settings_tabs.py b/src/ui/widget/settings/settings_tabs.py index aa1ca40..bc3dd54 100644 --- a/src/ui/widget/settings/settings_tabs.py +++ b/src/ui/widget/settings/settings_tabs.py @@ -1,7 +1,9 @@ from tkinter import ttk, messagebox from typing import Optional -from constants.app_info import APP_NAME_WITH_VERSION +from pydantic.config import JsonDict + +from constants.app_info import TITLE_ERROR from constants.log import LOG from constants.ui import ExtendedTreeviewEvents from service.config_service import ConfigService @@ -20,7 +22,7 @@ class SettingsTabs(ttk.Notebook): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self._config: Optional[dict] = None + self._config: Optional[JsonDict] = None self._create_tabs() self.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._update_tabs_state(), "+") @@ -68,7 +70,7 @@ def save_data(self) -> bool: if self.has_error(): messagebox.showerror( - f"Error Detected - {APP_NAME_WITH_VERSION}", + TITLE_ERROR, "Unable to save: The current rules are invalid. " "Ensure all rules are correct before saving." ) @@ -84,8 +86,8 @@ def save_data(self) -> bool: return True except: - LOG.exception("Error when saving file.") - messagebox.showerror(f"Error Detected - {APP_NAME_WITH_VERSION}", "An error occurred while saving.") + LOG.exception("An error occurred while saving.") + messagebox.showerror(TITLE_ERROR, "An error occurred while saving.") return False def frames(self) -> list[BaseTab]: diff --git a/src/ui/widget/settings/tabs/processes/process_tab.py b/src/ui/widget/settings/tabs/processes/process_tab.py index 9fbe71b..a16ea7d 100644 --- a/src/ui/widget/settings/tabs/processes/process_tab.py +++ b/src/ui/widget/settings/tabs/processes/process_tab.py @@ -96,7 +96,7 @@ def load_data(): LOG.info("Loading data...") try: - self.process_list.set_data(ProcessesInfoService.get_processes(False)) + self.process_list.set_data(ProcessesInfoService.get_processes()) self.after(0, update_process_list) except BaseException as e: if ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE not in str(e): diff --git a/src/util/lock_instance.py b/src/util/lock_instance.py index a9a671d..ba52faf 100644 --- a/src/util/lock_instance.py +++ b/src/util/lock_instance.py @@ -3,7 +3,7 @@ import psutil -from constants.app_info import APP_PROCESSES, APP_NAME_WITH_VERSION +from constants.app_info import APP_PROCESSES from constants.files import LOCK_FILE_NAME from constants.log import LOG from util.messages import show_error @@ -48,7 +48,7 @@ def create_lock_file(): "Please close the existing instance before starting a new one.") LOG.error(message) - show_error(f"Error Detected - {APP_NAME_WITH_VERSION}", message) + show_error(message) sys.exit(1) # Create the lock file with the current process's PID diff --git a/src/util/messages.py b/src/util/messages.py index a2fc92f..c1b07e0 100644 --- a/src/util/messages.py +++ b/src/util/messages.py @@ -1,9 +1,10 @@ from win32api import MessageBoxEx +from constants.app_info import APP_NAME_WITH_VERSION, TITLE_ERROR from enums.messages import MBIcon, MBButton, MBResult -def message_box(title: str, message: str, icon: MBIcon, btn: MBButton) -> MBResult: +def _message_box(title: str, message: str, icon: MBIcon, btn: MBButton) -> MBResult: """ Display a message box with the specified title, message, icon, and button. @@ -19,37 +20,21 @@ def message_box(title: str, message: str, icon: MBIcon, btn: MBButton) -> MBResu return MessageBoxEx(None, message, title, icon | btn) -def yesno_error_box(title: str, message: str) -> bool: - """ - Display a yes/no error message box with a specified title and message. +def show_info(message: str, title: str = APP_NAME_WITH_VERSION): + _message_box(title, message, MBIcon.INFORMATION, MBButton.OK) - Args: - title (str): The title of the message box. - message (str): The message to be displayed in the message box. - Returns: - bool: True if the user clicks "Yes," False if the user clicks "No." - """ - return message_box(title, message, MBIcon.ERROR, MBButton.YESNO) == MBResult.YES +def yesno_info_box(message: str, title: str = APP_NAME_WITH_VERSION) -> bool: + return _message_box(title, message, MBIcon.INFORMATION, MBButton.YESNO) == MBResult.YES -def show_error(title, message): - """ - Show an error message box with the given title and message. +def yesno_question_box(message: str, title: str = APP_NAME_WITH_VERSION) -> bool: + return _message_box(title, message, MBIcon.QUESTION, MBButton.YESNO) == MBResult.YES - Parameters: - title (str): The title of the error message box. - message (str): The message to display in the error message box. - """ - message_box(title, message, MBIcon.ERROR, MBButton.OK) +def show_error(message: str, title: str = TITLE_ERROR): + _message_box(title, message, MBIcon.ERROR, MBButton.OK) -def show_info(title, message): - """ - Show an info message box with the given title and message. - Parameters: - title (str): The title of the error message box. - message (str): The message to display in the error message box. - """ - message_box(title, message, MBIcon.INFORMATION, MBButton.OK) +def yesno_error_box(message: str, title: str = TITLE_ERROR) -> bool: + return _message_box(title, message, MBIcon.ERROR, MBButton.YESNO) == MBResult.YES diff --git a/src/util/updates.py b/src/util/updates.py index 149e046..c8599ad 100644 --- a/src/util/updates.py +++ b/src/util/updates.py @@ -1,13 +1,15 @@ import json +import webbrowser from typing import Optional, Union from urllib import request -from constants.app_info import CURRENT_TAG -from constants.updates import API_UPDATE_URL +from constants.app_info import CURRENT_TAG, APP_NAME +from constants.updates import API_UPDATE_URL, UPDATE_URL +from util.messages import show_error, show_info, yesno_info_box from util.utils import compare_version -def check_latest_version() -> Optional[Union[str, bool]]: +def check_new_version() -> Optional[Union[str, bool]]: """ Check the latest version by making a request to the update URL and comparing it with the current tag. @@ -25,3 +27,19 @@ def check_latest_version() -> Optional[Union[str, bool]]: return False except: return None + + +def check_updates(silent: bool = False): + new_version = check_new_version() + + if new_version is None: + if not silent: + show_error("Failed to check for updates. Please check your internet connection.") + elif not new_version: + if not silent: + show_info("You are using the latest version.") + else: + message = f"A new version {new_version} is available. Would you like to update {APP_NAME} now?" + + if yesno_info_box(message): + webbrowser.open(UPDATE_URL, new=0, autoraise=True) From 8174c79da3527c2894fe193c2423093b14895eb2 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Wed, 18 Sep 2024 01:27:54 +0800 Subject: [PATCH 34/39] Optimizing interface responsiveness --- src/configuration/config.py | 2 +- src/configuration/migration/all_migration.py | 4 +- src/configuration/migration/base.py | 6 +- .../m0_rules_to_split_rules_config.py | 6 +- .../migration/m1_new_fields_in_rule.py | 6 +- ...m2_remove_high_io_priority_and_logging.py} | 11 ++- src/ui/settings.py | 81 +++++-------------- src/ui/settings_actions.py | 42 ++++++++++ src/ui/widget/settings/settings_tabs.py | 4 +- .../settings/tabs/rules/base_rules_tab.py | 1 - .../settings/tabs/rules/rules_list_actions.py | 5 +- 11 files changed, 92 insertions(+), 76 deletions(-) rename src/configuration/migration/{m2_remove_high_io_priority.py => m2_remove_high_io_priority_and_logging.py} (63%) create mode 100644 src/ui/settings_actions.py diff --git a/src/configuration/config.py b/src/configuration/config.py index 2aba3c1..a43865b 100644 --- a/src/configuration/config.py +++ b/src/configuration/config.py @@ -9,7 +9,7 @@ class Config(BaseModel): """ The Config class represents a configuration object for application. - It defines the structure of the configuration, including rule application interval, logging settings, and rules. + It defines the structure of the configuration, including rule application interval, and rules. """ version: Optional[int] = Field(default=None) diff --git a/src/configuration/migration/all_migration.py b/src/configuration/migration/all_migration.py index 12c8981..58e301d 100644 --- a/src/configuration/migration/all_migration.py +++ b/src/configuration/migration/all_migration.py @@ -3,7 +3,7 @@ from configuration.migration.base import BaseMigration from configuration.migration.m0_rules_to_split_rules_config import MigrationRules2SplitRulesConfig from configuration.migration.m1_new_fields_in_rule import NewFieldsInRule -from configuration.migration.m2_remove_high_io_priority import RemoveHighIoPriority +from configuration.migration.m2_remove_high_io_priority_and_logging import RemoveHighIoPriorityAndLogging from constants.log import LOG from service.config_service import ConfigService from util.messages import show_error @@ -11,7 +11,7 @@ MIGRATIONS: list[type[BaseMigration]] = [ MigrationRules2SplitRulesConfig, NewFieldsInRule, - RemoveHighIoPriority + RemoveHighIoPriorityAndLogging ] """ List of migration classes to be executed in order. diff --git a/src/configuration/migration/base.py b/src/configuration/migration/base.py index 620baa5..6215606 100644 --- a/src/configuration/migration/base.py +++ b/src/configuration/migration/base.py @@ -1,10 +1,12 @@ from abc import ABC, abstractmethod +from pydantic.config import JsonDict + class BaseMigration(ABC): @staticmethod @abstractmethod - def should_migrate(config: dict) -> bool: + def should_migrate(config: JsonDict) -> bool: """ Checks if migration is necessary. @@ -15,7 +17,7 @@ def should_migrate(config: dict) -> bool: @staticmethod @abstractmethod - def migrate(config: dict) -> dict: + def migrate(config: JsonDict) -> JsonDict: """ Performs the migration and returns the updated configuration. diff --git a/src/configuration/migration/m0_rules_to_split_rules_config.py b/src/configuration/migration/m0_rules_to_split_rules_config.py index 1dceb56..fb26579 100644 --- a/src/configuration/migration/m0_rules_to_split_rules_config.py +++ b/src/configuration/migration/m0_rules_to_split_rules_config.py @@ -1,5 +1,7 @@ from typing import Optional +from pydantic.config import JsonDict + from configuration.migration.base import BaseMigration @@ -9,11 +11,11 @@ def get_target_version() -> int: return 1 @staticmethod - def should_migrate(config: dict) -> bool: + def should_migrate(config: JsonDict) -> bool: return 'version' not in config or config['version'] is None @staticmethod - def migrate(config: dict) -> Optional[dict]: + def migrate(config: JsonDict) -> Optional[JsonDict]: if 'rules' not in config: return config diff --git a/src/configuration/migration/m1_new_fields_in_rule.py b/src/configuration/migration/m1_new_fields_in_rule.py index 4e964ec..aefaba7 100644 --- a/src/configuration/migration/m1_new_fields_in_rule.py +++ b/src/configuration/migration/m1_new_fields_in_rule.py @@ -1,5 +1,7 @@ from typing import Optional +from pydantic.config import JsonDict + from configuration.migration.base import BaseMigration from enums.bool import BoolStr from enums.selector import SelectorType @@ -11,11 +13,11 @@ def get_target_version() -> int: return 2 @staticmethod - def should_migrate(config: dict) -> bool: + def should_migrate(config: JsonDict) -> bool: return config['version'] == 1 @staticmethod - def migrate(config: dict) -> Optional[dict]: + def migrate(config: JsonDict) -> Optional[JsonDict]: for rule in config.get('processRules', []): rule['selectorBy'] = SelectorType.NAME.value rule['force'] = BoolStr.NO.value diff --git a/src/configuration/migration/m2_remove_high_io_priority.py b/src/configuration/migration/m2_remove_high_io_priority_and_logging.py similarity index 63% rename from src/configuration/migration/m2_remove_high_io_priority.py rename to src/configuration/migration/m2_remove_high_io_priority_and_logging.py index 0fae0cb..4d35362 100644 --- a/src/configuration/migration/m2_remove_high_io_priority.py +++ b/src/configuration/migration/m2_remove_high_io_priority_and_logging.py @@ -1,22 +1,27 @@ import itertools from typing import Optional +from pydantic.config import JsonDict + from configuration.migration.base import BaseMigration -class RemoveHighIoPriority(BaseMigration): +class RemoveHighIoPriorityAndLogging(BaseMigration): @staticmethod def get_target_version() -> int: return 3 @staticmethod - def should_migrate(config: dict) -> bool: + def should_migrate(config: JsonDict) -> bool: return config['version'] == 2 @staticmethod - def migrate(config: dict) -> Optional[dict]: + def migrate(config: JsonDict) -> Optional[JsonDict]: for rule in itertools.chain(config.get('processRules', []), config.get('serviceRules', [])): if rule.get('ioPriority') == 'High': del rule['ioPriority'] + if 'logging' in config: + del config['logging'] + return config diff --git a/src/ui/settings.py b/src/ui/settings.py index 71fa303..20fe19c 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -1,16 +1,16 @@ import os -from tkinter import messagebox, ttk, Tk, X, TOP, BOTH, NORMAL, DISABLED +from tkinter import messagebox, ttk, Tk, X, TOP, BOTH, DISABLED, NORMAL from typing import Optional from configuration.migration.all_migration import run_all_migration from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME, TITLE_ERROR from constants.files import LOG_FILE_NAME from constants.log import LOG -from constants.resources import APP_ICON, UI_SAVE, UI_LOG, UI_CONFIG +from constants.resources import APP_ICON from constants.threads import THREAD_SETTINGS from constants.ui import UI_PADDING, RC_WIN_SIZE, ActionEvents, SETTINGS_TITLE, EditableTreeviewEvents, \ - RIGHT_PACK, LEFT_PACK, OPEN_CONFIG_LABEL, OPEN_LOG_LABEL, ExtendedTreeviewEvents -from ui.widget.common.button import ExtendedButton + ExtendedTreeviewEvents +from ui.settings_actions import SettingsActions from ui.widget.common.entry import ExtendedEntry from ui.widget.settings.settings_tabs import SettingsTabs from ui.widget.settings.tabs.base_tab import BaseTab @@ -22,7 +22,6 @@ from util.history import HistoryManager from util.messages import yesno_error_box from util.scheduler import TaskScheduler -from util.ui import load_img class Settings(Tk): @@ -35,9 +34,15 @@ def __init__(self): self._create_widgets() self._pack() - self._setup_tooltips() self._setup_window() + self.after(1, self._after_init) + + def _after_init(self): + self._setup_tooltips() + self._setup_binds() + self._tabs.load_data() + def _setup_window(self): self._center_window() @@ -46,9 +51,15 @@ def _setup_window(self): self.title(APP_NAME_WITH_VERSION) self.minsize(*RC_WIN_SIZE) + def _setup_binds(self): + self._tabs.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._update_actions_state(), "+") + + self._actions.bind(ActionEvents.SAVE, lambda _: self._save(), "+") + self._actions.bind(ActionEvents.CONFIG, lambda _: open_config_file(), "+") + self._actions.bind(ActionEvents.LOG, lambda _: open_log_file(), "+") + self.bind("", lambda _: self._tabs.next_tab(), "+") self.bind("", lambda _: self._tabs.prev_tab(), "+") - self.bind("", self._fix_cyrillic_binds, "+") self.bind("", self._global_actions, "+") @@ -118,26 +129,9 @@ def _center_window(self): self.geometry(f"{RC_WIN_SIZE[0]}x{RC_WIN_SIZE[1]}+{x}+{y}") def _create_widgets(self): - self._create_tabs() - self._create_tooltips() - self._create_actions() - - def _create_tooltips(self): + self._tabs = SettingsTabs(self) self._tooltip = Tooltip(self, text=self._tabs.get_default_tooltip()) - - def _create_tabs(self): - self._tabs = tabs = SettingsTabs(self) - tabs.load_data() - tabs.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._update_actions_state(), "+") - - def _create_actions(self): - self._actions = actions = SettingsActions(self) - - actions.bind(ActionEvents.SAVE, lambda _: self._save(), "+") - actions.bind(ActionEvents.CONFIG, lambda _: open_config_file(), "+") - actions.bind(ActionEvents.LOG, lambda _: open_log_file(), "+") - - self._update_actions_state() + self._actions = SettingsActions(self) def _save(self): result = self._tabs.save_data() @@ -345,41 +339,6 @@ def to_front(self): self.after_idle(self.attributes, '-topmost', False) -class SettingsActions(ttk.Frame): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._setup_btn() - - def _setup_btn(self): - self.open_config = open_config = ExtendedButton( - self, - text=f"{OPEN_CONFIG_LABEL}", - event=ActionEvents.CONFIG, - image=load_img(file=UI_CONFIG), - description="**Opens** the __config file__." - ) - - self.open_log = open_log = ExtendedButton( - self, - text=f"{OPEN_LOG_LABEL}", - event=ActionEvents.LOG, - image=load_img(file=UI_LOG), - description="**Opens** the __log file__." - ) - - self.save = save = ExtendedButton( - self, - text="Save", - event=ActionEvents.SAVE, - image=load_img(file=UI_SAVE), - description="**Saves** the __settings__. \n**Hotkey:** __Ctrl+S__." - ) - - open_config.pack(**LEFT_PACK) - open_log.pack(**LEFT_PACK) - save.pack(**RIGHT_PACK) - - __app: Optional[Settings] = None diff --git a/src/ui/settings_actions.py b/src/ui/settings_actions.py new file mode 100644 index 0000000..8c8aa00 --- /dev/null +++ b/src/ui/settings_actions.py @@ -0,0 +1,42 @@ +from tkinter import ttk, DISABLED + +from constants.resources import UI_CONFIG, UI_LOG, UI_SAVE +from constants.ui import OPEN_CONFIG_LABEL, ActionEvents, OPEN_LOG_LABEL, LEFT_PACK, RIGHT_PACK +from ui.widget.common.button import ExtendedButton +from util.ui import load_img + + +class SettingsActions(ttk.Frame): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._setup_btn() + + def _setup_btn(self): + self.open_config = open_config = ExtendedButton( + self, + text=f"{OPEN_CONFIG_LABEL}", + event=ActionEvents.CONFIG, + image=load_img(file=UI_CONFIG), + description="**Opens** the __config file__." + ) + + self.open_log = open_log = ExtendedButton( + self, + text=f"{OPEN_LOG_LABEL}", + event=ActionEvents.LOG, + image=load_img(file=UI_LOG), + description="**Opens** the __log file__." + ) + + self.save = save = ExtendedButton( + self, + text="Save", + state=DISABLED, + event=ActionEvents.SAVE, + image=load_img(file=UI_SAVE), + description="**Saves** the __settings__. \n**Hotkey:** __Ctrl+S__." + ) + + open_config.pack(**LEFT_PACK) + open_log.pack(**LEFT_PACK) + save.pack(**RIGHT_PACK) diff --git a/src/ui/widget/settings/settings_tabs.py b/src/ui/widget/settings/settings_tabs.py index bc3dd54..90a8f77 100644 --- a/src/ui/widget/settings/settings_tabs.py +++ b/src/ui/widget/settings/settings_tabs.py @@ -40,6 +40,8 @@ def _create_tabs(self): process_rules_tab.place() service_rules_tab.place() + self._update_tabs_state() + def current_tab(self) -> BaseTab: current_index = self.index(self.select()) tab_id = self.tabs()[current_index] @@ -106,7 +108,7 @@ def _update_tabs_state(self): tabs = self.frames_by_tab() for id, tab in tabs.items(): - star = "*" if tab.has_changes() or tab.has_error() else "" + star = "*" if tab.has_changes() or tab.has_error() else " " self.tab(id, text=f" {tab.title()} {star}") def next_tab(self): diff --git a/src/ui/widget/settings/tabs/rules/base_rules_tab.py b/src/ui/widget/settings/tabs/rules/base_rules_tab.py index 5e49154..8d0bfe3 100644 --- a/src/ui/widget/settings/tabs/rules/base_rules_tab.py +++ b/src/ui/widget/settings/tabs/rules/base_rules_tab.py @@ -26,7 +26,6 @@ def __init__(self, master: Notebook, rule_type: RuleType): self.rules_list = self._create_rules_list() self.actions = self._create_actions() - self._update_actions_state() self._pack() def _pack(self): diff --git a/src/ui/widget/settings/tabs/rules/rules_list_actions.py b/src/ui/widget/settings/tabs/rules/rules_list_actions.py index 3fc98d7..ce140d6 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list_actions.py +++ b/src/ui/widget/settings/tabs/rules/rules_list_actions.py @@ -1,4 +1,4 @@ -from tkinter import ttk +from tkinter import ttk, DISABLED from constants.resources import UI_ADD, UI_DELETE, UI_UP, UI_DOWN from constants.ui import ActionEvents, LEFT_PACK @@ -23,6 +23,7 @@ def _setup_btn(self): self.delete = delete = ExtendedButton( self, text="Del", + state=DISABLED, event=ActionEvents.DELETE, image=load_img(file=UI_DELETE), description="**Deletes** the selected rules. \n**Hotkey:** __Del__." @@ -31,6 +32,7 @@ def _setup_btn(self): self.move_up = move_up = ExtendedButton( self, text="Up", + state=DISABLED, event=ActionEvents.UP, image=load_img(file=UI_UP), description="**Moves** the current rule __up__." @@ -39,6 +41,7 @@ def _setup_btn(self): self.move_down = move_down = ExtendedButton( self, text="Down", + state=DISABLED, event=ActionEvents.DOWN, image=load_img(file=UI_DOWN), description="**Moves** the current rule __down__." From d67fd0de52fb4b7b0709c1699c59ac33a5745b89 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Wed, 18 Sep 2024 03:25:05 +0800 Subject: [PATCH 35/39] Fix selection in rules list when open context menu --- src/ui/widget/settings/tabs/rules/rules_list.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index c904851..1c3f842 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -82,7 +82,16 @@ def _setup_context_menu(self): accelerator="Del" ) - self.bind("", lambda event: menu.post(event.x_root, event.y_root), '+') + self.bind("", self._show_context_menu, '+') + + def _show_context_menu(self, event): + context_menu = self._context_menu + process_list = self + row_id = process_list.identify_row(event.y) + + if row_id: + process_list.selection_set(row_id) + context_menu.post(event.x_root, event.y_root) def _errors(self) -> dict[Any, Any]: errors = [ From 382fa95829c2c56e791f13795d03cfb61e8ffdea Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Thu, 19 Sep 2024 22:04:26 +0800 Subject: [PATCH 36/39] Added multi-selection in rules list for context menu, open folder after build, reduced the opening time of settings and fixed focus when opening settings --- build_portable.py | 5 +- src/model/service.py | 19 +------ src/service/processes_info_service.py | 7 ++- src/service/rules_service.py | 1 - src/service/services_info_service.py | 52 +++++++++++-------- src/ui/settings.py | 2 + .../settings/tabs/processes/process_tab.py | 6 +-- .../widget/settings/tabs/rules/rules_list.py | 4 +- src/util/utils.py | 3 +- 9 files changed, 50 insertions(+), 49 deletions(-) diff --git a/build_portable.py b/build_portable.py index 4ac05b1..4b39142 100644 --- a/build_portable.py +++ b/build_portable.py @@ -7,6 +7,7 @@ from constants.app_info import APP_NAME, APP_VERSION, APP_AUTHOR, APP_NAME_WITH_VERSION from constants.files import CONFIG_FILE_NAME +from util.files import explore # Setting paths and configuration parameters VERSION_FILE = "versionfile.txt" @@ -52,8 +53,10 @@ ]) # Creating an archive of the built application -shutil.make_archive(APP_DIST_WITH_VERSION, 'zip', APP_DIST) +archive_file_path = shutil.make_archive(APP_DIST_WITH_VERSION, 'zip', APP_DIST) # Copying the configuration file for tests into the built application if os.path.isfile(CONFIG_FILE_FOR_TESTS): shutil.copyfile(CONFIG_FILE_FOR_TESTS, CONFIG_FILE_IN_APP_DIST) + +explore(archive_file_path) \ No newline at end of file diff --git a/src/model/service.py b/src/model/service.py index e680ce9..76c7f7e 100644 --- a/src/model/service.py +++ b/src/model/service.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import Optional @dataclass @@ -7,8 +6,7 @@ class Service: """ The Service class represents information about a Windows service. - It includes attributes such as service process ID (pid), service name, display name, description, current status, - and binary path. + It includes attributes such as service process ID (pid), name and current status. """ pid: int @@ -21,22 +19,7 @@ class Service: The name of the Windows service. """ - display_name: str - """ - The display name of the Windows service. - """ - - description: Optional[str] - """ - A description of the Windows service. Default is None (no description available). - """ - status: str """ The current status of the Windows service. """ - - bin_path: str - """ - The binary path of the Windows service, specifying the location of the service executable. - """ diff --git a/src/service/processes_info_service.py b/src/service/processes_info_service.py index 54aad3e..baebecd 100644 --- a/src/service/processes_info_service.py +++ b/src/service/processes_info_service.py @@ -1,5 +1,6 @@ import subprocess from abc import ABC +from typing import Optional import psutil from psutil import NoSuchProcess @@ -12,7 +13,6 @@ class ProcessesInfoService(ABC): """ The ProcessesInfoService class provides methods for retrieving information about running processes. - It is an abstract base class (ABC) to be subclassed by specific implementation classes. """ _cache: dict[int, Process] = {} @@ -27,7 +27,7 @@ def get_processes(cls) -> dict[int, Process]: """ cache = cls._cache - services = ServicesInfoService.get_services() + services: Optional[dict] = None pids = set(psutil.pids()) for pid in pids: @@ -48,6 +48,9 @@ def get_processes(cls) -> dict[int, Process]: process.is_new = False continue + if services is None: + services = ServicesInfoService.get_running_services() + service = services.get(pid) info = process_info.as_dict(attrs=[ 'name', 'exe', 'cmdline', diff --git a/src/service/rules_service.py b/src/service/rules_service.py index b87e7e6..0163cc2 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -24,7 +24,6 @@ class RulesService(ABC): """ The RulesService class provides methods for applying rules to processes and services. - It is an abstract base class (ABC) to be subclassed by specific implementation classes. """ __ignore_pids: set[int] = {0, os.getpid()} diff --git a/src/service/services_info_service.py b/src/service/services_info_service.py index 3e27551..a5a48a3 100644 --- a/src/service/services_info_service.py +++ b/src/service/services_info_service.py @@ -4,7 +4,6 @@ from psutil import STATUS_STOPPED, NoSuchProcess, ZombieProcess, AccessDenied from psutil._pswindows import WindowsService -from constants.log import LOG from model.service import Service from util.decorators import suppress_exception @@ -23,37 +22,48 @@ class ServicesInfoService(ABC): """ - The ServicesInfoService class provides methods for retrieving information about running services. - It is an abstract base class (ABC) to be subclassed by specific implementation classes. + The ServicesInfoService class provides methods for retrieving information about Windows services. """ @staticmethod - def get_services() -> dict[int, Service]: - """ - Get a dictionary of running services and their information. - - Returns: - dict[int, Service]: A dictionary where keys are process IDs (pids) and values are Service objects - representing the running services. - """ + def get_running_services() -> dict[int, Service]: result: dict[int, Service] = {} for service in psutil.win_service_iter(): try: - info = service.as_dict() + # noinspection PyUnresolvedReferences + info = service._query_status() + status = info['status'] + pid = info['pid'] - if info['status'] == STATUS_STOPPED: + if pid == STATUS_STOPPED: continue - result[info['pid']] = Service( - info['pid'], - info['name'], - info['display_name'], - info['description'], - info['status'], - info['binpath'] + result[pid] = Service( + pid, + service.name(), + status ) except NoSuchProcess: - LOG.warning(f"No such service: {service.name}") + pass + + return result + + @staticmethod + def get_services() -> list[Service]: + result: list[Service] = [] + + for service in psutil.win_service_iter(): + try: + # noinspection PyUnresolvedReferences + info = service._query_status() + + result.append(Service( + info['pid'], + service.name(), + info['status'] + )) + except NoSuchProcess: + pass return result diff --git a/src/ui/settings.py b/src/ui/settings.py index 20fe19c..a624a08 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -41,6 +41,7 @@ def __init__(self): def _after_init(self): self._setup_tooltips() self._setup_binds() + self._tabs.load_data() def _setup_window(self): @@ -355,6 +356,7 @@ def settings(): try: __app = Settings() + __app.after_idle(__app.to_front) __app.mainloop() finally: __app = None diff --git a/src/ui/widget/settings/tabs/processes/process_tab.py b/src/ui/widget/settings/tabs/processes/process_tab.py index a16ea7d..c7329d0 100644 --- a/src/ui/widget/settings/tabs/processes/process_tab.py +++ b/src/ui/widget/settings/tabs/processes/process_tab.py @@ -82,10 +82,8 @@ def _update_process_list(self): LOG.exception("Update process list error") def _refresh(self): - LOG.info("Refreshing process list...") - def update_process_list(): - LOG.info("Updating process list...") + # LOG.info("Updating process list...") try: self._update_process_list() @@ -93,7 +91,7 @@ def update_process_list(): self._refresh_state() def load_data(): - LOG.info("Loading data...") + # LOG.info("Loading data...") try: self.process_list.set_data(ProcessesInfoService.get_processes()) diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index 1c3f842..014297a 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -88,9 +88,11 @@ def _show_context_menu(self, event): context_menu = self._context_menu process_list = self row_id = process_list.identify_row(event.y) + selected_items = process_list.selection() if row_id: - process_list.selection_set(row_id) + if selected_items and len(selected_items) == 1: + process_list.selection_set(row_id) context_menu.post(event.x_root, event.y_root) def _errors(self) -> dict[Any, Any]: diff --git a/src/util/utils.py b/src/util/utils.py index 4550f9e..1db6681 100644 --- a/src/util/utils.py +++ b/src/util/utils.py @@ -161,7 +161,8 @@ def get_values_from_enum(annotation): return values -def get_icon_from_exe(exe_path, icon_index=0, large=False, try_load_another_if_absent=True): +@cache +def get_icon_from_exe(exe_path, icon_index=0, large=False): if large: icon_size = ( win32api.GetSystemMetrics(win32con.SM_CXICON), From 077e726d55eda3a01cf8957513076a05a36db380 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Mon, 23 Sep 2024 01:23:28 +0800 Subject: [PATCH 37/39] Added "Go to Rules", "File Properties" and "Service Properties" items to the context menu of the process list, as well as refactoring, QoL improvement and bug fixes. --- resources/UI/file-properties.png | Bin 0 -> 2293 bytes resources/UI/go-to-rule.png | Bin 0 -> 2074 bytes resources/UI/open-folder.png | Bin 1502 -> 1896 bytes resources/UI/service-properties.png | Bin 0 -> 2541 bytes src/constants/app_info.py | 5 +- src/constants/resources.py | 3 + src/constants/threads.py | 1 + src/constants/ui.py | 5 - src/model/service.py | 7 +- src/service/rules_service.py | 48 +++- src/service/services_info_service.py | 1 + src/ui/settings.py | 8 +- src/ui/tray.py | 4 +- src/ui/widget/common/treeview/extended.py | 9 +- src/ui/widget/common/treeview/pydantic.py | 10 + src/ui/widget/common/treeview/sortable.py | 10 +- src/ui/widget/settings/settings_tabs.py | 18 +- .../settings/tabs/processes/process_list.py | 152 ++--------- .../processes/process_list_context_menu.py | 242 ++++++++++++++++++ .../settings/tabs/processes/process_tab.py | 46 +++- .../widget/settings/tabs/rules/rules_list.py | 3 + src/util/files.py | 45 ++++ src/util/messages.py | 8 +- src/util/scheduler.py | 10 +- src/util/utils.py | 2 +- 25 files changed, 444 insertions(+), 193 deletions(-) create mode 100644 resources/UI/file-properties.png create mode 100644 resources/UI/go-to-rule.png create mode 100644 resources/UI/service-properties.png create mode 100644 src/ui/widget/settings/tabs/processes/process_list_context_menu.py diff --git a/resources/UI/file-properties.png b/resources/UI/file-properties.png new file mode 100644 index 0000000000000000000000000000000000000000..beb1a32ee847edaa200aa8ed57010d635762837a GIT binary patch literal 2293 zcmb_eOKjXk7~UL+LLs6pLS0oHjDvWH&U(i7+8!(0DA`S$mDsSP3kecJ9oyqwE4#L1 zJK0SxR4qj9p-5a&kb33-;zAD`5Q1YxE6#8NpEBizx!YrZjXlxZ^fC+6HlktSmvXhY$h{t z!mF($E0tGGJ80#Y6IeXgX@y{&$xP35LT0b>M6h_>^9$mgFTWB6&nbw@`3kOtMc(ih zwjzFRYq4f;t=iNPXHE;#9TNhyc*2BEtLevPryzFYnlMhMB~j>_B&!8+Hccq3RH{NT zh`6BTFtRb$1fAv_W-;5cP6;xWiG)>&s0d?Ip{A+|{htWwBF8nCN@x1X;He-sk|Z=G zsoiep+Da~n>Jp)pN?4X;8G!|gH~oZlkRMMCB9wS+M_!nCfiI*HnH8)j1reb3IJClH zSU>LT1d2%=7D^ru0t+_5FzYn-CG3&Lj%~U@)M7x`Yq2_)LccBwLmACt&fdVzC$J&L19+-x5QAcl41!g}@~Vy~(I_$~v9NAYj8$zA?X}2* zj%3Zzs3|H3BHDSPU@GSk&r=;~u4*A>IV!R^(RG(N)FwDB`v;i^QD%W(3@aY@+iH&0 z`=h3J`tYEqrL?0UM6X$4Fo3EuN4G#cq*^SG92F>Ax()&=hGOVc?Pxtk*$AO!)S;S}SP?L}BZfP&@G27T5dLF8c za0>f?s~N~_dsU;kOmW>+rVvaW9D#OL@=+C<^~i#tz!pSd^w zY;p4IU-PHN|9zqI{(ex_OUmf6rZ_tcP#VQZ-2gX@0aUW(+`vK{9@_Tx$_tQ E1-hlsCIA2c literal 0 HcmV?d00001 diff --git a/resources/UI/go-to-rule.png b/resources/UI/go-to-rule.png new file mode 100644 index 0000000000000000000000000000000000000000..693aab15bdc596db00428fb7e0f94d0a3f73f05a GIT binary patch literal 2074 zcmb_dPiW*+7|*h>YNg2PW$~~ZvX@=-O1Zf+z8^e#!jV*|pm(#Xypm_kQ2^{l0(s z-q~2cxw!D`f}$vkt+nPRyq_-a$1lM1<)7c%hSw9x+AEo&Jo!vc>QZAzk3#2b9qbLEiqAV?s62^B$uKJ=E#x?EE*WYSt7}T`wY8$tchUkZDhpE^) zT<`G1UG4?i@(p!qL_t9$a;A==L7dT1O)K?MSQp#6rk0R=x2Dw#gX&IuLv6@ZsCES- zj{P#O=oE(RhJah?Izm|>H?%w^V>4^cfkzRv)}w%wlDIF?Hk z%}iwZ>OQzJ3COYNtaFeEeN$v|FXdu&A81}Jyh&&y6)cx&N6Nu8QyWvtDj^k1y|x|3 zfgEPn=LAHP<)WrR)*xRlGO8WJqg9)l?sM3s7>}WC8HC+~d8mg7=@3FqLP_;LDAY{A za`s4Yz-d>e5d(+Ai1mb?#63-&g^@PoK&D_A*qQVDtwv)bmECXv2ifM$6}7e6uno_) z5vdp@-FBO{;w)z|7p-PZgWy!cFrZz730L?83FbOT_?C%0!xYHEyz5$=FwIkvB2@W*h7}jswl852lqM9QqP!%elp*(6X;r4@IRQ?-4d_O7^r3OQ^t#?u4%leW)WzU?eLguIUbP`d*f5}OJ&Pb$*cLJz&vXR$17<=g zjX6C)-R{6|6+?r1)2=%U^@(oYXK_!!h|smOJ9E0e`mZy`{zCpgXUftXSD5}_@s($D zLj)38ZoyP?up^;WaqaWC?}@7`TLU&ZHtSzP$(^M9WD z;rG|Sxpn)(cLu$3<@RUwPnh-T_t(Uq&L3}IyngA+UypA6g+KoBsJ?aioYFb^?cF=? Sf3#9e@7C&i^NW>N-})Dnj)`>u literal 0 HcmV?d00001 diff --git a/resources/UI/open-folder.png b/resources/UI/open-folder.png index d72fa23ee8811418ddd8866a142094bea164f651..31b70fc8f3d58267bfd91bd6270980c8241e5baf 100644 GIT binary patch delta 728 zcmcb|{en-iGr-TCmrII^fq{Y7)59eQNDF~52OE$KJJ%OJQBi{N$wsSqCT=665JNL7 z0}CrdqsdE{6hM3m|fD%3{s{;I6~`~Us&W&i%~vHSM_w`SD;`~G47{}-0N_+M{t z|KFXh{@&e#`2rq{GJpR5{eS)M-vr+J{reUjP?!+uz}(j6xc}X|g?AR%ug`B#e)N{* zryCm(EaLg~{dN88|NNWJ{;R(i$MED2WB1=ZJ74~9|H=1XazTSev%v|MN37o3;tOzc!iv{=Z#W_P>3;*U$g! z;vZUtHUGPAykXDV@EPCN#s4#!@Q-WWXV5^Iq(Eow?&lwik!~Z2$YIyJ1^AtJJ^uZ(S<+*>o7Lx{4$*+;mvANA$tX RLSSNL@O1TaS?83{1OTME7AF7z delta 435 zcmaFCcaK}KGr-TCmrII^fq{Y7)59eQNDF{42OE%-|NK93qM`(&_(rRECT>IX5CcOi zQ!^_A!^umS6kvRFD^ttK=b4mH_N4S>){*DTF2P1hpLBw07f)I3qw($K)j z*di%8#Vo~Q@=RtK;uPLwRv}KIB1@PnF;*)n6qmS`l~|Q$q~_Tw85tOv=o(n+B71TV zi^JrTtdaFf=U(jqhDNTZi(`m|VDgXu|LvJoXFUAN^7BafU#`>leJ8}X_T2ZGpr4|^ zwrBQ&5Ax!5xApHkOl17Q8~%g2ELU9LeR z^~(A7{Lm~}HDYd{847f#VkWY7xr(QxOrX|68&hDl9{1ws_Z`47UGw7eJRvG%`eBV; z)|h~E8p|uy##&X<@F|nA;*^X6#GnnZR4f{|^8ZDQAY@e(H?Ha`@` z{6+#|yqh9aisCUra%(^Vs-jH97>c1uiX&-`peUJ@WRAl!KOCh?Xc4(0FfEe|J$dmO z+cssAOeT}=BTEBL zpmuSHnc1*$E29%qj7$NOq}`OmDQ&2!Sv#{X5ltu8R1!vE490B>+0t2Cv&OIutH$Uf zboTW%36Qp-P&P-eSYokk3d=67M>H~m^lEKYHkgpCfR<60P+@63f;q-vW6J&n1h$c= zG>mBXN`<>2V+`Zwu%dZ-Tr-l^_#O^00Bq>R(W;^K5(!$Wq(zx!Wty2li84iXnT8Ba zk2Lf&l?aBZWEh!dWs1GV6xECdY;Z$kO_d`?A_fp)JqD^FX~wH@EGwhzH=;%YB}VAj zp7TM!Kb$ZkdKA5|DyI9eV5y&{C7vf3H=TwX3dzB^WrMg1g8?s&#BuAoCVLcC;3-NX zB%YB7k>&(K6g?gS@=AnKHBF-Ftbf2z>zopB{JYvgGgK7gDm;z>qM$M=LG!AI5Fv^N zR3<`16ipFnN{ncN(2ZtxLPs45qCKNJs5BH&_0TLOF$ji75(qxRDFje7j!+;i2oYM7 zRGM=ykfUE4yVx>?BCQl4?|wH|%b*FYp$qzdm#isx}%* zXdj61BB26~CnQ1O2$o_a66665pwu^XNv3I;$?gXK26{$TwFbniAv(H9{6CPnsebQ5 z*>fFw-P-;?GU?Lnsxb1O#g~59<8VU@nVv!?rZdc*)#xF6+QT@~DS^)NxAzR{bh-L1 z4F*ao#UuMG_RZ*DGOTJTRycZa!Gz?>op-!4T={0)rMs6cUwheg@0yl8(BC)X;IxUy zUfg-SM%g%a@k=9GTV6kUs`1>%(c@M8>g8Ienf#$cx_DaLaq^E}Km2X@!Oyo(!p{tT zbj13a6=xq@o5;^uu;y&^bX~<1v2DXUzV_w;{!PjD@cFrcG32pv=XPDV@@jbQ=tU1}<0IzF@BOlU-G2CN%i+~CTL*qItGub@)BMA1 zLEVBaId{#B-gj*G(4Wmydv{fwu~+T=JwQ$!czg4g*0$u2-#_Oo&fA)M&qLcr8o>wt zY`U=Ng^xZPu%mGE!iq!Z4i{~{oEv(xetolk=&#gMlZ;PpTh!TBJ#EzHsyEgi*z+CP zd16IlZksS{9Uk34gqxl&C}3wE$=_DeapAFV@7KVkQCFIdKEL=YQW~2&E?yqC%=sV- MmX-(FeT!H84eiBFn*aa+ literal 0 HcmV?d00001 diff --git a/src/constants/app_info.py b/src/constants/app_info.py index 12c150a..d8a75ee 100644 --- a/src/constants/app_info.py +++ b/src/constants/app_info.py @@ -4,13 +4,14 @@ from util.utils import is_portable -APP_NAME: Final[str] = "Process Governor" -APP_VERSION: Final[str] = "1.2.2" APP_AUTHOR: Final[str] = "System X - Files" +APP_NAME: Final[str] = "Process Governor" +APP_VERSION: Final[str] = "2.0.0" APP_PROCESSES = {f"{APP_NAME}.exe", "python.exe"} CURRENT_TAG: Final[str] = f"v{APP_VERSION}" APP_NAME_WITH_VERSION: Final[str] = f"{APP_NAME} {CURRENT_TAG}" +APP_TITLE = f"{APP_NAME_WITH_VERSION} by {APP_AUTHOR}" TITLE_ERROR: Final[str] = f"Error Detected - {APP_NAME_WITH_VERSION}" if is_portable(): diff --git a/src/constants/resources.py b/src/constants/resources.py index f1574bf..5aa1566 100644 --- a/src/constants/resources.py +++ b/src/constants/resources.py @@ -26,6 +26,9 @@ UI_SERVICE: Final[str] = f"{APP_PATH}/resources/UI/service.png" UI_PROCESS: Final[str] = f"{APP_PATH}/resources/UI/process.png" UI_OPEN_FOLDER: Final[str] = f"{APP_PATH}/resources/UI/open-folder.png" +UI_OPEN_FILE_PROPERTIES: Final[str] = f"{APP_PATH}/resources/UI/file-properties.png" +UI_OPEN_SERVICE_PROPERTIES: Final[str] = f"{APP_PATH}/resources/UI/service-properties.png" +UI_GO_TO_RULE: Final[str] = f"{APP_PATH}/resources/UI/go-to-rule.png" UI_INFO_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/info-tooltip.png" UI_WARN_TOOLTIP: Final[str] = f"{APP_PATH}/resources/UI/warn-tooltip.png" diff --git a/src/constants/threads.py b/src/constants/threads.py index 1e128bf..23ea8d9 100644 --- a/src/constants/threads.py +++ b/src/constants/threads.py @@ -2,3 +2,4 @@ THREAD_TRAY = "tray" THREAD_PROCESS_LIST_DATA = "process_list_data" THREAD_PROCESS_LIST_ICONS = "process_list_icons" +THREAD_PROCESS_LIST_OPEN_SERVICE_PROPERTIES = "process_list_open_service_properties" diff --git a/src/constants/ui.py b/src/constants/ui.py index 3650c86..4d3dbcb 100644 --- a/src/constants/ui.py +++ b/src/constants/ui.py @@ -16,11 +16,6 @@ OPEN_CONFIG_LABEL = "Open config file" OPEN_LOG_LABEL = "Open log file" -CMENU_ADD_PROCESS_RULE_LABEL = " Add Process Rule" -CMENU_ADD_SERVICE_RULE_LABEL = " Add Service Rule" -CMENU_COPY_LABEL = " Copy Special" -CMENU_OPEN_PROCESS_FOLDER = " Open process folder" - class ActionEvents: ADD: Final[str] = "<>" diff --git a/src/model/service.py b/src/model/service.py index 76c7f7e..f622599 100644 --- a/src/model/service.py +++ b/src/model/service.py @@ -6,7 +6,7 @@ class Service: """ The Service class represents information about a Windows service. - It includes attributes such as service process ID (pid), name and current status. + It includes attributes such as service process ID (pid), name, display name and current status. """ pid: int @@ -19,6 +19,11 @@ class Service: The name of the Windows service. """ + display_name: str + """ + The display name of the Windows service. + """ + status: str """ The current status of the Windows service. diff --git a/src/service/rules_service.py b/src/service/rules_service.py index 0163cc2..8859949 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -66,7 +66,7 @@ def __handle_processes(cls, config: Config, processes: dict[int, Process], only_ continue if rule.delay > 0: - TaskScheduler.schedule_task(process, cls.__handle_process, rule.delay, process, rule) + TaskScheduler.schedule_task(process, cls.__handle_process, process, rule, delay=rule.delay) else: cls.__handle_process(process, rule) @@ -127,22 +127,48 @@ def __first_rule_by_process(cls, config: Config, process: Process) -> Optional[P return rule for rule in config.processRules: - if rule.selectorBy == SelectorType.NAME: - value = process.process_name - elif rule.selectorBy == SelectorType.PATH: - value = process.bin_path - elif rule.selectorBy == SelectorType.CMDLINE: - value = process.cmd_line - else: - message = f"Unknown selector type: {rule.selectorBy}" - LOG.error(message) - raise ValueError(message) + value = cls._get_value_for_matching(process, rule) if path_match(rule.selector, value): return rule return None + @classmethod + def find_rules_ids_by_process( + cls, + process: Process, + process_rules: dict[str, ProcessRule], + service_rules: dict[str, ServiceRule], + ) -> list[tuple[str, ProcessRule | ServiceRule]]: + result = [] + + if process.service: + for row_id, rule in service_rules.items(): + if path_match(rule.selector, process.service_name): + result.append((row_id, rule)) + + for row_id, rule in process_rules.items(): + value = cls._get_value_for_matching(process, rule) + + if path_match(rule.selector, value): + result.append((row_id, rule)) + + return result + + @classmethod + def _get_value_for_matching(cls, process, rule): + if rule.selectorBy == SelectorType.NAME: + return process.process_name + elif rule.selectorBy == SelectorType.PATH: + return process.bin_path + elif rule.selectorBy == SelectorType.CMDLINE: + return process.cmd_line + + message = f"Unknown selector type: {rule.selectorBy}" + LOG.error(message) + raise ValueError(message) + @classmethod @cached(5) # Workaround to ensure the procedure runs only once every 5 seconds def __light_gc_ignored_process_parameters(cls) -> None: diff --git a/src/service/services_info_service.py b/src/service/services_info_service.py index a5a48a3..01ae005 100644 --- a/src/service/services_info_service.py +++ b/src/service/services_info_service.py @@ -42,6 +42,7 @@ def get_running_services() -> dict[int, Service]: result[pid] = Service( pid, service.name(), + service.display_name(), status ) except NoSuchProcess: diff --git a/src/ui/settings.py b/src/ui/settings.py index a624a08..5c4b40f 100644 --- a/src/ui/settings.py +++ b/src/ui/settings.py @@ -3,7 +3,7 @@ from typing import Optional from configuration.migration.all_migration import run_all_migration -from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME, TITLE_ERROR +from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME, TITLE_ERROR, APP_TITLE from constants.files import LOG_FILE_NAME from constants.log import LOG from constants.resources import APP_ICON @@ -49,7 +49,7 @@ def _setup_window(self): self.protocol("WM_DELETE_WINDOW", self.close) self.iconbitmap(APP_ICON) - self.title(APP_NAME_WITH_VERSION) + self.title(APP_TITLE) self.minsize(*RC_WIN_SIZE) def _setup_binds(self): @@ -158,7 +158,7 @@ def close(self): message = ("There are unsaved changes. " "Do you want to save them before exiting?") - result = messagebox.askyesnocancel(APP_NAME_WITH_VERSION, message) + result = messagebox.askyesnocancel(APP_TITLE, message) if result is None: return False @@ -172,7 +172,7 @@ def close(self): message = ( f"There are errors in the rules, and they must be corrected before the application can work properly. " f"Do you still want to close the {SETTINGS_TITLE}?") - result = messagebox.askyesno(APP_NAME_WITH_VERSION, message) + result = messagebox.askyesno(APP_TITLE, message) if not result: return False diff --git a/src/ui/tray.py b/src/ui/tray.py index 8235dc5..5202aae 100644 --- a/src/ui/tray.py +++ b/src/ui/tray.py @@ -3,7 +3,7 @@ from pystray import MenuItem, Menu from pystray._win32 import Icon -from constants.app_info import APP_NAME_WITH_VERSION, APP_NAME +from constants.app_info import APP_NAME_WITH_VERSION, APP_TITLE from constants.resources import APP_ICON from constants.ui import OPEN_LOG_LABEL, OPEN_CONFIG_LABEL from ui.settings import open_settings, is_opened_settings, get_settings @@ -58,4 +58,4 @@ def init_tray() -> Icon: MenuItem('Quit', close_app), ) - return pystray.Icon("tray_icon", image, APP_NAME, menu) + return pystray.Icon("tray_icon", image, APP_TITLE, menu) diff --git a/src/ui/widget/common/treeview/extended.py b/src/ui/widget/common/treeview/extended.py index e8977f5..0364dd2 100644 --- a/src/ui/widget/common/treeview/extended.py +++ b/src/ui/widget/common/treeview/extended.py @@ -3,8 +3,6 @@ from tkinter import ttk from typing import Optional, Literal, Any -from pydantic.config import JsonDict - from constants.ui import COLUMN_TITLE_PADDING, ExtendedTreeviewEvents from util.ui import get_default_font from util.utils import get_values_from_enum @@ -132,8 +130,9 @@ def _calculate_columns_width(self, _=None): @lru_cache def _calculate_max_width(self, column_name): column_name = super().column(column_name, 'id') + typ = self._types.get(column_name) - values = get_values_from_enum(self._types.get(column_name)) + values = get_values_from_enum(typ) if typ else [] values.append(self.heading(column_name)['text']) return max(map(self._font.measure, values)) + COLUMN_TITLE_PADDING @@ -156,7 +155,7 @@ def as_list(self, row_id): def as_list_of_list(self) -> list[list[str]]: return [self.as_list(row_id) for row_id in self.get_children()] - def as_dict(self, row_id) -> JsonDict: + def as_dict(self, row_id) -> dict[str, any]: column_names = self["columns"] values = self.as_list(row_id) @@ -165,7 +164,7 @@ def as_dict(self, row_id) -> JsonDict: if value and value.strip() } - def as_list_of_dict(self) -> list[JsonDict]: + def as_list_of_dict(self) -> list[dict[str, any]]: return [self.as_dict(row_id) for row_id in self.get_children()] def begin_changes(self, disable_before_change_event=False): diff --git a/src/ui/widget/common/treeview/pydantic.py b/src/ui/widget/common/treeview/pydantic.py index 47ea0d1..9c91c96 100644 --- a/src/ui/widget/common/treeview/pydantic.py +++ b/src/ui/widget/common/treeview/pydantic.py @@ -116,3 +116,13 @@ def get_default_row(self) -> JsonDict: result[column_name] = str(default_value) return result + + def as_dict_of_models(self, validate: bool) -> dict[str, BaseModel]: + treeview = self._treeview + constructor = self._model if validate else self._model.model_construct + result = OrderedDict() + + for row_id in treeview.get_children(): + result[row_id] = constructor(**treeview.as_dict(row_id)) + + return result diff --git a/src/ui/widget/common/treeview/sortable.py b/src/ui/widget/common/treeview/sortable.py index 1174a12..1edfe40 100644 --- a/src/ui/widget/common/treeview/sortable.py +++ b/src/ui/widget/common/treeview/sortable.py @@ -39,8 +39,14 @@ def sort_column(self): column = self._sort_column_name reverse = self._sort_reverse + def sorter(value): + if isinstance(value, str): + return (True, value.strip() == '', value) + + return (False, False, value) + items = [(self._get_value_as_type(self.set(k, column)), k) for k in self.get_children()] - items.sort(key=lambda x: (isinstance(x[0], str), x[0]), reverse=reverse) + items.sort(key=lambda x: sorter(x[0]), reverse=reverse) for index, (_, k) in enumerate(items): self.move(k, '', index) @@ -95,7 +101,7 @@ def sort_column_name(self, column_name): ('Papaya', 16, 120), ('Quince', 15, 110), ('Raspberry', 18, 35), - ('Strawberry', 19, 95), + ('', 19, 95), ('Tangerine', 17, 55), ('Ugli Fruit', 21, 130), ('Vanilla', 22, 300), diff --git a/src/ui/widget/settings/settings_tabs.py b/src/ui/widget/settings/settings_tabs.py index 90a8f77..2f4788b 100644 --- a/src/ui/widget/settings/settings_tabs.py +++ b/src/ui/widget/settings/settings_tabs.py @@ -28,17 +28,13 @@ def __init__(self, *args, **kwargs): self.bind(ExtendedTreeviewEvents.CHANGE, lambda _: self._update_tabs_state(), "+") def _create_tabs(self): - process_rules_tab = ProcessRulesTab(self) - service_rules_tab = ServiceRulesTab(self) - process_list_tab = ProcessesTab( - self, - process_rules_tab.rules_list, - service_rules_tab.rules_list - ) - - process_list_tab.place() - process_rules_tab.place() - service_rules_tab.place() + self._process_rules_tab = ProcessRulesTab(self) + self._service_rules_tab = ServiceRulesTab(self) + self._process_list_tab = ProcessesTab(self) + + self._process_list_tab.place() + self._process_rules_tab.place() + self._service_rules_tab.place() self._update_tabs_state() diff --git a/src/ui/widget/settings/tabs/processes/process_list.py b/src/ui/widget/settings/tabs/processes/process_list.py index 2ffd86b..e1e10a1 100644 --- a/src/ui/widget/settings/tabs/processes/process_list.py +++ b/src/ui/widget/settings/tabs/processes/process_list.py @@ -1,25 +1,25 @@ import os.path -from tkinter import Menu, LEFT, END, NORMAL, DISABLED from typing import Callable, Optional from PIL import ImageTk from pydantic import BaseModel +from configuration.rule import ProcessRule, ServiceRule from constants.log import LOG -from constants.resources import UI_ADD_PROCESS_RULE, UI_ADD_SERVICE_RULE, UI_COPY, UI_SERVICE, \ - UI_PROCESS, UI_OPEN_FOLDER +from constants.resources import UI_SERVICE, \ + UI_PROCESS from constants.threads import THREAD_PROCESS_LIST_ICONS -from constants.ui import CMENU_ADD_PROCESS_RULE_LABEL, CMENU_ADD_SERVICE_RULE_LABEL, COLUMN_WIDTH_WITH_ICON, \ - CMENU_COPY_LABEL, ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE, CMENU_OPEN_PROCESS_FOLDER +from constants.ui import COLUMN_WIDTH_WITH_ICON, \ + ERROR_TRYING_UPDATE_TERMINATED_TKINTER_INSTANCE from enums.filters import FilterByProcessType from enums.rules import RuleType from enums.selector import SelectorType from model.process import Process from ui.widget.common.treeview.pydantic import PydanticTreeviewLoader from ui.widget.common.treeview.sortable import SortableTreeview -from util.files import explore +from ui.widget.settings.tabs.processes.process_list_context_menu import ProcessContextMenu from util.scheduler import TaskScheduler -from util.ui import load_img, trim_cmenu_label +from util.ui import load_img from util.utils import get_icon_from_exe @@ -28,6 +28,8 @@ def __init__( self, model: type[BaseModel], add_rule_command: Callable[[RuleType, Optional[SelectorType]], None], + find_rules_by_process_command: Callable[[Process], list[tuple[str, ProcessRule | ServiceRule]]], + go_to_rule_command: Callable[[str, RuleType], None], *args, **kwargs ): columns = [key for key, field_info in model.model_fields.items() if not field_info.exclude] @@ -50,113 +52,13 @@ def __init__( self._service_icon = load_img(UI_SERVICE) self._icons = {} - self._add_rule: Callable[[RuleType, Optional[SelectorType]], None] = add_rule_command self._data: dict[int, Process] = {} self._loader = PydanticTreeviewLoader(self, model) - self._setup_context_menu() + self._setup_context_menu(add_rule_command, find_rules_by_process_command, go_to_rule_command) def set_data(self, values: dict[int, Process]): self._data = values - def _setup_context_menu(self): - self._context_menu_icons = icons = { - CMENU_ADD_PROCESS_RULE_LABEL: load_img(UI_ADD_PROCESS_RULE), - CMENU_ADD_SERVICE_RULE_LABEL: load_img(UI_ADD_SERVICE_RULE), - CMENU_COPY_LABEL: load_img(UI_COPY), - CMENU_OPEN_PROCESS_FOLDER: load_img(UI_OPEN_FOLDER), - } - self._context_menu = menu = Menu(self, tearoff=0) - self._process_menu = Menu(menu, tearoff=0) - self._copy_menu = Menu(menu, tearoff=0) - - menu.add_cascade( - label=CMENU_ADD_PROCESS_RULE_LABEL, - menu=self._process_menu, - image=icons[CMENU_ADD_PROCESS_RULE_LABEL], - compound=LEFT - ) - - menu.add_command( - label=CMENU_ADD_SERVICE_RULE_LABEL, - command=lambda: self._add_rule(RuleType.SERVICE, None), - image=icons[CMENU_ADD_SERVICE_RULE_LABEL], - compound=LEFT - ) - - menu.add_separator() - - menu.add_cascade( - label=CMENU_COPY_LABEL, - menu=self._copy_menu, - image=icons[CMENU_COPY_LABEL], - compound=LEFT - ) - - menu.add_command( - label=CMENU_OPEN_PROCESS_FOLDER, - command=self._open_process_folder, - image=icons[CMENU_OPEN_PROCESS_FOLDER], - compound=LEFT - ) - - self.bind("", self._show_context_menu, '+') - - def _open_process_folder(self): - selected_item = self.selection() - - if not selected_item: - return - - row = self.as_model(selected_item[0]) - explore(row.bin_path) - - def _show_context_menu(self, event): - context_menu = self._context_menu - process_list = self - row_id = process_list.identify_row(event.y) - - if row_id: - process_list.selection_set(row_id) - row = self.as_model(row_id) - process_exists = self._update_process_menu(row) - self._update_copy_menu(row) - - self._context_menu.entryconfig(CMENU_ADD_PROCESS_RULE_LABEL, state=NORMAL if process_exists else DISABLED) - self._context_menu.entryconfig(CMENU_ADD_SERVICE_RULE_LABEL, state=NORMAL if row.service else DISABLED) - self._context_menu.entryconfig(CMENU_OPEN_PROCESS_FOLDER, - state=NORMAL if os.path.isfile(row.bin_path or '') else DISABLED) - - context_menu.post(event.x_root, event.y_root) - - def _update_process_menu(self, row): - process_menu = self._process_menu - exists = False - - process_menu.delete(0, END) - - if row.process_name: - exists = True - process_menu.add_command( - label=f"By {SelectorType.NAME.value}: {row.process_name}", - command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.NAME) - ) - - if row.bin_path: - exists = True - process_menu.add_command( - label=trim_cmenu_label(f"By {SelectorType.PATH.value}: {row.bin_path}"), - command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.PATH) - ) - - if row.cmd_line: - exists = True - process_menu.add_command( - label=trim_cmenu_label(f"By {SelectorType.CMDLINE.value}: {row.cmd_line}"), - command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.CMDLINE) - ) - - return exists - def set_display_columns(self, filter_by_type): display_columns = list(self['columns']) @@ -220,30 +122,6 @@ def as_model(self, row_id) -> Process: pid = int(self.as_dict(row_id)['pid']) return self._data[pid] - def _update_copy_menu(self, row): - copy_menu = self._copy_menu - copy_menu.delete(0, END) - - values = [ - row.pid, - row.process_name, - row.service_name, - row.bin_path, - row.cmd_line - ] - - values = map(lambda o: str(o) if o else '', values) - values = filter(lambda o: o, values) - values = [*dict.fromkeys(values)] - - for value in values: - copy_menu.add_command(label=trim_cmenu_label(value), command=lambda v=value: self._copy_to_clipboard(v)) - - def _copy_to_clipboard(self, text): - self.clipboard_clear() - self.clipboard_append(text) - self.update() - def get_process_icon(self, process: Process): bin_path = process.bin_path @@ -270,3 +148,13 @@ def get_process_icon(self, process: Process): self._icons[bin_path] = image return image + + def _setup_context_menu( + self, + add_rule_command: Callable[[RuleType, Optional[SelectorType]], None], + find_rules_by_process_command: Callable[[Process], list[tuple[str, ProcessRule | ServiceRule]]], + go_to_rule_command: Callable[[str, RuleType], None] + ): + self._context_menu = ProcessContextMenu(self, add_rule_command, find_rules_by_process_command, + go_to_rule_command) + self.bind("", self._context_menu.show, '+') diff --git a/src/ui/widget/settings/tabs/processes/process_list_context_menu.py b/src/ui/widget/settings/tabs/processes/process_list_context_menu.py new file mode 100644 index 0000000..20748ac --- /dev/null +++ b/src/ui/widget/settings/tabs/processes/process_list_context_menu.py @@ -0,0 +1,242 @@ +import os +from tkinter import Menu, LEFT, END, NORMAL, DISABLED +from typing import Callable, Optional + +from configuration.rule import ProcessRule, ServiceRule +from constants.resources import UI_ADD_PROCESS_RULE, UI_ADD_SERVICE_RULE, UI_COPY, UI_OPEN_FOLDER, \ + UI_OPEN_FILE_PROPERTIES, UI_OPEN_SERVICE_PROPERTIES, UI_GO_TO_RULE, UI_PROCESS_RULES, UI_SERVICE_RULES +from enums.rules import RuleType +from enums.selector import SelectorType +from model.process import Process +from util.files import explore, show_file_properties, show_service_properties +from util.ui import load_img, trim_cmenu_label + +CMENU_ADD_PROCESS_RULE_LABEL = " Add Process Rule" +CMENU_ADD_SERVICE_RULE_LABEL = " Add Service Rule" +CMENU_COPY_LABEL = " Copy Special" +CMENU_OPEN_PROCESS_FOLDER_LABEL = " Open file location" +CMENU_OPEN_FILE_PROPERTIES_LABEL = " File Properties" +CMENU_OPEN_SERVICE_PROPERTIES_LABEL = " Service Properties" +CMENU_GO_TO_RULE_LABEL = " Go to Rule" + + +class ProcessContextMenu: + def __init__( + self, + master, + add_rule_command: Callable[[RuleType, Optional[SelectorType]], None], + find_rules_by_process_command: Callable[[Process], list[tuple[str, ProcessRule | ServiceRule]]], + go_to_rule_command: Callable[[str, RuleType], None] + ): + self.master = master + self._add_rule = add_rule_command + self._find_rules_by_process = find_rules_by_process_command + self._go_to_rule = go_to_rule_command + + self._context_menu_icons = { + CMENU_ADD_PROCESS_RULE_LABEL: load_img(UI_ADD_PROCESS_RULE), + CMENU_ADD_SERVICE_RULE_LABEL: load_img(UI_ADD_SERVICE_RULE), + CMENU_COPY_LABEL: load_img(UI_COPY), + CMENU_OPEN_PROCESS_FOLDER_LABEL: load_img(UI_OPEN_FOLDER), + CMENU_OPEN_FILE_PROPERTIES_LABEL: load_img(UI_OPEN_FILE_PROPERTIES), + CMENU_OPEN_SERVICE_PROPERTIES_LABEL: load_img(UI_OPEN_SERVICE_PROPERTIES), + CMENU_GO_TO_RULE_LABEL: load_img(UI_GO_TO_RULE), + ProcessRule: load_img(UI_PROCESS_RULES), + ServiceRule: load_img(UI_SERVICE_RULES) + } + + self._setup_context_menu() + + def _setup_context_menu(self): + icons = self._context_menu_icons + + self._root_menu = menu = Menu(self.master, tearoff=0) + self._process_menu = Menu(menu, tearoff=0) + self._copy_menu = Menu(menu, tearoff=0) + self._rules_menu = Menu(menu, tearoff=0) + + menu.add_cascade( + label=CMENU_ADD_PROCESS_RULE_LABEL, + menu=self._process_menu, + image=icons[CMENU_ADD_PROCESS_RULE_LABEL], + compound=LEFT + ) + + menu.add_command( + label=CMENU_ADD_SERVICE_RULE_LABEL, + command=lambda: self._add_rule(RuleType.SERVICE, None), + image=icons[CMENU_ADD_SERVICE_RULE_LABEL], + compound=LEFT + ) + + menu.add_cascade( + label=CMENU_GO_TO_RULE_LABEL, + menu=self._rules_menu, + image=icons[CMENU_GO_TO_RULE_LABEL], + compound=LEFT + ) + + menu.add_separator() + + menu.add_cascade( + label=CMENU_COPY_LABEL, + menu=self._copy_menu, + image=icons[CMENU_COPY_LABEL], + compound=LEFT + ) + + menu.add_separator() + + menu.add_command( + label=CMENU_OPEN_PROCESS_FOLDER_LABEL, + command=self._open_process_folder, + image=icons[CMENU_OPEN_PROCESS_FOLDER_LABEL], + compound=LEFT + ) + + menu.add_command( + label=CMENU_OPEN_FILE_PROPERTIES_LABEL, + command=self._open_file_properties, + image=icons[CMENU_OPEN_FILE_PROPERTIES_LABEL], + compound=LEFT + ) + + menu.add_command( + label=CMENU_OPEN_SERVICE_PROPERTIES_LABEL, + command=self.open_service_properties, + image=icons[CMENU_OPEN_SERVICE_PROPERTIES_LABEL], + compound=LEFT + ) + + def _open_file_properties(self): + selected_item = self.master.selection() + + if not selected_item: + return + + row = self.master.as_model(selected_item[0]) + show_file_properties(row.bin_path, self.master.winfo_toplevel().winfo_id()) + + def _open_process_folder(self): + selected_item = self.master.selection() + + if not selected_item: + return + + row = self.master.as_model(selected_item[0]) + explore(row.bin_path) + + def open_service_properties(self): + selected_item = self.master.selection() + + if not selected_item: + return + + row = self.master.as_model(selected_item[0]) + show_service_properties(row.service.display_name) + + def _copy_to_clipboard(self, text): + self.master.clipboard_clear() + self.master.clipboard_append(text) + self.master.update() + + def _update_process_menu(self, row): + process_menu = self._process_menu + exists = False + + process_menu.delete(0, END) + + if row.process_name: + exists = True + process_menu.add_command( + label=f"By {SelectorType.NAME.value}: {row.process_name}", + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.NAME) + ) + + if row.bin_path: + exists = True + process_menu.add_command( + label=trim_cmenu_label(f"By {SelectorType.PATH.value}: {row.bin_path}"), + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.PATH) + ) + + if row.cmd_line: + exists = True + process_menu.add_command( + label=trim_cmenu_label(f"By {SelectorType.CMDLINE.value}: {row.cmd_line}"), + command=lambda: self._add_rule(RuleType.PROCESS, SelectorType.CMDLINE) + ) + + return exists + + def _update_copy_menu(self, row): + copy_menu = self._copy_menu + copy_menu.delete(0, END) + + values = [ + row.pid, + row.process_name, + row.service_name, + row.bin_path, + row.cmd_line + ] + + values = map(lambda o: str(o) if o else '', values) + values = filter(lambda o: o, values) + values = [*dict.fromkeys(values)] + + for value in values: + copy_menu.add_command(label=trim_cmenu_label(value), command=lambda v=value: self._copy_to_clipboard(v)) + + def _update_rules_menu(self, row): + icons = self._context_menu_icons + rules_menu = self._rules_menu + rules_menu.delete(0, END) + + rules = self._find_rules_by_process(row) + + if not rules: + return False + + to_state = (DISABLED, NORMAL) + is_first = True + + for row_id, rule in rules: + rule_type = RuleType.PROCESS if isinstance(rule, ProcessRule) else RuleType.SERVICE + + rules_menu.add_command( + label=f" {trim_cmenu_label(rule.selector)}", + command=lambda ri=row_id, rt=rule_type: self._go_to_rule(ri, rt), + image=icons[type(rule)], + compound=LEFT, + state=to_state[is_first] + ) + + is_first = False + + return True + + def show(self, event): + context_menu = self._root_menu + process_list = self.master + row_id = process_list.identify_row(event.y) + + if row_id: + process_list.selection_set(row_id) + row: Process = process_list.as_model(row_id) + is_file = os.path.isfile(row.bin_path or '') + is_service = row.service is not None + to_state = (DISABLED, NORMAL) + + not_empty_process_menu = self._update_process_menu(row) + self._update_copy_menu(row) + not_empty_rules_menu = self._update_rules_menu(row) + + context_menu.entryconfig(CMENU_ADD_PROCESS_RULE_LABEL, state=to_state[not_empty_process_menu]) + context_menu.entryconfig(CMENU_ADD_SERVICE_RULE_LABEL, state=to_state[is_service]) + context_menu.entryconfig(CMENU_OPEN_PROCESS_FOLDER_LABEL, state=to_state[is_file]) + context_menu.entryconfig(CMENU_OPEN_FILE_PROPERTIES_LABEL, state=to_state[is_file]) + context_menu.entryconfig(CMENU_OPEN_SERVICE_PROPERTIES_LABEL, state=to_state[is_service]) + context_menu.entryconfig(CMENU_GO_TO_RULE_LABEL, state=to_state[not_empty_rules_menu]) + + context_menu.post(event.x_root, event.y_root) diff --git a/src/ui/widget/settings/tabs/processes/process_tab.py b/src/ui/widget/settings/tabs/processes/process_tab.py index c7329d0..5a4b118 100644 --- a/src/ui/widget/settings/tabs/processes/process_tab.py +++ b/src/ui/widget/settings/tabs/processes/process_tab.py @@ -2,6 +2,7 @@ from tkinter.ttk import Notebook from typing import Optional +from configuration.rule import ServiceRule, ProcessRule from constants.log import LOG from constants.resources import UI_PROCESS_LIST from constants.threads import THREAD_PROCESS_LIST_DATA @@ -10,10 +11,10 @@ from enums.selector import SelectorType from model.process import Process from service.processes_info_service import ProcessesInfoService +from service.rules_service import RulesService from ui.widget.settings.tabs.base_tab import BaseTab from ui.widget.settings.tabs.processes.process_list import ProcessList from ui.widget.settings.tabs.processes.process_list_actions import ProcessListActions -from ui.widget.settings.tabs.rules.rules_list import RulesList from util.scheduler import TaskScheduler from util.ui import load_img @@ -21,7 +22,7 @@ class ProcessesTab(BaseTab): @staticmethod def default_tooltip() -> str: - return "Use the **context menu** to add a __process__ or __service__ as a rule." + return "Use the **context menu** to add a __process__ or __service__ as a rule, as well as for other actions." @staticmethod def icon() -> PhotoImage: @@ -36,10 +37,9 @@ def description() -> str: return ("Interface for **browsing** the list of active __processes__ and __services__ with the option to " "**add** selected items to the rules configuration.") - def __init__(self, master: Notebook, process_rules_list: RulesList, service_rules_list: RulesList): + def __init__(self, master: Notebook): self.model = Process - self.process_rules_list = process_rules_list - self.service_rules_list = service_rules_list + self.master = master super().__init__(master) @@ -50,7 +50,13 @@ def __init__(self, master: Notebook, process_rules_list: RulesList, service_rule self._pack() def _create_process_list(self): - self.process_list = process_list = ProcessList(self.model, self._add_rule, self) + self.process_list = process_list = ProcessList( + self.model, + self._add_rule, + self._find_rules_by_process, + self._go_to_rule, + self + ) process_list.bind("", lambda _: self._refresh(), "+") def _create_progress_bar(self): @@ -150,9 +156,9 @@ def _add_rule(self, rule_type: RuleType, selector_type: Optional[SelectorType] = rules_list = None if rule_type == RuleType.PROCESS: - rules_list = self.process_rules_list + rules_list = self.master._process_rules_tab.rules_list elif rule_type == RuleType.SERVICE: - rules_list = self.service_rules_list + rules_list = self.master._service_rules_tab.rules_list if rules_list is None: raise ValueError("rules_list is None") @@ -172,3 +178,27 @@ def _add_rule(self, rule_type: RuleType, selector_type: Optional[SelectorType] = rule_row['selector'] = row['cmd_line'] rules_list.add_row([*rule_row.values()], index=0) + + def _find_rules_by_process(self, process: Process) -> list[tuple[str, ProcessRule | ServiceRule]]: + master = self.master + + return RulesService.find_rules_ids_by_process( + process, + master._process_rules_tab.rules_list.as_dict_of_models(), + master._service_rules_tab.rules_list.as_dict_of_models() + ) + + def _go_to_rule(self, row_id: str, rule_type: RuleType): + master = self.master + tab = None + + if rule_type == RuleType.PROCESS: + tab = master._process_rules_tab + elif rule_type == RuleType.SERVICE: + tab = master._service_rules_tab + + if tab is None: + raise ValueError("tab is None") + + master.select(tab) + tab.rules_list.selection_set(row_id) diff --git a/src/ui/widget/settings/tabs/rules/rules_list.py b/src/ui/widget/settings/tabs/rules/rules_list.py index 014297a..c175ae6 100644 --- a/src/ui/widget/settings/tabs/rules/rules_list.py +++ b/src/ui/widget/settings/tabs/rules/rules_list.py @@ -198,3 +198,6 @@ def has_changes(self) -> bool: def commit_changes(self): self._loader.commit_changes() + + def as_dict_of_models(self) -> dict[str, BaseModel]: + return self._loader.as_dict_of_models(False) diff --git a/src/util/files.py b/src/util/files.py index ab71be1..38c7d1e 100644 --- a/src/util/files.py +++ b/src/util/files.py @@ -1,7 +1,11 @@ +import ctypes import os import subprocess +import win32com.client + from constants.files import LOG_FILE_NAME, CONFIG_FILE_NAME +from util.messages import show_error def open_log_file(): @@ -13,6 +17,7 @@ def open_config_file(): FILEBROWSER_PATH = os.path.join(os.getenv('WINDIR'), 'explorer.exe') +SHELL32 = ctypes.WinDLL('shell32', use_last_error=True) def explore(path): @@ -22,3 +27,43 @@ def explore(path): subprocess.run([FILEBROWSER_PATH, path]) elif os.path.isfile(path): subprocess.run([FILEBROWSER_PATH, '/select,', path]) + + +def show_file_properties(filepath, hwnd=None): + filepath = os.path.abspath(filepath) + + if not os.path.exists(filepath): + raise FileNotFoundError(f"File '{filepath}' does not exist") + + SHELL32.SHObjectProperties(hwnd, 0x00000002, filepath, None) + + +__mmc = None + + +def show_service_properties(service_name): + global __mmc + + try: + __mmc.Document + except: + __mmc = None + + if __mmc is None: + __mmc = win32com.client.Dispatch("MMC20.Application") + __mmc.Load("services.msc") + + doc = __mmc.Document + view = doc.ActiveView + items = view.ListItems + + for item in items: + if item.Name == service_name: + __mmc.UserControl = True + view.Select(item) + view.DisplaySelectionPropertySheet() + break + else: + __mmc.Quit() + show_error(f"The properties window for the '{service_name}' service " + f"could not be opened, because the service was not found.") diff --git a/src/util/messages.py b/src/util/messages.py index c1b07e0..cc47d35 100644 --- a/src/util/messages.py +++ b/src/util/messages.py @@ -1,6 +1,6 @@ from win32api import MessageBoxEx -from constants.app_info import APP_NAME_WITH_VERSION, TITLE_ERROR +from constants.app_info import APP_NAME_WITH_VERSION, TITLE_ERROR, APP_TITLE from enums.messages import MBIcon, MBButton, MBResult @@ -20,15 +20,15 @@ def _message_box(title: str, message: str, icon: MBIcon, btn: MBButton) -> MBRes return MessageBoxEx(None, message, title, icon | btn) -def show_info(message: str, title: str = APP_NAME_WITH_VERSION): +def show_info(message: str, title: str = APP_TITLE): _message_box(title, message, MBIcon.INFORMATION, MBButton.OK) -def yesno_info_box(message: str, title: str = APP_NAME_WITH_VERSION) -> bool: +def yesno_info_box(message: str, title: str = APP_TITLE) -> bool: return _message_box(title, message, MBIcon.INFORMATION, MBButton.YESNO) == MBResult.YES -def yesno_question_box(message: str, title: str = APP_NAME_WITH_VERSION) -> bool: +def yesno_question_box(message: str, title: str = APP_TITLE) -> bool: return _message_box(title, message, MBIcon.QUESTION, MBButton.YESNO) == MBResult.YES diff --git a/src/util/scheduler.py b/src/util/scheduler.py index dd99a3b..e1bf76d 100644 --- a/src/util/scheduler.py +++ b/src/util/scheduler.py @@ -12,7 +12,7 @@ def _execute_task(cls, key, callback, *args, **kwargs): del cls._tasks[key] @classmethod - def schedule_task(cls, key, callback, delay=0, *args, **kwargs): + def schedule_task(cls, key, callback, *args, delay=0, **kwargs): if key not in cls._tasks: if delay: cls._tasks[key] = threading.Timer(delay, cls._execute_task, args=(key, callback) + args, kwargs=kwargs) @@ -31,10 +31,10 @@ def my_function(message): print(f"Function executed with message: {message}") - TaskScheduler.schedule_task("task1", my_function, 5, "Hello after 5 seconds") - TaskScheduler.schedule_task("task1", my_function, 2, "Hello after 2 seconds") - TaskScheduler.schedule_task("task2", my_function, 3, "Hello after 3 seconds") - TaskScheduler.schedule_task("task3", my_function, 0, "Immediate execution") + TaskScheduler.schedule_task("task1", my_function, "Hello after 5 seconds", delay=5) + TaskScheduler.schedule_task("task1", my_function, "Hello after 2 seconds", delay=2) + TaskScheduler.schedule_task("task2", my_function, "Hello after 3 seconds", delay=3) + TaskScheduler.schedule_task("task3", my_function, "Immediate execution", delay=0) import time diff --git a/src/util/utils.py b/src/util/utils.py index 1db6681..29c45d9 100644 --- a/src/util/utils.py +++ b/src/util/utils.py @@ -52,7 +52,7 @@ def path_match(pattern: str, value: str) -> bool: Args: pattern (str): The pattern to match against, supporting wildcards. - *values (str): The values to test against the pattern. + value (str): The value to test against the pattern. Returns: bool: True if any value matches the pattern, False otherwise. From 4abec0e20f371c8cf049aeae1b89758991b1e990 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Mon, 23 Sep 2024 01:49:05 +0800 Subject: [PATCH 38/39] Added service name when logging --- src/service/rules_service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/service/rules_service.py b/src/service/rules_service.py index 8859949..52fc607 100644 --- a/src/service/rules_service.py +++ b/src/service/rules_service.py @@ -85,7 +85,8 @@ def __handle_process(cls, process: Process, rule: ProcessRule | ServiceRule): if param in ignored_parameters: continue - logger_string = f"{param.value} `{logger_value}` for {process.process_name} ({process.pid})" + service_name = f", {process.service_name}" if process.service else '' + logger_string = f"{param.value} `{logger_value}` for {process.process_name} ({process.pid}{service_name})" try: if method(process, rule): From 3e6f028c234dfba6fe237df1df4fa2e3992ee9e4 Mon Sep 17 00:00:00 2001 From: SystemXFiles Date: Tue, 24 Sep 2024 01:35:06 +0800 Subject: [PATCH 39/39] Updated documentation --- docs/README.md | 41 +-- docs/configuration_file.md | 189 +++++++++---- ..._artiacle_rule_configurator_screenshot.png | Bin 18624 -> 0 bytes docs/images/game-theme-header.png | Bin 39474 -> 0 bytes ...imization_rule_configurator_screenshot.png | Bin 15233 -> 0 bytes .../{ => headers}/github-banner-readme.png | Bin docs/images/rule_configurator_screenshot.png | Bin 23088 -> 0 bytes ...ule_configurator_with_error_screenshot.png | Bin 25659 -> 0 bytes docs/images/screenshots/other_actions.png | Bin 0 -> 2261 bytes docs/images/screenshots/process_list.png | Bin 0 -> 52157 bytes .../screenshots/process_list_actions.png | Bin 0 -> 3258 bytes docs/images/screenshots/process_list_menu.png | Bin 0 -> 9718 bytes docs/images/screenshots/process_list_only.png | Bin 0 -> 7638 bytes docs/images/screenshots/process_rules.png | Bin 0 -> 34482 bytes .../screenshots/process_rules_actions.png | Bin 0 -> 3012 bytes .../screenshots/process_rules_add_rule.gif | Bin 0 -> 122433 bytes .../screenshots/process_rules_error.png | Bin 0 -> 19853 bytes .../images/screenshots/process_rules_menu.png | Bin 0 -> 4698 bytes .../images/screenshots/process_rules_only.png | Bin 0 -> 5968 bytes .../screenshots/process_rules_unsaved.png | Bin 0 -> 2610 bytes docs/images/screenshots/save_action.png | Bin 0 -> 1193 bytes .../images/screenshots/service_rules_only.png | Bin 0 -> 4184 bytes docs/images/screenshots/tooltips.png | Bin 0 -> 4041 bytes docs/images/screenshots/tray_menu.png | Bin 0 -> 7313 bytes docs/images/sound-theme-header.png | Bin 791318 -> 0 bytes docs/images/tray_menu_screenshot.png | Bin 12356 -> 0 bytes docs/rule_behavior_and_tips.md | 164 +++++++++++ docs/tips'n'tricks/audio.md | 259 ------------------ docs/tips'n'tricks/game_optimization.md | 120 -------- docs/ui_process_governor.md | 235 ++++++++++++++++ docs/ui_rule_configurator.md | 95 ------- src/constants/app_info.py | 2 +- .../tabs/processes/process_list_actions.py | 4 +- 33 files changed, 553 insertions(+), 556 deletions(-) delete mode 100644 docs/images/audio_artiacle_rule_configurator_screenshot.png delete mode 100644 docs/images/game-theme-header.png delete mode 100644 docs/images/game_optimization_rule_configurator_screenshot.png rename docs/images/{ => headers}/github-banner-readme.png (100%) delete mode 100644 docs/images/rule_configurator_screenshot.png delete mode 100644 docs/images/rule_configurator_with_error_screenshot.png create mode 100644 docs/images/screenshots/other_actions.png create mode 100644 docs/images/screenshots/process_list.png create mode 100644 docs/images/screenshots/process_list_actions.png create mode 100644 docs/images/screenshots/process_list_menu.png create mode 100644 docs/images/screenshots/process_list_only.png create mode 100644 docs/images/screenshots/process_rules.png create mode 100644 docs/images/screenshots/process_rules_actions.png create mode 100644 docs/images/screenshots/process_rules_add_rule.gif create mode 100644 docs/images/screenshots/process_rules_error.png create mode 100644 docs/images/screenshots/process_rules_menu.png create mode 100644 docs/images/screenshots/process_rules_only.png create mode 100644 docs/images/screenshots/process_rules_unsaved.png create mode 100644 docs/images/screenshots/save_action.png create mode 100644 docs/images/screenshots/service_rules_only.png create mode 100644 docs/images/screenshots/tooltips.png create mode 100644 docs/images/screenshots/tray_menu.png delete mode 100644 docs/images/sound-theme-header.png delete mode 100644 docs/images/tray_menu_screenshot.png create mode 100644 docs/rule_behavior_and_tips.md delete mode 100644 docs/tips'n'tricks/audio.md delete mode 100644 docs/tips'n'tricks/game_optimization.md create mode 100644 docs/ui_process_governor.md delete mode 100644 docs/ui_rule_configurator.md diff --git a/docs/README.md b/docs/README.md index b91a950..0f1673b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,28 +1,28 @@ -![Logo Process Governor](images/github-banner-readme.png) +![Logo Process Governor](images/headers/github-banner-readme.png) --- **Process Governor** is a Python utility designed to manage Windows processes and services by adjusting their priorities, I/O priorities, and core affinity based on user-defined rules. -
- Screenshots - - >![tray_menu_screenshot.png](images/tray_menu_screenshot.png) - > - >![audio_artiacle_rule_configurator_screenshot.png](images/audio_artiacle_rule_configurator_screenshot.png) - > - >![rule_configurator_with_error_screenshot.png](images/rule_configurator_with_error_screenshot.png) -
- -## Features +### Features - Adjust process and service priorities for better performance. - Control I/O priorities to optimize resource utilization. - Define core affinity for processes. -- Fine-tune Windows services and processes based on [user-defined rules](ui_rule_configurator.md). -- Continuous monitoring of the configuration file for rule application. -- Ability to add ProcessGovernor to autorun. +- Fine-tune Windows services and processes based on user-defined rules. + +### Screenshots + +
+ Click to expand + +> ![process_list.png](images/screenshots/process_list.png) +> +> ![process_rules.png](images/screenshots/process_rules.png) +> +> ![tray_menu.png](images/screenshots/tray_menu.png) +
## Getting started @@ -33,18 +33,19 @@ To get started with **Process Governor**, follow these steps: 2. Run the `Process Governor.exe` executable with **administrative privileges**. This is important to allow the program to make the necessary adjustments to process and service priorities, I/O priorities, and core affinity. -3. [Configure the rules](ui_rule_configurator.md) for processes and services. +3. Configure the rules for processes and services. +4. **Optionally**, you can enable auto-start for the program to launch automatically with + the system. You can close the program by accessing the tray icon. ## Knowledge base -- [Configuring rules](ui_rule_configurator.md) +- [Process Governor UI](ui_process_governor.md) +- [Rule Behavior and Tips](rule_behavior_and_tips.md) - [Configuration file](configuration_file.md) - [Running from source and creating a portable build](run_and_build.md) -- **Tips and Tricks** - - [Optimizing Audio](tips'n'tricks/audio.md) - - [Optimizing Games](tips'n'tricks/game_optimization.md) + ## License This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](../LICENSE) file for details. \ No newline at end of file diff --git a/docs/configuration_file.md b/docs/configuration_file.md index af467a7..63810a0 100644 --- a/docs/configuration_file.md +++ b/docs/configuration_file.md @@ -4,110 +4,181 @@ --- -The `config.json` configuration file is used to manage the behavior of the **Process Governor** application. It allows -you to define how the application will regulate the priorities of processes and services, their I/O priorities, and -correspondence to CPU cores. +The `config.json` configuration file manages the behavior of the **Process Governor** application. This file allows +users to define rules for regulating process priorities, I/O priorities, and CPU core affinity, as well as manage +services with similar settings. -The configuration file is regularly checked by the application and applied if there are changes. +The application regularly checks the configuration file for changes and applies the updates accordingly. -### Configuration File Example +--- +## Configuration File Example + +Below is an example of the configuration file with several rules defined for processes and services: -In this example, two rules are defined: one for a process and one for a service. +
+ See an example ```json { "ruleApplyIntervalSeconds": 1, - "logging": { - "enable": true, - "level": "WARN", - "maxBytes": 1024, - "backupCount": 1 - }, - "rules": [ + "processRules": [ + { + "selectorBy": "Name", + "selector": "aida_bench64.dll", + "force": "N" + }, + { + "selectorBy": "Name", + "selector": "bg3*.exe", + "affinity": "0-15", + "force": "N", + "delay": "30" + }, + { + "selectorBy": "Name", + "selector": "logioptionsplus_*.exe", + "priority": "Idle", + "ioPriority": "Low", + "affinity": "0-15", + "force": "N" + }, + { + "selectorBy": "Name", + "selector": "discord.exe", + "priority": "Normal", + "affinity": "0-15", + "force": "Y" + }, { - "processSelector": "example.exe", - "priority": "High", - "ioPriority": "Normal", - "affinity": "1;3-5" + "selectorBy": "Name", + "selector": "audiodg.exe", + "priority": "Realtime", + "affinity": "16-23", + "force": "N" }, { - "serviceSelector": "Audio*", + "selectorBy": "Name", + "selector": "*", + "affinity": "0-15", + "force": "N" + } + ], + "serviceRules": [ + { "priority": "Realtime", - "ioPriority": "High", - "affinity": "0;2;4" + "selector": "*audio*", + "force": "N" } - ] + ], + "version": 3 } ``` +
+ +--- ## Structure of the `config.json` -The configuration file consists of several key sections: +The configuration file contains several sections, each serving a specific purpose. ### `ruleApplyIntervalSeconds` -This parameter defines the interval in seconds at which rules will be applied to processes and services. The default -value is `1`, which means that rules are applied every second. +This parameter defines the interval, in seconds, at which the application applies the rules to processes and services. +The default value is `1`, meaning rules are applied every second. -### `logging` +### `processRules` -This section contains logging settings. It allows you to enable or disable logging, set the logging level, the maximum -size of the log file, and the number of backup log files to keep. +This section lists the rules applied to processes. Each rule object specifies how the application should manage a +process based on several key parameters: #### Possible parameters: -- `enable`: Enables or disables logging. -- `level`: The logging level (`INFO`, `WARN`, etc.). -- `maxBytes`: The maximum size of the log file in bytes. -- `backupCount`: The number of backup log files. - -### `rules` - -This section defines the list of rules by which **Process Governor** will manage processes and services. Each rule is -defined by an object with a set of parameters. - -#### Possible parameters: +- **`selectorBy`** (string): Determines how the `selector` value is interpreted for process matching. + **Valid values:** + - `"Name"`: Match by process name (e.g., `"notepad.exe"`). + - `"Path"`: Match by full executable path (e.g., `"C:/Windows/System32/notepad.exe"`). + - `"Command line"`: Match by command line (e.g., `"App.exe Document.txt"`). -- `processSelector` (string, optional): Specifies the process name or pattern to match. - You can use wildcards, including `*` and `?`, to match multiple processes. - - Example: `"processSelector": "example.exe"` - - Example with wildcards: `"processSelector": "logioptionsplus_*.exe"` +- **`selector`** (string): Specifies the name, pattern, or path to the process. + **Supported wildcards:** + - `*`: Matches any number of characters. + - `?`: Matches a single character. + - `**`: Matches any sequence of directories. -- `serviceSelector` (string, optional): Specifies the service name or pattern to match. - You can use wildcards, including `*` and `?`, to match multiple services. - - Example: `"serviceSelector": "MyService"` - - Example with wildcards: `"serviceSelector": "Audio*"` + **Examples:** + - `"selector": "name.exe"` + - `"selector": "logioptionsplus_*.exe"` + - `"selector": "C:/Program Files/**/app.exe --file Document.txt"` -- `priority` (string, optional): Sets the process or service priority. - Valid values are: +- **`priority`** (string, optional): Sets the priority level of the process. + **Valid values:** - `"Idle"` - `"BelowNormal"` - `"Normal"` - `"AboveNormal"` - `"High"` - `"Realtime"` - - Example: `"priority": "High"` + + **Example:** `"priority": "High"` -- `ioPriority` (string, optional): Sets the I/O priority for the process or service. - Valid values are: +- **`ioPriority`** (string, optional): Sets the I/O priority of the process. + **Valid values:** - `"VeryLow"` - `"Low"` - `"Normal"` - - `"High"`: Setting the I/O priority to "High" may result in an AccessDenied error in most cases. - - Example: `"ioPriority": "Normal"` + + **Example:** `"ioPriority": "Low"` -- `affinity` (string, optional): Specifies CPU core affinity. - You can define affinity as: +- **`affinity`** (string, optional): Sets the CPU core affinity for the process. + **Formats:** - Range (inclusive): `"affinity": "0-3"` - Specific cores: `"affinity": "0;2;4"` - Combination: `"affinity": "1;3-5"` -### Validation -Built-in validation prevents the simultaneous assignment of `processSelector` and `serviceSelector` within a single -rule. If you attempt to set both parameters, the program will notify you of the error and require you to correct the -rule. \ No newline at end of file +- **`force`** (string, optional): Forces the application of the settings. + **Valid values:** + - `"Y"` for continuous enforcement. + - `"N"` for one-time application. + + +- **`delay`** (integer, optional): Delay in seconds before applying the settings. + **Examples:** + - If not specified, the settings are applied immediately. + - Positive values set a delay in seconds before applying the settings. + +### `serviceRules` + +This section contains a list of rules applied to services. Unlike `processRules`, the **Service Rule** does not include +the `selectorBy` field because service rules only match by service name using the `selector` field. + +#### Possible parameters: + +- **`selector`** (string): Specifies the name or pattern of the service to match. + **Supported wildcards:** + - `*`: Matches any number of characters. + - `?`: Matches a single character. + + **Examples:** + - `"selector": "ServiceName"` + - `"selector": "*audio*"` + +Other parameters such as `priority`, `ioPriority`, `affinity`, `force`, and `delay` are similar to those +in `processRules`. + +### `version` + +This field specifies the version of the configuration. It is required for ensuring proper migration and updates when the +program configuration changes over time. + +--- + +## Validation + +The configuration file undergoes validation to ensure consistency and correctness. If there are any issues, such as +invalid parameter combinations or missing required fields, the application will notify the user and prevent the +configuration from being applied until the errors are resolved. \ No newline at end of file diff --git a/docs/images/audio_artiacle_rule_configurator_screenshot.png b/docs/images/audio_artiacle_rule_configurator_screenshot.png deleted file mode 100644 index 82281565c8dfc48e8d926658725900c4965382f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18624 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 QFUca5HIxc&-+TN&0M4ZQ$p8QV diff --git a/docs/images/github-banner-readme.png b/docs/images/headers/github-banner-readme.png similarity index 100% rename from docs/images/github-banner-readme.png rename to docs/images/headers/github-banner-readme.png diff --git a/docs/images/rule_configurator_screenshot.png b/docs/images/rule_configurator_screenshot.png deleted file mode 100644 index 43c1e63b88c98d2f90021f5680cbf18174e4c936..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23088 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 diff --git a/docs/images/rule_configurator_with_error_screenshot.png b/docs/images/rule_configurator_with_error_screenshot.png deleted file mode 100644 index a317e2e7d0bc8df551968c23cb2a235cbd017946..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25659 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 G@qYmLT|JZl diff --git a/docs/images/screenshots/other_actions.png b/docs/images/screenshots/other_actions.png new file mode 100644 index 0000000000000000000000000000000000000000..e42be43c53bcd9f38a8e0724244d8f3c9246eab5 GIT binary patch literal 2261 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�j*X~-~x2}{-j?KH%yJ*#6S5!!; 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 E0w(z|o&W#< literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/process_list_actions.png b/docs/images/screenshots/process_list_actions.png new file mode 100644 index 0000000000000000000000000000000000000000..c596da394ce5698cd3fff85d226cf15ddf9caaa1 GIT binary patch literal 3258 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 literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/process_list_menu.png b/docs/images/screenshots/process_list_menu.png new file mode 100644 index 0000000000000000000000000000000000000000..7f946c91c29ecf3e489999d1a09c02997ae4a65a GIT binary patch literal 9718 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 literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/process_list_only.png b/docs/images/screenshots/process_list_only.png new file mode 100644 index 0000000000000000000000000000000000000000..a582e3e20c9d14dac36db4c496603e3daa5ee129 GIT binary patch literal 7638 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 literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/process_rules.png b/docs/images/screenshots/process_rules.png new file mode 100644 index 0000000000000000000000000000000000000000..9ab45df3f6e18d7bf2629ee70e83c4c990e9fc98 GIT binary patch literal 34482 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 XRBZL>q&xTsH0sy1f6u>S8T$VL=IEQ2 literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/process_rules_actions.png b/docs/images/screenshots/process_rules_actions.png new file mode 100644 index 0000000000000000000000000000000000000000..c684cf9799cce4d07b5014bea88cfd98dd80ae23 GIT binary patch literal 3012 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

nx_noM#Y(cMDc{BXWlDqL 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

mJ?D|kpnumZz|3`f=g1E7FPOMcSM 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

|@PYYgyg01!WwEFF1Bu3wQ;+ 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

;!sz(49@jC%0MfRb+Q-eXj7?@BDD8wp= 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 z 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 Ef){Ha0RR91 diff --git a/docs/images/tray_menu_screenshot.png b/docs/images/tray_menu_screenshot.png deleted file mode 100644 index e1ad4f76c20098249f823c40598c02d1140149cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12356 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 **Note:** Before proceeding, it is recommended to familiarize yourself +> with [Process Governor UI](ui_process_governor.md). + +## Rule Priority + +

+Click to expand + +When applying rules, the program first checks **service rules** and then moves to **process rules**. This means that if +a service matches a rule, it will take precedence. If no matching service rule is found, the program then applies the +first matching process rule. + +> **Note:** Only the first matching rule is applied, so the order of the rules in the configuration is important. + +
+ +## Ignoring a Process + +
+Click to expand + +To ignore a process without applying any specific settings: + +1. Go to the **Process Rules** tab. +2. Add a new rule. +3. Set **Process Selector** to the name of the process you want to ignore (e.g., `someprocess.exe`). +4. Leave all other fields unchanged. + +This will ensure that the process is excluded from any modifications by the governor. + +
+ +## Rule for All Processes + +
+Click to expand + +To apply a rule to all processes: + +1. Go to the **Process Rules** tab. +2. Add a new rule. +3. Set **Process Selector** to `*` to match all processes. +4. Configure the desired settings (e.g., affinity, priority). +5. Place this rule at the bottom of the list to allow more specific rules to take precedence. + +
+ +## Disabling Hyperthreading + +
+Click to expand + +To limit a process to physical CPU cores and disable the use of hyperthreaded (logical) cores: + +1. Go to the **Process Rules** tab. +2. Add a new rule. +3. Set **Process Selector** to the target process. +4. Set **Affinity** to even-numbered cores only (e.g., `0;2;4;6;8;10;12;14`). + +This will prevent the process from using hyperthreaded cores, which can be beneficial for certain workloads. + +
+ +## Using Delay to Avoid Side Effects + +
+Click to expand + +For some applications, especially games, applying settings like core affinity immediately upon startup can cause issues. +Adding a delay ensures the process has time to initialize before adjustments are applied. + +1. Go to the **Process Rules** tab. +2. Add a new rule. +3. Set **Process Selector** to the game executable (e.g., `bg3.exe`). +4. Set **Affinity** as needed (e.g., `0-15`). +5. Set a **Delay** of around 10 seconds to prevent early changes during startup. + +This helps avoid potential problems like sound not working. + +
+ +## Optimizing for Older or Single-Threaded Games + +
+Click to expand + +Older or poorly optimized games that don’t efficiently use multiple cores can stutter if run with the default core +affinity settings. To improve performance: + +1. Go to the **Process Rules** tab. +2. Add a new rule. +3. Set **Process Selector** to the game process. +4. Set **Priority** to a higher level (e.g., `AboveNormal` or `High`). +5. Adjust the **Affinity** to exclude CPU core 0 (e.g., `1-15`). + +This setup can help distribute the load more effectively and reduce stuttering. + +
+ +## Fixing Audio Crackling Issues + +
+Click to expand + +To address audio crackling or stuttering under high CPU load, it’s recommended to increase the priority of audio-related +processes and services to ensure they have sufficient CPU resources. + +### Steps for Optimizing Audio Processes: + +1. Go to the **Process Rules** tab. +2. Add a new rule for each audio-related process. +3. Set **Process Selector** to the name of the audio process (e.g., `audiodg.exe`, `voicemeeter8x64.exe`). +4. Set **Priority** to `Realtime` or `High` depending on the process's importance. + +### Steps for Optimizing Audio Services: + +1. Go to the **Service Rules** tab. +2. Add a new rule for each audio-related service. +3. Set **Service Selector** to the service name (e.g., `AudioSrv`, `AudioEndpointBuilder`). +4. Set **Priority** to `Realtime` or `High`. + +This approach prioritizes audio processing over other tasks, preventing interruptions in sound quality during heavy CPU +usage. + +### Advanced Setup: Load Distribution Across CPU Cores + +For all previously added rules related to audio processes, it is recommended to configure **Affinity** to assign specific CPU cores dedicated to audio processing tasks. This helps ensure that audio processes have sufficient CPU resources, minimizing interference from other tasks. + +For example, if you have a **16-thread processor with 8 cores**, you can allocate the last 2 cores (threads 12-15) for audio tasks, while the first 6 cores (threads 0-11) can be reserved for other applications. + +#### Steps: + +1. For each previously configured audio process rule: + - Set **Affinity** to the last 2 cores (e.g., threads 12-15) for handling audio processing tasks. + +2. After configuring the audio processes, add a new rule for all other processes: + - Set **Process Selector** to `*`. + - Set **Affinity** to allocate the remaining CPU cores (e.g., threads 0-11) for non-audio tasks. + - **Important:** This rule must be placed **last** in the rule list, as it serves as a fallback for any processes that are not explicitly defined in previous rules. + +> **Note:** Avoid modifying the **Affinity** for audio services like **AudioSrv** or **AudioEndpointBuilder**, as this may worsen performance. Adjusting the priority for these services is usually sufficient to resolve audio issues such as crackling and stuttering. + +This configuration helps distribute the CPU load, isolating audio processes to specific cores, ensuring smoother and more stable sound under high system load. + +
\ No newline at end of file diff --git a/docs/tips'n'tricks/audio.md b/docs/tips'n'tricks/audio.md deleted file mode 100644 index 7efbb75..0000000 --- a/docs/tips'n'tricks/audio.md +++ /dev/null @@ -1,259 +0,0 @@ -![Logo Process Governor](../images/sound-theme-header.png) - -# Optimizing Audio using Process Governor - -[![README](../icons/readme.png) README](../README.md) - ---- - -> **Foreword:** -> -> If you are involved in music, streaming, or simply aim for perfect sound in Discord or at work, and you use real-time -> sound processing, this article is for you. It will discuss methods of system optimization to prevent sound problems -> such as stuttering or crackling under high CPU load. The proposed approach will help you configure CPU resources so -> that audio processes are prioritized and do not suffer from competition with other tasks. - -## Introduction - -In this article, we will explore the process of optimizing audio on a computer using the **Process Governor** tool. This -method allows for improved audio stability and reduced stuttering and crackling, especially during high processor loads. - -## Background of the Issue - -### Initial Situation - -My story began with audio instability on my computer, particularly when I was actively using real-time audio processing. -Stuttering and crackling became the norm during online performances and applications that processed audio through -multiple audio effects. This was not only annoying but also affected the quality of my audio projects. - -### Searching for a Solution - -I started looking for ways to address this problem. It involved experimenting with audio interface settings, optimizing -operating system parameters, and even reinstalling audio drivers. Some of these methods led to temporary improvements, -but as the number of audio effects and sound processors increased, the problem resurfaced. - -### A Radical and Effective Solution - -To find a more radical and reliable solution, I came up with the idea of redistributing my PC's computing resources. I -hypothesized that allocating specific processor cores to handle audio signals and the remaining cores for regular tasks -would help solve the problem. This should ensure stable audio playback even during high CPU loads. - -As a result, I manually reassigned audio processes to dedicated CPU cores and conducted testing. This proved to be an -effective solution. However, to simplify and automate this process, I decided to create a specialized application -capable of managing the distribution of processor resources between audio processes and other tasks. - -### The Birth of Process Governor - -From this need, the idea of creating a program capable of managing Windows processes and their CPU core assignments was -born. This gave rise to Process Governor. With its help, I could optimize audio processes and services by setting them -to run with high priority in real-time mode and assigning them to specific CPU cores. This ensured stable and -high-quality audio playback even in demanding scenarios. - -## Processes and Services Affecting Audio - -To process audio, I use the following programs: - -1. **Voicemeeter** - a virtual mixer. -2. **Equalizer APO** - for processing sound on Voicemeeter's output devices (headphones and speakers). -3. **Kushview Element** - DAW for processing sound on Voicemeeter's input devices (microphone). - -Additionally, there are Windows services and processes that interact with audio and are common to all Windows users: - -1. **AudioSrv** service. -2. **AudioEndpointBuilder** service. -3. **Audiodg.exe** process. - -## Preparing for Configuration - -### List of Processes and Services - -To set up the configuration, I created a list of processes and services responsible for handling audio: - -1. **voicemeeter8x64.exe** - Voicemeeter. -2. **voicemeeterclient.exe** - The Equalizer APO process for integration with Voicemeeter. -3. **element.exe** - Kushview Element. -4. **Audiodg.exe**. -5. **AudioSrv** service. -6. **AudioEndpointBuilder** service. - -### Distribution of Processor Resources - -> **Note:** -> -> 1. Process Governor perceives threads as CPU cores. So when we talk about cores, remember that it includes threads. -> 2. CPU core numbering starts from 0. - -I have a processor with 12 cores (24 threads), and I propose the following resource distribution: - -1. The first 8 cores/16 threads are dedicated to all processes except for audio (from thread 0 to thread 15). -2. The last 4 cores/8 threads are reserved for audio (from thread 16 to thread 23). - -I also recommend setting the maximum priority - real-time - for all processes responsible for audio. - -> **Note:** -> -> Through trial and error, I found that changing core affinity for the services: -> 1. **AudioSrv**; -> 2. **AudioEndpointBuilder**. -> -> Leads to worsening audio issues. Therefore, for these services, I only change the priority and leave the core affinity -> untouched. - -## Configuring Process Governor - -
- The old method of configuration through the configuration file. - -> ### Preliminary Setup -> -> Before starting the setup, familiarize yourself with the installation and initial configuration instructions for -> **Process Governor** through the configuration file, available in the sections: -> -> - [Getting Started](../README.md#getting-started) -> - [Configuration File](../configuration_file.md) -> -> ### Configuration File -> -> Based on the README and the configuration file information, I propose the following `config.json` file -> for Process Governor: -> -> ```json -> { -> "ruleApplyIntervalSeconds": 1, -> "logging": { -> "enable": true, -> "level": "INFO", -> "maxBytes": 1024, -> "backupCount": 1 -> }, -> "rules": [ -> { -> "processSelector": "voicemeeter8x64.exe", -> "priority": "Realtime", -> "affinity": "16-23" -> }, -> { -> "processSelector": "voicemeeterclient.exe", -> "priority": "Realtime", -> "affinity": "16-23" -> }, -> { -> "processSelector": "element.exe", -> "priority": "Realtime", -> "affinity": "16-23" -> }, -> { -> "processSelector": "Audiodg.exe", -> "priority": "Realtime", -> "affinity": "16-23" -> }, -> { -> "serviceSelector": "AudioSrv", -> "priority": "Realtime" -> }, -> { -> "serviceSelector": "AudioEndpointBuilder", -> "priority": "Realtime" -> }, -> { -> "processSelector": "*", -> "affinity": "0-15" -> } -> ] -> } -> ``` -> -> > **The key aspects to note:** -> > -> > - Processes and services responsible for audio are specified in the `serviceSelector` and `processSelector`. -> > - The "real-time" priority is set for all audio-related processes: `"priority": "Realtime"`. -> > - CPU core assignments for various scenarios are specified in: `"affinity": ""`. -> > - For services, CPU cores are intentionally not specified, only priority is set. -> > -> > Also, pay attention to the last rule and its `processSelector`: -> > -> > ```json -> > { -> > "processSelector": "*", -> > "affinity": "0-15" -> > } -> > ``` -> > -> > Here, the selector is `*`, indicating that ANY process will be subject to the rule specifying cores 0-15. Since -> > rules in Process Governor are executed in order until the first match is found, this rule will only apply to -> > processes not related to audio, automatically assigning them to cores 0-15. -> -> ### Running Process Governor -> -> To apply the settings, place the `config.json` configuration file next to the Process Governor program and run it. The -> program will run in the background, regularly applying rules to new processes and is accessible from the system tray. -
- -### Preliminary Setup - -Before starting the setup, familiarize yourself with the installation and initial configuration instructions for -**Process Governor**, available in the sections: - -- [Getting Started](../README.md#getting-started) -- [Configuring Rules](../ui_rule_configurator.md) - -To ensure **Process Governor** automatically starts with Windows, follow these steps: - -1. Launch the **Process Governor**. -2. Click on the application icon in the system tray to open the menu. -3. Enable the **Run on Startup** option. - -Example of the enabled **Run on Startup** option: - -![tray_menu_screenshot.png](../images/tray_menu_screenshot.png) - -### Creating Rules - -#### Opening the Settings - -1. Launch **Process Governor** if it is not already running. -2. Click on the application icon in the system tray to open the menu. -3. Select the **Settings** option to open the settings. - -#### Adding a Rule for process Voicemeeter - -1. In the Settings interface, press the **Add** button to add a new rule. -2. Enter the corresponding values in the columns: - - **Process Selector:** `voicemeeter8x64.exe` - - **Priority:** `Realtime` - - **Affinity:** `16-23` - -#### Adding a Rule for service AudioSrv - -1. Press the **Add** button. -2. Enter the corresponding values in the columns: - - **Service Selector:** `AudioSrv` - - **Priority:** `Realtime` - -#### Adding Other Rules - -Similarly, add the remaining rules in accordance with the screenshot: - -![audio_artiacle_rule_configurator_screenshot.png](../images/audio_artiacle_rule_configurator_screenshot.png) - -> **The key aspects to note:** -> -> - Processes and services responsible for audio are specified in the **Process Selector** and **Service Selector**. -> - The "real-time" priority is set for all audio-related processes: `Realtime`. -> - CPU core assignments for various scenarios are specified. -> - For services, CPU cores are intentionally not specified, only priority is set. -> -> Also, pay attention to the last rule and its **Process Selector**. -> Its selector is set to `*`, indicating that ANY process will be subject to the rule specifying cores 0-15. Since rules -> in Process Governor are executed in order until the first match is found, this rule will only apply to processes not -> related to audio, automatically assigning them to cores `0-15`. - -### Saving the Settings - -Once all the rules are configured, save them by pressing the **Apply** button. Then you can close Settings. -After that, the program will regularly apply the rules to the corresponding processes and manage PC resources. - -## Conclusion - -Configuring Process Governor provides a powerful means of optimizing audio on my PC, enhancing its stability and -quality. I hope this article helps you achieve better results in audio processing. \ No newline at end of file diff --git a/docs/tips'n'tricks/game_optimization.md b/docs/tips'n'tricks/game_optimization.md deleted file mode 100644 index 07745c6..0000000 --- a/docs/tips'n'tricks/game_optimization.md +++ /dev/null @@ -1,120 +0,0 @@ -![game-theme-header.png](../images/game-theme-header.png) - -# Optimizing Games using Process Governor - -[![README](../icons/readme.png) README](../README.md) - ---- - -## Introduction - -Enhancing performance and reducing response time for PC games, such as **Starfield** and **Red Dead Redemption 2**, is -achieved through system resource management. **Process Governor** is a tool that gives users control over processes and -resource distribution, which can significantly improve the gaming experience. In this guide, we will thoroughly examine -the process of configuring **Process Governor** to optimize these popular games. - -## Preliminary Setup - -Before starting the setup, familiarize yourself with the installation and initial configuration instructions for -**Process Governor**, available in the sections: - -- [Getting Started](../README.md#getting-started) -- [Configuring Rules](../ui_rule_configurator.md) - -To ensure **Process Governor** automatically starts with Windows, follow these steps: - -1. Launch the **Process Governor**. -2. Click on the application icon in the system tray to open the menu. -3. Enable the **Run on Startup** option. - -Example of the enabled **Run on Startup** option: - -![tray_menu_screenshot.png](../images/tray_menu_screenshot.png) - -## Creating Rules for Games - -Let's look at setting up optimization for two popular games: - -1. **Starfield:** To reduce freezes and lags, an optimal strategy would be to exclude the 0th CPU core from processing - the game, thereby reducing competition with Windows system processes for resources. - -2. **Red Dead Redemption 2:** To reduce the number of freezes, it is recommended to disable the use of - Hyper-threading and limit the game process to working only on physical processor cores (even "core" numbers). It - may also be helpful to limit CPU usage, for example, using the first 6 cores. - -Let's proceed to set up the rules. - -### Opening the Settings - -1. Launch **Process Governor** if it is not already running. -2. Click on the application icon in the system tray to open the menu. -3. Select the **Settings** option to open the settings. - -### Adding a Rule for Starfield - -1. In the Settings interface, press the **Add** button to add a new rule. -2. Enter the corresponding values in the columns: - - **Process Selector:** `starfield.exe`. - - **Priority:** `High`. - - **I/O Priority:** `High`. - - **Affinity:** `1-N`, meaning use all cores except the first one. - > Replace `N` with the number of the highest available core/thread on your processor, starting from 0. - -### Adding a Rule for RDR2 - -1. Press the **Add** button. -2. Enter the corresponding values in the columns: - - **Process Selector:** `rdr2.exe`. - - **Priority:** `High`. - - **I/O Priority:** `High`. - - **Affinity:** `0;2;4;6;8;10`, meaning use 6 cores excluding multi-threading (odd cores). - -### Saving the Settings - -Check the entered data to ensure that the rule settings match your system configuration and the parameters displayed on -the screenshot. For a system with 12 cores and 24 threads, as in my example, the last available "core" is number 23 -starting from 0. That's why for the game **Starfield** we set the range of cores as `1-23`, excluding the first core -from use. - -![game_optimization_rule_configurator_screenshot.png](../images/game_optimization_rule_configurator_screenshot.png) - -Once all the rules are configured, save them by pressing the **Apply** button. Then you can close the settings. - -### Game Process Monitoring - -- After starting the game, carefully monitor its performance as well as the load on the graphics and central processors. -- If you encounter performance issues, return to the Process Governor settings and make the necessary adjustments. -- If the game **RDR2** requires more resources, consider distributing the game across more cores. - -## Alternative Setup Method - -You can also configure **Process Governor** by manually editing the JSON configuration file, following the -instructions [here](../configuration_file.md). - -The correctly configured configuration file should look like this: - -```json -{ - "ruleApplyIntervalSeconds": 1, - "logging": { - "enable": true, - "level": "INFO", - "maxBytes": 1024, - "backupCount": 1 - }, - "rules": [ - { - "processSelector": "starfield.exe", - "priority": "High", - "ioPriority": "High", - "affinity": "1-23" - }, - { - "processSelector": "rdr2.exe", - "priority": "High", - "ioPriority": "High", - "affinity": "0;2;4;6;8;10" - } - ] -} -``` \ No newline at end of file diff --git a/docs/ui_process_governor.md b/docs/ui_process_governor.md new file mode 100644 index 0000000..3500964 --- /dev/null +++ b/docs/ui_process_governor.md @@ -0,0 +1,235 @@ +# Process Governor UI + +[![README](icons/readme.png) README](README.md) + +--- + +## Table of Contents + +1. [System Tray](#system-tray) +2. [Main Window](#main-window) +3. [Process List](#process-list) +4. [Rule Lists](#rule-lists) + - [Process Rules](#process-rules) + - [Service Rules](#service-rules) + - [Managing Rules](#managing-rules) + - [Rules List Context Menu](#rules-list-context-menu) + - [Editing Rules](#editing-rules) + - [Error Handling](#error-handling) + +--- + +## System Tray + +
+Click to expand + +![](images/screenshots/tray_menu.png) + +The system tray menu provides quick access to the main program functions: + +- **Process Governor**: Open settings. +- **Open config file**: Open the configuration file for manual settings editing. +- **Open log file**: Open the log file with the program's operation records. +- **Run on Startup**: Enable or disable program startup with the system. +- **Check for Updates**: Check for program updates. +- **Quit**: Exit the program. + +
+ +## Main Window + +
+Click to expand + +![](images/screenshots/process_list.png) + +### Tooltips + +![](images/screenshots/tooltips.png) + +- In the settings interface, tooltips are available, describing the functions of buttons and fields. +- Hover over an interface element to view its tooltip. + +### Action Buttons + +![](images/screenshots/other_actions.png) +![](images/screenshots/save_action.png) + +Main action buttons are available in the settings interface: + +- **Open config file**: Open the configuration file. +- **Open log file**: Open the log file. +- **Save**: Save changes made to the settings. + Hotkey: **Ctrl+S**. + **Details:** + - The button is disabled if there are errors in the settings. + - If no changes have been made, the save button is also disabled. + +### Unsaved Changes Status + +![](images/screenshots/process_rules_unsaved.png) + +Unsaved changes are marked with an asterisk (`*`) on the corresponding rule tab. + +
+ +## Process List + +
+Click to expand + +![](images/screenshots/process_list_only.png) + +The process list provides important information about running processes: + +- **PID**: Unique process identifier. +- **Process Name**: Name of the process. +- **Service Name**: Name of the service, if applicable. +- **Executable Path**: Full path to the executable file. +- **Command Line**: Command with which the process was started. + +### Filtering and Search + +![](images/screenshots/process_list_actions.png) + +- **Search**: Enter text into the search bar to find processes by name or other attributes (e.g., command line). + Hotkey: **Ctrl+F**. + +- **Filter by type**: Use the filter to display processes by type: + - **Show All**: Display all processes. + - **Show Processes**: Display only processes. + - **Show Services**: Display only services. + +- **Refresh**: Refresh the process list. + Hotkey: **F5**. + +### Process Context Menu + +![](images/screenshots/process_list_menu.png) + +- **Add Process Rule**: Add a rule for a process by name, path, or command line. +- **Add Service Rule**: Add a rule for a service by name. +- **Go to Rule**: Go to the existing rule for a process/service. +- **Copy Special**: Copy process attributes (PID, process name, etc.). +- **Open file location**: Open the folder containing the process’s executable file. +- **File Properties**: Open file properties. +- **Service Properties**: Open service properties. + +
+ +## Rule Lists + +
+Click to expand + +![](images/screenshots/process_rules.png) + +The rule lists are divided into two categories: **Process Rules** and **Service Rules**. + +### Process Rules + +![](images/screenshots/process_rules_only.png) + +- **Selector By**: Determines how the **Process Selector** value is interpreted for process matching: + - `Name` — by process name (e.g., `notepad.exe`). + - `Path` — by the full executable path (e.g., `C:/Windows/System32/notepad.exe`). + - `Command line` — by command line arguments (e.g., `App.exe Document.txt` or `D:/Folder/App.exe Document.txt`). + + +- **Process Selector**: Specifies the name, pattern, or path to the process. + **Supported wildcards:** + - `*` — matches any number of characters. + - `?` — matches a single character. + - `**` — matches any sequence of directories. + **Examples:** `name.exe`, `logioptionsplus_*.exe`, `D:/FolderName/App.exe`, + or `C:/Program Files/**/app.exe --file Document.txt`. + + +- **Priority**: Sets the priority level of the process. + +- **I/O Priority**: Sets the I/O priority of the process. + + +- **Affinity**: Sets the CPU core affinity for the process. + **Formats:** + - Range: `0-3`, + - Specific cores: `0;2;4`, + - Combination: `1;3-5`. + + +- **Force**: Forces the application of the settings. + **Possible values:** + - `Y` — for continuous application, + - `N` — for one-time application. + + +- **Delay**: Delay in seconds before applying the settings. + **Possible values:** + - If not specified, the settings are applied immediately. + - Positive values set a delay in seconds before applying the settings. + +### Service Rules + +![](images/screenshots/service_rules_only.png) + +- **Service Selector**: Specifies the name or pattern of the service to match. + **Supported wildcards:** + - `*`: Matches any number of characters. + - `?`: Matches a single character. + + **Examples:** + - `"selector": "ServiceName"` + - `"selector": "*audio*"` + +Other parameters such as **Priority**, **I/O Priority**, **Affinity**, **Force**, and **Delay** are similar to those in +**Process Rules**. +> **Note:** The **Selector By** field is not used in **Service Rules** since services are matched only by name. + +### Managing Rules + +![](images/screenshots/process_rules_actions.png) + +- **Add**: Add a new rule. +- **Del**: Delete the selected rules. +- **Up/Down**: Move the selected rule up or down in the rule list. + +### Rules List Context Menu + +![](images/screenshots/process_rules_menu.png) + +- **Undo**: Undo the last action. + Hotkey: **Ctrl+Z**. + + +- **Redo**: Redo the undone action. + Hotkeys: **Ctrl+Shift+Z** or **Ctrl+Y**. + + +- **Add**: Add a new rule. + Hotkey: **Ctrl+D**. + + +- **Select all**: Select all rules in the list. + Hotkey: **Ctrl+A**. + + +- **Delete**: Delete the selected rules. + Hotkey: **Del**. + +### Editing Rules + +![](images/screenshots/process_rules_add_rule.gif) + +1. Double-click on the rule cell you want to edit. +2. Enter new data into the selected cell. +3. After editing, the changes are automatically saved in the table. + +### Error Handling + +![](images/screenshots/process_rules_error.png) + +- If incorrect data is entered, the corresponding cell is highlighted, and an error icon appears next to it. +- Hover over the error icon to view the error description. + +
\ No newline at end of file diff --git a/docs/ui_rule_configurator.md b/docs/ui_rule_configurator.md deleted file mode 100644 index bede03b..0000000 --- a/docs/ui_rule_configurator.md +++ /dev/null @@ -1,95 +0,0 @@ -# Configuring Rules - -[![README](icons/readme.png) README](README.md) - ---- - -## Opening the Settings - -1. Launch the **Process Governor**. -2. Click on the application icon in the system tray to open the menu. -3. Select the **Settings** option to open the settings. - -![tray_menu_screenshot.png](images/tray_menu_screenshot.png) - -## Interface of the Settings - -![rule_configurator_screenshot.png](images/rule_configurator_screenshot.png) - -The Settings interface is a table with several columns: - -- **Process Selector**: Specifies the process name or pattern to match. - You can use wildcards, including `*` and `?`, to match multiple processes. - - Example: `example.exe` - - Example with wildcards: `logioptionsplus_*.exe` - - -- **Service Selector**: Specifies the service name or pattern to match. - You can use wildcards, including `*` and `?`, to match multiple services. - - Example: `MyService` - - Example with wildcards: `Audio*` - - -- **Priority**: Sets the priority for processes or services. -- **I/O Priority**: Sets the I/O priority for processes or services. -- **Affinity**: Specifies CPU core affinity. - You can define affinity as: - - Range (inclusive): `0-3` - - Specific cores: `0;2;4` - - Combination: `1;3-5` - -> **Note:** -> -> Do not fill in both the **Process Selector** and **Service Selector** fields for a single rule simultaneously. -> If you set both selectors at the same time, it could lead to conflicts or unpredictable rule behavior. -> -> To prevent such situations, validation has been implemented in the program, which will notify you of the need to -> correct the rule. - -## Working with Rules - -### Adding a New Rule - -1. Press the **Add** button. -2. Edit the rule in accordance with the steps described in [Editing a Rule](#editing-a-rule). - -### Editing a Rule - -1. Double-click on the cell of the rule you want to edit. -2. Enter new data into the selected cell. -3. After editing the cell, the changes will be automatically saved in the table. - -### Deleting a Rule - -1. Select the rule(s) you want to delete by clicking on the corresponding line. -2. Press the **Delete** button. - -### Changing the Order of Rules - -1. Select the rule whose order you want to change. -2. Use the **Up** and **Down** buttons to move the rule up or down the list. - -### Saving Changes - -1. After you have added, edited, or deleted rules, press the **Apply** button at the bottom of the window to apply the - changes. -2. A confirmation message will appear upon successful save. - -### Closing the Settings - -1. To close the Settings, close the window in the usual way. -2. If there are unsaved changes in the table, the program will offer to save them before closing. - -### Tooltips - -- In the Settings interface, tooltips are present at the top, describing the functions of buttons and fields. -- Hover over an interface element to view the tooltip. - -### Error Handling - -- If the entered data is incorrect, the corresponding cell will be highlighted, and an error icon will appear next to - it. -- Hovering over the error icon will display a tooltip with the reason for the error. -- If there are errors, the **Apply** button and the option to save upon closing are not available. - -![rule_configurator_with_error_screenshot.png](images/rule_configurator_with_error_screenshot.png) \ No newline at end of file diff --git a/src/constants/app_info.py b/src/constants/app_info.py index d8a75ee..436428e 100644 --- a/src/constants/app_info.py +++ b/src/constants/app_info.py @@ -6,7 +6,7 @@ APP_AUTHOR: Final[str] = "System X - Files" APP_NAME: Final[str] = "Process Governor" -APP_VERSION: Final[str] = "2.0.0" +APP_VERSION: Final[str] = "1.3.0" APP_PROCESSES = {f"{APP_NAME}.exe", "python.exe"} CURRENT_TAG: Final[str] = f"v{APP_VERSION}" diff --git a/src/ui/widget/settings/tabs/processes/process_list_actions.py b/src/ui/widget/settings/tabs/processes/process_list_actions.py index 69ee80b..8fd65c1 100644 --- a/src/ui/widget/settings/tabs/processes/process_list_actions.py +++ b/src/ui/widget/settings/tabs/processes/process_list_actions.py @@ -22,7 +22,7 @@ def _setup_btn(self): text="Refresh", event=ActionEvents.REFRESH, image=load_img(file=UI_REFRESH), - description="**Refreshes** the list of __processes__. \n**Hotkey:** __F5__." + description="**Refreshes** the list of __processes__.\n**Hotkey:** __F5__." ) self.filterByType = filterByType = EnumCombobox( @@ -34,7 +34,7 @@ def _setup_btn(self): self.search = search = ExtendedEntry( self, - description="**Searches** processes by __name__ or __attribute__.", + description="**Searches** processes by __name__ or __attribute__.\n**Hotkey:** __Ctrl+F__.", placeholder="Search", width=30 )

ny^WnhMy(?eo`*hJZwd0oO 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 X&24vmtpaXp`@h^@{&)kPWoXs_ox)%h literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/process_rules_error.png b/docs/images/screenshots/process_rules_error.png new file mode 100644 index 0000000000000000000000000000000000000000..6a46dafa6da959e9a3311f2cc6e264fc64a7e274 GIT binary patch literal 19853 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 G_J06^Mqa1@ literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/process_rules_menu.png b/docs/images/screenshots/process_rules_menu.png new file mode 100644 index 0000000000000000000000000000000000000000..8033d2bf13f3ffa096589919ecfa0184e6745a91 GIT binary patch literal 4698 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 literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/process_rules_only.png b/docs/images/screenshots/process_rules_only.png new file mode 100644 index 0000000000000000000000000000000000000000..363c97562a3fd5b316e92583935ebd43f89fdbf8 GIT binary patch literal 5968 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 literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/process_rules_unsaved.png b/docs/images/screenshots/process_rules_unsaved.png new file mode 100644 index 0000000000000000000000000000000000000000..8f3b2963ee4a0e4091db22cd61269e6f11cb721a GIT binary patch literal 2610 zcmV-23eEM2P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D3CBr9K~#8N?VVpp zWY-+b`Hx#!P4_gr^=-~0Rh&eaXvy?ZwehGCc@IifxphGB|=#e-oOU$A&E4C4zH4~AiU z!Q#O%j4v#^Ejv3q*xueoI?Wp}OqM_(fXd2BR8&-`7KX_YkIl_ZoIH6FM~<*V!en{) z@FCXM*KzFFG1bB_Bpx?z+_1PAr%s(xM+}qY&Ye5zh&e12@;Cz<8ygw%xOeX!iw9$i z5RVflPN*7l7!c`;`}glVdYl}eFbrdh@I2h|pPoFAXMVA*jtcY7A6BX(=23z@kHd-3 zgyYALtC|(xo=4yFhDey7f1kb}KN*HO9F)cLc;l@ftD3>DfAX$6Vh$>9p2v@pY5et8 z056_S<7c6OYGob;cE$6!`uf9yg*iNIe_?!X?vU4c#}JH<=<`1hjAzjo&Y?2%h~U}t z@FEW1`puD&a~_L>RS3mYMG``MZ4RA5RXu>@-xJZF#MW?=suV`dF;csRxib79Qj@KS zV8V57-SfD5D~+Co02;oM#_D7<=#Pcax=(H@c&-5r=erE3BF zmpqQEw+-Q_J(y5tX&igZIDY2KX}li};H~Eac>f0h z)R2$}9w!f^?^$^$5#EMbie)KUjp}NxM3+?0?qggligH{b?>>CoiV4DgSTp;Q4HPOV!xcsxT1H%6PxQ6R za~#{fK<7rffq2Aw&LbCJYqn!Cff$8U$^IA;Zc3%`=bONl&y3^0+yZt~I!t_uKEdx& zXD}5Wwh%C2rdW&!P_VSXDyhL~5!{3kBMceUKZTOLS=oQP~$o zRD=#Wp@KZWZA#v|U07h9U(BaE2F)Z3V(8*EK9fo%>3}vv`P| zltM)?{rf+ZobyO_pU)UtXgN+#S6vvaUWj~h>V{$xJV&j|_(c4$SlRDbXS+Q}$G)NYA{oZ6kpBus^fbz{QIIZpUpa~>qJb4tWWOy}k_F>;~*IiUJ6 z;5!tSJW&NH7{B^Q0RQ?tAnPKO`I5|eWIYdmIS=E>JQjA2^M&Em&tAle844uo&{Jp`ApRSd3c z5W*9_j&XVKqVJ+SXSeVq9%B1dl%cQvQI_1gUUmb0w`I%Y7rHe1wU8%UjQC#|7}Y7v zSq=#!HS-Wo?S*K zoG$%^v0%rHG+43-`Si4k$Pz9K>{N`AJw3S`H-Gfeu;mc*P&a5i)Aw07Uu%BQHXrTyiX zWHB-8xuqOA4@aJ^Mac9pbW)#CtMW*k#t7W{bi|Wc7~gy{E$f0x5)wh`=50&9qo|yR2^s8+d~)_;UWkYpH!NMj z7=<-G^`=`cN2PVBNQ z?~eacwd?|oL(&Ur9vjtS_ugzsp_L(9H85zT(8Wkns*uIr?eIYH*Ur+2Arix}aH-qE zZfgjlV}|PVGrLZq-)?U~7bPCKISf6o;a18`)3A7%Y+1(mX8b?hZhae5j1fBunK9?5 zh0WUciSuhO7_J~a~kQ!=-uQmT4 zd9S}q7CqNde9prLJ&Agz2FA9^GzE+X!JI_NHh4X9DMl5e<2*J)dOYCnqhnPD%#=6^K?bFVeu745jHpsd27OnCU znVe1&hBNaGqe;%6O%&VxT#8=vK|>_`@^(f>v!MhT#Q=pM)+A*LQ&D5*#2FR3jLwQ| zrG3aEu$!OOG$ks&udPF#!GH+G`jjVi1~ttzXC{_eLNq+4j%_HkhNWm;xMB_AN`wEB z7~=`M->Nn97p6DiHJ{<#`w&}~VG;`+;ig+(;u71dx{WoDuV6-I2E|rwJyr*7LJ6^j zDR&~Q2}?28XpMQkfpz|7%Q?>1&PR?FFT7b6W2~_U<5-yyiBJ8W>0VcAFj~Kg0d>!X z*Qc#Ph;MyQ#&dC7n-gxo+rr|(cw%qFgV}3XJeZQ#e-oOU$A&E4C4dfe@5`? UDyadfp8x;=07*qoM6N<$f`&Zx_y7O^ literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/save_action.png b/docs/images/screenshots/save_action.png new file mode 100644 index 0000000000000000000000000000000000000000..1b02eba8b1035fbc46b9d92f06ff4218c94765a9 GIT binary patch literal 1193 zcmV;a1XlZrP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1U^YbK~!i%?V3Sr z8%G$1-&)28Uu=wRj4!rTsM~|irD5(I)? zdfP(@C5G)T$hovfgP@6HGrmk&hBZ6#sI^Sq^wUQO$XxD2u%mW`@&8&2IGTU%QgA0PLG3#&9SHa3RQ(NQHj1jr#RS}IBl7h$$q ztzvL+Pz)%-gJe@IyLihu7K_O%MOcti|Nf^kBSMty2sw4xYumr$_M^L~)tlM&x^k+r zN%Xw+HCCKQc(C@99DRK`HQ7)9{sRm4Ej-(QhVv62;?uW3mNPG>l#7YY$E#dP&YW#d zMK+0^w-)eE?O!2!{(~Ec^&F=ga!^dikc5qTz3!Dgz0POOK9S4rUNpzCV3;Wsu4{6j zfi^pf33+{%iBxtV(Zs}?NWjF}pYm}hoFdZxh)EZ{RWIVFEpnVMG+e{>t^d_MClNy2F0kdfai|Eto=0sH(e{Y#?`^R3b$Spah z3be9+eDVOLjTOeU!D81ixu6*#4MJ@%F|(Hr!-XetGLOr_0Fwd{c;~=m{|8CWBk8?<9LDse(0X|Bv)IPQ1`>&c z9O|C>VIBEj?!l_qCmS9ABg*A6CMPGwbto&_g~aObeSy#4{Y;7OK&Y|_5`6hB-g+s~ zM+jZE;>8Hr^lLEnlZtR@cPeD}_4T#<%&%Uu0RT1($<~hlke5A=-87n&iFJWCS1tfby7o`VlnwXJL(c;MWjMuU z_l+`L!SAY5AONtndF@`;hRXK<0JibWFP*mwb>j_^QTw^6fZ^nO=L)k80{q_W)Au}b zspg~ff%%UI*I!uHT^)_~-f+NAc}KZo-lyHBe_rzkZ2=v=op0`5`B3$YTmj_6$t@dg z@S`AYIdw&whl&cPLQfNk157sQ+jEMm>9$kDU0nf@-QbyeVJCR!rcIl!tdsc!*g_+7 zqSjUq4!jCozb1EFtzXm6DI8u45AbHg4%C{wE*A@4lSi5;O-)TVRwaz&N%mOQ+N<03 z5vvnA{-L2M3rf~)6qu1L>U<`Pg>7$dug4KTfFK#(DnB~-UsHp7-Rj&xGxuT6Bc1r% zHQWE%_D{;bH9g_nh|-$0_>I4oSAe=n)T&A2(lm)+3E6hx?{EELPV%jhr5Q3V8F=fi z>*DV#CAW5<&UuD7Xv5*}z7$W5U5qX@Do#9t++0dLF(Gwh5ym0_2?aUznKgSFo({Wb zT>NaR5?AQm5M+d!CQvAqokx7%CHXK6>eX2pO?GghbNOK16fCh5DQUE0S9P+L>Ug~4 z_`FK*)F(TDo@Qn%j(<#91$4%jjP^zr&x!e?VhJ}(*!ambk3DZWqIBfEVM;2NcgD!b zXu9fNrfAD+Yp)Q)j8?CX@s(!bcydk=NaYB?AdSs9d$JS_KA4nC(s7Rt-s-s*r%#F* z+mFHMCZTj&?das4$J-yX2JmqV-ORw!6D>iS?VDK{jrJOp!4#aNn8bfG7+vVy8kh4V zZt!E3k8tqK(u;^Y2D_2&4b>Ef@{rIXlwC51rhw#p&{WvlHV2m2VWa+c` zck|SjN}h}45whXd$p}~fx@#>X#hfQ0ZT4iU9rGEojSQ{(xGDube~BIn(~*8FWW7Ha z3x2bK=pTqMrH?zW?@z0E@Vb$7Ju1Ot$>IdG&)TfuO7%?3HMfkY`EZ*DkYlDpPO+QN z)kg9^nBwFTN{G)gX`i0$embH*xY;S`of~<^V1_xWz-kY_id>(~=FShmBD01(!wvcZ zY>t(5w=QA;qcaw7(=18_eySWVl0GKnLm)Gh68}S7 zcjhuGI)3b$%qw?a?{f3Ch3)C~GQp9|abv+7s$JOZ;XUQ^i6QMqaXBeneG}=XW<3=4 zz<|qr@%I=XQjp_fy4&HQ2R7g260+?&H{)Bg?KQkhRW^TOraM)R!H0J$f)Qn+N6g7G z7w;JS1V6!SLL4s_O4`2NTDKKW@8wn~Mwg#x3twqu)mO*kP}Qo-)-5C9lj;M}^9p`u zQ-o`6HbTieWSAqo*62&EcgOB{O|AEX6CT_l=MJDt=ji)_nz~b($c%>{cBZf$Aw!UI zwP2WazxGgndFg8ln8fg0Ws%l1E9bjG*m-DA;6e;=(+EQSZ)0%Nh)@V^;Z$6*1IjlCIM;{L(WGNXp1%LLm z4ND{ZIiQeyv{(zhyfpW63V{#%<#4)du|qfNA6|mOMW}0X+R{r0-J!ar-;PxtYtd<} z)Du_Wlkdua$f;q8t&Mo^`ka#7$eMI(!B+hP!h2kQ&|f zBNRDwL2;7?fB#>+NO?P8&pss3o-`OIS-!Bk>wW37==h|)gYXsKX0ui+LPs%;<+3j* zwS2yMKkIS2PGVl$Jh#wnR`q4*`eqONC-HTJ6{(^vMm%?*Whon-zK{lo9mr@!AM&~OmTDyTrolbANS9|!>%MbO zs9fGU0I_0|3SQ(}wua$3wcoxPo5`BxyCw3koIeALH%B?Up1}lK zHxwt%L9JL+$#Evp*J!$H&UaF)$oX|b1Mgw(yCl9f8#-Rp{NA_sq`T9vKIv0C)EUiD z(Vmz=gEb7FqujyM$qu@*LtLrY#mDw;UXOg=q2H6$$zO#h%;Po7lzA!CLEi7!KbRUKQOFk$rF&a=)eEhTbCb&qp4 z6l^Z!!kP6# zpQKI3CMF$Zbqzxqc^Qr?pp5grlfMQUWCQL0kmj?+##Gq>&$#)9^edOLUzDyQF*!KK z30I~mzH?nR?$r=*W}`x00?&#(b^Oa*=6Qj0{FZtkTr!$^W^ts!v1@5*K6hLN@Bo~rwht8inBlM5<2m>AkhL0K?o?(W z_c5E&>alwHd|>7yqWds~MJFcTFs}pq@Veqt#8Y{WRGEF%n*FP@LzW}W24>et4UAe7 zr)j0W1vVBBaeXSO2M714?tb7Oa&nLKOK9Wp)K3UMNnWiDEj-yOQaN3=5=jpRM{nVx zskgvpYEO{_JfLtb-VI7SL1cp++EJk{ze%LWB@2eU!o_Z(-Ggiq%91wZA3k@lO63@X`0p_Y`RWW z4+x)Tsp!o&X+f1w4dZiXZarbPVaf#J3ogKK8tGD;kUw1HY$zRMJUjf`-r-t~!8xZ0 zG^B*4v72G4S)}=z8dH@lud@IN-Fv)JYM!?=?ST*!H_PHabypkMvbae(T^gDh^|B31 z#<=11$Ps(7Q3Ra^`B-=26^nRmKBF5!H=ds`umo0&plEzIjQH4HNLnl&a%mtRdQW(Arf;k^#iDg(?97jX@VP1b)q=PRZCJWA zw&CWDSfO4#@7o|(R$|KN<$%Wx1l{gm`@X*dWfeBoyeSJ`#@=_-TwS?;jib2^aNDn&SQT^^ z;uUEky!_VbRrpPxg#|+dq+|kDjMUKXW<@+ae_x9tqW}!qUVGqS48=_E|WMDr+4YRl*JNlJV;ha0?LMj0b5I4o`{2f0A_i>)`M~EskHQ%!c21wu>%oIn9 zlj=%@3LhLlxmCP~8uv~;BfCCBG?xNa(#68>GeXlfJOcm# literal 0 HcmV?d00001 diff --git a/docs/images/screenshots/tooltips.png b/docs/images/screenshots/tooltips.png new file mode 100644 index 0000000000000000000000000000000000000000..f6079721e0045e18af62f2243856a54f889aa2ad GIT binary patch literal 4041 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 MYZ$0kJ+goGKdiy-6aWAK literal 0 HcmV?d00001 diff --git a/docs/images/sound-theme-header.png b/docs/images/sound-theme-header.png deleted file mode 100644 index 9695961ad31db74d4bfef7007d049176ee4c3223..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 791318 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⁡0L`r-Dx4mu33|K+wR@NPt?bcfb^~Fl3Q(*(GqF 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 z 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