pygpt-net 2.4.37__py3-none-any.whl → 2.4.42__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.
- CHANGELOG.md +37 -0
- README.md +176 -182
- pygpt_net/CHANGELOG.txt +37 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +3 -1
- pygpt_net/controller/__init__.py +7 -3
- pygpt_net/controller/access/control.py +1 -1
- pygpt_net/controller/access/voice.py +11 -5
- pygpt_net/controller/agent/experts.py +11 -6
- pygpt_net/controller/agent/legacy.py +8 -6
- pygpt_net/controller/agent/llama.py +4 -2
- pygpt_net/controller/assistant/__init__.py +9 -4
- pygpt_net/controller/assistant/batch.py +38 -21
- pygpt_net/controller/assistant/editor.py +7 -6
- pygpt_net/controller/assistant/files.py +23 -7
- pygpt_net/controller/assistant/store.py +20 -7
- pygpt_net/controller/assistant/threads.py +34 -8
- pygpt_net/controller/attachment.py +29 -10
- pygpt_net/controller/audio/__init__.py +26 -5
- pygpt_net/controller/calendar/__init__.py +23 -4
- pygpt_net/controller/calendar/note.py +57 -11
- pygpt_net/controller/camera.py +4 -12
- pygpt_net/controller/chat/__init__.py +5 -3
- pygpt_net/controller/chat/attachment.py +34 -7
- pygpt_net/controller/chat/audio.py +2 -2
- pygpt_net/controller/chat/command.py +4 -2
- pygpt_net/controller/chat/common.py +11 -4
- pygpt_net/controller/chat/files.py +10 -3
- pygpt_net/controller/chat/image.py +17 -5
- pygpt_net/controller/chat/input.py +10 -7
- pygpt_net/controller/chat/output.py +21 -6
- pygpt_net/controller/chat/render.py +100 -21
- pygpt_net/controller/chat/response.py +34 -7
- pygpt_net/controller/chat/stream.py +4 -2
- pygpt_net/controller/chat/text.py +6 -4
- pygpt_net/controller/command.py +11 -3
- pygpt_net/controller/config/__init__.py +34 -6
- pygpt_net/controller/config/field/checkbox.py +7 -4
- pygpt_net/controller/config/field/cmd.py +7 -5
- pygpt_net/controller/config/field/combo.py +14 -6
- pygpt_net/controller/config/field/dictionary.py +14 -11
- pygpt_net/controller/config/field/input.py +9 -6
- pygpt_net/controller/config/field/slider.py +11 -8
- pygpt_net/controller/config/field/textarea.py +8 -5
- pygpt_net/controller/config/placeholder.py +66 -21
- pygpt_net/controller/ctx/__init__.py +138 -49
- pygpt_net/controller/ctx/common.py +15 -4
- pygpt_net/controller/ctx/extra.py +11 -3
- pygpt_net/controller/ctx/summarizer.py +24 -5
- pygpt_net/controller/debug/__init__.py +27 -6
- pygpt_net/controller/dialogs/confirm.py +34 -7
- pygpt_net/controller/dialogs/debug.py +4 -2
- pygpt_net/controller/dialogs/info.py +7 -2
- pygpt_net/controller/files.py +48 -10
- pygpt_net/controller/finder.py +11 -5
- pygpt_net/controller/idx/__init__.py +10 -3
- pygpt_net/controller/idx/common.py +4 -2
- pygpt_net/controller/idx/indexer.py +25 -17
- pygpt_net/controller/idx/settings.py +9 -3
- pygpt_net/controller/kernel/__init__.py +34 -8
- pygpt_net/controller/kernel/reply.py +12 -3
- pygpt_net/controller/kernel/stack.py +5 -3
- pygpt_net/controller/lang/custom.py +2 -7
- pygpt_net/controller/lang/mapping.py +5 -3
- pygpt_net/controller/layout.py +2 -2
- pygpt_net/controller/mode.py +16 -4
- pygpt_net/controller/model/__init__.py +14 -3
- pygpt_net/controller/model/editor.py +8 -3
- pygpt_net/controller/notepad.py +26 -12
- pygpt_net/controller/painter/capture.py +23 -4
- pygpt_net/controller/painter/common.py +9 -7
- pygpt_net/controller/plugins/__init__.py +19 -5
- pygpt_net/controller/plugins/presets.py +15 -6
- pygpt_net/controller/plugins/settings.py +9 -3
- pygpt_net/controller/presets/__init__.py +55 -16
- pygpt_net/controller/presets/editor.py +26 -10
- pygpt_net/controller/settings/__init__.py +3 -2
- pygpt_net/controller/settings/editor.py +29 -7
- pygpt_net/controller/settings/profile.py +22 -5
- pygpt_net/controller/theme/__init__.py +54 -12
- pygpt_net/controller/theme/common.py +24 -2
- pygpt_net/controller/theme/markdown.py +32 -16
- pygpt_net/controller/theme/menu.py +26 -5
- pygpt_net/controller/theme/nodes.py +2 -5
- pygpt_net/controller/tools/__init__.py +40 -2
- pygpt_net/controller/ui/__init__.py +4 -6
- pygpt_net/controller/ui/mode.py +16 -21
- pygpt_net/controller/ui/tabs.py +363 -65
- pygpt_net/core/access/actions.py +6 -4
- pygpt_net/core/access/shortcuts.py +4 -3
- pygpt_net/core/access/voice.py +6 -5
- pygpt_net/core/agents/legacy.py +4 -2
- pygpt_net/core/agents/memory.py +7 -2
- pygpt_net/core/agents/observer/evaluation.py +15 -7
- pygpt_net/core/agents/provider.py +9 -4
- pygpt_net/core/agents/runner.py +61 -15
- pygpt_net/core/agents/tools.py +23 -5
- pygpt_net/core/assistants/__init__.py +6 -4
- pygpt_net/core/assistants/files.py +35 -12
- pygpt_net/core/assistants/store.py +20 -10
- pygpt_net/core/attachments/__init__.py +54 -15
- pygpt_net/core/attachments/context.py +92 -29
- pygpt_net/core/audio/__init__.py +74 -3
- pygpt_net/core/audio/context.py +7 -2
- pygpt_net/core/audio/whisper.py +37 -0
- pygpt_net/core/bridge/__init__.py +22 -6
- pygpt_net/core/bridge/context.py +5 -3
- pygpt_net/core/bridge/worker.py +2 -2
- pygpt_net/core/calendar/__init__.py +57 -11
- pygpt_net/core/chain/__init__.py +8 -2
- pygpt_net/core/chain/chat.py +10 -8
- pygpt_net/core/chain/completion.py +10 -7
- pygpt_net/core/command.py +62 -17
- pygpt_net/core/ctx/__init__.py +260 -58
- pygpt_net/core/ctx/bag.py +25 -4
- pygpt_net/core/ctx/container.py +28 -17
- pygpt_net/core/ctx/idx.py +45 -8
- pygpt_net/core/ctx/output.py +95 -74
- pygpt_net/core/ctx/reply.py +5 -2
- pygpt_net/core/db/__init__.py +8 -7
- pygpt_net/core/db/viewer.py +17 -11
- pygpt_net/core/debug/__init__.py +10 -9
- pygpt_net/core/debug/events.py +22 -10
- pygpt_net/core/debug/tabs.py +9 -3
- pygpt_net/core/docker/__init__.py +11 -5
- pygpt_net/core/docker/builder.py +11 -3
- pygpt_net/core/events/app.py +5 -3
- pygpt_net/core/events/base.py +11 -5
- pygpt_net/core/events/control.py +5 -3
- pygpt_net/core/events/event.py +17 -7
- pygpt_net/core/events/kernel.py +5 -3
- pygpt_net/core/events/render.py +5 -3
- pygpt_net/core/experts/__init__.py +5 -4
- pygpt_net/core/filesystem/__init__.py +52 -34
- pygpt_net/core/filesystem/actions.py +8 -5
- pygpt_net/core/filesystem/editor.py +13 -3
- pygpt_net/core/filesystem/types.py +12 -7
- pygpt_net/core/filesystem/url.py +7 -3
- pygpt_net/core/history.py +3 -2
- pygpt_net/core/idx/__init__.py +48 -27
- pygpt_net/core/idx/chat.py +51 -17
- pygpt_net/core/idx/context.py +6 -2
- pygpt_net/core/idx/indexing.py +107 -42
- pygpt_net/core/idx/llm.py +11 -3
- pygpt_net/core/idx/metadata.py +13 -3
- pygpt_net/core/idx/types/ctx.py +32 -6
- pygpt_net/core/idx/types/external.py +41 -7
- pygpt_net/core/idx/types/files.py +31 -6
- pygpt_net/core/image.py +15 -4
- pygpt_net/core/installer.py +2 -4
- pygpt_net/core/llm/__init__.py +13 -3
- pygpt_net/core/locale.py +34 -8
- pygpt_net/core/models.py +63 -17
- pygpt_net/core/modes.py +11 -13
- pygpt_net/core/notepad.py +10 -5
- pygpt_net/core/plugins.py +31 -19
- pygpt_net/core/presets.py +37 -17
- pygpt_net/core/profile.py +21 -7
- pygpt_net/core/prompt/__init__.py +10 -3
- pygpt_net/core/prompt/custom.py +7 -6
- pygpt_net/core/prompt/template.py +9 -3
- pygpt_net/core/render/base.py +117 -22
- pygpt_net/core/render/markdown/body.py +27 -7
- pygpt_net/core/render/markdown/renderer.py +119 -22
- pygpt_net/core/render/plain/body.py +22 -5
- pygpt_net/core/render/plain/renderer.py +97 -21
- pygpt_net/core/render/web/body.py +75 -25
- pygpt_net/core/render/web/parser.py +3 -1
- pygpt_net/core/render/web/renderer.py +313 -63
- pygpt_net/core/settings.py +10 -5
- pygpt_net/core/tabs/__init__.py +290 -103
- pygpt_net/core/tabs/tab.py +26 -5
- pygpt_net/core/tokens.py +47 -12
- pygpt_net/core/updater/__init__.py +20 -7
- pygpt_net/core/vision/analyzer.py +29 -6
- pygpt_net/core/{web.py → web/__init__.py} +29 -7
- pygpt_net/core/web/helpers.py +237 -0
- pygpt_net/data/config/config.json +15 -4
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/modes.json +3 -3
- pygpt_net/data/config/settings.json +55 -10
- pygpt_net/data/config/settings_section.json +3 -0
- pygpt_net/data/css/style.light.css +1 -0
- pygpt_net/data/css/{web.css → web-blocks.css} +162 -133
- pygpt_net/data/css/{web.light.css → web-blocks.light.css} +7 -0
- pygpt_net/data/css/web-chatgpt.css +350 -0
- pygpt_net/data/css/web-chatgpt.dark.css +64 -0
- pygpt_net/data/css/web-chatgpt.light.css +75 -0
- pygpt_net/data/css/web-chatgpt_wide.css +350 -0
- pygpt_net/data/css/web-chatgpt_wide.dark.css +64 -0
- pygpt_net/data/css/web-chatgpt_wide.light.css +75 -0
- pygpt_net/data/icons/split_screen.svg +1 -0
- pygpt_net/data/locale/locale.de.ini +12 -0
- pygpt_net/data/locale/locale.en.ini +18 -2
- pygpt_net/data/locale/locale.es.ini +12 -0
- pygpt_net/data/locale/locale.fr.ini +12 -0
- pygpt_net/data/locale/locale.it.ini +12 -0
- pygpt_net/data/locale/locale.pl.ini +12 -0
- pygpt_net/data/locale/locale.uk.ini +12 -0
- pygpt_net/data/locale/locale.zh.ini +12 -0
- pygpt_net/data/locale/plugin.cmd_web.de.ini +2 -0
- pygpt_net/data/locale/plugin.cmd_web.en.ini +22 -10
- pygpt_net/data/locale/plugin.cmd_web.es.ini +2 -0
- pygpt_net/data/locale/plugin.cmd_web.fr.ini +2 -0
- pygpt_net/data/locale/plugin.cmd_web.it.ini +2 -0
- pygpt_net/data/locale/plugin.cmd_web.pl.ini +2 -0
- pygpt_net/data/locale/plugin.cmd_web.uk.ini +2 -0
- pygpt_net/data/locale/plugin.cmd_web.zh.ini +2 -0
- pygpt_net/data/locale/plugin.mailer.en.ini +21 -0
- pygpt_net/icons.qrc +1 -0
- pygpt_net/icons_rc.py +165 -136
- pygpt_net/item/ctx.py +58 -25
- pygpt_net/plugin/agent/__init__.py +7 -2
- pygpt_net/plugin/audio_input/simple.py +21 -5
- pygpt_net/plugin/audio_output/__init__.py +9 -1
- pygpt_net/plugin/base/config.py +4 -2
- pygpt_net/plugin/base/plugin.py +75 -23
- pygpt_net/plugin/base/worker.py +42 -11
- pygpt_net/plugin/cmd_code_interpreter/__init__.py +39 -37
- pygpt_net/plugin/cmd_code_interpreter/runner.py +25 -12
- pygpt_net/plugin/cmd_history/config.py +2 -2
- pygpt_net/plugin/cmd_web/__init__.py +48 -9
- pygpt_net/plugin/cmd_web/config.py +135 -41
- pygpt_net/plugin/cmd_web/websearch.py +74 -33
- pygpt_net/plugin/cmd_web/worker.py +142 -13
- pygpt_net/plugin/idx_llama_index/config.py +3 -3
- pygpt_net/plugin/mailer/__init__.py +123 -0
- pygpt_net/plugin/mailer/config.py +149 -0
- pygpt_net/plugin/mailer/runner.py +285 -0
- pygpt_net/plugin/mailer/worker.py +123 -0
- pygpt_net/provider/agents/base.py +5 -2
- pygpt_net/provider/agents/openai.py +4 -2
- pygpt_net/provider/agents/openai_assistant.py +4 -2
- pygpt_net/provider/agents/planner.py +4 -2
- pygpt_net/provider/agents/react.py +4 -2
- pygpt_net/provider/audio_output/openai_tts.py +5 -11
- pygpt_net/provider/core/assistant/base.py +5 -3
- pygpt_net/provider/core/assistant/json_file.py +8 -5
- pygpt_net/provider/core/assistant_file/base.py +4 -3
- pygpt_net/provider/core/assistant_file/db_sqlite/__init__.py +4 -3
- pygpt_net/provider/core/assistant_file/db_sqlite/storage.py +3 -2
- pygpt_net/provider/core/assistant_store/base.py +6 -4
- pygpt_net/provider/core/assistant_store/db_sqlite/__init__.py +5 -4
- pygpt_net/provider/core/assistant_store/db_sqlite/storage.py +5 -3
- pygpt_net/provider/core/attachment/base.py +5 -3
- pygpt_net/provider/core/attachment/json_file.py +4 -3
- pygpt_net/provider/core/calendar/base.py +5 -3
- pygpt_net/provider/core/calendar/db_sqlite/__init__.py +6 -5
- pygpt_net/provider/core/calendar/db_sqlite/storage.py +5 -4
- pygpt_net/provider/core/config/base.py +8 -6
- pygpt_net/provider/core/config/json_file.py +9 -7
- pygpt_net/provider/core/config/patch.py +43 -1
- pygpt_net/provider/core/ctx/base.py +30 -25
- pygpt_net/provider/core/ctx/db_sqlite/__init__.py +59 -34
- pygpt_net/provider/core/ctx/db_sqlite/storage.py +62 -30
- pygpt_net/provider/core/ctx/db_sqlite/utils.py +11 -9
- pygpt_net/provider/core/index/base.py +129 -23
- pygpt_net/provider/core/index/db_sqlite/__init__.py +130 -23
- pygpt_net/provider/core/index/db_sqlite/storage.py +130 -23
- pygpt_net/provider/core/index/db_sqlite/utils.py +4 -2
- pygpt_net/provider/core/mode/base.py +5 -3
- pygpt_net/provider/core/mode/json_file.py +7 -6
- pygpt_net/provider/core/model/base.py +6 -4
- pygpt_net/provider/core/model/json_file.py +9 -7
- pygpt_net/provider/core/notepad/base.py +5 -3
- pygpt_net/provider/core/notepad/db_sqlite/__init__.py +5 -4
- pygpt_net/provider/core/notepad/db_sqlite/storage.py +4 -3
- pygpt_net/provider/core/plugin_preset/base.py +4 -2
- pygpt_net/provider/core/plugin_preset/json_file.py +5 -3
- pygpt_net/provider/core/preset/base.py +6 -4
- pygpt_net/provider/core/preset/json_file.py +9 -9
- pygpt_net/provider/core/prompt/base.py +6 -3
- pygpt_net/provider/core/prompt/json_file.py +11 -6
- pygpt_net/provider/gpt/assistants.py +21 -11
- pygpt_net/provider/gpt/audio.py +6 -5
- pygpt_net/provider/gpt/chat.py +10 -7
- pygpt_net/provider/gpt/completion.py +11 -5
- pygpt_net/provider/gpt/image.py +9 -2
- pygpt_net/provider/gpt/store.py +53 -18
- pygpt_net/provider/gpt/vision.py +17 -11
- pygpt_net/provider/llms/anthropic.py +7 -2
- pygpt_net/provider/llms/azure_openai.py +26 -5
- pygpt_net/provider/llms/base.py +47 -9
- pygpt_net/provider/llms/google.py +7 -2
- pygpt_net/provider/llms/hugging_face.py +13 -3
- pygpt_net/provider/llms/hugging_face_api.py +18 -4
- pygpt_net/provider/llms/local.py +7 -2
- pygpt_net/provider/llms/ollama.py +30 -6
- pygpt_net/provider/llms/openai.py +32 -6
- pygpt_net/provider/vector_stores/__init__.py +45 -14
- pygpt_net/provider/vector_stores/base.py +35 -8
- pygpt_net/provider/vector_stores/chroma.py +13 -3
- pygpt_net/provider/vector_stores/ctx_attachment.py +31 -12
- pygpt_net/provider/vector_stores/elasticsearch.py +12 -3
- pygpt_net/provider/vector_stores/pinecode.py +12 -3
- pygpt_net/provider/vector_stores/redis.py +12 -3
- pygpt_net/provider/vector_stores/simple.py +12 -3
- pygpt_net/provider/vector_stores/temp.py +16 -4
- pygpt_net/provider/web/base.py +10 -3
- pygpt_net/provider/web/google_custom_search.py +9 -3
- pygpt_net/provider/web/microsoft_bing.py +9 -3
- pygpt_net/tools/__init__.py +20 -4
- pygpt_net/tools/audio_transcriber/__init__.py +4 -3
- pygpt_net/tools/base.py +28 -7
- pygpt_net/tools/code_interpreter/__init__.py +177 -77
- pygpt_net/tools/code_interpreter/ui/dialogs.py +21 -103
- pygpt_net/tools/code_interpreter/ui/widgets.py +284 -9
- pygpt_net/tools/html_canvas/__init__.py +81 -25
- pygpt_net/tools/html_canvas/ui/dialogs.py +46 -62
- pygpt_net/tools/html_canvas/ui/widgets.py +96 -3
- pygpt_net/tools/image_viewer/__init__.py +10 -4
- pygpt_net/tools/indexer/__init__.py +8 -7
- pygpt_net/tools/media_player/__init__.py +4 -3
- pygpt_net/tools/text_editor/__init__.py +36 -10
- pygpt_net/ui/base/context_menu.py +2 -2
- pygpt_net/ui/layout/chat/input.py +10 -18
- pygpt_net/ui/layout/chat/output.py +27 -45
- pygpt_net/ui/layout/ctx/ctx_list.py +13 -4
- pygpt_net/ui/layout/toolbox/footer.py +18 -2
- pygpt_net/ui/main.py +2 -2
- pygpt_net/ui/menu/audio.py +12 -1
- pygpt_net/ui/menu/config.py +7 -11
- pygpt_net/ui/menu/debug.py +11 -1
- pygpt_net/ui/menu/theme.py +9 -2
- pygpt_net/ui/widget/filesystem/explorer.py +2 -2
- pygpt_net/ui/widget/lists/context.py +27 -5
- pygpt_net/ui/widget/tabs/Input.py +2 -2
- pygpt_net/ui/widget/tabs/body.py +2 -1
- pygpt_net/ui/widget/tabs/layout.py +195 -0
- pygpt_net/ui/widget/tabs/output.py +218 -55
- pygpt_net/ui/widget/textarea/html.py +11 -1
- pygpt_net/ui/widget/textarea/output.py +10 -1
- pygpt_net/ui/widget/textarea/search_input.py +4 -1
- pygpt_net/ui/widget/textarea/web.py +49 -9
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/METADATA +177 -183
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/RECORD +340 -325
- /pygpt_net/data/css/{web.dark.css → web-blocks.dark.css} +0 -0
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/LICENSE +0 -0
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/WHEEL +0 -0
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/entry_points.txt +0 -0
pygpt_net/controller/ui/tabs.py
CHANGED
@@ -6,13 +6,16 @@
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
7
7
|
# MIT License #
|
8
8
|
# Created By : Marcin Szczygliński #
|
9
|
-
# Updated Date: 2024.
|
9
|
+
# Updated Date: 2024.12.14 07:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
|
+
from typing import Any, Optional
|
13
|
+
|
12
14
|
from PySide6.QtCore import QTimer
|
13
15
|
|
14
16
|
from pygpt_net.core.events import AppEvent, RenderEvent
|
15
17
|
from pygpt_net.core.tabs.tab import Tab
|
18
|
+
from pygpt_net.item.ctx import CtxMeta
|
16
19
|
from pygpt_net.utils import trans
|
17
20
|
|
18
21
|
|
@@ -29,40 +32,91 @@ class Tabs:
|
|
29
32
|
self.initialized = False
|
30
33
|
self.appended = False
|
31
34
|
self.current = 0
|
35
|
+
self.column_idx = 0
|
36
|
+
self.tmp_column_idx = 0
|
37
|
+
self.locked = False
|
38
|
+
self.col = {}
|
32
39
|
|
33
40
|
def setup(self):
|
34
41
|
"""Setup tabs"""
|
35
42
|
self.window.core.tabs.load()
|
36
43
|
self.window.controller.notepad.load()
|
44
|
+
self.setup_options()
|
37
45
|
self.initialized = True
|
38
46
|
|
39
|
-
def
|
40
|
-
"""
|
41
|
-
|
47
|
+
def setup_options(self):
|
48
|
+
"""Setup options"""
|
49
|
+
state = self.window.core.config.get("layout.split", False)
|
50
|
+
self.window.ui.nodes['layout.split'].setChecked(state)
|
51
|
+
if not state:
|
52
|
+
self.window.ui.splitters['columns'].setSizes([1, 0])
|
53
|
+
|
54
|
+
def add(
|
55
|
+
self,
|
56
|
+
type: int,
|
57
|
+
title: str,
|
58
|
+
icon: Optional[str] = None,
|
59
|
+
child: Any = None,
|
60
|
+
data_id: Optional[int] = None,
|
61
|
+
tool_id: Optional[str] = None,
|
62
|
+
):
|
63
|
+
"""
|
64
|
+
Add a new tab
|
42
65
|
|
43
66
|
:param type: Tab type
|
44
67
|
:param title: Tab title
|
45
68
|
:param icon: Tab icon
|
46
|
-
:param
|
47
|
-
:param data_id: Tab data ID
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
69
|
+
:param child: Tab child (child widget)
|
70
|
+
:param data_id: Tab data ID (child data ID)
|
71
|
+
:param tool_id: Tool ID
|
72
|
+
"""
|
73
|
+
self.window.core.tabs.add(
|
74
|
+
type=type,
|
75
|
+
title=title,
|
76
|
+
icon=icon,
|
77
|
+
child=child,
|
78
|
+
data_id=data_id,
|
79
|
+
tool_id=tool_id
|
80
|
+
)
|
81
|
+
|
82
|
+
def append(
|
83
|
+
self,
|
84
|
+
type: int,
|
85
|
+
tool_id: Optional[str] = None,
|
86
|
+
idx: int = 0,
|
87
|
+
column_idx: int = 0
|
88
|
+
):
|
89
|
+
"""
|
90
|
+
Append tab at tab index
|
54
91
|
|
55
92
|
:param type: Tab type
|
93
|
+
:param tool_id: Tool ID
|
56
94
|
:param idx: Tab index
|
95
|
+
:param column_idx: Column index
|
57
96
|
"""
|
58
97
|
self.appended = True # lock reload in previous tab
|
59
|
-
self.
|
60
|
-
self.
|
98
|
+
self.column_idx = column_idx # switch to column
|
99
|
+
tab = self.window.core.tabs.append(
|
100
|
+
type=type,
|
101
|
+
idx=idx,
|
102
|
+
column_idx=column_idx,
|
103
|
+
tool_id=tool_id
|
104
|
+
)
|
105
|
+
self.switch_tab_by_idx(tab.idx, column_idx) # switch to new tab
|
61
106
|
|
62
107
|
def reload_titles(self):
|
63
108
|
"""Reload tab titles"""
|
64
109
|
self.window.core.tabs.reload_titles()
|
65
110
|
|
111
|
+
def update_current(self):
|
112
|
+
"""Update current tab"""
|
113
|
+
curr_tab = self.get_current_tab()
|
114
|
+
curr_column = self.get_current_column_idx()
|
115
|
+
if curr_column not in self.col:
|
116
|
+
self.col[curr_column] = -1
|
117
|
+
if curr_tab is not None:
|
118
|
+
self.col[curr_column] = curr_tab.pid
|
119
|
+
|
66
120
|
def reload(self):
|
67
121
|
"""Reload tabs"""
|
68
122
|
self.window.core.tabs.reload()
|
@@ -78,15 +132,20 @@ class Tabs:
|
|
78
132
|
else:
|
79
133
|
self.window.ui.nodes['output_plain'][pid].setVisible(False)
|
80
134
|
self.window.ui.nodes['output'][pid].setVisible(True)
|
81
|
-
self.switch_tab(Tab.TAB_CHAT)
|
135
|
+
#self.switch_tab(Tab.TAB_CHAT)
|
82
136
|
|
83
|
-
def on_tab_changed(
|
137
|
+
def on_tab_changed(
|
138
|
+
self,
|
139
|
+
idx: int,
|
140
|
+
column_idx: int = 0
|
141
|
+
):
|
84
142
|
"""
|
85
143
|
Output tab changed
|
86
144
|
|
87
145
|
:param idx: tab index
|
146
|
+
:param column_idx: column index
|
88
147
|
"""
|
89
|
-
tab = self.window.core.tabs.get_tab_by_index(idx)
|
148
|
+
tab = self.window.core.tabs.get_tab_by_index(idx, column_idx)
|
90
149
|
if tab is None:
|
91
150
|
self.appended = False
|
92
151
|
return
|
@@ -99,147 +158,242 @@ class Tabs:
|
|
99
158
|
if meta is not None:
|
100
159
|
self.window.controller.ctx.load(meta.id) # reload
|
101
160
|
|
102
|
-
|
103
161
|
prev_tab = self.current
|
162
|
+
prev_column = self.column_idx
|
104
163
|
self.current = idx
|
164
|
+
self.column_idx = column_idx
|
105
165
|
self.window.controller.ui.mode.update()
|
106
166
|
self.window.controller.ui.vision.update()
|
107
167
|
|
108
168
|
# check type
|
109
169
|
if tab.type == Tab.TAB_NOTEPAD:
|
110
170
|
self.window.controller.notepad.opened_once = True
|
111
|
-
self.window.controller.notepad.on_open(idx)
|
171
|
+
self.window.controller.notepad.on_open(idx, column_idx)
|
112
172
|
elif tab.type == Tab.TAB_CHAT:
|
113
|
-
|
114
|
-
|
173
|
+
# get meta for selected tab, if not loaded yet then append meta here
|
174
|
+
meta_id = self.window.core.ctx.output.prepare_meta(tab)
|
175
|
+
meta = self.window.core.ctx.get_meta_by_id(meta_id)
|
115
176
|
if meta is not None:
|
116
|
-
self.window.controller.ctx.load(
|
177
|
+
self.window.controller.ctx.load(meta.id) # reload renderer
|
117
178
|
elif tab.type == Tab.TAB_TOOL_PAINTER:
|
118
179
|
if self.window.core.config.get('vision.capture.enabled'):
|
119
180
|
self.window.controller.camera.enable_capture()
|
120
181
|
|
121
|
-
if prev_tab != idx:
|
182
|
+
if prev_tab != idx or prev_column != column_idx:
|
122
183
|
self.window.dispatch(AppEvent(AppEvent.TAB_SELECTED)) # app event
|
123
184
|
|
124
|
-
|
185
|
+
self.window.controller.ui.update()
|
186
|
+
self.update_current()
|
187
|
+
|
188
|
+
def get_current_idx(self, column_idx: int = 0) -> int:
|
125
189
|
"""
|
126
190
|
Get current tab index
|
127
191
|
|
192
|
+
:param column_idx: column index
|
128
193
|
:return: tab index
|
129
194
|
"""
|
130
195
|
return self.current
|
131
196
|
|
132
|
-
def
|
197
|
+
def get_current_column_idx(self) -> int:
|
198
|
+
"""
|
199
|
+
Get current column index
|
200
|
+
|
201
|
+
:return: column index
|
202
|
+
"""
|
203
|
+
return self.column_idx
|
204
|
+
|
205
|
+
def get_current_tab(self) -> Optional[Tab]:
|
133
206
|
"""
|
134
207
|
Get current tab
|
135
208
|
|
136
209
|
:return: tab
|
137
210
|
"""
|
138
|
-
return self.window.core.tabs.get_tab_by_index(self.
|
211
|
+
return self.window.core.tabs.get_tab_by_index(self.get_current_idx(), self.column_idx)
|
139
212
|
|
140
|
-
def get_current_type(self) -> int
|
213
|
+
def get_current_type(self) -> Optional[int]:
|
141
214
|
"""
|
142
215
|
Get current tab type
|
143
216
|
|
144
217
|
:return: tab type
|
145
218
|
"""
|
146
|
-
tab = self.window.core.tabs.get_tab_by_index(self.
|
219
|
+
tab = self.window.core.tabs.get_tab_by_index(self.get_current_idx(), self.column_idx)
|
220
|
+
|
147
221
|
if tab is None:
|
148
222
|
return None
|
149
223
|
return tab.type
|
150
224
|
|
151
|
-
def get_current_pid(self) -> int
|
225
|
+
def get_current_pid(self) -> Optional[int]:
|
152
226
|
"""
|
153
227
|
Get current tab PID
|
154
228
|
|
155
229
|
:return: tab PID
|
156
230
|
"""
|
157
|
-
tab = self.window.core.tabs.get_tab_by_index(self.
|
231
|
+
tab = self.window.core.tabs.get_tab_by_index(self.get_current_idx(), self.column_idx)
|
158
232
|
if tab is None:
|
159
233
|
return None
|
160
234
|
return tab.pid
|
161
235
|
|
162
|
-
def get_type_by_idx(self, idx: int) -> int
|
236
|
+
def get_type_by_idx(self, idx: int) -> Optional[int]:
|
163
237
|
"""
|
164
238
|
Get tab type by index
|
165
239
|
|
166
240
|
:param idx: tab index
|
167
241
|
:return: tab type
|
168
242
|
"""
|
169
|
-
tab = self.window.core.tabs.get_tab_by_index(idx)
|
243
|
+
tab = self.window.core.tabs.get_tab_by_index(idx, self.column_idx)
|
170
244
|
if tab is None:
|
171
245
|
return None
|
172
246
|
return tab.type
|
173
247
|
|
174
|
-
def get_first_idx_by_type(self, type: int) -> int
|
248
|
+
def get_first_idx_by_type(self, type: int) -> Optional[int]:
|
175
249
|
"""
|
176
250
|
Get first tab index by type
|
177
251
|
|
178
252
|
:param type: tab type
|
179
253
|
:return: tab index
|
180
254
|
"""
|
181
|
-
return self.window.core.tabs.get_min_idx_by_type(type)
|
255
|
+
return self.window.core.tabs.get_min_idx_by_type(type, self.column_idx)
|
182
256
|
|
183
|
-
def
|
257
|
+
def on_column_changed(self):
|
258
|
+
"""Column changed event"""
|
259
|
+
if self.locked:
|
260
|
+
return
|
261
|
+
tabs = self.window.ui.layout.get_tabs_by_idx(self.column_idx)
|
262
|
+
tabs.set_active(True)
|
263
|
+
|
264
|
+
if self.column_idx == 0:
|
265
|
+
second_tabs = self.window.ui.layout.get_tabs_by_idx(1)
|
266
|
+
else:
|
267
|
+
second_tabs = self.window.ui.layout.get_tabs_by_idx(0)
|
268
|
+
second_tabs.set_active(False)
|
269
|
+
idx = tabs.currentIndex()
|
270
|
+
self.current = idx
|
271
|
+
tab = self.window.core.tabs.get_tab_by_index(self.current, self.column_idx)
|
272
|
+
if tab is None:
|
273
|
+
return
|
274
|
+
current_ctx = self.window.core.ctx.get_current()
|
275
|
+
if (current_ctx is not None and current_ctx != tab.data_id) or current_ctx is None:
|
276
|
+
self.window.controller.ctx.select_on_list_only(tab.data_id)
|
277
|
+
self.window.controller.ui.update()
|
278
|
+
self.update_current()
|
279
|
+
|
280
|
+
def on_tab_clicked(
|
281
|
+
self,
|
282
|
+
idx: int,
|
283
|
+
column_idx: int = 0
|
284
|
+
):
|
184
285
|
"""
|
185
286
|
Tab click event
|
186
287
|
|
187
288
|
:param idx: tab index
|
289
|
+
:param column_idx: column index
|
290
|
+
"""
|
291
|
+
self.current = idx
|
292
|
+
self.column_idx = column_idx
|
293
|
+
self.on_column_changed()
|
294
|
+
self.update_current()
|
295
|
+
|
296
|
+
def on_column_focus(self, idx: int):
|
297
|
+
"""
|
298
|
+
Column focus event
|
299
|
+
|
300
|
+
:param idx: column index
|
188
301
|
"""
|
189
|
-
|
302
|
+
self.column_idx = idx
|
303
|
+
self.on_column_changed()
|
304
|
+
self.update_current()
|
190
305
|
|
191
|
-
def on_tab_dbl_clicked(
|
306
|
+
def on_tab_dbl_clicked(
|
307
|
+
self,
|
308
|
+
idx: int,
|
309
|
+
column_idx: int = 0
|
310
|
+
):
|
192
311
|
"""
|
193
312
|
Tab double click event
|
194
313
|
|
195
314
|
:param idx: tab index
|
315
|
+
:param column_idx: column index
|
196
316
|
"""
|
197
|
-
|
317
|
+
self.column_idx = column_idx
|
318
|
+
self.on_tab_changed(idx, column_idx)
|
319
|
+
self.update_current()
|
198
320
|
|
199
|
-
def on_tab_closed(
|
321
|
+
def on_tab_closed(
|
322
|
+
self,
|
323
|
+
idx: int,
|
324
|
+
column_idx: int = 0
|
325
|
+
):
|
200
326
|
"""
|
201
327
|
Tab close event
|
202
328
|
|
203
329
|
:param idx: tab index
|
330
|
+
:param column_idx: column index
|
204
331
|
"""
|
205
|
-
self.
|
332
|
+
if self.locked:
|
333
|
+
return
|
334
|
+
self.window.core.tabs.remove_tab_by_idx(idx, column_idx)
|
335
|
+
self.update_current()
|
206
336
|
|
207
|
-
def on_tab_moved(
|
337
|
+
def on_tab_moved(
|
338
|
+
self,
|
339
|
+
idx: int,
|
340
|
+
column_idx: int = 0
|
341
|
+
):
|
208
342
|
"""
|
209
343
|
Tab moved event
|
210
344
|
|
211
345
|
:param idx: tab index
|
346
|
+
:param column_idx: column index
|
212
347
|
"""
|
348
|
+
if self.locked:
|
349
|
+
return
|
213
350
|
self.window.core.tabs.update()
|
351
|
+
self.update_current()
|
214
352
|
|
215
|
-
def close(
|
353
|
+
def close(
|
354
|
+
self,
|
355
|
+
idx: int,
|
356
|
+
column_idx: int = 0
|
357
|
+
):
|
216
358
|
"""
|
217
359
|
Close tab
|
218
360
|
|
219
361
|
:param idx: tab index
|
362
|
+
:param column_idx: column index
|
220
363
|
"""
|
221
|
-
self.on_tab_closed(idx)
|
364
|
+
self.on_tab_closed(idx, column_idx)
|
365
|
+
self.update_current()
|
222
366
|
|
223
|
-
def close_all(
|
367
|
+
def close_all(
|
368
|
+
self,
|
369
|
+
type: int,
|
370
|
+
column_idx: int = 0,
|
371
|
+
force: bool = False
|
372
|
+
):
|
224
373
|
"""
|
225
374
|
Close all tabs
|
226
375
|
|
227
376
|
:param type: tab type
|
377
|
+
:param column_idx: column index
|
228
378
|
:param force: force close
|
229
379
|
"""
|
230
380
|
if not force:
|
381
|
+
self.tmp_column_idx = column_idx
|
231
382
|
self.window.ui.dialogs.confirm(
|
232
383
|
type='tab.close_all',
|
233
384
|
id=type,
|
234
385
|
msg=trans('tab.close_all.confirm'),
|
235
386
|
)
|
236
387
|
return
|
237
|
-
self.
|
388
|
+
column_idx = self.tmp_column_idx
|
389
|
+
self.window.core.tabs.remove_all_by_type(type, column_idx)
|
390
|
+
self.update_current()
|
238
391
|
|
239
392
|
def next_tab(self):
|
240
393
|
"""Switch to next tab"""
|
241
|
-
|
242
|
-
|
394
|
+
tabs = self.window.ui.layout.get_active_tabs()
|
395
|
+
current = tabs.currentIndex()
|
396
|
+
all = len(tabs.children())
|
243
397
|
next = current + 1
|
244
398
|
if next >= all:
|
245
399
|
next = 0
|
@@ -247,8 +401,9 @@ class Tabs:
|
|
247
401
|
|
248
402
|
def prev_tab(self):
|
249
403
|
"""Switch to previous tab"""
|
250
|
-
|
251
|
-
|
404
|
+
tabs = self.window.ui.layout.get_active_tabs()
|
405
|
+
current = tabs.currentIndex()
|
406
|
+
all = len(tabs.children())
|
252
407
|
prev = current - 1
|
253
408
|
if prev < 0:
|
254
409
|
prev = all - 1
|
@@ -264,14 +419,20 @@ class Tabs:
|
|
264
419
|
if idx is not None:
|
265
420
|
self.switch_tab_by_idx(idx)
|
266
421
|
|
267
|
-
def switch_tab_by_idx(
|
422
|
+
def switch_tab_by_idx(
|
423
|
+
self,
|
424
|
+
idx: int,
|
425
|
+
column_idx: int = 0
|
426
|
+
):
|
268
427
|
"""
|
269
428
|
Switch tab by index
|
270
429
|
|
271
430
|
:param idx: tab index
|
431
|
+
:param column_idx: column index
|
272
432
|
"""
|
273
|
-
self.window.ui.
|
274
|
-
|
433
|
+
tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
|
434
|
+
tabs.setCurrentIndex(idx)
|
435
|
+
self.on_tab_changed(idx, column_idx)
|
275
436
|
|
276
437
|
def get_current_tab_name(self) -> str:
|
277
438
|
"""
|
@@ -279,7 +440,8 @@ class Tabs:
|
|
279
440
|
|
280
441
|
:return: tab name
|
281
442
|
"""
|
282
|
-
|
443
|
+
tabs = self.window.ui.layout.get_active_tabs()
|
444
|
+
return tabs.tabText(self.current)
|
283
445
|
|
284
446
|
def get_current_tab_name_for_audio(self) -> str:
|
285
447
|
"""
|
@@ -309,18 +471,24 @@ class Tabs:
|
|
309
471
|
"""
|
310
472
|
Update tab tooltip
|
311
473
|
|
312
|
-
:param tooltip: tooltip
|
474
|
+
:param tooltip: tooltip text
|
313
475
|
"""
|
314
|
-
self.window.ui.
|
476
|
+
tabs = self.window.ui.layout.get_active_tabs()
|
477
|
+
tabs.setTabToolTip(self.current, tooltip)
|
315
478
|
|
316
|
-
def rename(
|
479
|
+
def rename(
|
480
|
+
self,
|
481
|
+
idx: int,
|
482
|
+
column_idx: int = 0
|
483
|
+
):
|
317
484
|
"""
|
318
|
-
Rename tab
|
485
|
+
Rename tab (show dialog)
|
319
486
|
|
320
487
|
:param idx: tab idx
|
488
|
+
:param column_idx: column idx
|
321
489
|
"""
|
322
490
|
# get tab
|
323
|
-
tab = self.window.core.tabs.get_tab_by_index(idx)
|
491
|
+
tab = self.window.core.tabs.get_tab_by_index(idx, column_idx)
|
324
492
|
if tab is None:
|
325
493
|
return
|
326
494
|
# set dialog and show
|
@@ -329,7 +497,12 @@ class Tabs:
|
|
329
497
|
self.window.ui.dialog['rename'].current = idx
|
330
498
|
self.window.ui.dialog['rename'].show()
|
331
499
|
|
332
|
-
def update_name(
|
500
|
+
def update_name(
|
501
|
+
self,
|
502
|
+
idx: int,
|
503
|
+
name: str,
|
504
|
+
close: bool = True
|
505
|
+
):
|
333
506
|
"""
|
334
507
|
Update tab title
|
335
508
|
|
@@ -349,7 +522,11 @@ class Tabs:
|
|
349
522
|
"""
|
350
523
|
self.update_name(self.current, name)
|
351
524
|
|
352
|
-
def update_title(
|
525
|
+
def update_title(
|
526
|
+
self,
|
527
|
+
idx: int,
|
528
|
+
title: str
|
529
|
+
):
|
353
530
|
"""
|
354
531
|
Update tab title
|
355
532
|
|
@@ -359,8 +536,9 @@ class Tabs:
|
|
359
536
|
# check if current tab is chat
|
360
537
|
if self.get_current_type() != Tab.TAB_CHAT:
|
361
538
|
return
|
539
|
+
tabs = self.window.ui.layout.get_active_tabs()
|
362
540
|
tooltip = title
|
363
|
-
|
541
|
+
tabs.setTabToolTip(idx, tooltip)
|
364
542
|
if len(title) > 8:
|
365
543
|
title = title[:8] + '...' # truncate to max 8 chars
|
366
544
|
self.window.core.tabs.update_title(idx, title, tooltip)
|
@@ -373,6 +551,18 @@ class Tabs:
|
|
373
551
|
"""
|
374
552
|
self.update_title(self.current, title)
|
375
553
|
|
554
|
+
def on_load_ctx(self, meta: CtxMeta):
|
555
|
+
"""
|
556
|
+
Load context
|
557
|
+
|
558
|
+
:param meta: context meta
|
559
|
+
"""
|
560
|
+
# get current tab
|
561
|
+
tab = self.get_current_tab()
|
562
|
+
if tab is not None and tab.type == Tab.TAB_CHAT:
|
563
|
+
tab.data_id = meta.id
|
564
|
+
self.update_title_current(meta.name)
|
565
|
+
|
376
566
|
def open_by_type(self, type: int):
|
377
567
|
"""
|
378
568
|
Open first tab by type
|
@@ -383,7 +573,115 @@ class Tabs:
|
|
383
573
|
if idx is not None:
|
384
574
|
self.switch_tab_by_idx(idx)
|
385
575
|
|
386
|
-
def new_tab(self):
|
387
|
-
"""
|
388
|
-
|
389
|
-
|
576
|
+
def new_tab(self, column_idx: int = 0):
|
577
|
+
"""
|
578
|
+
Handle [+] button
|
579
|
+
|
580
|
+
:param column_idx: column index
|
581
|
+
"""
|
582
|
+
idx = self.get_current_idx(column_idx)
|
583
|
+
self.append(
|
584
|
+
type=Tab.TAB_CHAT,
|
585
|
+
tool_id=None,
|
586
|
+
idx=idx,
|
587
|
+
column_idx=column_idx
|
588
|
+
)
|
589
|
+
|
590
|
+
def restore_data(self):
|
591
|
+
"""Restore tab data"""
|
592
|
+
data = self.window.core.config.get("tabs.opened", [])
|
593
|
+
if not data:
|
594
|
+
self.switch_tab_by_idx(0, 0)
|
595
|
+
return
|
596
|
+
|
597
|
+
# reverse order, second column is first
|
598
|
+
data = dict(reversed(list(data.items())))
|
599
|
+
for col_idx in data:
|
600
|
+
tab_idx = data[col_idx]
|
601
|
+
self.switch_tab_by_idx(int(tab_idx), int(col_idx))
|
602
|
+
|
603
|
+
# set default column to 0
|
604
|
+
self.column_idx = 0
|
605
|
+
self.on_column_changed()
|
606
|
+
|
607
|
+
def move_tab(
|
608
|
+
self,
|
609
|
+
idx: int,
|
610
|
+
column_idx: int,
|
611
|
+
new_column_idx: int
|
612
|
+
):
|
613
|
+
"""
|
614
|
+
Move tab to another column
|
615
|
+
|
616
|
+
:param idx: tab index
|
617
|
+
:param column_idx: column index
|
618
|
+
:param new_column_idx: new column index
|
619
|
+
"""
|
620
|
+
self.locked = True
|
621
|
+
tab = self.window.core.tabs.get_tab_by_index(idx, column_idx)
|
622
|
+
self.window.core.tabs.move_tab(tab, new_column_idx)
|
623
|
+
self.locked = False
|
624
|
+
# switch to new column
|
625
|
+
self.column_idx = new_column_idx
|
626
|
+
self.on_column_changed()
|
627
|
+
# switch to new tab
|
628
|
+
self.switch_tab_by_idx(tab.idx, new_column_idx)
|
629
|
+
|
630
|
+
def toggle_split_screen(self, state):
|
631
|
+
"""
|
632
|
+
Toggle split screen mode
|
633
|
+
|
634
|
+
:param state: True if split screen is enabled
|
635
|
+
"""
|
636
|
+
if state:
|
637
|
+
# self.rightWidget.show()
|
638
|
+
self.window.ui.splitters['columns'].setSizes([1, 1])
|
639
|
+
else:
|
640
|
+
# self.rightWidget.hide()
|
641
|
+
self.window.ui.splitters['columns'].setSizes([1, 0])
|
642
|
+
# set to first column
|
643
|
+
self.column_idx = 0
|
644
|
+
self.on_column_changed()
|
645
|
+
self.window.core.config.set("layout.split", state)
|
646
|
+
self.window.core.config.save()
|
647
|
+
|
648
|
+
def is_current_by_type(self, type: int) -> bool:
|
649
|
+
"""
|
650
|
+
Check if one of current tabs is of given type
|
651
|
+
|
652
|
+
:param type: tab type
|
653
|
+
:return: True if one of tab is of given type
|
654
|
+
"""
|
655
|
+
for col in self.col:
|
656
|
+
pid = self.col[col]
|
657
|
+
tab = self.window.core.tabs.get_tab_by_pid(pid)
|
658
|
+
if tab is not None and tab.type == type:
|
659
|
+
return True
|
660
|
+
|
661
|
+
def is_current_tool(self, tool_id: str) -> bool:
|
662
|
+
"""
|
663
|
+
Check if one of current tabs is of given tool ID
|
664
|
+
|
665
|
+
:param tool_id: tool ID
|
666
|
+
:return: True if one of tab is of given tool ID
|
667
|
+
"""
|
668
|
+
for col in self.col:
|
669
|
+
pid = self.col[col]
|
670
|
+
tab = self.window.core.tabs.get_tab_by_pid(pid)
|
671
|
+
if tab is not None and tab.tool_id == tool_id:
|
672
|
+
return True
|
673
|
+
|
674
|
+
def switch_to_first_chat(self):
|
675
|
+
"""Switch to first chat tab"""
|
676
|
+
if self.is_current_by_type(Tab.TAB_CHAT):
|
677
|
+
return
|
678
|
+
# abort if active tab is chat
|
679
|
+
if self.get_current_type() == Tab.TAB_CHAT:
|
680
|
+
return
|
681
|
+
# find first chat tab
|
682
|
+
for col in self.col:
|
683
|
+
pid = self.col[col]
|
684
|
+
tab = self.window.core.tabs.get_tab_by_pid(pid)
|
685
|
+
if tab is not None and tab.type == Tab.TAB_CHAT:
|
686
|
+
self.switch_tab_by_idx(tab.idx, col)
|
687
|
+
return
|