Skip to content

Commit 382fa95

Browse files
committed
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
1 parent d67fd0d commit 382fa95

9 files changed

Lines changed: 50 additions & 49 deletions

File tree

build_portable.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from constants.app_info import APP_NAME, APP_VERSION, APP_AUTHOR, APP_NAME_WITH_VERSION
99
from constants.files import CONFIG_FILE_NAME
10+
from util.files import explore
1011

1112
# Setting paths and configuration parameters
1213
VERSION_FILE = "versionfile.txt"
@@ -52,8 +53,10 @@
5253
])
5354

5455
# Creating an archive of the built application
55-
shutil.make_archive(APP_DIST_WITH_VERSION, 'zip', APP_DIST)
56+
archive_file_path = shutil.make_archive(APP_DIST_WITH_VERSION, 'zip', APP_DIST)
5657

5758
# Copying the configuration file for tests into the built application
5859
if os.path.isfile(CONFIG_FILE_FOR_TESTS):
5960
shutil.copyfile(CONFIG_FILE_FOR_TESTS, CONFIG_FILE_IN_APP_DIST)
61+
62+
explore(archive_file_path)

src/model/service.py

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
from dataclasses import dataclass
2-
from typing import Optional
32

43

54
@dataclass
65
class Service:
76
"""
87
The Service class represents information about a Windows service.
98
10-
It includes attributes such as service process ID (pid), service name, display name, description, current status,
11-
and binary path.
9+
It includes attributes such as service process ID (pid), name and current status.
1210
"""
1311

1412
pid: int
@@ -21,22 +19,7 @@ class Service:
2119
The name of the Windows service.
2220
"""
2321

24-
display_name: str
25-
"""
26-
The display name of the Windows service.
27-
"""
28-
29-
description: Optional[str]
30-
"""
31-
A description of the Windows service. Default is None (no description available).
32-
"""
33-
3422
status: str
3523
"""
3624
The current status of the Windows service.
3725
"""
38-
39-
bin_path: str
40-
"""
41-
The binary path of the Windows service, specifying the location of the service executable.
42-
"""

src/service/processes_info_service.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import subprocess
22
from abc import ABC
3+
from typing import Optional
34

45
import psutil
56
from psutil import NoSuchProcess
@@ -12,7 +13,6 @@
1213
class ProcessesInfoService(ABC):
1314
"""
1415
The ProcessesInfoService class provides methods for retrieving information about running processes.
15-
It is an abstract base class (ABC) to be subclassed by specific implementation classes.
1616
"""
1717

1818
_cache: dict[int, Process] = {}
@@ -27,7 +27,7 @@ def get_processes(cls) -> dict[int, Process]:
2727
"""
2828

2929
cache = cls._cache
30-
services = ServicesInfoService.get_services()
30+
services: Optional[dict] = None
3131
pids = set(psutil.pids())
3232

3333
for pid in pids:
@@ -48,6 +48,9 @@ def get_processes(cls) -> dict[int, Process]:
4848
process.is_new = False
4949
continue
5050

51+
if services is None:
52+
services = ServicesInfoService.get_running_services()
53+
5154
service = services.get(pid)
5255
info = process_info.as_dict(attrs=[
5356
'name', 'exe', 'cmdline',

src/service/rules_service.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
class RulesService(ABC):
2525
"""
2626
The RulesService class provides methods for applying rules to processes and services.
27-
It is an abstract base class (ABC) to be subclassed by specific implementation classes.
2827
"""
2928

3029
__ignore_pids: set[int] = {0, os.getpid()}

src/service/services_info_service.py

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from psutil import STATUS_STOPPED, NoSuchProcess, ZombieProcess, AccessDenied
55
from psutil._pswindows import WindowsService
66

7-
from constants.log import LOG
87
from model.service import Service
98
from util.decorators import suppress_exception
109

@@ -23,37 +22,48 @@
2322

2423
class ServicesInfoService(ABC):
2524
"""
26-
The ServicesInfoService class provides methods for retrieving information about running services.
27-
It is an abstract base class (ABC) to be subclassed by specific implementation classes.
25+
The ServicesInfoService class provides methods for retrieving information about Windows services.
2826
"""
2927

3028
@staticmethod
31-
def get_services() -> dict[int, Service]:
32-
"""
33-
Get a dictionary of running services and their information.
34-
35-
Returns:
36-
dict[int, Service]: A dictionary where keys are process IDs (pids) and values are Service objects
37-
representing the running services.
38-
"""
29+
def get_running_services() -> dict[int, Service]:
3930
result: dict[int, Service] = {}
4031

4132
for service in psutil.win_service_iter():
4233
try:
43-
info = service.as_dict()
34+
# noinspection PyUnresolvedReferences
35+
info = service._query_status()
36+
status = info['status']
37+
pid = info['pid']
4438

45-
if info['status'] == STATUS_STOPPED:
39+
if pid == STATUS_STOPPED:
4640
continue
4741

48-
result[info['pid']] = Service(
49-
info['pid'],
50-
info['name'],
51-
info['display_name'],
52-
info['description'],
53-
info['status'],
54-
info['binpath']
42+
result[pid] = Service(
43+
pid,
44+
service.name(),
45+
status
5546
)
5647
except NoSuchProcess:
57-
LOG.warning(f"No such service: {service.name}")
48+
pass
49+
50+
return result
51+
52+
@staticmethod
53+
def get_services() -> list[Service]:
54+
result: list[Service] = []
55+
56+
for service in psutil.win_service_iter():
57+
try:
58+
# noinspection PyUnresolvedReferences
59+
info = service._query_status()
60+
61+
result.append(Service(
62+
info['pid'],
63+
service.name(),
64+
info['status']
65+
))
66+
except NoSuchProcess:
67+
pass
5868

5969
return result

src/ui/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def __init__(self):
4141
def _after_init(self):
4242
self._setup_tooltips()
4343
self._setup_binds()
44+
4445
self._tabs.load_data()
4546

4647
def _setup_window(self):
@@ -355,6 +356,7 @@ def settings():
355356

356357
try:
357358
__app = Settings()
359+
__app.after_idle(__app.to_front)
358360
__app.mainloop()
359361
finally:
360362
__app = None

src/ui/widget/settings/tabs/processes/process_tab.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,16 @@ def _update_process_list(self):
8282
LOG.exception("Update process list error")
8383

8484
def _refresh(self):
85-
LOG.info("Refreshing process list...")
86-
8785
def update_process_list():
88-
LOG.info("Updating process list...")
86+
# LOG.info("Updating process list...")
8987

9088
try:
9189
self._update_process_list()
9290
finally:
9391
self._refresh_state()
9492

9593
def load_data():
96-
LOG.info("Loading data...")
94+
# LOG.info("Loading data...")
9795

9896
try:
9997
self.process_list.set_data(ProcessesInfoService.get_processes())

src/ui/widget/settings/tabs/rules/rules_list.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,11 @@ def _show_context_menu(self, event):
8888
context_menu = self._context_menu
8989
process_list = self
9090
row_id = process_list.identify_row(event.y)
91+
selected_items = process_list.selection()
9192

9293
if row_id:
93-
process_list.selection_set(row_id)
94+
if selected_items and len(selected_items) == 1:
95+
process_list.selection_set(row_id)
9496
context_menu.post(event.x_root, event.y_root)
9597

9698
def _errors(self) -> dict[Any, Any]:

src/util/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ def get_values_from_enum(annotation):
161161
return values
162162

163163

164-
def get_icon_from_exe(exe_path, icon_index=0, large=False, try_load_another_if_absent=True):
164+
@cache
165+
def get_icon_from_exe(exe_path, icon_index=0, large=False):
165166
if large:
166167
icon_size = (
167168
win32api.GetSystemMetrics(win32con.SM_CXICON),

0 commit comments

Comments
 (0)