forked from OneDragon-Anything/ZenlessZoneZero-OneDragon
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstandalone_app_run_interface.py
More file actions
232 lines (189 loc) · 8.67 KB
/
Copy pathstandalone_app_run_interface.py
File metadata and controls
232 lines (189 loc) · 8.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
from __future__ import annotations
import contextlib
from PySide6.QtCore import QSize, Qt, QCollator, QLocale
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QAbstractItemView, QHBoxLayout, QListWidgetItem, QWidget
from qfluentwidgets import (
FluentIcon,
FluentIconBase,
MessageBoxBase,
PrimaryPushButton,
SubtitleLabel,
getFont,
)
import locale
from one_dragon.base.operation.application import application_const
from one_dragon.base.operation.one_dragon_context import OneDragonContext
from one_dragon.utils.i18_utils import gt
from one_dragon_qt.view.app_run_interface import SplitAppRunInterface
from one_dragon_qt.widgets.column import Column
from one_dragon_qt.widgets.multi_select_list import MultiSelectListWidget
from one_dragon_qt.widgets.selectable_app_list import SelectableAppList
from one_dragon_qt.windows.main_app_window_base import MainAppWindowBase
class StandaloneRunInterface(SplitAppRunInterface):
"""独立应用运行界面基类
左侧为用户手动添加的应用卡片列表,
右侧为标准的运行/停止/日志控件。
选中某个应用后,点击"开始"即运行该应用。
"""
def __init__(self, ctx: OneDragonContext,
object_name: str = 'standalone_run_interface',
nav_text_cn: str = '运行',
nav_icon: FluentIconBase | QIcon | str = FluentIcon.PLAY,
parent: QWidget | None = None):
self.ctx: OneDragonContext = ctx
SplitAppRunInterface.__init__(
self,
ctx=ctx,
app_id='',
object_name=object_name,
nav_text_cn=nav_text_cn,
nav_icon=nav_icon,
parent=parent,
left_stretch=1,
right_stretch=1,
)
self.all_apps: list[[str, str]] = []
def get_left_widget(self) -> QWidget:
left = Column(spacing=4)
self.app_list_widget = SelectableAppList()
self.app_list_widget.app_selected.connect(self._on_app_selected)
self.app_list_widget.app_removed.connect(self._on_app_removed)
self.app_list_widget.app_setting_clicked.connect(self._on_app_setting_clicked)
self.app_list_widget.app_order_changed.connect(self._on_app_order_changed)
left.add_widget(self.app_list_widget, alignment=Qt.AlignmentFlag(0))
self.add_app_btn = PrimaryPushButton(
text=gt('添加应用'), icon=FluentIcon.ADD
)
self.add_app_btn.clicked.connect(self._on_add_app_clicked)
btn_container = QWidget()
btn_layout = QHBoxLayout(btn_container)
btn_layout.setContentsMargins(0, 0, 16, 0)
btn_layout.addWidget(self.add_app_btn)
left.add_widget(btn_container, alignment=Qt.AlignmentFlag(0))
left.add_stretch(1)
return left
def on_interface_shown(self) -> None:
SplitAppRunInterface.on_interface_shown(self)
self._refresh_app_list()
# AppSettingManager 可能尚未就绪,监听信号以在就绪后刷新
window = self.window()
if isinstance(window, MainAppWindowBase):
window.app_setting_manager.ready.connect(self._update_setting_btn_visibility)
def on_interface_hidden(self) -> None:
SplitAppRunInterface.on_interface_hidden(self)
window = self.window()
if isinstance(window, MainAppWindowBase):
with contextlib.suppress(RuntimeError):
window.app_setting_manager.ready.disconnect(self._update_setting_btn_visibility)
# ── 应用列表管理 ──
def _get_all_apps(self) -> list[[str, str]]:
"""获取所有已注册的默认组应用, 并按拼音排序 {app_id: app_name}"""
if len(self.all_apps) > 0:
return self.all_apps
all_apps: list[[str, str]] = []
for app_id in self.ctx.run_context.default_group_apps:
name = self.ctx.run_context.get_application_name(app_id)
all_apps.append([app_id, name or app_id])
# 按拼音排序以便查找
_old_collate = locale.getlocale(locale.LC_COLLATE)
try:
locale.setlocale(locale.LC_COLLATE, "zh_CN.UTF-8")
except locale.Error:
locale.setlocale(locale.LC_COLLATE, "")
try:
all_apps.sort(key=lambda x: locale.strxfrm(x[1]))
finally:
locale.setlocale(locale.LC_COLLATE, _old_collate)
self.all_apps = all_apps
return all_apps
def _refresh_app_list(self) -> None:
"""刷新应用列表"""
all_apps: list = self._get_all_apps()
config = self.ctx.standalone_app_config
app_list = [aid for aid in all_apps if len([item for item in config.app_list if item == aid[0]]) > 0]
valid_ids = [aid[0] for aid in app_list]
self.app_list_widget.set_app_list(app_list)
self._update_setting_btn_visibility()
active_id = config.active_app_id
if active_id and active_id in valid_ids:
target = active_id
elif valid_ids:
target = valid_ids[0]
else:
target = None
if target:
self.app_list_widget.select_app(target)
self.app_id = target or ''
self.ctx.standalone_app_config.active_app_id = target or ''
# ── 事件处理 ──
def _on_app_selected(self, app_id: str) -> None:
self.app_id = app_id
self.ctx.standalone_app_config.active_app_id = app_id
def _on_app_removed(self, app_id: str) -> None:
self.ctx.standalone_app_config.app_list = self.app_list_widget.app_ids
def _on_app_order_changed(self, app_ids: list[str]) -> None:
self.ctx.standalone_app_config.app_list = app_ids
def _on_add_app_clicked(self) -> None:
all_apps = self._get_all_apps()
existing_ids = set(self.app_list_widget.app_ids)
available = [[aid, name] for aid, name in all_apps if aid not in existing_ids]
if not available:
return
dialog = AddAppDialog(available, self.window())
if dialog.exec():
selected_ids = dialog.get_selected_ids()
for app_id in selected_ids:
self.app_list_widget.add_app(app_id, [item[1] for item in all_apps if item[0] == app_id][0])
self._update_setting_btn_visibility()
self.ctx.standalone_app_config.app_list = self.app_list_widget.app_ids
def _on_app_setting_clicked(self, app_id: str) -> None:
window = self.window()
if not isinstance(window, MainAppWindowBase):
return
target = self._find_setting_btn(app_id) or self.add_app_btn
window.app_setting_manager.show_app_setting(
app_id=app_id,
parent=self,
group_id=application_const.DEFAULT_GROUP_ID,
target=target,
)
def _find_setting_btn(self, app_id: str) -> QWidget | None:
"""找到对应 app_id 的卡片上的设置按钮"""
for card in self.app_list_widget._cards:
if card.app_id == app_id:
return card.setting_btn
return None
def _update_setting_btn_visibility(self) -> None:
"""根据 app_setting_manager 的注册信息,显示或隐藏卡片的设置按钮"""
window = self.window()
if not isinstance(window, MainAppWindowBase):
return
settable = window.app_setting_manager.settable_app_ids
for card in self.app_list_widget._cards:
card.setting_btn.setVisible(card.app_id in settable)
class AddAppDialog(MessageBoxBase):
"""添加应用对话框"""
def __init__(self, available_apps: list[[str, str]], parent: QWidget):
super().__init__(parent=parent)
self.titleLabel = SubtitleLabel(gt('添加应用'))
self.viewLayout.addWidget(self.titleLabel)
self.viewLayout.addSpacing(10)
self.available_apps = available_apps
self._list_widget = MultiSelectListWidget()
self._list_widget.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
self._list_widget.setViewportMargins(0, 0, 16, 0)
self._list_widget.setMinimumHeight(400)
self._list_widget.setMinimumWidth(480)
item_font = getFont(16)
for _, app_name in available_apps:
item = QListWidgetItem(gt(app_name))
item.setSizeHint(QSize(0, 36))
item.setFont(item_font)
self._list_widget.addItem(item)
self.viewLayout.addWidget(self._list_widget)
self.yesButton.setText(gt('确定'))
self.cancelButton.setText(gt('取消'))
def get_selected_ids(self) -> list[str]:
selected_rows = {idx.row() for idx in self._list_widget.selectedIndexes()}
return [self.available_apps[i][0] for i in sorted(selected_rows)]