je-editor 0.0.221__tar.gz → 0.0.223__tar.gz
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.
Potentially problematic release.
This version of je-editor might be problematic. Click here for more details.
- {je_editor-0.0.221 → je_editor-0.0.223}/PKG-INFO +3 -3
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/__init__.py +2 -2
- je_editor-0.0.223/je_editor/code_scan/ruff_thread.py +58 -0
- je_editor-0.0.223/je_editor/code_scan/watchdog_implement.py +56 -0
- je_editor-0.0.223/je_editor/code_scan/watchdog_thread.py +78 -0
- je_editor-0.0.223/je_editor/git_client/commit_graph.py +77 -0
- je_editor-0.0.221/je_editor/git_client/git.py → je_editor-0.0.223/je_editor/git_client/git_action.py +1 -1
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/git_client/git_cli.py +4 -4
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/browser/browser_download_window.py +41 -5
- je_editor-0.0.223/je_editor/pyside_ui/browser/browser_serach_lineedit.py +51 -0
- je_editor-0.0.223/je_editor/pyside_ui/browser/browser_view.py +88 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/browser/browser_widget.py +52 -22
- je_editor-0.0.223/je_editor/pyside_ui/browser/main_browser_widget.py +72 -0
- je_editor-0.0.223/je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +90 -0
- je_editor-0.0.223/je_editor/pyside_ui/git_ui/code_diff_compare/line_number_code_viewer.py +141 -0
- je_editor-0.0.223/je_editor/pyside_ui/git_ui/code_diff_compare/multi_file_diff_viewer.py +88 -0
- je_editor-0.0.223/je_editor/pyside_ui/git_ui/code_diff_compare/side_by_side_diff_widget.py +271 -0
- {je_editor-0.0.221/je_editor/pyside_ui/git_ui → je_editor-0.0.223/je_editor/pyside_ui/git_ui/git_client}/git_branch_tree_widget.py +17 -14
- je_editor-0.0.223/je_editor/pyside_ui/git_ui/git_client/git_client_gui.py +799 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +1 -1
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/main_editor.py +5 -8
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +17 -17
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +2 -2
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +21 -21
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/multi_language/english.py +2 -1
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/multi_language/traditional_chinese.py +2 -2
- je_editor-0.0.223/je_editor/utils/redirect_manager/__init__.py +0 -0
- je_editor-0.0.223/je_editor/utils/venv_check/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor.egg-info/PKG-INFO +3 -3
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor.egg-info/SOURCES.txt +12 -6
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor.egg-info/requires.txt +2 -2
- {je_editor-0.0.221 → je_editor-0.0.223}/pyproject.toml +2 -2
- je_editor-0.0.221/je_editor/code_scan/ruff_thread.py +0 -31
- je_editor-0.0.221/je_editor/code_scan/watchdog_implement.py +0 -34
- je_editor-0.0.221/je_editor/code_scan/watchdog_thread.py +0 -33
- je_editor-0.0.221/je_editor/git_client/commit_graph.py +0 -88
- je_editor-0.0.221/je_editor/git_client/github.py +0 -50
- je_editor-0.0.221/je_editor/pyside_ui/browser/browser_serach_lineedit.py +0 -27
- je_editor-0.0.221/je_editor/pyside_ui/browser/browser_view.py +0 -35
- je_editor-0.0.221/je_editor/pyside_ui/git_ui/git_client_gui.py +0 -291
- {je_editor-0.0.221 → je_editor-0.0.223}/LICENSE +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/README.md +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/__main__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/code_scan/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/git_client/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/browser/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/auto_save/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/auto_save/auto_save_manager.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/auto_save/auto_save_thread.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/code_format/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/code_format/pep8_format.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/code_process/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/code_process/code_exec.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/plaintext_code_edit/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/plaintext_code_edit/code_edit_plaintext.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/running_process_manager.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/shell_process/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/shell_process/shell_exec.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/syntax/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/syntax/python_syntax.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/syntax/syntax_setting.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/textedit_code_result/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/textedit_code_result/code_record.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/variable_inspector/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/code/variable_inspector/inspector_gui.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/ai_dialog/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/ai_dialog/set_ai_dialog.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/file_dialog/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/file_dialog/create_file_dialog.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/file_dialog/open_file_dialog.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/file_dialog/save_file_dialog.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/search_ui/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/search_ui/search_error_box.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/dialog/search_ui/search_text_box.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/git_ui/__init__.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui → je_editor-0.0.223/je_editor/pyside_ui/git_ui/code_diff_compare}/__init__.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/ai_widget → je_editor-0.0.223/je_editor/pyside_ui/git_ui/git_client}/__init__.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/git_ui → je_editor-0.0.223/je_editor/pyside_ui/git_ui/git_client}/commit_table.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/git_ui → je_editor-0.0.223/je_editor/pyside_ui/git_ui/git_client}/graph_view.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/console_widget → je_editor-0.0.223/je_editor/pyside_ui/main_ui}/__init__.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/dock → je_editor-0.0.223/je_editor/pyside_ui/main_ui/ai_widget}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/ai_widget/ai_config.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/ai_widget/ask_thread.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/ai_widget/chat_ui.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/editor → je_editor-0.0.223/je_editor/pyside_ui/main_ui/console_widget}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/console_widget/console_gui.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/console_widget/qprocess_adapter.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/ipython_widget → je_editor-0.0.223/je_editor/pyside_ui/main_ui/dock}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/dock/destroy_dock.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/editor}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/editor/editor_widget.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/editor/editor_widget_dock.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/editor/process_input.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/check_style_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/ipython_widget}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/ipython_widget/rich_jupyter.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/dock_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu}/__init__.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/file_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/check_style_menu}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/check_style_menu/build_check_style_menu.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/help_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/dock_menu}/__init__.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/language_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/file_menu}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/file_menu/build_file_menu.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/python_env_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/help_menu}/__init__.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/run_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/language_menu}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/language_menu/build_language_server.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/python_env_menu}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/python_env_menu/build_venv_menu.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/style_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/run_menu}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/run_menu/build_run_menu.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/tab_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_debug_menu.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_program_menu.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_shell_menu.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/utils.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/set_menu_bar.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/menu/text_menu → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/style_menu}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/style_menu/build_style_menu.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/save_settings → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/tab_menu}/__init__.py +0 -0
- {je_editor-0.0.221/je_editor/pyside_ui/main_ui/system_tray → je_editor-0.0.223/je_editor/pyside_ui/main_ui/menu/text_menu}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/menu/text_menu/build_text_menu.py +0 -0
- {je_editor-0.0.221/je_editor/utils/encodings → je_editor-0.0.223/je_editor/pyside_ui/main_ui/save_settings}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/save_settings/setting_utils.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/save_settings/user_color_setting_file.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/save_settings/user_setting_file.py +0 -0
- {je_editor-0.0.221/je_editor/utils/file → je_editor-0.0.223/je_editor/pyside_ui/main_ui/system_tray}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/main_ui/system_tray/extend_system_tray.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/start_editor.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/__init__.py +0 -0
- {je_editor-0.0.221/je_editor/utils/json → je_editor-0.0.223/je_editor/utils/encodings}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/encodings/python_encodings.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/exception/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/exception/exception_tags.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/exception/exceptions.py +0 -0
- {je_editor-0.0.221/je_editor/utils/logging → je_editor-0.0.223/je_editor/utils/file}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/file/open/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/file/open/open_file.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/file/save/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/file/save/save_file.py +0 -0
- {je_editor-0.0.221/je_editor/utils/multi_language → je_editor-0.0.223/je_editor/utils/json}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/json/json_file.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/json_format/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/json_format/json_process.py +0 -0
- {je_editor-0.0.221/je_editor/utils/redirect_manager → je_editor-0.0.223/je_editor/utils/logging}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/logging/loggin_instance.py +0 -0
- {je_editor-0.0.221/je_editor/utils/venv_check → je_editor-0.0.223/je_editor/utils/multi_language}/__init__.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/multi_language/multi_language_wrapper.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/redirect_manager/redirect_manager_class.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor/utils/venv_check/check_venv.py +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor.egg-info/dependency_links.txt +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/je_editor.egg-info/top_level.txt +0 -0
- {je_editor-0.0.221 → je_editor-0.0.223}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: je_editor
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.223
|
|
4
4
|
Summary: JEditor is basic but powerful editor include GPT
|
|
5
5
|
Author-email: JE-Chen <jechenmailman@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/JE-Chen/je_editor
|
|
@@ -23,8 +23,8 @@ Requires-Dist: frontengine
|
|
|
23
23
|
Requires-Dist: pycodestyle
|
|
24
24
|
Requires-Dist: jedi
|
|
25
25
|
Requires-Dist: qtconsole
|
|
26
|
-
Requires-Dist: langchain_openai
|
|
27
|
-
Requires-Dist: langchain
|
|
26
|
+
Requires-Dist: langchain_openai==1.0.0
|
|
27
|
+
Requires-Dist: langchain==1.0.0
|
|
28
28
|
Requires-Dist: pydantic
|
|
29
29
|
Requires-Dist: watchdog
|
|
30
30
|
Requires-Dist: ruff
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from je_editor.pyside_ui.browser.
|
|
1
|
+
from je_editor.pyside_ui.browser.main_browser_widget import MainBrowserWidget
|
|
2
2
|
from je_editor.pyside_ui.code.code_process.code_exec import ExecManager
|
|
3
3
|
from je_editor.pyside_ui.code.shell_process.shell_exec import ShellManager
|
|
4
4
|
from je_editor.pyside_ui.code.syntax.python_syntax import PythonHighlighter
|
|
@@ -28,7 +28,7 @@ __all__ = [
|
|
|
28
28
|
"JEditorRunOnShellException", "JEditorSaveFileException", "syntax_rule_setting_dict",
|
|
29
29
|
"JEditorOpenFileException", "JEditorContentFileException", "syntax_extend_setting_dict",
|
|
30
30
|
"JEditorCantFindLanguageException", "JEditorJsonException", "PythonHighlighter",
|
|
31
|
-
"user_setting_dict", "user_setting_color_dict", "EditorWidget", "
|
|
31
|
+
"user_setting_dict", "user_setting_color_dict", "EditorWidget", "MainBrowserWidget",
|
|
32
32
|
"ExecManager", "ShellManager", "traditional_chinese_word_dict", "english_word_dict",
|
|
33
33
|
"language_wrapper"
|
|
34
34
|
]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import threading
|
|
3
|
+
import time
|
|
4
|
+
from queue import Queue
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class RuffThread(threading.Thread):
|
|
8
|
+
"""
|
|
9
|
+
A thread class to run Ruff (a Python linter/formatter) as a subprocess.
|
|
10
|
+
使用子執行緒執行 Ruff (Python 程式碼檢查/格式化工具)。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, ruff_commands: list, std_queue: Queue, stderr_queue: Queue):
|
|
14
|
+
"""
|
|
15
|
+
Initialize the RuffThread.
|
|
16
|
+
初始化 RuffThread。
|
|
17
|
+
|
|
18
|
+
:param ruff_commands: list of commands to run Ruff, e.g. ["ruff", "check"]
|
|
19
|
+
要執行的 Ruff 指令,例如 ["ruff", "check"]
|
|
20
|
+
:param std_queue: queue to store standard output
|
|
21
|
+
用來存放標準輸出的佇列
|
|
22
|
+
:param stderr_queue: queue to store error output
|
|
23
|
+
用來存放錯誤輸出的佇列
|
|
24
|
+
"""
|
|
25
|
+
super().__init__()
|
|
26
|
+
if ruff_commands is None:
|
|
27
|
+
self.ruff_commands = ["ruff", "check"]
|
|
28
|
+
else:
|
|
29
|
+
self.ruff_commands = ruff_commands
|
|
30
|
+
|
|
31
|
+
self.ruff_process = None
|
|
32
|
+
self.std_queue = std_queue
|
|
33
|
+
self.stderr_queue = stderr_queue
|
|
34
|
+
|
|
35
|
+
def run(self):
|
|
36
|
+
"""
|
|
37
|
+
Run the Ruff process in a separate thread.
|
|
38
|
+
在子執行緒中執行 Ruff 程式。
|
|
39
|
+
"""
|
|
40
|
+
# 啟動子程序,捕捉 stdout 與 stderr
|
|
41
|
+
self.ruff_process = subprocess.Popen(
|
|
42
|
+
self.ruff_commands,
|
|
43
|
+
stdout=subprocess.PIPE,
|
|
44
|
+
stderr=subprocess.PIPE,
|
|
45
|
+
text=True,
|
|
46
|
+
bufsize=1
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# 等待子程序結束
|
|
50
|
+
while self.ruff_process.poll() is None:
|
|
51
|
+
time.sleep(1)
|
|
52
|
+
else:
|
|
53
|
+
# 子程序結束後,讀取 stdout 與 stderr
|
|
54
|
+
for line in self.ruff_process.stdout:
|
|
55
|
+
self.std_queue.put(line.strip())
|
|
56
|
+
|
|
57
|
+
for line in self.ruff_process.stderr:
|
|
58
|
+
self.stderr_queue.put(line.strip())
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from queue import Queue
|
|
3
|
+
from typing import Dict
|
|
4
|
+
|
|
5
|
+
from watchdog.events import FileSystemEventHandler
|
|
6
|
+
|
|
7
|
+
from je_editor.code_scan.ruff_thread import RuffThread
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RuffPythonFileChangeHandler(FileSystemEventHandler):
|
|
11
|
+
"""
|
|
12
|
+
File system event handler that runs Ruff when Python files are modified.
|
|
13
|
+
當 Python 檔案被修改時,自動觸發 Ruff 檢查。
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, ruff_commands: list = None, debounce_interval: float = 1.0):
|
|
17
|
+
"""
|
|
18
|
+
:param ruff_commands: Ruff command list, e.g. ["ruff", "check"]
|
|
19
|
+
:param debounce_interval: Minimum interval (seconds) between re-runs for the same file
|
|
20
|
+
同一檔案觸發 Ruff 的最小間隔秒數
|
|
21
|
+
"""
|
|
22
|
+
super().__init__()
|
|
23
|
+
self.ruff_commands = ruff_commands or ["ruff", "check"]
|
|
24
|
+
self.stdout_queue: Queue = Queue()
|
|
25
|
+
self.stderr_queue: Queue = Queue()
|
|
26
|
+
self.ruff_threads_dict: Dict[str, RuffThread] = {}
|
|
27
|
+
self.last_run_time: Dict[str, float] = {}
|
|
28
|
+
self.debounce_interval = debounce_interval
|
|
29
|
+
|
|
30
|
+
def _start_new_thread(self, file_path: str):
|
|
31
|
+
"""Helper to start a new Ruff thread for a given file."""
|
|
32
|
+
ruff_thread = RuffThread(self.ruff_commands, self.stdout_queue, self.stderr_queue)
|
|
33
|
+
self.ruff_threads_dict[file_path] = ruff_thread
|
|
34
|
+
self.last_run_time[file_path] = time.time()
|
|
35
|
+
ruff_thread.start()
|
|
36
|
+
|
|
37
|
+
def on_modified(self, event):
|
|
38
|
+
"""Triggered when a file is modified."""
|
|
39
|
+
if event.is_directory:
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
if not event.src_path.endswith(".py"):
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
now = time.time()
|
|
46
|
+
last_time = self.last_run_time.get(event.src_path, 0)
|
|
47
|
+
|
|
48
|
+
# Debounce: skip if last run was too recent
|
|
49
|
+
if now - last_time < self.debounce_interval:
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
ruff_thread = self.ruff_threads_dict.get(event.src_path)
|
|
53
|
+
|
|
54
|
+
if ruff_thread is None or not ruff_thread.is_alive():
|
|
55
|
+
self._start_new_thread(event.src_path)
|
|
56
|
+
# else: thread still running, skip
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
import time
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from watchdog.observers import Observer
|
|
7
|
+
|
|
8
|
+
from je_editor.code_scan.watchdog_implement import RuffPythonFileChangeHandler
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WatchdogThread(threading.Thread):
|
|
12
|
+
"""
|
|
13
|
+
A thread that runs a watchdog observer to monitor file changes.
|
|
14
|
+
使用 watchdog 監控檔案變化的執行緒。
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, check_path: str):
|
|
18
|
+
"""
|
|
19
|
+
:param check_path: Path to monitor (directory or file)
|
|
20
|
+
要監控的路徑(資料夾或檔案)
|
|
21
|
+
"""
|
|
22
|
+
super().__init__(daemon=True) # 設為 daemon,主程式結束時自動退出
|
|
23
|
+
self.check_path = Path(check_path).resolve()
|
|
24
|
+
self.ruff_handler = RuffPythonFileChangeHandler()
|
|
25
|
+
self.running = True
|
|
26
|
+
self.observer = Observer()
|
|
27
|
+
|
|
28
|
+
def run(self):
|
|
29
|
+
"""Start the watchdog observer loop."""
|
|
30
|
+
if not self.check_path.exists():
|
|
31
|
+
print(f"[Error] Path does not exist: {self.check_path}", file=sys.stderr)
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
# 設定監控
|
|
35
|
+
self.observer.schedule(self.ruff_handler, str(self.check_path), recursive=True)
|
|
36
|
+
self.observer.start()
|
|
37
|
+
print(f"[Watchdog] Monitoring started on {self.check_path}")
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
while self.running:
|
|
41
|
+
time.sleep(1)
|
|
42
|
+
# 這裡可以加上 queue 輸出處理
|
|
43
|
+
self._process_ruff_output()
|
|
44
|
+
except KeyboardInterrupt:
|
|
45
|
+
print("[Watchdog] Interrupted by user")
|
|
46
|
+
finally:
|
|
47
|
+
self.observer.stop()
|
|
48
|
+
self.observer.join()
|
|
49
|
+
print("[Watchdog] Monitoring stopped")
|
|
50
|
+
|
|
51
|
+
def stop(self):
|
|
52
|
+
"""Stop the watchdog thread safely."""
|
|
53
|
+
self.running = False
|
|
54
|
+
|
|
55
|
+
def _process_ruff_output(self):
|
|
56
|
+
"""Process stdout/stderr queues from Ruff threads."""
|
|
57
|
+
while not self.ruff_handler.stdout_queue.empty():
|
|
58
|
+
line = self.ruff_handler.stdout_queue.get()
|
|
59
|
+
print(f"[Ruff STDOUT] {line}")
|
|
60
|
+
|
|
61
|
+
while not self.ruff_handler.stderr_queue.empty():
|
|
62
|
+
line = self.ruff_handler.stderr_queue.get()
|
|
63
|
+
print(f"[Ruff STDERR] {line}", file=sys.stderr)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == '__main__':
|
|
67
|
+
# 預設監控當前目錄
|
|
68
|
+
path_to_watch = "."
|
|
69
|
+
watchdog_thread = WatchdogThread(path_to_watch)
|
|
70
|
+
watchdog_thread.start()
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
while True:
|
|
74
|
+
time.sleep(1)
|
|
75
|
+
except KeyboardInterrupt:
|
|
76
|
+
print("[Main] Stopping watchdog...")
|
|
77
|
+
watchdog_thread.stop()
|
|
78
|
+
watchdog_thread.join()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import List, Dict, Any
|
|
4
|
+
|
|
5
|
+
log = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class CommitNode:
|
|
10
|
+
commit_sha: str
|
|
11
|
+
author_name: str
|
|
12
|
+
commit_date: str
|
|
13
|
+
commit_message: str
|
|
14
|
+
parent_shas: List[str]
|
|
15
|
+
lane_index: int = -1 # assigned later
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class CommitGraph:
|
|
20
|
+
nodes: List[CommitNode] = field(default_factory=list)
|
|
21
|
+
index: Dict[str, int] = field(default_factory=dict) # sha -> row
|
|
22
|
+
|
|
23
|
+
def build(self, commits: List[Dict[str, Any]], refs: Dict[str, str] | None = None) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Build commit graph from topo-ordered commits.
|
|
26
|
+
從 topo-order 的 commits 建立 commit graph。
|
|
27
|
+
"""
|
|
28
|
+
self.nodes = [
|
|
29
|
+
CommitNode(
|
|
30
|
+
commit_sha=c["sha"],
|
|
31
|
+
author_name=c["author"],
|
|
32
|
+
commit_date=c["date"],
|
|
33
|
+
commit_message=c["message"],
|
|
34
|
+
parent_shas=c["parents"],
|
|
35
|
+
)
|
|
36
|
+
for c in commits
|
|
37
|
+
]
|
|
38
|
+
self.index = {n.commit_sha: i for i, n in enumerate(self.nodes)}
|
|
39
|
+
self._assign_lanes()
|
|
40
|
+
|
|
41
|
+
def _assign_lanes(self) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Assign lanes to commits, similar to `git log --graph`.
|
|
44
|
+
分配 lanes,模擬 `git log --graph` 的效果。
|
|
45
|
+
"""
|
|
46
|
+
active: Dict[int, str] = {} # lane -> sha
|
|
47
|
+
free_lanes: List[int] = []
|
|
48
|
+
|
|
49
|
+
for node in self.nodes:
|
|
50
|
+
# Step 1: 找到 lane
|
|
51
|
+
lane_found = next((lane for lane, sha in active.items() if sha == node.commit_sha), None)
|
|
52
|
+
|
|
53
|
+
if lane_found is not None:
|
|
54
|
+
node.lane_index = lane_found
|
|
55
|
+
elif free_lanes:
|
|
56
|
+
node.lane_index = free_lanes.pop(0)
|
|
57
|
+
else:
|
|
58
|
+
node.lane_index = 0 if not active else max(active.keys()) + 1
|
|
59
|
+
|
|
60
|
+
# Step 2: 更新 active
|
|
61
|
+
# 移除舊的 sha
|
|
62
|
+
active = {lane: sha for lane, sha in active.items() if sha != node.commit_sha}
|
|
63
|
+
|
|
64
|
+
# 父節點分配 lane
|
|
65
|
+
if node.parent_shas:
|
|
66
|
+
first_parent = node.parent_shas[0]
|
|
67
|
+
active[node.lane_index] = first_parent
|
|
68
|
+
for p in node.parent_shas[1:]:
|
|
69
|
+
pl = free_lanes.pop(0) if free_lanes else (max(active.keys()) + 1)
|
|
70
|
+
active[pl] = p
|
|
71
|
+
|
|
72
|
+
# Step 3: 更新 free_lanes
|
|
73
|
+
if active:
|
|
74
|
+
max_lane = max(active.keys())
|
|
75
|
+
used = set(active.keys())
|
|
76
|
+
all_lanes = set(range(max_lane + 1))
|
|
77
|
+
free_lanes = sorted(set(free_lanes).union(all_lanes - used))
|
je_editor-0.0.221/je_editor/git_client/git.py → je_editor-0.0.223/je_editor/git_client/git_action.py
RENAMED
|
@@ -160,7 +160,7 @@ NULL_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
|
|
160
160
|
# -----------------------
|
|
161
161
|
# Worker thread wrapper
|
|
162
162
|
# -----------------------
|
|
163
|
-
class
|
|
163
|
+
class GitWorker(QThread):
|
|
164
164
|
"""
|
|
165
165
|
Runs a function in a separate thread to avoid blocking the UI.
|
|
166
166
|
Emits (result, error) when done.
|
|
@@ -11,12 +11,12 @@ class GitCLI:
|
|
|
11
11
|
self.repo_path = Path(repo_path)
|
|
12
12
|
|
|
13
13
|
def is_git_repo(self) -> bool:
|
|
14
|
-
return (self.repo_path / ".
|
|
14
|
+
return (self.repo_path / ".git").exists()
|
|
15
15
|
|
|
16
16
|
def _run(self, args: List[str]) -> str:
|
|
17
|
-
log.debug("
|
|
17
|
+
log.debug("git %s", " ".join(args))
|
|
18
18
|
res = subprocess.run(
|
|
19
|
-
["
|
|
19
|
+
["git"] + args,
|
|
20
20
|
cwd=self.repo_path,
|
|
21
21
|
stdout=subprocess.PIPE,
|
|
22
22
|
stderr=subprocess.PIPE,
|
|
@@ -63,4 +63,4 @@ class GitCLI:
|
|
|
63
63
|
"date": date,
|
|
64
64
|
"message": msg,
|
|
65
65
|
})
|
|
66
|
-
return commits
|
|
66
|
+
return commits
|
{je_editor-0.0.221 → je_editor-0.0.223}/je_editor/pyside_ui/browser/browser_download_window.py
RENAMED
|
@@ -7,33 +7,69 @@ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapp
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class BrowserDownloadWindow(QWidget):
|
|
10
|
+
"""
|
|
11
|
+
A window widget to display details of a browser download.
|
|
12
|
+
瀏覽器下載視窗,用來顯示下載的詳細資訊。
|
|
13
|
+
"""
|
|
10
14
|
|
|
11
15
|
def __init__(self, download_instance: QWebEngineDownloadRequest):
|
|
16
|
+
"""
|
|
17
|
+
Initialize the download window with a given QWebEngineDownloadRequest.
|
|
18
|
+
使用指定的 QWebEngineDownloadRequest 初始化下載視窗。
|
|
19
|
+
"""
|
|
12
20
|
super().__init__()
|
|
21
|
+
# 記錄初始化訊息到 logger
|
|
13
22
|
jeditor_logger.info("Init BrowserDownloadWindow "
|
|
14
23
|
f"download_instance: {download_instance}")
|
|
24
|
+
|
|
25
|
+
# 設定視窗屬性:當視窗關閉時自動刪除
|
|
15
26
|
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
|
|
27
|
+
|
|
28
|
+
# 建立垂直方向的 BoxLayout
|
|
16
29
|
self.box_layout = QBoxLayout(QBoxLayout.Direction.TopToBottom)
|
|
30
|
+
|
|
31
|
+
# 建立文字框來顯示下載細節,並設為唯讀
|
|
17
32
|
self.show_download_detail_plaintext = QPlainTextEdit()
|
|
18
33
|
self.show_download_detail_plaintext.setReadOnly(True)
|
|
34
|
+
|
|
35
|
+
# 設定視窗標題,支援多語言
|
|
19
36
|
self.setWindowTitle(language_wrapper.language_word_dict.get("browser_download_detail"))
|
|
37
|
+
|
|
38
|
+
# 儲存下載實例
|
|
20
39
|
self.download_instance = download_instance
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
self.download_instance.
|
|
40
|
+
|
|
41
|
+
# 綁定下載事件到對應的處理函式
|
|
42
|
+
self.download_instance.isFinishedChanged.connect(self.print_finish) # 當下載完成時
|
|
43
|
+
self.download_instance.interruptReasonChanged.connect(self.print_interrupt) # 當下載被中斷時
|
|
44
|
+
self.download_instance.stateChanged.connect(self.print_state) # 當下載狀態改變時
|
|
45
|
+
|
|
46
|
+
# 接受下載請求,開始下載
|
|
24
47
|
self.download_instance.accept()
|
|
48
|
+
|
|
49
|
+
# 將文字框加入版面配置
|
|
25
50
|
self.box_layout.addWidget(self.show_download_detail_plaintext)
|
|
26
51
|
self.setLayout(self.box_layout)
|
|
27
52
|
|
|
28
|
-
|
|
29
53
|
def print_finish(self):
|
|
54
|
+
"""
|
|
55
|
+
Slot function triggered when download finishes.
|
|
56
|
+
當下載完成時觸發,將完成狀態輸出到 logger 與文字框。
|
|
57
|
+
"""
|
|
30
58
|
jeditor_logger.info("BrowserDownloadWindow Print Download is Finished")
|
|
31
59
|
self.show_download_detail_plaintext.appendPlainText(str(self.download_instance.isFinished()))
|
|
32
60
|
|
|
33
61
|
def print_interrupt(self):
|
|
62
|
+
"""
|
|
63
|
+
Slot function triggered when download is interrupted.
|
|
64
|
+
當下載被中斷時觸發,將中斷原因輸出到 logger 與文字框。
|
|
65
|
+
"""
|
|
34
66
|
jeditor_logger.info("BrowserDownloadWindow Print interruptReason")
|
|
35
67
|
self.show_download_detail_plaintext.appendPlainText(str(self.download_instance.interruptReason()))
|
|
36
68
|
|
|
37
69
|
def print_state(self):
|
|
70
|
+
"""
|
|
71
|
+
Slot function triggered when download state changes.
|
|
72
|
+
當下載狀態改變時觸發,將狀態輸出到 logger 與文字框。
|
|
73
|
+
"""
|
|
38
74
|
jeditor_logger.info("BrowserDownloadWindow Print State")
|
|
39
|
-
self.show_download_detail_plaintext.appendPlainText(str(self.download_instance.state()))
|
|
75
|
+
self.show_download_detail_plaintext.appendPlainText(str(self.download_instance.state()))
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from PySide6.QtCore import Qt
|
|
6
|
+
from PySide6.QtWidgets import QLineEdit
|
|
7
|
+
|
|
8
|
+
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
# Forward declaration to avoid circular import at runtime
|
|
12
|
+
# 僅在型別檢查時匯入,避免執行時循環匯入問題
|
|
13
|
+
from je_editor.pyside_ui.browser.browser_widget import BrowserWidget
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BrowserLineSearch(QLineEdit):
|
|
17
|
+
"""
|
|
18
|
+
A custom QLineEdit widget for browser search input.
|
|
19
|
+
自訂的 QLineEdit,用於瀏覽器搜尋輸入。
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, browser_widget: BrowserWidget):
|
|
23
|
+
"""
|
|
24
|
+
Initialize the search line with a reference to the browser widget.
|
|
25
|
+
初始化搜尋輸入框,並保存瀏覽器元件的參考。
|
|
26
|
+
"""
|
|
27
|
+
super().__init__()
|
|
28
|
+
# 記錄初始化訊息到 logger
|
|
29
|
+
jeditor_logger.info("Init BrowserLineSearch "
|
|
30
|
+
f"browser_widget: {browser_widget}")
|
|
31
|
+
|
|
32
|
+
# 設定屬性:當視窗關閉時自動刪除
|
|
33
|
+
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
|
|
34
|
+
|
|
35
|
+
# 保存瀏覽器元件的參考,用於觸發搜尋
|
|
36
|
+
self.browser = browser_widget
|
|
37
|
+
|
|
38
|
+
def keyPressEvent(self, event) -> None:
|
|
39
|
+
"""
|
|
40
|
+
Handle key press events.
|
|
41
|
+
當使用者按下按鍵時觸發:
|
|
42
|
+
- 如果是 Enter 或 Return,則呼叫瀏覽器的 search() 方法。
|
|
43
|
+
- 其他情況則交由父類別處理。
|
|
44
|
+
"""
|
|
45
|
+
if event.key() in [Qt.Key.Key_Enter, Qt.Key.Key_Return]:
|
|
46
|
+
jeditor_logger.info("Browser Search")
|
|
47
|
+
# 呼叫瀏覽器元件的搜尋方法
|
|
48
|
+
self.browser.search()
|
|
49
|
+
|
|
50
|
+
# 呼叫父類別的 keyPressEvent,確保其他按鍵行為正常
|
|
51
|
+
super().keyPressEvent(event)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import List, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from PySide6.QtCore import Signal
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from je_editor.pyside_ui.browser.browser_widget import BrowserWidget
|
|
9
|
+
|
|
10
|
+
from PySide6.QtWebEngineCore import QWebEngineDownloadRequest
|
|
11
|
+
from PySide6.QtWebEngineWidgets import QWebEngineView
|
|
12
|
+
|
|
13
|
+
from je_editor.pyside_ui.browser.browser_download_window import BrowserDownloadWindow
|
|
14
|
+
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BrowserView(QWebEngineView):
|
|
18
|
+
new_tab_requested = Signal(QWebEngineView)
|
|
19
|
+
"""
|
|
20
|
+
A custom QWebEngineView that supports file downloads and manages download windows.
|
|
21
|
+
自訂的 QWebEngineView,支援檔案下載並管理下載視窗。
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, start_url: str = "https://www.google.com/",
|
|
25
|
+
main_widget: BrowserWidget = None, parent=None):
|
|
26
|
+
"""
|
|
27
|
+
Initialize the browser view with a start URL.
|
|
28
|
+
使用指定的起始網址初始化瀏覽器視圖。
|
|
29
|
+
"""
|
|
30
|
+
super().__init__(parent)
|
|
31
|
+
# 記錄初始化訊息
|
|
32
|
+
jeditor_logger.info("Init BrowserView "
|
|
33
|
+
f"start_url: {start_url}")
|
|
34
|
+
|
|
35
|
+
# 設定初始網址
|
|
36
|
+
self.setUrl(start_url)
|
|
37
|
+
|
|
38
|
+
# 儲存下載請求的清單
|
|
39
|
+
self.download_list: List[QWebEngineDownloadRequest] = list()
|
|
40
|
+
|
|
41
|
+
# 儲存下載視窗的清單
|
|
42
|
+
self.download_window_list: List[BrowserDownloadWindow] = list()
|
|
43
|
+
|
|
44
|
+
# 綁定下載事件:當有下載請求時觸發 download_file
|
|
45
|
+
self.page().profile().downloadRequested.connect(self.download_file)
|
|
46
|
+
|
|
47
|
+
self.main_widget = main_widget
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def download_file(self, download_instance: QWebEngineDownloadRequest):
|
|
51
|
+
"""
|
|
52
|
+
Handle a new download request.
|
|
53
|
+
當有新的下載請求時觸發:
|
|
54
|
+
- 將下載請求加入清單
|
|
55
|
+
- 建立並顯示下載細節視窗
|
|
56
|
+
"""
|
|
57
|
+
jeditor_logger.info("Download File "
|
|
58
|
+
f"download_instance: {download_instance}")
|
|
59
|
+
|
|
60
|
+
# 加入下載請求到清單
|
|
61
|
+
self.download_list.append(download_instance)
|
|
62
|
+
|
|
63
|
+
# 建立下載細節視窗
|
|
64
|
+
download_detail_window = BrowserDownloadWindow(download_instance)
|
|
65
|
+
|
|
66
|
+
# 加入視窗到清單並顯示
|
|
67
|
+
self.download_window_list.append(download_detail_window)
|
|
68
|
+
download_detail_window.show()
|
|
69
|
+
|
|
70
|
+
def closeEvent(self, event) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Handle the close event of the browser view.
|
|
73
|
+
當瀏覽器視窗關閉時:
|
|
74
|
+
- 取消所有進行中的下載
|
|
75
|
+
- 關閉所有下載細節視窗
|
|
76
|
+
"""
|
|
77
|
+
jeditor_logger.info(f"BrowserView closeEvent event: {event}")
|
|
78
|
+
|
|
79
|
+
# 取消所有下載
|
|
80
|
+
for download_instance in self.download_list:
|
|
81
|
+
download_instance.cancel()
|
|
82
|
+
|
|
83
|
+
# 關閉所有下載視窗
|
|
84
|
+
for download_window in self.download_window_list:
|
|
85
|
+
download_window.close()
|
|
86
|
+
|
|
87
|
+
# 呼叫父類別的 closeEvent,確保正常關閉
|
|
88
|
+
super().closeEvent(event)
|
|
@@ -1,60 +1,90 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from je_editor.pyside_ui.browser.main_browser_widget import MainBrowserWidget
|
|
7
|
+
|
|
8
|
+
from PySide6.QtCore import Qt
|
|
9
|
+
from PySide6.QtGui import QAction
|
|
10
|
+
from PySide6.QtWidgets import QWidget, QPushButton, QGridLayout, QInputDialog
|
|
3
11
|
|
|
4
12
|
from je_editor.pyside_ui.browser.browser_serach_lineedit import BrowserLineSearch
|
|
5
|
-
from je_editor.pyside_ui.browser.browser_view import BrowserView
|
|
6
13
|
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
7
14
|
from je_editor.utils.multi_language.multi_language_wrapper import language_wrapper
|
|
8
15
|
|
|
16
|
+
from je_editor.pyside_ui.browser.browser_view import BrowserView
|
|
9
17
|
|
|
10
|
-
class BrowserWidget(QWidget):
|
|
11
18
|
|
|
19
|
+
class BrowserWidget(QWidget):
|
|
12
20
|
def __init__(self, start_url: str = "https://www.google.com/",
|
|
13
|
-
search_prefix: str = "https://www.google.com.tw/search?q="
|
|
21
|
+
search_prefix: str = "https://www.google.com.tw/search?q=",
|
|
22
|
+
main_widget: MainBrowserWidget = None, browser_view: BrowserView = None):
|
|
23
|
+
# --- Browser setting / 瀏覽器設定 ---
|
|
14
24
|
super().__init__()
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
self.search_prefix = search_prefix
|
|
25
|
+
self.main_widget = main_widget
|
|
26
|
+
if browser_view:
|
|
27
|
+
self.browser = browser_view
|
|
28
|
+
else:
|
|
29
|
+
self.browser = BrowserView(start_url, main_widget=main_widget) # 內嵌的瀏覽器視圖
|
|
30
|
+
self.search_prefix = search_prefix # 搜尋引擎前綴字串
|
|
21
31
|
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
|
|
22
|
-
|
|
32
|
+
|
|
33
|
+
# --- Top bar buttons / 上方工具列按鈕 ---
|
|
23
34
|
self.back_button = QPushButton(language_wrapper.language_word_dict.get("browser_back_button"))
|
|
24
|
-
self.back_button.clicked.connect(self.browser.back)
|
|
35
|
+
self.back_button.clicked.connect(self.browser.back) # 返回上一頁
|
|
36
|
+
|
|
25
37
|
self.forward_button = QPushButton(language_wrapper.language_word_dict.get("browser_forward_button"))
|
|
26
|
-
self.forward_button.clicked.connect(self.browser.forward)
|
|
38
|
+
self.forward_button.clicked.connect(self.browser.forward) # 前往下一頁
|
|
39
|
+
|
|
27
40
|
self.reload_button = QPushButton(language_wrapper.language_word_dict.get("browser_reload_button"))
|
|
28
|
-
self.reload_button.clicked.connect(self.browser.reload)
|
|
41
|
+
self.reload_button.clicked.connect(self.browser.reload) # 重新整理
|
|
42
|
+
|
|
29
43
|
self.search_button = QPushButton(language_wrapper.language_word_dict.get("browser_search_button"))
|
|
30
|
-
self.search_button.clicked.connect(self.search)
|
|
44
|
+
self.search_button.clicked.connect(self.search) # 搜尋按鈕
|
|
45
|
+
|
|
46
|
+
# URL / Search input line (custom QLineEdit)
|
|
31
47
|
self.url_input = BrowserLineSearch(self)
|
|
32
|
-
|
|
48
|
+
|
|
49
|
+
# --- Action: Ctrl+F to find text / 快捷鍵 Ctrl+F 搜尋文字 ---
|
|
33
50
|
self.find_action = QAction()
|
|
34
51
|
self.find_action.setShortcut("Ctrl+f")
|
|
35
52
|
self.find_action.triggered.connect(self.find_text)
|
|
36
53
|
self.addAction(self.find_action)
|
|
37
|
-
|
|
54
|
+
|
|
55
|
+
# --- Layout / 版面配置 ---
|
|
38
56
|
self.grid_layout = QGridLayout()
|
|
39
57
|
self.grid_layout.addWidget(self.back_button, 0, 0)
|
|
40
58
|
self.grid_layout.addWidget(self.forward_button, 0, 1)
|
|
41
59
|
self.grid_layout.addWidget(self.reload_button, 0, 2)
|
|
42
60
|
self.grid_layout.addWidget(self.url_input, 0, 3)
|
|
43
61
|
self.grid_layout.addWidget(self.search_button, 0, 4)
|
|
44
|
-
self.grid_layout.addWidget(self.browser, 1, 0, -1, -1)
|
|
62
|
+
self.grid_layout.addWidget(self.browser, 1, 0, -1, -1) # 瀏覽器視圖佔滿下方
|
|
45
63
|
self.setLayout(self.grid_layout)
|
|
46
64
|
|
|
47
65
|
def search(self):
|
|
66
|
+
"""
|
|
67
|
+
Perform a search using the text in the input line.
|
|
68
|
+
使用輸入框的文字進行搜尋,將字串附加到 search_prefix 後送出。
|
|
69
|
+
"""
|
|
48
70
|
jeditor_logger.info("BrowserWidget Search")
|
|
49
71
|
self.browser.setUrl(f"{self.search_prefix}{self.url_input.text()}")
|
|
50
72
|
|
|
51
73
|
def find_text(self):
|
|
74
|
+
"""
|
|
75
|
+
Open a dialog to find text in the current page.
|
|
76
|
+
開啟輸入對話框,在當前頁面中搜尋文字。
|
|
77
|
+
- 如果按下 OK,搜尋輸入的文字
|
|
78
|
+
- 如果取消,清除搜尋
|
|
79
|
+
"""
|
|
52
80
|
jeditor_logger.info("BrowserWidget Find Text")
|
|
53
81
|
search_box = QInputDialog(self)
|
|
54
82
|
search_text, press_ok = search_box.getText(
|
|
55
|
-
self,
|
|
56
|
-
language_wrapper.language_word_dict.get("
|
|
83
|
+
self,
|
|
84
|
+
language_wrapper.language_word_dict.get("browser_find_text"),
|
|
85
|
+
language_wrapper.language_word_dict.get("browser_find_text_input")
|
|
86
|
+
)
|
|
57
87
|
if press_ok:
|
|
58
88
|
self.browser.findText(search_text)
|
|
59
89
|
else:
|
|
60
|
-
self.browser.findText("")
|
|
90
|
+
self.browser.findText("")
|