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/core/tabs/__init__.py
CHANGED
@@ -6,29 +6,26 @@
|
|
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 08:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import uuid
|
13
13
|
from datetime import datetime
|
14
|
+
from typing import Optional, Any, Dict
|
14
15
|
|
15
16
|
from PySide6.QtGui import QIcon
|
16
17
|
from PySide6.QtWidgets import QVBoxLayout, QWidget, QLayout
|
17
18
|
|
18
|
-
from .tab import Tab
|
19
19
|
from pygpt_net.ui.widget.tabs.body import TabBody
|
20
20
|
from pygpt_net.utils import trans
|
21
21
|
|
22
|
+
from .tab import Tab
|
23
|
+
|
22
24
|
|
23
25
|
class Tabs:
|
24
26
|
|
25
|
-
#
|
26
|
-
|
27
|
-
TAB_CHAT = 0
|
28
|
-
TAB_NOTEPAD = 1
|
29
|
-
TAB_FILES = 2
|
30
|
-
TAB_TOOL_PAINTER = 3
|
31
|
-
TAB_TOOL_CALENDAR = 4
|
27
|
+
# number of columns
|
28
|
+
NUM_COLS = 2
|
32
29
|
|
33
30
|
def __init__(self, window=None):
|
34
31
|
"""
|
@@ -40,33 +37,40 @@ class Tabs:
|
|
40
37
|
self.last_pid = -1
|
41
38
|
self.pids = {} # pid: Tab data
|
42
39
|
self.icons = {
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
Tab.TAB_CHAT: ":/icons/chat.svg",
|
41
|
+
Tab.TAB_NOTEPAD: ":/icons/paste.svg",
|
42
|
+
Tab.TAB_FILES: ":/icons/folder_filled.svg",
|
43
|
+
Tab.TAB_TOOL_PAINTER: ":/icons/brush.svg",
|
44
|
+
Tab.TAB_TOOL_CALENDAR: ":/icons/calendar.svg",
|
45
|
+
Tab.TAB_TOOL: ":/icons/build.svg",
|
48
46
|
}
|
49
47
|
self.titles = {
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
48
|
+
Tab.TAB_CHAT: "output.tab.chat",
|
49
|
+
Tab.TAB_NOTEPAD: "output.tab.notepad",
|
50
|
+
Tab.TAB_FILES: "output.tab.files",
|
51
|
+
Tab.TAB_TOOL_PAINTER: "output.tab.painter",
|
52
|
+
Tab.TAB_TOOL_CALENDAR: "output.tab.calendar",
|
53
|
+
Tab.TAB_TOOL: "output.tab.tool",
|
55
54
|
}
|
56
55
|
|
57
|
-
def get_tab_by_index(
|
56
|
+
def get_tab_by_index(
|
57
|
+
self,
|
58
|
+
idx: int,
|
59
|
+
column_idx: int = 0
|
60
|
+
) -> Optional[Tab]:
|
58
61
|
"""
|
59
62
|
Get tab by index
|
60
63
|
|
61
64
|
:param idx: Tab index
|
65
|
+
:param column_idx: Column index
|
62
66
|
:return: Tab
|
63
67
|
"""
|
64
|
-
tab = self.window.ui.
|
68
|
+
tab = self.window.ui.layout.get_tabs_by_idx(column_idx).widget(idx)
|
65
69
|
if tab is None:
|
66
70
|
return None
|
67
71
|
return tab.getOwner()
|
68
72
|
|
69
|
-
def get_tab_by_pid(self, pid: int) -> Tab
|
73
|
+
def get_tab_by_pid(self, pid: int) -> Optional[Tab]:
|
70
74
|
"""
|
71
75
|
Get tab by PID
|
72
76
|
|
@@ -77,7 +81,7 @@ class Tabs:
|
|
77
81
|
return self.pids[pid]
|
78
82
|
return None
|
79
83
|
|
80
|
-
def get_first_tab_by_type(self, type: int) -> Tab
|
84
|
+
def get_first_tab_by_type(self, type: int) -> Optional[Tab]:
|
81
85
|
"""
|
82
86
|
Get first tab by type
|
83
87
|
|
@@ -90,26 +94,37 @@ class Tabs:
|
|
90
94
|
return tab
|
91
95
|
return None
|
92
96
|
|
93
|
-
def get_active_pid(self) -> int
|
97
|
+
def get_active_pid(self) -> Optional[int]:
|
94
98
|
"""
|
95
99
|
Get PID by active tab
|
96
100
|
|
97
101
|
:return: PID
|
98
102
|
"""
|
99
|
-
|
103
|
+
current_column_idx = self.window.controller.ui.tabs.get_current_column_idx()
|
104
|
+
tabs = self.window.ui.layout.get_tabs_by_idx(current_column_idx)
|
105
|
+
tab = self.get_tab_by_index(tabs.currentIndex(), current_column_idx)
|
100
106
|
if tab is None:
|
101
107
|
return 0
|
102
108
|
return tab.pid
|
103
109
|
|
104
|
-
def add(
|
110
|
+
def add(
|
111
|
+
self,
|
112
|
+
type: int,
|
113
|
+
title: str,
|
114
|
+
icon: Optional[str] = None,
|
115
|
+
child: Optional[TabBody] = None,
|
116
|
+
data_id: Optional[int] = None,
|
117
|
+
tool_id: Optional[str] = None
|
118
|
+
) -> Tab:
|
105
119
|
"""
|
106
120
|
Add tab
|
107
121
|
|
108
122
|
:param type: Tab type
|
109
123
|
:param title: Tab title
|
110
124
|
:param icon: Tab icon
|
111
|
-
:param
|
125
|
+
:param child: Tab child (TabBody)
|
112
126
|
:param data_id: Tab data ID
|
127
|
+
:param tool_id: Tool ID
|
113
128
|
:return: Tab
|
114
129
|
"""
|
115
130
|
self.last_pid += 1 # PID++, start from 0
|
@@ -120,8 +135,9 @@ class Tabs:
|
|
120
135
|
tab.type = type
|
121
136
|
tab.title = title
|
122
137
|
tab.icon = icon
|
123
|
-
tab.
|
138
|
+
tab.child = child
|
124
139
|
tab.data_id = data_id
|
140
|
+
tab.tool_id = tool_id
|
125
141
|
|
126
142
|
if type == Tab.TAB_CHAT:
|
127
143
|
self.add_chat(tab)
|
@@ -133,24 +149,34 @@ class Tabs:
|
|
133
149
|
self.add_tool_painter(tab)
|
134
150
|
elif type == Tab.TAB_TOOL_CALENDAR:
|
135
151
|
self.add_tool_calendar(tab)
|
152
|
+
elif type == Tab.TAB_TOOL:
|
153
|
+
self.add_tool(tab)
|
136
154
|
|
137
155
|
self.pids[tab.pid] = tab
|
138
156
|
return tab
|
139
157
|
|
140
|
-
def append(
|
158
|
+
def append(
|
159
|
+
self,
|
160
|
+
type: int,
|
161
|
+
tool_id: str,
|
162
|
+
idx: int,
|
163
|
+
column_idx: int = 0
|
164
|
+
) -> Tab:
|
141
165
|
"""
|
142
166
|
Append tab to the right side of the tab with the specified index
|
143
167
|
|
144
168
|
:param type: tab type
|
169
|
+
:param tool_id: tool ID
|
145
170
|
:param idx: index of the tab to the right of which the new tab will be added
|
171
|
+
:param column_idx: index of the column in which the tab will be added
|
146
172
|
:return: Tab
|
147
173
|
"""
|
148
174
|
self.last_pid += 1 # PID++, start from 0
|
149
175
|
title = ""
|
150
176
|
icon = self.icons[type]
|
151
|
-
if type ==
|
177
|
+
if type == Tab.TAB_CHAT:
|
152
178
|
title = trans('output.tab.chat') + " {}".format(self.count_by_type(type) + 1)
|
153
|
-
elif type ==
|
179
|
+
elif type == Tab.TAB_NOTEPAD:
|
154
180
|
title = trans('output.tab.notepad') + " {}".format(self.count_by_type(type) + 1)
|
155
181
|
|
156
182
|
tab = Tab()
|
@@ -160,11 +186,15 @@ class Tabs:
|
|
160
186
|
tab.title = title
|
161
187
|
tab.icon = icon
|
162
188
|
tab.new_idx = idx + 1 # place on right side
|
189
|
+
tab.column_idx = column_idx
|
190
|
+
tab.tool_id = tool_id
|
163
191
|
|
164
192
|
if type == Tab.TAB_CHAT:
|
165
193
|
self.add_chat(tab)
|
166
194
|
elif type == Tab.TAB_NOTEPAD:
|
167
195
|
self.add_notepad(tab)
|
196
|
+
elif type == Tab.TAB_TOOL:
|
197
|
+
self.add_tool(tab)
|
168
198
|
|
169
199
|
self.pids[tab.pid] = tab
|
170
200
|
self.update()
|
@@ -186,11 +216,20 @@ class Tabs:
|
|
186
216
|
tab.type = data["type"]
|
187
217
|
tab.title = data["title"]
|
188
218
|
tab.data_id = data["data_id"]
|
189
|
-
tab.
|
219
|
+
tab.child = None
|
190
220
|
|
191
221
|
if 'tooltip' in data and data['tooltip'] is not None:
|
192
222
|
tab.tooltip = data['tooltip']
|
193
223
|
|
224
|
+
if 'custom_name' in data and data['custom_name'] is not None:
|
225
|
+
tab.custom_name = data['custom_name']
|
226
|
+
|
227
|
+
if 'column_idx' in data and data['column_idx'] is not None:
|
228
|
+
tab.column_idx = data['column_idx']
|
229
|
+
|
230
|
+
if 'tool_id' in data and data['tool_id'] is not None:
|
231
|
+
tab.tool_id = data['tool_id']
|
232
|
+
|
194
233
|
if tab.type in self.icons:
|
195
234
|
tab.icon = self.icons[tab.type]
|
196
235
|
|
@@ -207,17 +246,24 @@ class Tabs:
|
|
207
246
|
self.add_tool_painter(tab)
|
208
247
|
elif tab.type == Tab.TAB_TOOL_CALENDAR: # calendar
|
209
248
|
self.add_tool_calendar(tab)
|
249
|
+
elif tab.type == Tab.TAB_TOOL: # custom tools, id 100+
|
250
|
+
self.add_tool(tab)
|
210
251
|
|
211
252
|
self.pids[tab.pid] = tab
|
212
253
|
self.last_pid = self.get_max_pid()
|
213
254
|
|
214
|
-
def remove_tab_by_idx(
|
255
|
+
def remove_tab_by_idx(
|
256
|
+
self,
|
257
|
+
idx: int,
|
258
|
+
column_idx: int = 0
|
259
|
+
):
|
215
260
|
"""
|
216
261
|
Remove tab by index
|
217
262
|
|
218
263
|
:param idx: Tab index
|
264
|
+
:param column_idx: Column index
|
219
265
|
"""
|
220
|
-
tab = self.get_tab_by_index(idx)
|
266
|
+
tab = self.get_tab_by_index(idx, column_idx)
|
221
267
|
if tab is None:
|
222
268
|
return
|
223
269
|
self.remove(tab.pid)
|
@@ -231,7 +277,8 @@ class Tabs:
|
|
231
277
|
tab = self.get_tab_by_pid(pid)
|
232
278
|
if tab is None:
|
233
279
|
return
|
234
|
-
|
280
|
+
column_idx = tab.column_idx
|
281
|
+
self.window.ui.layout.get_tabs_by_idx(column_idx).removeTab(tab.idx)
|
235
282
|
del self.pids[pid]
|
236
283
|
self.update()
|
237
284
|
|
@@ -241,16 +288,21 @@ class Tabs:
|
|
241
288
|
self.remove(pid) # delete from PIDs and UI
|
242
289
|
self.window.core.ctx.output.clear() # clear mapping
|
243
290
|
|
244
|
-
def remove_all_by_type(
|
291
|
+
def remove_all_by_type(
|
292
|
+
self,
|
293
|
+
type: int,
|
294
|
+
column_idx: int = 0
|
295
|
+
):
|
245
296
|
"""
|
246
297
|
Remove all tabs by type
|
247
298
|
|
248
299
|
:param type: Tab type
|
300
|
+
:param column_idx: Column index
|
249
301
|
"""
|
250
302
|
for pid in list(self.pids):
|
251
303
|
tab = self.pids[pid]
|
252
|
-
if tab.type == type:
|
253
|
-
if type ==
|
304
|
+
if tab.type == type and tab.column_idx == column_idx:
|
305
|
+
if type == Tab.TAB_CHAT:
|
254
306
|
if self.count_by_type(type) == 1:
|
255
307
|
continue # do not remove last chat tab
|
256
308
|
self.remove(pid)
|
@@ -312,7 +364,25 @@ class Tabs:
|
|
312
364
|
count += 1
|
313
365
|
return count
|
314
366
|
|
315
|
-
def
|
367
|
+
def get_max_data_id_by_type(self, type: int) -> int:
|
368
|
+
"""
|
369
|
+
Get max data ID by type
|
370
|
+
|
371
|
+
:param type: Tab type
|
372
|
+
:return: Max data ID
|
373
|
+
"""
|
374
|
+
max = 0
|
375
|
+
for pid in self.pids:
|
376
|
+
tab = self.pids[pid]
|
377
|
+
if tab.type == type and tab.data_id > max:
|
378
|
+
max = tab.data_id
|
379
|
+
return max
|
380
|
+
|
381
|
+
def get_order_by_idx_and_type(
|
382
|
+
self,
|
383
|
+
idx: int,
|
384
|
+
type: int
|
385
|
+
) -> int:
|
316
386
|
"""
|
317
387
|
Get the order of the tab by index and type
|
318
388
|
|
@@ -328,28 +398,46 @@ class Tabs:
|
|
328
398
|
return order
|
329
399
|
return -1 # Return -1 if the tab with the specified index and type is not found
|
330
400
|
|
331
|
-
def get_min_idx_by_type(
|
401
|
+
def get_min_idx_by_type(
|
402
|
+
self,
|
403
|
+
type: int,
|
404
|
+
column_idx: int = 0
|
405
|
+
) -> int:
|
332
406
|
"""
|
333
407
|
Get min index by type
|
334
408
|
|
335
409
|
:param type: Tab type
|
410
|
+
:param column_idx: Column index
|
336
411
|
:return: Min index
|
337
412
|
"""
|
338
413
|
min = 999999
|
339
414
|
for pid in self.pids:
|
340
415
|
tab = self.pids[pid]
|
341
|
-
if tab.type == type
|
416
|
+
if (tab.type == type
|
417
|
+
and tab.column_idx == column_idx
|
418
|
+
and tab.idx < min):
|
342
419
|
min = tab.idx
|
343
420
|
return min
|
344
421
|
|
345
422
|
def update(self):
|
346
|
-
"""Update tabs data (pids) from UI"""
|
423
|
+
"""Update tabs data (pids) from UI (all columns)"""
|
424
|
+
for n in range(0, self.NUM_COLS):
|
425
|
+
self.update_column(n)
|
426
|
+
|
427
|
+
def update_column(self, column_idx: int):
|
428
|
+
"""
|
429
|
+
Update column data by index
|
430
|
+
|
431
|
+
:param column_idx: Column index
|
432
|
+
"""
|
433
|
+
tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
|
347
434
|
for pid in self.pids:
|
348
435
|
tab = self.pids[pid]
|
349
|
-
tab.
|
350
|
-
|
351
|
-
|
352
|
-
|
436
|
+
if tab.column_idx == column_idx:
|
437
|
+
tab.idx = tabs.indexOf(tab.child)
|
438
|
+
tab.title = tabs.tabText(tab.idx)
|
439
|
+
tab.tooltip = tabs.tabToolTip(tab.idx)
|
440
|
+
tab.updated_at = datetime.now()
|
353
441
|
|
354
442
|
def add_chat(self, tab: Tab):
|
355
443
|
"""
|
@@ -357,15 +445,18 @@ class Tabs:
|
|
357
445
|
|
358
446
|
:param tab: Tab instance
|
359
447
|
"""
|
360
|
-
|
448
|
+
column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
|
449
|
+
tabs = column.get_tabs()
|
450
|
+
tab.parent = column
|
451
|
+
tab.child = self.window.core.ctx.container.get(tab)
|
361
452
|
if tab.new_idx is not None:
|
362
|
-
tab.idx =
|
453
|
+
tab.idx = tabs.insertTab(tab.new_idx, tab.child, tab.title)
|
363
454
|
else:
|
364
|
-
tab.idx =
|
365
|
-
tab.
|
366
|
-
|
455
|
+
tab.idx = tabs.addTab(tab.child, tab.title)
|
456
|
+
tab.child.setOwner(tab)
|
457
|
+
tabs.setTabIcon(tab.idx, QIcon(tab.icon))
|
367
458
|
if tab.tooltip is not None:
|
368
|
-
|
459
|
+
tabs.setTabToolTip(tab.idx, tab.tooltip)
|
369
460
|
|
370
461
|
def add_notepad(self, tab: Tab):
|
371
462
|
"""
|
@@ -374,18 +465,22 @@ class Tabs:
|
|
374
465
|
:param tab: Tab instance
|
375
466
|
"""
|
376
467
|
idx = None
|
468
|
+
column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
|
469
|
+
tabs = column.get_tabs()
|
470
|
+
tab.parent = column
|
471
|
+
tab.parent = tabs.get_column()
|
377
472
|
if tab.data_id is not None:
|
378
473
|
idx = tab.data_id # restore prev idx
|
379
|
-
tab.
|
380
|
-
tab.data_id =
|
474
|
+
tab.child, idx, data_id = self.window.controller.notepad.create(idx)
|
475
|
+
tab.data_id = data_id # notepad idx in db, enumerated from 1
|
381
476
|
if tab.new_idx is not None:
|
382
|
-
tab.idx =
|
477
|
+
tab.idx = tabs.insertTab(tab.new_idx, tab.child, tab.title)
|
383
478
|
else:
|
384
|
-
tab.idx =
|
385
|
-
tab.
|
386
|
-
|
479
|
+
tab.idx = tabs.addTab(tab.child, tab.title)
|
480
|
+
tab.child.setOwner(tab)
|
481
|
+
tabs.setTabIcon(tab.idx, QIcon(tab.icon))
|
387
482
|
if tab.tooltip is not None:
|
388
|
-
|
483
|
+
tabs.setTabToolTip(tab.idx, tab.tooltip)
|
389
484
|
|
390
485
|
def add_tool_explorer(self, tab: Tab):
|
391
486
|
"""
|
@@ -393,12 +488,15 @@ class Tabs:
|
|
393
488
|
|
394
489
|
:param tab: Tab instance
|
395
490
|
"""
|
396
|
-
|
397
|
-
|
398
|
-
tab.
|
399
|
-
self.window.ui.
|
491
|
+
column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
|
492
|
+
tabs = column.get_tabs()
|
493
|
+
tab.parent = column
|
494
|
+
tab.child = self.window.ui.chat.output.explorer.setup()
|
495
|
+
tab.idx = tabs.addTab(tab.child, tab.title)
|
496
|
+
tab.child.setOwner(tab)
|
497
|
+
tabs.setTabIcon(tab.idx, QIcon(tab.icon))
|
400
498
|
if tab.tooltip is not None:
|
401
|
-
|
499
|
+
tabs.setTabToolTip(tab.idx, tab.tooltip)
|
402
500
|
|
403
501
|
def add_tool_painter(self, tab: Tab):
|
404
502
|
"""
|
@@ -406,12 +504,15 @@ class Tabs:
|
|
406
504
|
|
407
505
|
:param tab: Tab instance
|
408
506
|
"""
|
409
|
-
|
410
|
-
|
411
|
-
tab.
|
412
|
-
self.window.ui.
|
507
|
+
column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
|
508
|
+
tabs = column.get_tabs()
|
509
|
+
tab.parent = column
|
510
|
+
tab.child = self.window.ui.chat.output.painter.setup()
|
511
|
+
tab.idx = tabs.addTab(tab.child, tab.title)
|
512
|
+
tab.child.setOwner(tab)
|
513
|
+
tabs.setTabIcon(tab.idx, QIcon(tab.icon))
|
413
514
|
if tab.tooltip is not None:
|
414
|
-
|
515
|
+
tabs.setTabToolTip(tab.idx, tab.tooltip)
|
415
516
|
|
416
517
|
def add_tool_calendar(self, tab: Tab):
|
417
518
|
"""
|
@@ -419,14 +520,63 @@ class Tabs:
|
|
419
520
|
|
420
521
|
:param tab: Tab instance
|
421
522
|
"""
|
422
|
-
|
423
|
-
|
424
|
-
tab.
|
425
|
-
self.window.ui.
|
523
|
+
column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
|
524
|
+
tabs = column.get_tabs()
|
525
|
+
tab.parent = column
|
526
|
+
tab.child = self.window.ui.chat.output.calendar.setup()
|
527
|
+
tab.idx = tabs.addTab(tab.child, tab.title)
|
528
|
+
tab.child.setOwner(tab)
|
529
|
+
tabs.setTabIcon(tab.idx, QIcon(tab.icon))
|
426
530
|
if tab.tooltip is not None:
|
427
|
-
|
531
|
+
tabs.setTabToolTip(tab.idx, tab.tooltip)
|
532
|
+
|
533
|
+
def add_tool(self, tab: Tab):
|
534
|
+
"""
|
535
|
+
Add custom tool tab
|
428
536
|
|
429
|
-
|
537
|
+
:param tab: Tab instance
|
538
|
+
"""
|
539
|
+
column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
|
540
|
+
tabs = column.get_tabs()
|
541
|
+
tool = self.window.tools.get(tab.tool_id)
|
542
|
+
if tool is None:
|
543
|
+
raise Exception("Tool not found: {}".format(tab.tool_id))
|
544
|
+
widget = tool.as_tab(tab)
|
545
|
+
if widget is None:
|
546
|
+
raise Exception("Tool widget not found: {}".format(tab.tool_id))
|
547
|
+
tab.icon = tool.tab_icon
|
548
|
+
tab.title = trans(tool.tab_title)
|
549
|
+
tab.parent = column
|
550
|
+
tab.child = self.from_widget(widget)
|
551
|
+
tab.idx = tabs.addTab(tab.child, tab.title)
|
552
|
+
tab.child.setOwner(tab)
|
553
|
+
tabs.setTabIcon(tab.idx, QIcon(tab.icon))
|
554
|
+
if tab.tooltip is not None:
|
555
|
+
tabs.setTabToolTip(tab.idx, tab.tooltip)
|
556
|
+
|
557
|
+
def move_tab(self, tab: Tab, column_idx: int):
|
558
|
+
"""
|
559
|
+
Move tab to column
|
560
|
+
|
561
|
+
:param tab: Tab instance
|
562
|
+
:param column_idx: Column index
|
563
|
+
"""
|
564
|
+
if tab is None:
|
565
|
+
return
|
566
|
+
if tab.column_idx == column_idx:
|
567
|
+
return
|
568
|
+
|
569
|
+
old_column = self.window.ui.layout.get_column_by_idx(tab.column_idx)
|
570
|
+
old_tabs = old_column.get_tabs()
|
571
|
+
old_tabs.removeTab(tab.idx)
|
572
|
+
new_column = self.window.ui.layout.get_column_by_idx(column_idx)
|
573
|
+
new_tabs = new_column.get_tabs()
|
574
|
+
tab.idx = new_tabs.addTab(tab.child, QIcon(tab.icon), tab.title)
|
575
|
+
tab.parent = new_column
|
576
|
+
tab.column_idx = column_idx
|
577
|
+
self.update()
|
578
|
+
|
579
|
+
def get_first_by_type(self, type: int) -> Optional[Tab]:
|
430
580
|
"""
|
431
581
|
Get first tab by type
|
432
582
|
|
@@ -439,7 +589,7 @@ class Tabs:
|
|
439
589
|
return tab
|
440
590
|
return None
|
441
591
|
|
442
|
-
def from_defaults(self) ->
|
592
|
+
def from_defaults(self) -> Dict[int, Any]:
|
443
593
|
"""
|
444
594
|
Prepare default tabs data
|
445
595
|
|
@@ -450,37 +600,44 @@ class Tabs:
|
|
450
600
|
"uuid": uuid.uuid4(),
|
451
601
|
"pid": 0,
|
452
602
|
"idx": 0,
|
453
|
-
"type":
|
603
|
+
"type": Tab.TAB_CHAT,
|
454
604
|
"data_id": None,
|
455
605
|
"title": "Chat",
|
456
606
|
"tooltip": "Chat",
|
607
|
+
"column_idx": 0,
|
457
608
|
}
|
458
609
|
data[1] = {
|
459
610
|
"uuid": uuid.uuid4(),
|
460
611
|
"pid": 1,
|
461
612
|
"idx": 1,
|
462
|
-
"type":
|
613
|
+
"type": Tab.TAB_FILES,
|
463
614
|
"data_id": None,
|
464
615
|
"title": "Files",
|
465
616
|
"tooltip": "Files",
|
617
|
+
"column_idx": 0,
|
618
|
+
"tool_id": "explorer",
|
466
619
|
}
|
467
620
|
data[2] = {
|
468
621
|
"uuid": uuid.uuid4(),
|
469
622
|
"pid": 2,
|
470
623
|
"idx": 2,
|
471
|
-
"type":
|
624
|
+
"type": Tab.TAB_TOOL_CALENDAR,
|
472
625
|
"data_id": None,
|
473
626
|
"title": "Calendar",
|
474
627
|
"tooltip": "Calendar",
|
628
|
+
"column_idx": 0,
|
629
|
+
"tool_id": "calendar",
|
475
630
|
}
|
476
631
|
data[3] = {
|
477
632
|
"uuid": uuid.uuid4(),
|
478
633
|
"pid": 3,
|
479
634
|
"idx": 3,
|
480
|
-
"type":
|
635
|
+
"type": Tab.TAB_TOOL_PAINTER,
|
481
636
|
"data_id": None,
|
482
637
|
"title": "Painter",
|
483
638
|
"tooltip": "Painter",
|
639
|
+
"column_idx": 0,
|
640
|
+
"tool_id": "painter",
|
484
641
|
}
|
485
642
|
"""
|
486
643
|
data[4] = {
|
@@ -491,6 +648,8 @@ class Tabs:
|
|
491
648
|
"data_id": 1,
|
492
649
|
"title": "Notepad",
|
493
650
|
"tooltip": "Notepad",
|
651
|
+
"column_idx": 0,
|
652
|
+
"tool_id": "notepad",
|
494
653
|
}
|
495
654
|
"""
|
496
655
|
# load notepads from db
|
@@ -503,10 +662,12 @@ class Tabs:
|
|
503
662
|
"uuid": uuid.uuid4(),
|
504
663
|
"pid": next_idx,
|
505
664
|
"idx": next_idx,
|
506
|
-
"type":
|
665
|
+
"type": Tab.TAB_NOTEPAD,
|
507
666
|
"data_id": item['data_id'],
|
508
667
|
"title": item['title'],
|
509
668
|
"tooltip": item['title'],
|
669
|
+
"column_idx": 0,
|
670
|
+
"tool_id": "notepad",
|
510
671
|
}
|
511
672
|
next_idx += 1
|
512
673
|
return data
|
@@ -536,6 +697,8 @@ class Tabs:
|
|
536
697
|
"title": trans(self.titles[type]),
|
537
698
|
"tooltip": trans(self.titles[type]),
|
538
699
|
"custom_name": False,
|
700
|
+
"column_idx": 0,
|
701
|
+
"tool_id": None,
|
539
702
|
}
|
540
703
|
tmp_pid += 1
|
541
704
|
|
@@ -564,11 +727,23 @@ class Tabs:
|
|
564
727
|
"title": tab.title,
|
565
728
|
"tooltip": tab.tooltip,
|
566
729
|
"custom_name": tab.custom_name,
|
730
|
+
"column_idx": tab.column_idx,
|
731
|
+
"tool_id": tab.tool_id,
|
567
732
|
}
|
733
|
+
opened_tabs = {}
|
734
|
+
for column_idx in range(0, self.NUM_COLS):
|
735
|
+
tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
|
736
|
+
opened_tabs[column_idx] = tabs.currentIndex()
|
737
|
+
self.window.core.config.set("tabs.opened", opened_tabs)
|
568
738
|
self.window.core.config.set("tabs.data", data)
|
569
739
|
self.window.core.config.save()
|
570
740
|
|
571
|
-
def update_title(
|
741
|
+
def update_title(
|
742
|
+
self,
|
743
|
+
idx: int,
|
744
|
+
title: str,
|
745
|
+
tooltip: Optional[str] = None
|
746
|
+
):
|
572
747
|
"""
|
573
748
|
Update tab title
|
574
749
|
|
@@ -576,37 +751,49 @@ class Tabs:
|
|
576
751
|
:param title: Tab title
|
577
752
|
:param tooltip: Tab tooltip
|
578
753
|
"""
|
579
|
-
|
754
|
+
column_idx = self.window.controller.ui.tabs.get_current_column_idx()
|
755
|
+
tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
|
756
|
+
tab = self.get_tab_by_index(idx, column_idx)
|
580
757
|
if tab is None:
|
581
758
|
return
|
582
759
|
tab.title = title
|
583
760
|
tab.tooltip = tooltip
|
584
761
|
tab.custom_name = True
|
585
762
|
if title is not None:
|
586
|
-
|
763
|
+
tabs.setTabText(idx, title)
|
587
764
|
if tooltip is not None:
|
588
|
-
|
765
|
+
tabs.setTabToolTip(idx, tooltip)
|
589
766
|
|
590
767
|
def reload_titles(self):
|
591
768
|
"""Reload default tab titles"""
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
self.
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
769
|
+
return
|
770
|
+
processed = []
|
771
|
+
for column_idx in range(0, self.NUM_COLS):
|
772
|
+
tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
|
773
|
+
counters = {
|
774
|
+
Tab.TAB_CHAT: 1,
|
775
|
+
Tab.TAB_NOTEPAD: 1,
|
776
|
+
Tab.TAB_FILES: 1,
|
777
|
+
Tab.TAB_TOOL_PAINTER: 1,
|
778
|
+
Tab.TAB_TOOL_CALENDAR: 1,
|
779
|
+
}
|
780
|
+
for pid in self.pids:
|
781
|
+
tab = self.pids[pid]
|
782
|
+
if tab.pid in processed:
|
783
|
+
continue
|
784
|
+
if tab.custom_name or tab.type == Tab.TAB_TOOL:
|
785
|
+
continue # leave custom names and tools
|
786
|
+
tab.title = trans(self.titles[tab.type])
|
787
|
+
num_tabs = self.count_by_type(tab.type)
|
788
|
+
if num_tabs > 1:
|
789
|
+
if tab.type in counters:
|
790
|
+
tab.title += " {}".format(counters[tab.type])
|
791
|
+
else:
|
792
|
+
counters[tab.type] = 1
|
793
|
+
counters[tab.type] += 1
|
794
|
+
tabs.setTabText(tab.idx, tab.title)
|
795
|
+
tabs.setTabToolTip(tab.idx, tab.title)
|
796
|
+
processed.append(pid)
|
610
797
|
|
611
798
|
def from_widget(self, widget: QWidget) -> TabBody:
|
612
799
|
"""
|