pygpt-net 2.6.66__py3-none-any.whl → 2.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pygpt_net/CHANGELOG.txt +18 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/assistant/assistant.py +13 -8
- pygpt_net/controller/assistant/batch.py +29 -15
- pygpt_net/controller/assistant/files.py +19 -14
- pygpt_net/controller/assistant/store.py +63 -41
- pygpt_net/controller/attachment/attachment.py +45 -35
- pygpt_net/controller/chat/attachment.py +50 -39
- pygpt_net/controller/config/field/dictionary.py +26 -14
- pygpt_net/controller/config/field/textarea.py +2 -2
- pygpt_net/controller/ctx/common.py +27 -17
- pygpt_net/controller/ctx/ctx.py +182 -101
- pygpt_net/controller/dialogs/info.py +2 -2
- pygpt_net/controller/files/files.py +101 -41
- pygpt_net/controller/idx/indexer.py +87 -31
- pygpt_net/controller/kernel/kernel.py +13 -2
- pygpt_net/controller/media/media.py +29 -1
- pygpt_net/controller/mode/mode.py +3 -3
- pygpt_net/controller/model/editor.py +141 -21
- pygpt_net/controller/model/importer.py +153 -54
- pygpt_net/controller/painter/painter.py +2 -2
- pygpt_net/controller/presets/experts.py +68 -15
- pygpt_net/controller/presets/presets.py +72 -36
- pygpt_net/controller/settings/editor.py +25 -1
- pygpt_net/controller/settings/profile.py +76 -35
- pygpt_net/controller/settings/workdir.py +70 -39
- pygpt_net/core/assistants/files.py +20 -18
- pygpt_net/core/filesystem/actions.py +111 -10
- pygpt_net/core/filesystem/filesystem.py +2 -1
- pygpt_net/core/idx/idx.py +12 -11
- pygpt_net/core/idx/worker.py +13 -1
- pygpt_net/core/models/models.py +4 -4
- pygpt_net/core/profile/profile.py +13 -3
- pygpt_net/core/types/image.py +10 -1
- pygpt_net/core/video/video.py +43 -3
- pygpt_net/data/config/config.json +3 -3
- pygpt_net/data/config/models.json +25 -14
- pygpt_net/data/css/style.dark.css +39 -1
- pygpt_net/data/css/style.light.css +39 -1
- pygpt_net/data/locale/locale.de.ini +4 -1
- pygpt_net/data/locale/locale.en.ini +4 -1
- pygpt_net/data/locale/locale.es.ini +4 -1
- pygpt_net/data/locale/locale.fr.ini +4 -1
- pygpt_net/data/locale/locale.it.ini +4 -1
- pygpt_net/data/locale/locale.pl.ini +5 -2
- pygpt_net/data/locale/locale.uk.ini +4 -1
- pygpt_net/data/locale/locale.zh.ini +4 -1
- pygpt_net/item/model.py +1 -1
- pygpt_net/provider/api/openai/__init__.py +4 -2
- pygpt_net/provider/api/openai/video.py +2 -2
- pygpt_net/provider/core/config/patch.py +9 -1
- pygpt_net/provider/core/model/patch.py +26 -1
- pygpt_net/tools/image_viewer/tool.py +17 -0
- pygpt_net/tools/text_editor/tool.py +9 -0
- pygpt_net/ui/__init__.py +2 -2
- pygpt_net/ui/dialog/models.py +10 -1
- pygpt_net/ui/layout/ctx/ctx_list.py +16 -6
- pygpt_net/ui/layout/toolbox/video.py +14 -6
- pygpt_net/ui/main.py +3 -1
- pygpt_net/ui/widget/calendar/select.py +3 -3
- pygpt_net/ui/widget/filesystem/explorer.py +1082 -142
- pygpt_net/ui/widget/lists/assistant.py +185 -24
- pygpt_net/ui/widget/lists/assistant_store.py +245 -42
- pygpt_net/ui/widget/lists/attachment.py +230 -47
- pygpt_net/ui/widget/lists/attachment_ctx.py +189 -33
- pygpt_net/ui/widget/lists/base_list_combo.py +2 -2
- pygpt_net/ui/widget/lists/context.py +1253 -70
- pygpt_net/ui/widget/lists/experts.py +110 -8
- pygpt_net/ui/widget/lists/model_editor.py +217 -14
- pygpt_net/ui/widget/lists/model_importer.py +125 -6
- pygpt_net/ui/widget/lists/preset.py +460 -71
- pygpt_net/ui/widget/lists/profile.py +149 -27
- pygpt_net/ui/widget/lists/uploaded.py +230 -38
- pygpt_net/ui/widget/option/combo.py +1046 -32
- pygpt_net/ui/widget/option/dictionary.py +35 -7
- pygpt_net/ui/widget/option/input.py +3 -1
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/METADATA +20 -57
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/RECORD +81 -81
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/entry_points.txt +0 -0
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.
|
|
9
|
+
# Updated Date: 2025.12.27 21:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
+
from PySide6 import QtCore
|
|
13
|
+
|
|
12
14
|
from pygpt_net.core.types import (
|
|
13
15
|
MODE_EXPERT,
|
|
14
16
|
)
|
|
@@ -23,6 +25,8 @@ class Experts:
|
|
|
23
25
|
:param window: Window instance
|
|
24
26
|
"""
|
|
25
27
|
self.window = window
|
|
28
|
+
self.selected_available_uuids = [] # multi-selected available experts
|
|
29
|
+
self.selected_selected_uuids = [] # multi-selected selected experts
|
|
26
30
|
|
|
27
31
|
def refresh(self):
|
|
28
32
|
"""Refresh presets"""
|
|
@@ -78,13 +82,43 @@ class Experts:
|
|
|
78
82
|
|
|
79
83
|
self.update_tab()
|
|
80
84
|
|
|
85
|
+
def _selected_uuids_from_view(self, node_id: str, fallback_idx_resolver) -> list[str]:
|
|
86
|
+
"""
|
|
87
|
+
Resolve selected expert UUIDs from a given list view using stored tooltip role,
|
|
88
|
+
falling back to idx -> uuid resolver when needed.
|
|
89
|
+
|
|
90
|
+
:param node_id: ui node id
|
|
91
|
+
:param fallback_idx_resolver: callable that maps row index -> uuid
|
|
92
|
+
:return: list of selected uuids
|
|
93
|
+
"""
|
|
94
|
+
uuids = []
|
|
95
|
+
try:
|
|
96
|
+
view = self.window.ui.nodes[node_id]
|
|
97
|
+
sel_model = view.selectionModel()
|
|
98
|
+
rows = sel_model.selectedRows() if sel_model else []
|
|
99
|
+
for ix in rows:
|
|
100
|
+
uuid = ix.data(QtCore.Qt.ToolTipRole)
|
|
101
|
+
if not uuid:
|
|
102
|
+
uuid = fallback_idx_resolver(ix.row())
|
|
103
|
+
if uuid and uuid not in uuids:
|
|
104
|
+
uuids.append(uuid)
|
|
105
|
+
except Exception:
|
|
106
|
+
pass
|
|
107
|
+
return uuids
|
|
108
|
+
|
|
81
109
|
def change_available(self):
|
|
82
|
-
"""Change selected expert"""
|
|
83
|
-
|
|
110
|
+
"""Change selected expert(s) in available list"""
|
|
111
|
+
self.selected_available_uuids = self._selected_uuids_from_view(
|
|
112
|
+
"preset.experts.available",
|
|
113
|
+
self.get_available_by_idx
|
|
114
|
+
)
|
|
84
115
|
|
|
85
116
|
def change_selected(self):
|
|
86
|
-
"""Change selected expert"""
|
|
87
|
-
|
|
117
|
+
"""Change selected expert(s) in selected list"""
|
|
118
|
+
self.selected_selected_uuids = self._selected_uuids_from_view(
|
|
119
|
+
"preset.experts.selected",
|
|
120
|
+
self.get_selected_by_idx
|
|
121
|
+
)
|
|
88
122
|
|
|
89
123
|
def get_current_available(self) -> str:
|
|
90
124
|
"""
|
|
@@ -138,27 +172,47 @@ class Experts:
|
|
|
138
172
|
i += 1
|
|
139
173
|
|
|
140
174
|
def add_expert(self):
|
|
141
|
-
"""Add expert"""
|
|
175
|
+
"""Add expert(s)"""
|
|
142
176
|
agent_uuid = self.get_current_agent_id()
|
|
143
177
|
if agent_uuid is None or not self.window.core.presets.exists_uuid(agent_uuid):
|
|
144
178
|
self.window.controller.presets.editor.save(close=False)
|
|
145
179
|
return
|
|
146
|
-
|
|
147
|
-
|
|
180
|
+
|
|
181
|
+
uuids = self.selected_available_uuids[:]
|
|
182
|
+
if not uuids:
|
|
183
|
+
one = self.get_current_available()
|
|
184
|
+
if one:
|
|
185
|
+
uuids = [one]
|
|
186
|
+
|
|
187
|
+
if not uuids:
|
|
148
188
|
return
|
|
149
|
-
|
|
189
|
+
|
|
190
|
+
for expert_uuid in uuids:
|
|
191
|
+
if expert_uuid and not self.is_active(expert_uuid):
|
|
192
|
+
self.window.core.presets.add_expert(agent_uuid, expert_uuid)
|
|
193
|
+
|
|
150
194
|
self.update_list()
|
|
151
195
|
|
|
152
196
|
def remove_expert(self):
|
|
153
|
-
"""Remove expert"""
|
|
197
|
+
"""Remove expert(s)"""
|
|
154
198
|
agent_uuid = self.get_current_agent_id()
|
|
155
199
|
if agent_uuid is None or not self.window.core.presets.exists_uuid(agent_uuid):
|
|
156
200
|
self.window.controller.presets.editor.save(close=False)
|
|
157
201
|
return
|
|
158
|
-
|
|
159
|
-
|
|
202
|
+
|
|
203
|
+
uuids = self.selected_selected_uuids[:]
|
|
204
|
+
if not uuids:
|
|
205
|
+
one = self.get_current_selected()
|
|
206
|
+
if one:
|
|
207
|
+
uuids = [one]
|
|
208
|
+
|
|
209
|
+
if not uuids:
|
|
160
210
|
return
|
|
161
|
-
|
|
211
|
+
|
|
212
|
+
for expert_uuid in uuids:
|
|
213
|
+
if expert_uuid and self.is_active(expert_uuid):
|
|
214
|
+
self.window.core.presets.remove_expert(agent_uuid, expert_uuid)
|
|
215
|
+
|
|
162
216
|
self.update_list()
|
|
163
217
|
|
|
164
218
|
def update_tab(self):
|
|
@@ -174,5 +228,4 @@ class Experts:
|
|
|
174
228
|
if num == 0:
|
|
175
229
|
tabs.setTabText(idx, trans("preset.tab.experts"))
|
|
176
230
|
else:
|
|
177
|
-
tabs.setTabText(idx, trans("preset.tab.experts") + f" ({num})")
|
|
178
|
-
|
|
231
|
+
tabs.setTabText(idx, trans("preset.tab.experts") + f" ({num})")
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.12.
|
|
9
|
+
# Updated Date: 2025.12.27 21:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import re
|
|
13
|
-
from typing import Optional, List, Dict
|
|
13
|
+
from typing import Optional, List, Dict, Union
|
|
14
14
|
|
|
15
15
|
from PySide6.QtCore import QTimer
|
|
16
16
|
from PySide6.QtGui import QTextCursor
|
|
@@ -536,25 +536,39 @@ class Presets:
|
|
|
536
536
|
"""
|
|
537
537
|
return _FILENAME_SANITIZE_RE.sub('_', name.lower())
|
|
538
538
|
|
|
539
|
-
def duplicate(self, idx: Optional[int] = None):
|
|
539
|
+
def duplicate(self, idx: Optional[Union[int, list]] = None):
|
|
540
540
|
"""
|
|
541
541
|
Duplicate preset
|
|
542
542
|
|
|
543
|
-
:param idx: preset
|
|
543
|
+
:param idx: preset ID (or list of IDs)
|
|
544
544
|
"""
|
|
545
|
-
if idx
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
545
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
546
|
+
last_id = None
|
|
547
|
+
updated = False
|
|
548
|
+
w = self.window
|
|
549
|
+
mode = w.core.config.get('mode')
|
|
550
|
+
for idx in ids:
|
|
551
|
+
if idx is not None:
|
|
552
|
+
if len(ids) > 1:
|
|
553
|
+
preset = w.core.presets.get_by_id(mode, idx) # by ID, PresetItem
|
|
554
|
+
preset_id = preset.filename if preset else None
|
|
555
|
+
else:
|
|
556
|
+
preset = w.core.presets.get_by_idx(idx, mode) # by index, str
|
|
557
|
+
preset_id = preset
|
|
558
|
+
if preset_id:
|
|
559
|
+
new_id = w.core.presets.duplicate(preset_id)
|
|
560
|
+
last_id = new_id
|
|
561
|
+
updated = True
|
|
562
|
+
|
|
563
|
+
if updated:
|
|
564
|
+
self.update_list()
|
|
565
|
+
self.refresh(no_scroll=True)
|
|
566
|
+
if len(ids) == 1 and idx is not None:
|
|
567
|
+
idx = w.core.presets.get_idx_by_id(mode, last_id)
|
|
568
|
+
self.editor.edit(idx)
|
|
569
|
+
self.select(idx) # switch to the new preset if only one was duplicated
|
|
570
|
+
w.update_status(trans('status.preset.duplicated'))
|
|
571
|
+
|
|
558
572
|
|
|
559
573
|
def enable(self, idx: Optional[int] = None):
|
|
560
574
|
"""
|
|
@@ -654,30 +668,49 @@ class Presets:
|
|
|
654
668
|
|
|
655
669
|
def delete(
|
|
656
670
|
self,
|
|
657
|
-
idx: Optional[int] = None,
|
|
671
|
+
idx: Optional[Union[int, list]] = None,
|
|
658
672
|
force: bool = False
|
|
659
673
|
):
|
|
660
674
|
"""
|
|
661
675
|
Delete preset
|
|
662
676
|
|
|
663
|
-
:param idx: preset index (row index)
|
|
677
|
+
:param idx: preset index (row index) or list of indices
|
|
664
678
|
:param force: force delete without confirmation
|
|
665
679
|
"""
|
|
666
|
-
if idx
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
680
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
681
|
+
w = self.window
|
|
682
|
+
mode = w.core.config.get('mode')
|
|
683
|
+
is_preset = False
|
|
684
|
+
updated = False
|
|
685
|
+
for tmp_id in ids:
|
|
686
|
+
if len(ids) > 1:
|
|
687
|
+
preset = w.core.presets.get_by_id(mode, tmp_id) # by ID, PresetItem
|
|
688
|
+
else:
|
|
689
|
+
preset = w.core.presets.get_by_idx(tmp_id, mode) # by index, str
|
|
690
|
+
if preset:
|
|
691
|
+
is_preset = True
|
|
692
|
+
break
|
|
693
|
+
|
|
694
|
+
if ids and is_preset:
|
|
695
|
+
if not force:
|
|
696
|
+
w.ui.dialogs.confirm(
|
|
697
|
+
type='preset_delete',
|
|
698
|
+
id=idx,
|
|
699
|
+
msg=trans('confirm.preset.delete'),
|
|
700
|
+
)
|
|
701
|
+
return
|
|
702
|
+
|
|
703
|
+
# Determine neighbor only if the deleted preset is currently active.
|
|
704
|
+
# This keeps API semantics untouched and prevents unexpected selection changes.
|
|
705
|
+
for idx in ids:
|
|
706
|
+
if len(ids) > 1:
|
|
707
|
+
preset = w.core.presets.get_by_id(mode, idx) # by ID, PresetItem
|
|
708
|
+
preset_id = preset.filename if preset else None
|
|
709
|
+
else:
|
|
710
|
+
preset = w.core.presets.get_by_idx(idx, mode) # by index, str
|
|
711
|
+
preset_id = preset
|
|
712
|
+
if not preset:
|
|
713
|
+
continue
|
|
681
714
|
is_current = (preset_id == w.core.config.get('preset'))
|
|
682
715
|
target_id = None
|
|
683
716
|
if is_current:
|
|
@@ -700,8 +733,11 @@ class Presets:
|
|
|
700
733
|
w.core.config.set('preset', None)
|
|
701
734
|
w.ui.nodes['preset.prompt'].setPlainText("")
|
|
702
735
|
|
|
703
|
-
|
|
704
|
-
|
|
736
|
+
updated = True
|
|
737
|
+
|
|
738
|
+
if updated:
|
|
739
|
+
self.refresh(no_scroll=True)
|
|
740
|
+
w.update_status(trans('status.preset.deleted'))
|
|
705
741
|
|
|
706
742
|
def restore(self, force: bool = False):
|
|
707
743
|
"""
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.
|
|
9
|
+
# Updated Date: 2025.12.26 12:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -206,6 +206,30 @@ class Editor:
|
|
|
206
206
|
if self.config_changed('access.shortcuts'):
|
|
207
207
|
self.window.setup_global_shortcuts()
|
|
208
208
|
|
|
209
|
+
# video: resolution
|
|
210
|
+
if self.config_changed('video.resolution'):
|
|
211
|
+
value = self.window.core.config.get('video.resolution')
|
|
212
|
+
self.window.core.config.set('video.resolution', value)
|
|
213
|
+
option = self.window.core.video.get_resolution_option()
|
|
214
|
+
self.window.controller.config.apply_value(
|
|
215
|
+
parent_id='global',
|
|
216
|
+
key='video.resolution',
|
|
217
|
+
option=option,
|
|
218
|
+
value=str(value),
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# video: duration
|
|
222
|
+
if self.config_changed('video.duration'):
|
|
223
|
+
value = self.window.core.config.get('video.duration')
|
|
224
|
+
self.window.core.config.set('video.duration', value)
|
|
225
|
+
option = self.window.core.video.get_duration_option()
|
|
226
|
+
self.window.controller.config.apply_value(
|
|
227
|
+
parent_id='global',
|
|
228
|
+
key='video.duration',
|
|
229
|
+
option=option,
|
|
230
|
+
value=int(value) or 8,
|
|
231
|
+
)
|
|
232
|
+
|
|
209
233
|
# update ENV
|
|
210
234
|
self.window.core.config.setup_env()
|
|
211
235
|
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.
|
|
9
|
+
# Updated Date: 2025.12.28 04:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
from typing import Optional, Dict, Any
|
|
14
|
+
from typing import Optional, Dict, Any, Union
|
|
15
15
|
|
|
16
16
|
from PySide6.QtCore import Slot, QTimer
|
|
17
17
|
from PySide6.QtGui import QAction
|
|
@@ -173,6 +173,8 @@ class Profile:
|
|
|
173
173
|
self.setup()
|
|
174
174
|
self.initialized = True
|
|
175
175
|
if not self.dialog or force:
|
|
176
|
+
self.update_menu()
|
|
177
|
+
self.update_list()
|
|
176
178
|
self.window.ui.dialogs.open(
|
|
177
179
|
'profile.editor',
|
|
178
180
|
width=self.width,
|
|
@@ -336,18 +338,26 @@ class Profile:
|
|
|
336
338
|
uuid = self.get_id_by_idx(idx)
|
|
337
339
|
self.switch(uuid)
|
|
338
340
|
|
|
339
|
-
def delete_by_idx(self, idx: int, force: bool = False):
|
|
341
|
+
def delete_by_idx(self, idx: Union[int, list], force: bool = False):
|
|
340
342
|
"""
|
|
341
343
|
Delete profile by index
|
|
342
344
|
|
|
343
|
-
:param idx: profile index
|
|
345
|
+
:param idx: profile index or list of indexes
|
|
344
346
|
:param force: force delete
|
|
345
347
|
"""
|
|
346
|
-
|
|
348
|
+
uuids = []
|
|
349
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
350
|
+
for i in ids:
|
|
351
|
+
uuid = self.get_id_by_idx(i)
|
|
352
|
+
uuids.append(uuid)
|
|
347
353
|
current = self.window.core.config.profile.get_current()
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
354
|
+
for uuid in list(uuids):
|
|
355
|
+
if uuid == current:
|
|
356
|
+
if len(uuids) == 1:
|
|
357
|
+
self.window.ui.dialogs.alert(trans("dialog.profile.alert.delete.current"))
|
|
358
|
+
return
|
|
359
|
+
else:
|
|
360
|
+
uuids.remove(uuid) # skip current
|
|
351
361
|
if not force:
|
|
352
362
|
self.window.ui.dialogs.confirm(
|
|
353
363
|
type='profile.delete',
|
|
@@ -355,35 +365,48 @@ class Profile:
|
|
|
355
365
|
msg=trans('confirm.profile.delete'),
|
|
356
366
|
)
|
|
357
367
|
return
|
|
358
|
-
self.delete(
|
|
368
|
+
self.delete(uuids)
|
|
359
369
|
|
|
360
|
-
def delete(self, uuid: str):
|
|
370
|
+
def delete(self, uuid: Union[str, list]):
|
|
361
371
|
"""
|
|
362
372
|
Delete profile (remove only)
|
|
363
373
|
|
|
364
|
-
:param uuid: profile ID
|
|
374
|
+
:param uuid: profile ID or list of IDs
|
|
365
375
|
"""
|
|
366
376
|
profiles = self.get_profiles()
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
if
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
self.
|
|
377
|
+
updated = False
|
|
378
|
+
ids = uuid if isinstance(uuid, list) else [uuid]
|
|
379
|
+
for uuid in ids:
|
|
380
|
+
if uuid in profiles:
|
|
381
|
+
profile = profiles[uuid]
|
|
382
|
+
name = profile['name']
|
|
383
|
+
if self.window.core.config.profile.remove(uuid):
|
|
384
|
+
updated = True
|
|
385
|
+
self.window.update_status(trans("dialog.profile.status.removed") + ": " + name)
|
|
386
|
+
if updated:
|
|
387
|
+
self.update_list()
|
|
388
|
+
self.update_menu()
|
|
374
389
|
|
|
375
|
-
def delete_all_by_idx(self, idx: int, force: bool = False):
|
|
390
|
+
def delete_all_by_idx(self, idx: Union[int, list], force: bool = False):
|
|
376
391
|
"""
|
|
377
392
|
Delete profile with files by index
|
|
378
393
|
|
|
379
|
-
:param idx: profile index
|
|
394
|
+
:param idx: profile index or list of indexes
|
|
380
395
|
:param force: force delete
|
|
381
396
|
"""
|
|
382
|
-
|
|
397
|
+
uuids = []
|
|
398
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
399
|
+
for i in ids:
|
|
400
|
+
uuid = self.get_id_by_idx(i)
|
|
401
|
+
uuids.append(uuid)
|
|
383
402
|
current = self.window.core.config.profile.get_current()
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
403
|
+
for uuid in list(uuids):
|
|
404
|
+
if uuid == current:
|
|
405
|
+
if len(uuids) == 1:
|
|
406
|
+
self.window.ui.dialogs.alert(trans("dialog.profile.alert.delete.current"))
|
|
407
|
+
return
|
|
408
|
+
else:
|
|
409
|
+
uuids.remove(uuid) # skip current
|
|
387
410
|
if not force:
|
|
388
411
|
self.window.ui.dialogs.confirm(
|
|
389
412
|
type='profile.delete.all',
|
|
@@ -391,7 +414,7 @@ class Profile:
|
|
|
391
414
|
msg=trans('confirm.profile.delete_all'),
|
|
392
415
|
)
|
|
393
416
|
return
|
|
394
|
-
self.delete_all(
|
|
417
|
+
self.delete_all(uuids)
|
|
395
418
|
|
|
396
419
|
def duplicate_by_idx(self, idx: int):
|
|
397
420
|
"""
|
|
@@ -416,13 +439,20 @@ class Profile:
|
|
|
416
439
|
dialog.prepare()
|
|
417
440
|
dialog.show()
|
|
418
441
|
|
|
419
|
-
def delete_all(self, uuid: str):
|
|
442
|
+
def delete_all(self, uuid: Union[str, list]):
|
|
420
443
|
"""
|
|
421
444
|
Delete profile with files
|
|
422
445
|
|
|
423
|
-
:param uuid: profile ID
|
|
446
|
+
:param uuid: profile ID or list of IDs
|
|
424
447
|
"""
|
|
425
|
-
|
|
448
|
+
ids = uuid if isinstance(uuid, list) else [uuid]
|
|
449
|
+
batch = False
|
|
450
|
+
if len(ids) > 1:
|
|
451
|
+
batch = True
|
|
452
|
+
if not batch:
|
|
453
|
+
self.window.controller.settings.workdir.delete_files(uuid)
|
|
454
|
+
else:
|
|
455
|
+
self.window.controller.settings.workdir.delete_files(ids, batch=batch)
|
|
426
456
|
|
|
427
457
|
@Slot(str)
|
|
428
458
|
def after_delete(self, name: str):
|
|
@@ -468,22 +498,33 @@ class Profile:
|
|
|
468
498
|
if self.window.ui.nodes['dialog.profile.checkbox.switch'].isChecked():
|
|
469
499
|
self.switch(uuid, force=True)
|
|
470
500
|
|
|
471
|
-
def reset(self, uuid: str):
|
|
501
|
+
def reset(self, uuid: Union[str, list]):
|
|
472
502
|
"""
|
|
473
503
|
Reset profile
|
|
474
504
|
|
|
475
|
-
:param uuid: profile ID
|
|
505
|
+
:param uuid: profile ID or list of IDs
|
|
476
506
|
"""
|
|
477
|
-
|
|
507
|
+
ids = uuid if isinstance(uuid, list) else [uuid]
|
|
508
|
+
batch = False
|
|
509
|
+
if len(ids) > 1:
|
|
510
|
+
batch = True
|
|
511
|
+
if not batch:
|
|
512
|
+
self.window.controller.settings.workdir.reset(uuid)
|
|
513
|
+
else:
|
|
514
|
+
self.window.controller.settings.workdir.reset(ids, batch=batch)
|
|
478
515
|
|
|
479
|
-
def reset_by_idx(self, idx: int, force: bool = False):
|
|
516
|
+
def reset_by_idx(self, idx: Union[int, list], force: bool = False):
|
|
480
517
|
"""
|
|
481
518
|
Reset profile by index
|
|
482
519
|
|
|
483
|
-
:param idx: profile index
|
|
520
|
+
:param idx: profile index or list of indexes
|
|
484
521
|
:param force: force reset
|
|
485
522
|
"""
|
|
486
|
-
|
|
523
|
+
uuids = []
|
|
524
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
525
|
+
for i in ids:
|
|
526
|
+
uuid = self.get_id_by_idx(i)
|
|
527
|
+
uuids.append(uuid)
|
|
487
528
|
if not force:
|
|
488
529
|
self.window.ui.dialogs.confirm(
|
|
489
530
|
type='profile.reset',
|
|
@@ -491,7 +532,7 @@ class Profile:
|
|
|
491
532
|
msg=trans('confirm.profile.reset'),
|
|
492
533
|
)
|
|
493
534
|
return
|
|
494
|
-
self.reset(
|
|
535
|
+
self.reset(uuids)
|
|
495
536
|
|
|
496
537
|
def is_include_db(self):
|
|
497
538
|
"""Get include db"""
|