pygpt-net 2.7.7__py3-none-any.whl → 2.7.8__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 +7 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +5 -1
- pygpt_net/controller/assistant/batch.py +2 -2
- pygpt_net/controller/assistant/files.py +7 -6
- pygpt_net/controller/assistant/threads.py +0 -0
- pygpt_net/controller/chat/command.py +0 -0
- pygpt_net/controller/dialogs/confirm.py +35 -58
- pygpt_net/controller/lang/mapping.py +9 -9
- pygpt_net/controller/remote_store/{google/batch.py → batch.py} +209 -252
- pygpt_net/controller/remote_store/remote_store.py +982 -13
- pygpt_net/core/command/command.py +0 -0
- pygpt_net/core/db/viewer.py +1 -1
- pygpt_net/core/realtime/worker.py +3 -1
- pygpt_net/{controller/remote_store/google → core/remote_store/anthropic}/__init__.py +0 -1
- pygpt_net/core/remote_store/anthropic/files.py +211 -0
- pygpt_net/core/remote_store/anthropic/store.py +208 -0
- pygpt_net/core/remote_store/openai/store.py +5 -4
- pygpt_net/core/remote_store/remote_store.py +5 -1
- pygpt_net/{controller/remote_store/openai → core/remote_store/xai}/__init__.py +0 -1
- pygpt_net/core/remote_store/xai/files.py +225 -0
- pygpt_net/core/remote_store/xai/store.py +219 -0
- pygpt_net/data/config/config.json +9 -6
- pygpt_net/data/config/models.json +5 -4
- pygpt_net/data/config/settings.json +54 -1
- pygpt_net/data/icons/folder_eye.svg +1 -0
- pygpt_net/data/icons/folder_eye_filled.svg +1 -0
- pygpt_net/data/icons/folder_open.svg +1 -0
- pygpt_net/data/icons/folder_open_filled.svg +1 -0
- pygpt_net/data/locale/locale.de.ini +4 -3
- pygpt_net/data/locale/locale.en.ini +14 -4
- pygpt_net/data/locale/locale.es.ini +4 -3
- pygpt_net/data/locale/locale.fr.ini +4 -3
- pygpt_net/data/locale/locale.it.ini +4 -3
- pygpt_net/data/locale/locale.pl.ini +5 -4
- pygpt_net/data/locale/locale.uk.ini +4 -3
- pygpt_net/data/locale/locale.zh.ini +4 -3
- pygpt_net/icons.qrc +4 -0
- pygpt_net/icons_rc.py +282 -138
- pygpt_net/provider/api/anthropic/__init__.py +2 -0
- pygpt_net/provider/api/anthropic/chat.py +84 -1
- pygpt_net/provider/api/anthropic/store.py +307 -0
- pygpt_net/provider/api/anthropic/stream.py +75 -0
- pygpt_net/provider/api/anthropic/worker/__init__.py +0 -0
- pygpt_net/provider/api/anthropic/worker/importer.py +278 -0
- pygpt_net/provider/api/google/chat.py +59 -2
- pygpt_net/provider/api/google/store.py +124 -3
- pygpt_net/provider/api/google/stream.py +91 -24
- pygpt_net/provider/api/google/worker/importer.py +16 -28
- pygpt_net/provider/api/openai/assistants.py +2 -2
- pygpt_net/provider/api/openai/store.py +4 -1
- pygpt_net/provider/api/openai/worker/importer.py +19 -61
- pygpt_net/provider/api/openai/worker/importer_assistants.py +230 -0
- pygpt_net/provider/api/x_ai/__init__.py +30 -6
- pygpt_net/provider/api/x_ai/audio.py +43 -11
- pygpt_net/provider/api/x_ai/chat.py +92 -4
- pygpt_net/provider/api/x_ai/realtime/__init__.py +12 -0
- pygpt_net/provider/api/x_ai/realtime/client.py +1825 -0
- pygpt_net/provider/api/x_ai/realtime/realtime.py +198 -0
- pygpt_net/provider/api/x_ai/remote_tools.py +19 -1
- pygpt_net/provider/api/x_ai/store.py +610 -0
- pygpt_net/provider/api/x_ai/stream.py +30 -9
- pygpt_net/provider/api/x_ai/worker/importer.py +308 -0
- pygpt_net/provider/audio_input/xai_grok_voice.py +390 -0
- pygpt_net/provider/audio_output/xai_tts.py +325 -0
- pygpt_net/provider/core/config/patch.py +18 -3
- pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +2 -2
- pygpt_net/provider/core/model/patch.py +13 -0
- pygpt_net/tools/image_viewer/tool.py +334 -34
- pygpt_net/tools/image_viewer/ui/dialogs.py +317 -21
- pygpt_net/ui/dialog/assistant.py +1 -1
- pygpt_net/ui/dialog/plugins.py +13 -5
- pygpt_net/ui/dialog/remote_store.py +552 -0
- pygpt_net/ui/dialogs.py +3 -5
- pygpt_net/ui/layout/ctx/ctx_list.py +58 -7
- pygpt_net/ui/menu/tools.py +6 -13
- pygpt_net/ui/widget/dialog/{remote_store_google.py → remote_store.py} +10 -10
- pygpt_net/ui/widget/element/button.py +4 -4
- pygpt_net/ui/widget/image/display.py +2 -2
- pygpt_net/ui/widget/lists/context.py +2 -2
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/METADATA +9 -2
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/RECORD +82 -70
- pygpt_net/controller/remote_store/google/store.py +0 -615
- pygpt_net/controller/remote_store/openai/batch.py +0 -524
- pygpt_net/controller/remote_store/openai/store.py +0 -699
- pygpt_net/ui/dialog/remote_store_google.py +0 -539
- pygpt_net/ui/dialog/remote_store_openai.py +0 -539
- pygpt_net/ui/widget/dialog/remote_store_openai.py +0 -56
- pygpt_net/ui/widget/lists/remote_store_google.py +0 -248
- pygpt_net/ui/widget/lists/remote_store_openai.py +0 -317
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/LICENSE +0 -0
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/WHEEL +0 -0
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/entry_points.txt +0 -0
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# ================================================== #
|
|
4
|
-
# This file is a part of PYGPT package #
|
|
5
|
-
# Website: https://pygpt.net #
|
|
6
|
-
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
|
-
# MIT License #
|
|
8
|
-
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2026.01.02 20:00:00 #
|
|
10
|
-
# ================================================== #
|
|
11
|
-
|
|
12
|
-
from PySide6.QtGui import QAction, QIcon
|
|
13
|
-
from PySide6.QtCore import Qt, QItemSelectionModel
|
|
14
|
-
from PySide6.QtWidgets import QMenu, QAbstractItemView
|
|
15
|
-
|
|
16
|
-
from pygpt_net.ui.widget.lists.base import BaseList
|
|
17
|
-
from pygpt_net.utils import trans
|
|
18
|
-
import pygpt_net.icons_rc
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class RemoteStoreGoogleEditorList(BaseList):
|
|
22
|
-
def __init__(self, window=None, id=None):
|
|
23
|
-
"""
|
|
24
|
-
Store select menu (in editor) - Google File Search
|
|
25
|
-
|
|
26
|
-
:param window: main window
|
|
27
|
-
:param id: parent id
|
|
28
|
-
"""
|
|
29
|
-
super(RemoteStoreGoogleEditorList, self).__init__(window)
|
|
30
|
-
self.window = window
|
|
31
|
-
self.id = id
|
|
32
|
-
|
|
33
|
-
self._suppress_item_click = False
|
|
34
|
-
self._ctrl_multi_active = False
|
|
35
|
-
self._ctrl_multi_index = None
|
|
36
|
-
self._was_shift_click = False
|
|
37
|
-
|
|
38
|
-
self._backup_selection = None
|
|
39
|
-
self.restore_after_ctx_menu = True
|
|
40
|
-
|
|
41
|
-
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
42
|
-
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
|
43
|
-
|
|
44
|
-
# Disable BaseList click handler; business action handled manually
|
|
45
|
-
self.clicked.disconnect(self.click)
|
|
46
|
-
|
|
47
|
-
def _selected_rows(self) -> list[int]:
|
|
48
|
-
try:
|
|
49
|
-
return sorted([ix.row() for ix in self.selectionModel().selectedRows()])
|
|
50
|
-
except Exception:
|
|
51
|
-
return []
|
|
52
|
-
|
|
53
|
-
def _has_multi_selection(self) -> bool:
|
|
54
|
-
try:
|
|
55
|
-
return len(self.selectionModel().selectedRows()) > 1
|
|
56
|
-
except Exception:
|
|
57
|
-
return False
|
|
58
|
-
|
|
59
|
-
def mousePressEvent(self, event):
|
|
60
|
-
if event.button() == Qt.LeftButton and (event.modifiers() & Qt.ControlModifier):
|
|
61
|
-
idx = self.indexAt(event.pos())
|
|
62
|
-
if idx.isValid():
|
|
63
|
-
self._ctrl_multi_active = True
|
|
64
|
-
self._ctrl_multi_index = idx
|
|
65
|
-
self._suppress_item_click = True
|
|
66
|
-
event.accept()
|
|
67
|
-
return
|
|
68
|
-
self._suppress_item_click = True
|
|
69
|
-
event.accept()
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
if event.button() == Qt.LeftButton and (event.modifiers() & Qt.ShiftModifier):
|
|
73
|
-
idx = self.indexAt(event.pos())
|
|
74
|
-
self._suppress_item_click = True
|
|
75
|
-
self._was_shift_click = True
|
|
76
|
-
if idx.isValid():
|
|
77
|
-
super(RemoteStoreGoogleEditorList, self).mousePressEvent(event)
|
|
78
|
-
else:
|
|
79
|
-
event.accept()
|
|
80
|
-
return
|
|
81
|
-
|
|
82
|
-
if event.button() == Qt.LeftButton:
|
|
83
|
-
idx = self.indexAt(event.pos())
|
|
84
|
-
if self._has_multi_selection():
|
|
85
|
-
sel_model = self.selectionModel()
|
|
86
|
-
sel_model.clearSelection()
|
|
87
|
-
if not idx.isValid():
|
|
88
|
-
event.accept()
|
|
89
|
-
return
|
|
90
|
-
super(RemoteStoreGoogleEditorList, self).mousePressEvent(event)
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
if event.button() == Qt.RightButton:
|
|
94
|
-
idx = self.indexAt(event.pos())
|
|
95
|
-
sel_model = self.selectionModel()
|
|
96
|
-
selected_rows = [ix.row() for ix in sel_model.selectedRows()]
|
|
97
|
-
multi = len(selected_rows) > 1
|
|
98
|
-
|
|
99
|
-
if idx.isValid():
|
|
100
|
-
if multi and idx.row() in selected_rows:
|
|
101
|
-
self._backup_selection = None
|
|
102
|
-
else:
|
|
103
|
-
self._backup_selection = list(sel_model.selectedIndexes())
|
|
104
|
-
sel_model.clearSelection()
|
|
105
|
-
sel_model.select(idx, QItemSelectionModel.Select | QItemSelectionModel.Rows)
|
|
106
|
-
event.accept()
|
|
107
|
-
return
|
|
108
|
-
|
|
109
|
-
super(RemoteStoreGoogleEditorList, self).mousePressEvent(event)
|
|
110
|
-
|
|
111
|
-
def mouseReleaseEvent(self, event):
|
|
112
|
-
if event.button() == Qt.LeftButton and self._was_shift_click:
|
|
113
|
-
self._was_shift_click = False
|
|
114
|
-
self._suppress_item_click = False
|
|
115
|
-
super(RemoteStoreGoogleEditorList, self).mouseReleaseEvent(event)
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
if event.button() == Qt.LeftButton and self._ctrl_multi_active:
|
|
119
|
-
try:
|
|
120
|
-
idx = self.indexAt(event.pos())
|
|
121
|
-
if idx.isValid() and self._ctrl_multi_index and idx == self._ctrl_multi_index:
|
|
122
|
-
sel_model = self.selectionModel()
|
|
123
|
-
sel_model.select(idx, QItemSelectionModel.Toggle | QItemSelectionModel.Rows)
|
|
124
|
-
finally:
|
|
125
|
-
self._ctrl_multi_active = False
|
|
126
|
-
self._ctrl_multi_index = None
|
|
127
|
-
self._suppress_item_click = False
|
|
128
|
-
event.accept()
|
|
129
|
-
return
|
|
130
|
-
|
|
131
|
-
if event.button() == Qt.LeftButton:
|
|
132
|
-
idx = self.indexAt(event.pos())
|
|
133
|
-
if not self._has_multi_selection():
|
|
134
|
-
if idx.isValid() and not self._suppress_item_click:
|
|
135
|
-
self.window.controller.remote_store.google.select(idx.row())
|
|
136
|
-
self._suppress_item_click = False
|
|
137
|
-
super(RemoteStoreGoogleEditorList, self).mouseReleaseEvent(event)
|
|
138
|
-
return
|
|
139
|
-
|
|
140
|
-
super(RemoteStoreGoogleEditorList, self).mouseReleaseEvent(event)
|
|
141
|
-
|
|
142
|
-
def click(self, val):
|
|
143
|
-
pass
|
|
144
|
-
|
|
145
|
-
def contextMenuEvent(self, event):
|
|
146
|
-
actions = {}
|
|
147
|
-
actions['refresh'] = QAction(
|
|
148
|
-
QIcon(":/icons/reload.svg"),
|
|
149
|
-
trans('dialog.remote_store.menu.current.refresh_store'),
|
|
150
|
-
self
|
|
151
|
-
)
|
|
152
|
-
actions['delete'] = QAction(QIcon(":/icons/delete.svg"), trans('action.delete'), self)
|
|
153
|
-
actions['clear'] = QAction(
|
|
154
|
-
QIcon(":/icons/close.svg"),
|
|
155
|
-
trans('dialog.remote_store.menu.current.clear_files'),
|
|
156
|
-
self
|
|
157
|
-
)
|
|
158
|
-
actions['truncate'] = QAction(
|
|
159
|
-
QIcon(":/icons/delete.svg"),
|
|
160
|
-
trans('dialog.remote_store.menu.current.truncate_files'),
|
|
161
|
-
self
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
menu = QMenu(self)
|
|
165
|
-
menu.addAction(actions['refresh'])
|
|
166
|
-
menu.addAction(actions['delete'])
|
|
167
|
-
menu.addAction(actions['clear'])
|
|
168
|
-
menu.addAction(actions['truncate'])
|
|
169
|
-
|
|
170
|
-
index = self.indexAt(event.pos())
|
|
171
|
-
idx = index.row() if index.isValid() else -1
|
|
172
|
-
|
|
173
|
-
selected_rows = self._selected_rows()
|
|
174
|
-
multi = len(selected_rows) > 1
|
|
175
|
-
|
|
176
|
-
if not index.isValid() and not multi:
|
|
177
|
-
if self._backup_selection is not None and self.restore_after_ctx_menu:
|
|
178
|
-
sel_model = self.selectionModel()
|
|
179
|
-
sel_model.clearSelection()
|
|
180
|
-
for i in self._backup_selection:
|
|
181
|
-
sel_model.select(i, QItemSelectionModel.Select | QItemSelectionModel.Rows)
|
|
182
|
-
self._backup_selection = None
|
|
183
|
-
return
|
|
184
|
-
|
|
185
|
-
if multi:
|
|
186
|
-
actions['refresh'].triggered.connect(lambda: self.action_refresh(list(selected_rows)))
|
|
187
|
-
actions['delete'].triggered.connect(lambda: self.action_delete(list(selected_rows)))
|
|
188
|
-
actions['clear'].triggered.connect(lambda: self.action_clear(list(selected_rows)))
|
|
189
|
-
actions['truncate'].triggered.connect(lambda: self.action_truncate(list(selected_rows)))
|
|
190
|
-
else:
|
|
191
|
-
actions['refresh'].triggered.connect(lambda: self.action_refresh(idx))
|
|
192
|
-
actions['delete'].triggered.connect(lambda: self.action_delete(idx))
|
|
193
|
-
actions['clear'].triggered.connect(lambda: self.action_clear(idx))
|
|
194
|
-
actions['truncate'].triggered.connect(lambda: self.action_truncate(idx))
|
|
195
|
-
|
|
196
|
-
menu.exec_(event.globalPos())
|
|
197
|
-
|
|
198
|
-
if self.restore_after_ctx_menu and self._backup_selection is not None:
|
|
199
|
-
sel_model = self.selectionModel()
|
|
200
|
-
sel_model.clearSelection()
|
|
201
|
-
for i in self._backup_selection:
|
|
202
|
-
sel_model.select(i, QItemSelectionModel.Select | QItemSelectionModel.Rows)
|
|
203
|
-
self._backup_selection = None
|
|
204
|
-
self.restore_after_ctx_menu = True
|
|
205
|
-
|
|
206
|
-
def action_delete(self, item):
|
|
207
|
-
if isinstance(item, (list, tuple)):
|
|
208
|
-
if item:
|
|
209
|
-
self.restore_after_ctx_menu = False
|
|
210
|
-
self.window.controller.remote_store.google.delete_by_idx(list(item))
|
|
211
|
-
return
|
|
212
|
-
idx = int(item)
|
|
213
|
-
if idx >= 0:
|
|
214
|
-
self.restore_after_ctx_menu = False
|
|
215
|
-
self.window.controller.remote_store.google.delete_by_idx(idx)
|
|
216
|
-
|
|
217
|
-
def action_clear(self, item):
|
|
218
|
-
if isinstance(item, (list, tuple)):
|
|
219
|
-
if item:
|
|
220
|
-
self.restore_after_ctx_menu = False
|
|
221
|
-
self.window.controller.remote_store.google.batch.clear_store_files_by_idx(list(item))
|
|
222
|
-
return
|
|
223
|
-
idx = int(item)
|
|
224
|
-
if idx >= 0:
|
|
225
|
-
self.restore_after_ctx_menu = False
|
|
226
|
-
self.window.controller.remote_store.google.batch.clear_store_files_by_idx(idx)
|
|
227
|
-
|
|
228
|
-
def action_truncate(self, item):
|
|
229
|
-
if isinstance(item, (list, tuple)):
|
|
230
|
-
if item:
|
|
231
|
-
self.restore_after_ctx_menu = False
|
|
232
|
-
self.window.controller.remote_store.google.batch.truncate_store_files_by_idx(list(item))
|
|
233
|
-
return
|
|
234
|
-
idx = int(item)
|
|
235
|
-
if idx >= 0:
|
|
236
|
-
self.restore_after_ctx_menu = False
|
|
237
|
-
self.window.controller.remote_store.google.batch.truncate_store_files_by_idx(idx)
|
|
238
|
-
|
|
239
|
-
def action_refresh(self, item):
|
|
240
|
-
if isinstance(item, (list, tuple)):
|
|
241
|
-
if item:
|
|
242
|
-
self.restore_after_ctx_menu = False
|
|
243
|
-
self.window.controller.remote_store.google.refresh_by_idx(list(item))
|
|
244
|
-
return
|
|
245
|
-
idx = int(item)
|
|
246
|
-
if idx >= 0:
|
|
247
|
-
self.restore_after_ctx_menu = False
|
|
248
|
-
self.window.controller.remote_store.google.refresh_by_idx(idx)
|
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# ================================================== #
|
|
4
|
-
# This file is a part of PYGPT package #
|
|
5
|
-
# Website: https://pygpt.net #
|
|
6
|
-
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
|
-
# MIT License #
|
|
8
|
-
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2026.01.02 19:00:00 #
|
|
10
|
-
# ================================================== #
|
|
11
|
-
|
|
12
|
-
from PySide6.QtGui import QAction, QIcon
|
|
13
|
-
from PySide6.QtCore import Qt, QItemSelectionModel
|
|
14
|
-
from PySide6.QtWidgets import QMenu, QAbstractItemView
|
|
15
|
-
|
|
16
|
-
from pygpt_net.ui.widget.lists.base import BaseList
|
|
17
|
-
from pygpt_net.utils import trans
|
|
18
|
-
import pygpt_net.icons_rc
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class RemoteStoreOpenAIEditorList(BaseList):
|
|
22
|
-
def __init__(self, window=None, id=None):
|
|
23
|
-
"""
|
|
24
|
-
Store select menu (in editor)
|
|
25
|
-
|
|
26
|
-
:param window: main window
|
|
27
|
-
:param id: parent id
|
|
28
|
-
"""
|
|
29
|
-
super(RemoteStoreOpenAIEditorList, self).__init__(window)
|
|
30
|
-
self.window = window
|
|
31
|
-
self.id = id
|
|
32
|
-
|
|
33
|
-
# Virtual multi-select helpers
|
|
34
|
-
self._suppress_item_click = False # suppress business click after Ctrl/Shift selection
|
|
35
|
-
self._ctrl_multi_active = False # Ctrl gesture in progress
|
|
36
|
-
self._ctrl_multi_index = None
|
|
37
|
-
self._was_shift_click = False # Shift range gesture
|
|
38
|
-
|
|
39
|
-
# Context menu selection backup (temporary right-click selection)
|
|
40
|
-
self._backup_selection = None
|
|
41
|
-
self.restore_after_ctx_menu = True
|
|
42
|
-
|
|
43
|
-
# Row-based multi-selection behavior
|
|
44
|
-
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
45
|
-
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
|
46
|
-
|
|
47
|
-
# Disable default BaseList click handler; business action is handled manually
|
|
48
|
-
self.clicked.disconnect(self.click)
|
|
49
|
-
|
|
50
|
-
# ----------------------------
|
|
51
|
-
# Selection helpers
|
|
52
|
-
# ----------------------------
|
|
53
|
-
|
|
54
|
-
def _selected_rows(self) -> list[int]:
|
|
55
|
-
"""Return list of selected row numbers."""
|
|
56
|
-
try:
|
|
57
|
-
return sorted([ix.row() for ix in self.selectionModel().selectedRows()])
|
|
58
|
-
except Exception:
|
|
59
|
-
return []
|
|
60
|
-
|
|
61
|
-
def _has_multi_selection(self) -> bool:
|
|
62
|
-
"""Check whether more than one row is selected."""
|
|
63
|
-
try:
|
|
64
|
-
return len(self.selectionModel().selectedRows()) > 1
|
|
65
|
-
except Exception:
|
|
66
|
-
return False
|
|
67
|
-
|
|
68
|
-
# ----------------------------
|
|
69
|
-
# Mouse events (virtual multi-select)
|
|
70
|
-
# ----------------------------
|
|
71
|
-
|
|
72
|
-
def mousePressEvent(self, event):
|
|
73
|
-
"""
|
|
74
|
-
Mouse press event
|
|
75
|
-
|
|
76
|
-
:param event: mouse event
|
|
77
|
-
"""
|
|
78
|
-
# Ctrl+Left: virtual toggle without business click
|
|
79
|
-
if event.button() == Qt.LeftButton and (event.modifiers() & Qt.ControlModifier):
|
|
80
|
-
idx = self.indexAt(event.pos())
|
|
81
|
-
if idx.isValid():
|
|
82
|
-
self._ctrl_multi_active = True
|
|
83
|
-
self._ctrl_multi_index = idx
|
|
84
|
-
self._suppress_item_click = True
|
|
85
|
-
event.accept()
|
|
86
|
-
return
|
|
87
|
-
self._suppress_item_click = True
|
|
88
|
-
event.accept()
|
|
89
|
-
return
|
|
90
|
-
|
|
91
|
-
# Shift+Left: let Qt perform range selection (anchor->clicked), suppress business click
|
|
92
|
-
if event.button() == Qt.LeftButton and (event.modifiers() & Qt.ShiftModifier):
|
|
93
|
-
idx = self.indexAt(event.pos())
|
|
94
|
-
self._suppress_item_click = True
|
|
95
|
-
self._was_shift_click = True
|
|
96
|
-
if idx.isValid():
|
|
97
|
-
super(RemoteStoreOpenAIEditorList, self).mousePressEvent(event)
|
|
98
|
-
else:
|
|
99
|
-
event.accept()
|
|
100
|
-
return
|
|
101
|
-
|
|
102
|
-
# Plain left click
|
|
103
|
-
if event.button() == Qt.LeftButton:
|
|
104
|
-
idx = self.indexAt(event.pos())
|
|
105
|
-
|
|
106
|
-
# When multiple are selected, a single plain click clears the multi-selection.
|
|
107
|
-
if self._has_multi_selection():
|
|
108
|
-
sel_model = self.selectionModel()
|
|
109
|
-
sel_model.clearSelection()
|
|
110
|
-
if not idx.isValid():
|
|
111
|
-
event.accept()
|
|
112
|
-
return
|
|
113
|
-
# continue with default single selection for clicked row
|
|
114
|
-
|
|
115
|
-
super(RemoteStoreOpenAIEditorList, self).mousePressEvent(event)
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
# Right click: prepare selection for context menu
|
|
119
|
-
if event.button() == Qt.RightButton:
|
|
120
|
-
idx = self.indexAt(event.pos())
|
|
121
|
-
sel_model = self.selectionModel()
|
|
122
|
-
selected_rows = [ix.row() for ix in sel_model.selectedRows()]
|
|
123
|
-
multi = len(selected_rows) > 1
|
|
124
|
-
|
|
125
|
-
if idx.isValid():
|
|
126
|
-
if multi and idx.row() in selected_rows:
|
|
127
|
-
# Keep existing multi-selection; do not alter selection on right click
|
|
128
|
-
self._backup_selection = None
|
|
129
|
-
else:
|
|
130
|
-
# Temporarily select the clicked row; backup previous selection to restore later
|
|
131
|
-
self._backup_selection = list(sel_model.selectedIndexes())
|
|
132
|
-
sel_model.clearSelection()
|
|
133
|
-
sel_model.select(idx, QItemSelectionModel.Select | QItemSelectionModel.Rows)
|
|
134
|
-
event.accept()
|
|
135
|
-
return
|
|
136
|
-
|
|
137
|
-
super(RemoteStoreOpenAIEditorList, self).mousePressEvent(event)
|
|
138
|
-
|
|
139
|
-
def mouseReleaseEvent(self, event):
|
|
140
|
-
# If the click was a Shift-based range selection, bypass business click
|
|
141
|
-
if event.button() == Qt.LeftButton and self._was_shift_click:
|
|
142
|
-
self._was_shift_click = False
|
|
143
|
-
self._suppress_item_click = False
|
|
144
|
-
super(RemoteStoreOpenAIEditorList, self).mouseReleaseEvent(event)
|
|
145
|
-
return
|
|
146
|
-
|
|
147
|
-
# Finish "virtual" Ctrl toggle on same row (no business click)
|
|
148
|
-
if event.button() == Qt.LeftButton and self._ctrl_multi_active:
|
|
149
|
-
try:
|
|
150
|
-
idx = self.indexAt(event.pos())
|
|
151
|
-
if idx.isValid() and self._ctrl_multi_index and idx == self._ctrl_multi_index:
|
|
152
|
-
sel_model = self.selectionModel()
|
|
153
|
-
sel_model.select(idx, QItemSelectionModel.Toggle | QItemSelectionModel.Rows)
|
|
154
|
-
finally:
|
|
155
|
-
self._ctrl_multi_active = False
|
|
156
|
-
self._ctrl_multi_index = None
|
|
157
|
-
self._suppress_item_click = False
|
|
158
|
-
event.accept()
|
|
159
|
-
return
|
|
160
|
-
|
|
161
|
-
# Plain left: perform business selection only for single selection
|
|
162
|
-
if event.button() == Qt.LeftButton:
|
|
163
|
-
idx = self.indexAt(event.pos())
|
|
164
|
-
if not self._has_multi_selection():
|
|
165
|
-
if idx.isValid() and not self._suppress_item_click:
|
|
166
|
-
self.window.controller.remote_store.openai.select(idx.row())
|
|
167
|
-
self._suppress_item_click = False
|
|
168
|
-
super(RemoteStoreOpenAIEditorList, self).mouseReleaseEvent(event)
|
|
169
|
-
return
|
|
170
|
-
|
|
171
|
-
super(RemoteStoreOpenAIEditorList, self).mouseReleaseEvent(event)
|
|
172
|
-
|
|
173
|
-
def click(self, val):
|
|
174
|
-
# Not used; single-selection business click is handled in mouseReleaseEvent
|
|
175
|
-
pass
|
|
176
|
-
|
|
177
|
-
# ----------------------------
|
|
178
|
-
# Context menu
|
|
179
|
-
# ----------------------------
|
|
180
|
-
|
|
181
|
-
def contextMenuEvent(self, event):
|
|
182
|
-
"""
|
|
183
|
-
Context menu event
|
|
184
|
-
|
|
185
|
-
:param event: context menu event
|
|
186
|
-
"""
|
|
187
|
-
actions = {}
|
|
188
|
-
actions['refresh'] = QAction(
|
|
189
|
-
QIcon(":/icons/reload.svg"),
|
|
190
|
-
trans('dialog.remote_store.menu.current.refresh_store'),
|
|
191
|
-
self
|
|
192
|
-
)
|
|
193
|
-
actions['delete'] = QAction(QIcon(":/icons/delete.svg"), trans('action.delete'), self)
|
|
194
|
-
actions['clear'] = QAction(
|
|
195
|
-
QIcon(":/icons/close.svg"),
|
|
196
|
-
trans('dialog.remote_store.menu.current.clear_files'),
|
|
197
|
-
self
|
|
198
|
-
)
|
|
199
|
-
actions['truncate'] = QAction(
|
|
200
|
-
QIcon(":/icons/delete.svg"),
|
|
201
|
-
trans('dialog.remote_store.menu.current.truncate_files'),
|
|
202
|
-
self
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
menu = QMenu(self)
|
|
206
|
-
menu.addAction(actions['refresh'])
|
|
207
|
-
menu.addAction(actions['delete'])
|
|
208
|
-
menu.addAction(actions['clear'])
|
|
209
|
-
menu.addAction(actions['truncate'])
|
|
210
|
-
|
|
211
|
-
index = self.indexAt(event.pos())
|
|
212
|
-
idx = index.row() if index.isValid() else -1
|
|
213
|
-
|
|
214
|
-
# Selection state for multi / single
|
|
215
|
-
selected_rows = self._selected_rows()
|
|
216
|
-
multi = len(selected_rows) > 1
|
|
217
|
-
|
|
218
|
-
# Allow menu on empty area only when multi-selection is active
|
|
219
|
-
if not index.isValid() and not multi:
|
|
220
|
-
if self._backup_selection is not None and self.restore_after_ctx_menu:
|
|
221
|
-
sel_model = self.selectionModel()
|
|
222
|
-
sel_model.clearSelection()
|
|
223
|
-
for i in self._backup_selection:
|
|
224
|
-
sel_model.select(i, QItemSelectionModel.Select | QItemSelectionModel.Rows)
|
|
225
|
-
self._backup_selection = None
|
|
226
|
-
return
|
|
227
|
-
|
|
228
|
-
# Route actions: pass list on multi, int on single
|
|
229
|
-
if multi:
|
|
230
|
-
actions['refresh'].triggered.connect(lambda: self.action_refresh(list(selected_rows)))
|
|
231
|
-
actions['delete'].triggered.connect(lambda: self.action_delete(list(selected_rows)))
|
|
232
|
-
actions['clear'].triggered.connect(lambda: self.action_clear(list(selected_rows)))
|
|
233
|
-
actions['truncate'].triggered.connect(lambda: self.action_truncate(list(selected_rows)))
|
|
234
|
-
else:
|
|
235
|
-
actions['refresh'].triggered.connect(lambda: self.action_refresh(idx))
|
|
236
|
-
actions['delete'].triggered.connect(lambda: self.action_delete(idx))
|
|
237
|
-
actions['clear'].triggered.connect(lambda: self.action_clear(idx))
|
|
238
|
-
actions['truncate'].triggered.connect(lambda: self.action_truncate(idx))
|
|
239
|
-
|
|
240
|
-
menu.exec_(event.globalPos())
|
|
241
|
-
|
|
242
|
-
# Restore selection after context menu if it was temporarily changed
|
|
243
|
-
if self.restore_after_ctx_menu and self._backup_selection is not None:
|
|
244
|
-
sel_model = self.selectionModel()
|
|
245
|
-
sel_model.clearSelection()
|
|
246
|
-
for i in self._backup_selection:
|
|
247
|
-
sel_model.select(i, QItemSelectionModel.Select | QItemSelectionModel.Rows)
|
|
248
|
-
self._backup_selection = None
|
|
249
|
-
self.restore_after_ctx_menu = True
|
|
250
|
-
|
|
251
|
-
# ----------------------------
|
|
252
|
-
# Context actions (single or multi)
|
|
253
|
-
# If 'item' is a list/tuple -> pass list of row ints to external code.
|
|
254
|
-
# If 'item' is an int -> pass single row int to external code.
|
|
255
|
-
# ----------------------------
|
|
256
|
-
|
|
257
|
-
def action_delete(self, item):
|
|
258
|
-
"""
|
|
259
|
-
Delete action handler
|
|
260
|
-
|
|
261
|
-
:param item: int row or list of rows
|
|
262
|
-
"""
|
|
263
|
-
if isinstance(item, (list, tuple)):
|
|
264
|
-
if item:
|
|
265
|
-
self.restore_after_ctx_menu = False
|
|
266
|
-
self.window.controller.remote_store.openai.delete_by_idx(list(item))
|
|
267
|
-
return
|
|
268
|
-
idx = int(item)
|
|
269
|
-
if idx >= 0:
|
|
270
|
-
self.restore_after_ctx_menu = False
|
|
271
|
-
self.window.controller.remote_store.openai.delete_by_idx(idx)
|
|
272
|
-
|
|
273
|
-
def action_clear(self, item):
|
|
274
|
-
"""
|
|
275
|
-
Clear action handler
|
|
276
|
-
|
|
277
|
-
:param item: int row or list of rows
|
|
278
|
-
"""
|
|
279
|
-
if isinstance(item, (list, tuple)):
|
|
280
|
-
if item:
|
|
281
|
-
self.restore_after_ctx_menu = False
|
|
282
|
-
self.window.controller.remote_store.openai.batch.clear_store_files_by_idx(list(item))
|
|
283
|
-
return
|
|
284
|
-
idx = int(item)
|
|
285
|
-
if idx >= 0:
|
|
286
|
-
self.restore_after_ctx_menu = False
|
|
287
|
-
self.window.controller.remote_store.openai.batch.clear_store_files_by_idx(idx)
|
|
288
|
-
|
|
289
|
-
def action_truncate(self, item):
|
|
290
|
-
"""
|
|
291
|
-
Truncate action handler
|
|
292
|
-
|
|
293
|
-
:param item: int row or list of rows
|
|
294
|
-
"""
|
|
295
|
-
if isinstance(item, (list, tuple)):
|
|
296
|
-
if item:
|
|
297
|
-
self.restore_after_ctx_menu = False
|
|
298
|
-
self.window.controller.remote_store.openai.batch.truncate_store_files_by_idx(list(item))
|
|
299
|
-
return
|
|
300
|
-
idx = int(item)
|
|
301
|
-
if idx >= 0:
|
|
302
|
-
self.restore_after_ctx_menu = False
|
|
303
|
-
self.window.controller.remote_store.openai.batch.truncate_store_files_by_idx(idx)
|
|
304
|
-
|
|
305
|
-
def action_refresh(self, item):
|
|
306
|
-
"""
|
|
307
|
-
Refresh action handler
|
|
308
|
-
"""
|
|
309
|
-
if isinstance(item, (list, tuple)):
|
|
310
|
-
if item:
|
|
311
|
-
self.restore_after_ctx_menu = False
|
|
312
|
-
self.window.controller.remote_store.openai.refresh_by_idx(list(item))
|
|
313
|
-
return
|
|
314
|
-
idx = int(item)
|
|
315
|
-
if idx >= 0:
|
|
316
|
-
self.restore_after_ctx_menu = False
|
|
317
|
-
self.window.controller.remote_store.openai.refresh_by_idx(idx)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|