pygpt-net 2.6.1__py3-none-any.whl → 2.6.6__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 +23 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +20 -1
- pygpt_net/config.py +55 -65
- pygpt_net/controller/__init__.py +5 -2
- pygpt_net/controller/calendar/note.py +101 -126
- pygpt_net/controller/chat/chat.py +38 -35
- pygpt_net/controller/chat/render.py +154 -214
- pygpt_net/controller/chat/response.py +5 -3
- pygpt_net/controller/chat/stream.py +92 -27
- pygpt_net/controller/config/config.py +39 -42
- pygpt_net/controller/config/field/checkbox.py +16 -12
- pygpt_net/controller/config/field/checkbox_list.py +36 -31
- pygpt_net/controller/config/field/cmd.py +51 -57
- pygpt_net/controller/config/field/combo.py +33 -16
- pygpt_net/controller/config/field/dictionary.py +48 -55
- pygpt_net/controller/config/field/input.py +50 -32
- pygpt_net/controller/config/field/slider.py +40 -45
- pygpt_net/controller/config/field/textarea.py +20 -6
- pygpt_net/controller/config/placeholder.py +110 -231
- pygpt_net/controller/ctx/common.py +48 -48
- pygpt_net/controller/ctx/ctx.py +91 -132
- pygpt_net/controller/lang/mapping.py +57 -95
- pygpt_net/controller/lang/plugins.py +64 -55
- pygpt_net/controller/lang/settings.py +39 -38
- pygpt_net/controller/layout/layout.py +176 -109
- pygpt_net/controller/mode/mode.py +88 -85
- pygpt_net/controller/model/model.py +73 -73
- pygpt_net/controller/plugins/plugins.py +209 -223
- pygpt_net/controller/plugins/presets.py +54 -55
- pygpt_net/controller/plugins/settings.py +54 -69
- pygpt_net/controller/presets/editor.py +33 -88
- pygpt_net/controller/presets/experts.py +20 -1
- pygpt_net/controller/presets/presets.py +293 -298
- pygpt_net/controller/settings/profile.py +16 -4
- pygpt_net/controller/theme/theme.py +72 -81
- pygpt_net/controller/ui/mode.py +118 -186
- pygpt_net/controller/ui/tabs.py +69 -90
- pygpt_net/controller/ui/ui.py +47 -56
- pygpt_net/controller/ui/vision.py +24 -23
- pygpt_net/core/agents/runner.py +15 -7
- pygpt_net/core/bridge/bridge.py +5 -5
- pygpt_net/core/command/command.py +149 -219
- pygpt_net/core/ctx/ctx.py +94 -146
- pygpt_net/core/debug/debug.py +48 -58
- pygpt_net/core/experts/experts.py +3 -3
- pygpt_net/core/models/models.py +74 -112
- pygpt_net/core/modes/modes.py +13 -21
- pygpt_net/core/plugins/plugins.py +154 -177
- pygpt_net/core/presets/presets.py +103 -176
- pygpt_net/core/render/web/body.py +217 -215
- pygpt_net/core/render/web/renderer.py +330 -474
- pygpt_net/core/text/utils.py +28 -44
- pygpt_net/core/tokens/tokens.py +104 -203
- pygpt_net/data/config/config.json +3 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/locale/locale.de.ini +2 -0
- pygpt_net/data/locale/locale.en.ini +2 -0
- pygpt_net/data/locale/locale.es.ini +2 -0
- pygpt_net/data/locale/locale.fr.ini +2 -0
- pygpt_net/data/locale/locale.it.ini +2 -0
- pygpt_net/data/locale/locale.pl.ini +3 -1
- pygpt_net/data/locale/locale.uk.ini +2 -0
- pygpt_net/data/locale/locale.zh.ini +2 -0
- pygpt_net/item/ctx.py +141 -139
- pygpt_net/plugin/agent/plugin.py +2 -1
- pygpt_net/plugin/audio_output/plugin.py +5 -2
- pygpt_net/plugin/base/plugin.py +101 -85
- pygpt_net/plugin/bitbucket/__init__.py +12 -0
- pygpt_net/plugin/bitbucket/config.py +267 -0
- pygpt_net/plugin/bitbucket/plugin.py +126 -0
- pygpt_net/plugin/bitbucket/worker.py +569 -0
- pygpt_net/plugin/cmd_code_interpreter/plugin.py +3 -2
- pygpt_net/plugin/cmd_custom/plugin.py +3 -2
- pygpt_net/plugin/cmd_files/plugin.py +3 -2
- pygpt_net/plugin/cmd_history/plugin.py +3 -2
- pygpt_net/plugin/cmd_mouse_control/plugin.py +5 -2
- pygpt_net/plugin/cmd_serial/plugin.py +3 -2
- pygpt_net/plugin/cmd_system/plugin.py +3 -6
- pygpt_net/plugin/cmd_web/plugin.py +3 -2
- pygpt_net/plugin/experts/plugin.py +2 -2
- pygpt_net/plugin/facebook/__init__.py +12 -0
- pygpt_net/plugin/facebook/config.py +359 -0
- pygpt_net/plugin/facebook/plugin.py +113 -0
- pygpt_net/plugin/facebook/worker.py +698 -0
- pygpt_net/plugin/github/__init__.py +12 -0
- pygpt_net/plugin/github/config.py +441 -0
- pygpt_net/plugin/github/plugin.py +126 -0
- pygpt_net/plugin/github/worker.py +674 -0
- pygpt_net/plugin/google/__init__.py +12 -0
- pygpt_net/plugin/google/config.py +367 -0
- pygpt_net/plugin/google/plugin.py +126 -0
- pygpt_net/plugin/google/worker.py +826 -0
- pygpt_net/plugin/idx_llama_index/plugin.py +3 -2
- pygpt_net/plugin/mailer/plugin.py +3 -5
- pygpt_net/plugin/openai_vision/plugin.py +3 -2
- pygpt_net/plugin/real_time/plugin.py +52 -60
- pygpt_net/plugin/slack/__init__.py +12 -0
- pygpt_net/plugin/slack/config.py +349 -0
- pygpt_net/plugin/slack/plugin.py +115 -0
- pygpt_net/plugin/slack/worker.py +639 -0
- pygpt_net/plugin/telegram/__init__.py +12 -0
- pygpt_net/plugin/telegram/config.py +308 -0
- pygpt_net/plugin/telegram/plugin.py +117 -0
- pygpt_net/plugin/telegram/worker.py +563 -0
- pygpt_net/plugin/twitter/__init__.py +12 -0
- pygpt_net/plugin/twitter/config.py +491 -0
- pygpt_net/plugin/twitter/plugin.py +125 -0
- pygpt_net/plugin/twitter/worker.py +837 -0
- pygpt_net/provider/agents/llama_index/legacy/openai_assistant.py +35 -3
- pygpt_net/tools/code_interpreter/tool.py +0 -1
- pygpt_net/tools/translator/tool.py +1 -1
- pygpt_net/ui/base/config_dialog.py +86 -100
- pygpt_net/ui/base/context_menu.py +48 -46
- pygpt_net/ui/dialog/preset.py +34 -77
- pygpt_net/ui/layout/ctx/ctx_list.py +10 -6
- pygpt_net/ui/layout/toolbox/presets.py +41 -41
- pygpt_net/ui/main.py +49 -31
- pygpt_net/ui/tray.py +61 -60
- pygpt_net/ui/widget/calendar/select.py +86 -70
- pygpt_net/ui/widget/lists/attachment.py +86 -44
- pygpt_net/ui/widget/lists/base_list_combo.py +85 -33
- pygpt_net/ui/widget/lists/context.py +135 -188
- pygpt_net/ui/widget/lists/preset.py +59 -61
- pygpt_net/ui/widget/textarea/web.py +161 -48
- pygpt_net/utils.py +8 -1
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/METADATA +164 -2
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/RECORD +131 -103
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/entry_points.txt +0 -0
|
@@ -6,14 +6,14 @@
|
|
|
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.08.
|
|
9
|
+
# Updated Date: 2025.08.15 03:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from functools import partial
|
|
13
13
|
|
|
14
14
|
from PySide6.QtCore import Qt
|
|
15
15
|
from PySide6.QtGui import QAction, QIcon, QResizeEvent, QImage
|
|
16
|
-
from PySide6.QtWidgets import QMenu, QApplication
|
|
16
|
+
from PySide6.QtWidgets import QMenu, QApplication
|
|
17
17
|
|
|
18
18
|
from pygpt_net.item.attachment import AttachmentItem
|
|
19
19
|
from pygpt_net.ui.widget.lists.base import BaseList
|
|
@@ -22,6 +22,11 @@ import pygpt_net.icons_rc
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class AttachmentList(BaseList):
|
|
25
|
+
_ICON_VIEW = QIcon(":/icons/view.svg")
|
|
26
|
+
_ICON_FOLDER = QIcon(":/icons/folder_filled.svg")
|
|
27
|
+
_ICON_EDIT = QIcon(":/icons/edit.svg")
|
|
28
|
+
_ICON_DELETE = QIcon(":/icons/delete.svg")
|
|
29
|
+
|
|
25
30
|
def __init__(self, window=None, id=None):
|
|
26
31
|
"""
|
|
27
32
|
Attachments menu
|
|
@@ -36,22 +41,35 @@ class AttachmentList(BaseList):
|
|
|
36
41
|
self.setHeaderHidden(False)
|
|
37
42
|
self.clicked.disconnect(self.click)
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
hdr = self.header()
|
|
45
|
+
hdr.setStretchLastSection(False)
|
|
41
46
|
|
|
42
47
|
self.column_proportion = 0.3
|
|
48
|
+
self._last_width = -1
|
|
43
49
|
self.adjustColumnWidths()
|
|
44
50
|
|
|
45
51
|
def adjustColumnWidths(self):
|
|
46
|
-
|
|
52
|
+
hdr = self.header()
|
|
53
|
+
cols = hdr.count()
|
|
54
|
+
if cols <= 0:
|
|
55
|
+
return
|
|
56
|
+
total_width = self.viewport().width() or self.width()
|
|
47
57
|
first_column_width = int(total_width * self.column_proportion)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
self.setColumnWidth(
|
|
58
|
+
remaining = max(total_width - first_column_width, 0)
|
|
59
|
+
if self.columnWidth(0) != first_column_width:
|
|
60
|
+
self.setColumnWidth(0, first_column_width)
|
|
61
|
+
if cols > 1:
|
|
62
|
+
other = remaining // (cols - 1)
|
|
63
|
+
for column in range(1, cols):
|
|
64
|
+
if self.columnWidth(column) != other:
|
|
65
|
+
self.setColumnWidth(column, other)
|
|
51
66
|
|
|
52
67
|
def resizeEvent(self, event: QResizeEvent):
|
|
53
68
|
super().resizeEvent(event)
|
|
54
|
-
|
|
69
|
+
w = event.size().width()
|
|
70
|
+
if w != self._last_width:
|
|
71
|
+
self._last_width = w
|
|
72
|
+
self.adjustColumnWidths()
|
|
55
73
|
|
|
56
74
|
def mousePressEvent(self, event):
|
|
57
75
|
"""
|
|
@@ -59,7 +77,7 @@ class AttachmentList(BaseList):
|
|
|
59
77
|
|
|
60
78
|
:param event: mouse event
|
|
61
79
|
"""
|
|
62
|
-
if event.
|
|
80
|
+
if event.button() == Qt.LeftButton:
|
|
63
81
|
index = self.indexAt(event.pos())
|
|
64
82
|
if index.isValid():
|
|
65
83
|
mode = self.window.core.config.get('mode')
|
|
@@ -89,58 +107,61 @@ class AttachmentList(BaseList):
|
|
|
89
107
|
|
|
90
108
|
:param event: context menu event
|
|
91
109
|
"""
|
|
92
|
-
|
|
93
|
-
def ignore_trigger(func, arg, *args, **kwargs):
|
|
94
|
-
func(arg)
|
|
95
|
-
|
|
96
110
|
mode = self.window.core.config.get('mode')
|
|
97
111
|
item = self.indexAt(event.pos())
|
|
98
112
|
idx = item.row()
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
attachment = None
|
|
113
|
+
if idx < 0:
|
|
114
|
+
return
|
|
102
115
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if self.window.core.filesystem.actions.has_preview(path):
|
|
108
|
-
preview_actions = self.window.core.filesystem.actions.get_preview(self, path)
|
|
116
|
+
attachment = self.window.controller.attachment.get_by_idx(mode, idx)
|
|
117
|
+
path = attachment.path if attachment else None
|
|
118
|
+
|
|
119
|
+
menu = QMenu(self)
|
|
109
120
|
|
|
110
121
|
actions = {}
|
|
111
|
-
actions['open'] = QAction(
|
|
112
|
-
actions['open'].triggered.connect(partial(
|
|
122
|
+
actions['open'] = QAction(self._ICON_VIEW, trans('action.open'), menu)
|
|
123
|
+
actions['open'].triggered.connect(partial(self._action_open_idx, idx))
|
|
113
124
|
|
|
114
|
-
actions['open_dir'] = QAction(
|
|
115
|
-
actions['open_dir'].triggered.connect(partial(
|
|
125
|
+
actions['open_dir'] = QAction(self._ICON_FOLDER, trans('action.open_dir'), menu)
|
|
126
|
+
actions['open_dir'].triggered.connect(partial(self._action_open_dir_idx, idx))
|
|
116
127
|
|
|
117
|
-
actions['rename'] = QAction(
|
|
118
|
-
actions['rename'].triggered.connect(partial(
|
|
128
|
+
actions['rename'] = QAction(self._ICON_EDIT, trans('action.rename'), menu)
|
|
129
|
+
actions['rename'].triggered.connect(partial(self._action_rename_idx, idx))
|
|
119
130
|
|
|
120
|
-
actions['delete'] = QAction(
|
|
121
|
-
actions['delete'].triggered.connect(partial(
|
|
131
|
+
actions['delete'] = QAction(self._ICON_DELETE, trans('action.delete'), menu)
|
|
132
|
+
actions['delete'].triggered.connect(partial(self._action_delete_idx, idx))
|
|
122
133
|
|
|
123
|
-
menu = QMenu(self)
|
|
124
134
|
if attachment and attachment.type == AttachmentItem.TYPE_FILE:
|
|
125
|
-
|
|
126
|
-
|
|
135
|
+
fs_actions = self.window.core.filesystem.actions
|
|
136
|
+
if fs_actions.has_preview(path):
|
|
137
|
+
preview_actions = fs_actions.get_preview(self, path)
|
|
138
|
+
for preview_action in preview_actions or []:
|
|
139
|
+
try:
|
|
140
|
+
preview_action.setParent(menu)
|
|
141
|
+
except Exception:
|
|
142
|
+
pass
|
|
127
143
|
menu.addAction(preview_action)
|
|
128
144
|
|
|
129
145
|
menu.addAction(actions['open'])
|
|
130
146
|
menu.addAction(actions['open_dir'])
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
147
|
+
|
|
148
|
+
if fs_actions.has_use(path):
|
|
149
|
+
use_actions = fs_actions.get_use(self, path)
|
|
150
|
+
use_menu = QMenu(trans('action.use'), menu)
|
|
151
|
+
for use_action in use_actions or []:
|
|
152
|
+
try:
|
|
153
|
+
use_action.setParent(use_menu)
|
|
154
|
+
except Exception:
|
|
155
|
+
pass
|
|
135
156
|
use_menu.addAction(use_action)
|
|
136
157
|
menu.addMenu(use_menu)
|
|
137
158
|
|
|
138
159
|
menu.addAction(actions['rename'])
|
|
160
|
+
|
|
139
161
|
menu.addAction(actions['delete'])
|
|
140
162
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
menu.exec_(event.globalPos())
|
|
163
|
+
self.window.controller.attachment.select(mode, item.row())
|
|
164
|
+
menu.exec_(event.globalPos())
|
|
144
165
|
|
|
145
166
|
def keyPressEvent(self, event):
|
|
146
167
|
"""
|
|
@@ -148,7 +169,7 @@ class AttachmentList(BaseList):
|
|
|
148
169
|
|
|
149
170
|
:param event: Event
|
|
150
171
|
"""
|
|
151
|
-
if event.key() == Qt.Key_V and
|
|
172
|
+
if event.key() == Qt.Key_V and (event.modifiers() & Qt.ControlModifier):
|
|
152
173
|
self.handle_paste()
|
|
153
174
|
|
|
154
175
|
def handle_paste(self):
|
|
@@ -159,13 +180,15 @@ class AttachmentList(BaseList):
|
|
|
159
180
|
image = source.imageData()
|
|
160
181
|
if isinstance(image, QImage):
|
|
161
182
|
self.window.controller.attachment.from_clipboard_image(image)
|
|
162
|
-
|
|
183
|
+
return
|
|
184
|
+
if source.hasUrls():
|
|
163
185
|
urls = source.urls()
|
|
164
186
|
for url in urls:
|
|
165
187
|
if url.isLocalFile():
|
|
166
188
|
local_path = url.toLocalFile()
|
|
167
189
|
self.window.controller.attachment.from_clipboard_url(local_path, all=True)
|
|
168
|
-
|
|
190
|
+
return
|
|
191
|
+
if source.hasText():
|
|
169
192
|
text = source.text()
|
|
170
193
|
self.window.controller.attachment.from_clipboard_text(text, all=True)
|
|
171
194
|
|
|
@@ -215,3 +238,22 @@ class AttachmentList(BaseList):
|
|
|
215
238
|
idx = item.row()
|
|
216
239
|
if idx >= 0:
|
|
217
240
|
self.window.controller.attachment.delete(idx)
|
|
241
|
+
|
|
242
|
+
def _action_open_idx(self, idx, checked=False):
|
|
243
|
+
if idx >= 0:
|
|
244
|
+
mode = self.window.core.config.get('mode')
|
|
245
|
+
self.window.controller.attachment.open(mode, idx)
|
|
246
|
+
|
|
247
|
+
def _action_open_dir_idx(self, idx, checked=False):
|
|
248
|
+
if idx >= 0:
|
|
249
|
+
mode = self.window.core.config.get('mode')
|
|
250
|
+
self.window.controller.attachment.open_dir(mode, idx)
|
|
251
|
+
|
|
252
|
+
def _action_rename_idx(self, idx, checked=False):
|
|
253
|
+
if idx >= 0:
|
|
254
|
+
mode = self.window.core.config.get('mode')
|
|
255
|
+
self.window.controller.attachment.rename(mode, idx)
|
|
256
|
+
|
|
257
|
+
def _action_delete_idx(self, idx, checked=False):
|
|
258
|
+
if idx >= 0:
|
|
259
|
+
self.window.controller.attachment.delete(idx)
|
|
@@ -6,10 +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.08.
|
|
9
|
+
# Updated Date: 2025.08.15 03:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtWidgets import QHBoxLayout, QWidget, QComboBox
|
|
13
|
+
from PySide6.QtCore import QSignalBlocker
|
|
13
14
|
|
|
14
15
|
from pygpt_net.ui.widget.option.combo import SeparatorComboBox, NoScrollCombo
|
|
15
16
|
|
|
@@ -32,8 +33,10 @@ class BaseListCombo(QWidget):
|
|
|
32
33
|
self.combo.currentIndexChanged.connect(self.on_combo_change)
|
|
33
34
|
self.initialized = False
|
|
34
35
|
self.locked = False
|
|
36
|
+
self._data_index_map = {}
|
|
37
|
+
self._keys_cache = None
|
|
38
|
+
self._keys_cache_id = 0
|
|
35
39
|
|
|
36
|
-
# add items
|
|
37
40
|
self.update()
|
|
38
41
|
|
|
39
42
|
self.layout = QHBoxLayout()
|
|
@@ -45,20 +48,53 @@ class BaseListCombo(QWidget):
|
|
|
45
48
|
|
|
46
49
|
def update(self):
|
|
47
50
|
"""Prepare items"""
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
combo = self.combo
|
|
52
|
+
blocker = QSignalBlocker(combo)
|
|
53
|
+
combo.setUpdatesEnabled(False)
|
|
54
|
+
try:
|
|
55
|
+
combo.clear()
|
|
56
|
+
self._data_index_map = {}
|
|
57
|
+
idx = 0
|
|
58
|
+
keys = self.keys
|
|
59
|
+
add_item = combo.addItem
|
|
60
|
+
if isinstance(keys, list):
|
|
61
|
+
for item in keys:
|
|
62
|
+
if isinstance(item, dict):
|
|
63
|
+
for key, value in item.items():
|
|
64
|
+
add_item(value, key)
|
|
65
|
+
if key not in self._data_index_map:
|
|
66
|
+
self._data_index_map[key] = idx
|
|
67
|
+
idx += 1
|
|
68
|
+
else:
|
|
69
|
+
add_item(item, item)
|
|
70
|
+
if item not in self._data_index_map:
|
|
71
|
+
self._data_index_map[item] = idx
|
|
72
|
+
idx += 1
|
|
73
|
+
elif isinstance(keys, dict):
|
|
74
|
+
add_sep = combo.addSeparator
|
|
75
|
+
for key, value in keys.items():
|
|
76
|
+
if isinstance(key, str) and key.startswith("separator::"):
|
|
77
|
+
add_sep(value)
|
|
78
|
+
idx += 1
|
|
79
|
+
else:
|
|
80
|
+
add_item(value, key)
|
|
81
|
+
if key not in self._data_index_map:
|
|
82
|
+
self._data_index_map[key] = idx
|
|
83
|
+
idx += 1
|
|
84
|
+
cache = set()
|
|
85
|
+
if isinstance(keys, list):
|
|
86
|
+
for item in keys:
|
|
87
|
+
if isinstance(item, dict):
|
|
88
|
+
cache.update(item.keys())
|
|
89
|
+
else:
|
|
90
|
+
cache.add(item)
|
|
91
|
+
elif isinstance(keys, dict):
|
|
92
|
+
cache.update(keys.keys())
|
|
93
|
+
self._keys_cache = cache
|
|
94
|
+
self._keys_cache_id = id(keys)
|
|
95
|
+
finally:
|
|
96
|
+
combo.setUpdatesEnabled(True)
|
|
97
|
+
del blocker
|
|
62
98
|
|
|
63
99
|
def set_value(self, value):
|
|
64
100
|
"""
|
|
@@ -67,10 +103,21 @@ class BaseListCombo(QWidget):
|
|
|
67
103
|
:param value: value
|
|
68
104
|
"""
|
|
69
105
|
self.locked = True
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
106
|
+
combo = self.combo
|
|
107
|
+
blocker = QSignalBlocker(combo)
|
|
108
|
+
try:
|
|
109
|
+
index = self._data_index_map.get(value, -1)
|
|
110
|
+
if index == -1:
|
|
111
|
+
index = combo.findData(value)
|
|
112
|
+
if index != -1 and value not in self._data_index_map:
|
|
113
|
+
self._data_index_map[value] = index
|
|
114
|
+
if index != -1:
|
|
115
|
+
if index != combo.currentIndex():
|
|
116
|
+
combo.setCurrentIndex(index)
|
|
117
|
+
self.current_id = value
|
|
118
|
+
finally:
|
|
119
|
+
del blocker
|
|
120
|
+
self.locked = False
|
|
74
121
|
|
|
75
122
|
def get_value(self):
|
|
76
123
|
"""
|
|
@@ -87,17 +134,20 @@ class BaseListCombo(QWidget):
|
|
|
87
134
|
:param name: key name
|
|
88
135
|
:return:
|
|
89
136
|
"""
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
137
|
+
keys = self.keys
|
|
138
|
+
if self._keys_cache is None or self._keys_cache_id != id(keys):
|
|
139
|
+
cache = set()
|
|
140
|
+
if isinstance(keys, list):
|
|
141
|
+
for item in keys:
|
|
142
|
+
if isinstance(item, dict):
|
|
143
|
+
cache.update(item.keys())
|
|
144
|
+
else:
|
|
145
|
+
cache.add(item)
|
|
146
|
+
elif isinstance(keys, dict):
|
|
147
|
+
cache.update(keys.keys())
|
|
148
|
+
self._keys_cache = cache
|
|
149
|
+
self._keys_cache_id = id(keys)
|
|
150
|
+
return name in self._keys_cache
|
|
101
151
|
|
|
102
152
|
def set_keys(self, keys):
|
|
103
153
|
"""
|
|
@@ -107,7 +157,9 @@ class BaseListCombo(QWidget):
|
|
|
107
157
|
"""
|
|
108
158
|
self.locked = True
|
|
109
159
|
self.keys = keys
|
|
110
|
-
self.
|
|
160
|
+
self._keys_cache = None
|
|
161
|
+
self._keys_cache_id = 0
|
|
162
|
+
self.update()
|
|
111
163
|
self.locked = False
|
|
112
164
|
|
|
113
165
|
def on_combo_change(self, index):
|
|
@@ -118,7 +170,7 @@ class BaseListCombo(QWidget):
|
|
|
118
170
|
"""
|
|
119
171
|
if not self.initialized or self.locked:
|
|
120
172
|
return
|
|
121
|
-
self.current_id = self.combo.itemData(index)
|
|
173
|
+
self.current_id = self.combo.itemData(index) if index >= 0 else None
|
|
122
174
|
|
|
123
175
|
def fit_to_content(self):
|
|
124
176
|
"""Fit to content"""
|