PrEditor 1.2.0__tar.gz → 1.4.0__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 PrEditor might be problematic. Click here for more details.
- {preditor-1.2.0 → preditor-1.4.0}/PKG-INFO +1 -1
- {preditor-1.2.0 → preditor-1.4.0}/PrEditor.egg-info/PKG-INFO +1 -1
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/console.py +17 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/drag_tab_bar.py +4 -1
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/group_tab_widget/__init__.py +42 -19
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/group_tab_widget/grouped_tab_widget.py +26 -4
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/group_tab_widget/one_tab_widget.py +42 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/logger_window_plugin.py +3 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/loggerwindow.py +43 -47
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/ui/loggerwindow.ui +11 -1
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/workbox_mixin.py +102 -4
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/workbox_text_edit.py +2 -2
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/workboxwidget.py +9 -4
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/documenteditor.py +64 -20
- {preditor-1.2.0 → preditor-1.4.0}/preditor/version.py +3 -3
- {preditor-1.2.0 → preditor-1.4.0}/.coveragerc +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/.github/ISSUE_TEMPLATE/BUG_REPORT.md +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/.github/workflows/release.yml +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/.github/workflows/static-analysis-and-test.yml +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/.gitignore +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/.pre-commit-config.yaml +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/CODE_OF_CONDUCT.md +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/CONTRIBUTING.md +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/LICENSE +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/MANIFEST.in +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/PrEditor.egg-info/SOURCES.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/PrEditor.egg-info/dependency_links.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/PrEditor.egg-info/entry_points.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/PrEditor.egg-info/requires.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/PrEditor.egg-info/top_level.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/README.md +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/examples/add_to_app.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/examples/output_capture_and_show.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/__main__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/about_module.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/cli.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/config.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/contexts.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/cores/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/cores/core.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/dccs/.hab.json +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/dccs/maya/PrEditor_maya.mod +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/dccs/maya/README.md +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/dccs/maya/plug-ins/PrEditor_maya.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/dccs/studiomax/PackageContents.xml +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/dccs/studiomax/PrEditor-PrEditor_Show.mcr +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/dccs/studiomax/README.md +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/dccs/studiomax/preditor.ms +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/dccs/studiomax/preditor_menu.mnx +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/debug.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/delayable_engine/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/delayable_engine/delayables.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/enum.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/excepthooks.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/app.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/codehighlighter.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/completer.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/dialog.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/editor_chooser.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/errordialog.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/find_files.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/fuzzy_search/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/fuzzy_search/fuzzy_search.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/group_tab_widget/grouped_tab_menu.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/group_tab_widget/grouped_tab_models.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/level_buttons.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/logger_window_handler.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/newtabwidget.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/set_text_editor_path_dialog.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/status_label.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/suggest_path_quotes_dialog.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/ui/editor_chooser.ui +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/ui/errordialog.ui +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/ui/find_files.ui +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/ui/set_text_editor_path_dialog.ui +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/ui/suggest_path_quotes_dialog.ui +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/gui/window.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/logging_config.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/osystem.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/plugins.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/prefs.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/environment_variables.html +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/error_mail.html +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/error_mail_inline.html +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/README.md +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/arrow_forward.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/check-bold.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/chevron-down.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/chevron-up.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/close-thick.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/comment-edit.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/content-copy.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/content-cut.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/content-duplicate.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/content-paste.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/content-save.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/debug_disabled.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/eye-check.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/file-plus.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/file-remove.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/format-align-left.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/format-letter-case-lower.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/format-letter-case-upper.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/format-letter-case.svg +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/information.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/logging_critical.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/logging_custom.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/logging_debug.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/logging_error.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/logging_info.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/logging_not_set.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/logging_warning.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/marker.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/play.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/playlist-play.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/plus-minus-variant.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/preditor.ico +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/preditor.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/preditor.psd +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/preditor.svg +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/regex.svg +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/restart.svg +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/skip-forward-outline.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/skip-next-outline.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/skip-next.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/skip-previous.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/subdirectory-arrow-right.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/text-search-variant.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/img/warning-big.png +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/lang/python.json +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/settings.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/stylesheet/Bright.css +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/resource/stylesheet/Dark.css +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/delayables/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/delayables/smart_highlight.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/delayables/spell_check.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/finddialog.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/bash.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/batch.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/cpp.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/css.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/eyeonscript.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/html.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/javascript.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/lua.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/maxscript.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/mel.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/mu.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/nsi.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/perl.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/puppet.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/python.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/ruby.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/sql.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/xml.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/config/yaml.ini +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lang/language.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lexers/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lexers/cpplexer.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lexers/javascriptlexer.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lexers/maxscriptlexer.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lexers/mellexer.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lexers/mulexer.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/lexers/pythonlexer.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/scintilla/ui/finddialog.ui +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/settings.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/stream/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/stream/director.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/stream/manager.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/streamhandler_helper.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/utils/__init__.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/utils/cute.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/utils/stylesheets.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/utils/text_search.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/preditor/weakref.py +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/pyproject.toml +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/requirements-cli.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/requirements-dev.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/requirements-qsci5.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/requirements-qsci6.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/requirements-shortcut.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/requirements.txt +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/setup.cfg +0 -0
- {preditor-1.2.0 → preditor-1.4.0}/tox.ini +0 -0
|
@@ -63,6 +63,8 @@ class ConsolePrEdit(QTextEdit):
|
|
|
63
63
|
|
|
64
64
|
self._firstShow = True
|
|
65
65
|
|
|
66
|
+
self.addSepNewline = False
|
|
67
|
+
|
|
66
68
|
# When executing code, that takes longer than this seconds, flash the window
|
|
67
69
|
self.flash_time = 1.0
|
|
68
70
|
self.flash_window = None
|
|
@@ -817,6 +819,10 @@ class ConsolePrEdit(QTextEdit):
|
|
|
817
819
|
hasattr(window, 'uiErrorHyperlinksACT')
|
|
818
820
|
and window.uiErrorHyperlinksACT.isChecked()
|
|
819
821
|
)
|
|
822
|
+
sepPreditorTrace = (
|
|
823
|
+
hasattr(window, 'uiSeparateTracebackACT')
|
|
824
|
+
and window.uiSeparateTracebackACT.isChecked()
|
|
825
|
+
)
|
|
820
826
|
self.moveCursor(QTextCursor.MoveOperation.End)
|
|
821
827
|
|
|
822
828
|
charFormat = QTextCharFormat()
|
|
@@ -855,6 +861,17 @@ class ConsolePrEdit(QTextEdit):
|
|
|
855
861
|
filename = info.get("filename", "") if info else ""
|
|
856
862
|
isConsolePrEdit = '<ConsolePrEdit>' in filename
|
|
857
863
|
|
|
864
|
+
# To make it easier to see relevant lines of a traceback, optionally insert
|
|
865
|
+
# a newline separating internal PrEditor code from the code run by user.
|
|
866
|
+
if self.addSepNewline:
|
|
867
|
+
if sepPreditorTrace:
|
|
868
|
+
msg += "\n"
|
|
869
|
+
self.addSepNewline = False
|
|
870
|
+
|
|
871
|
+
preditorCalls = ("cmdresult = e", "exec(compiled,")
|
|
872
|
+
if msg.strip().startswith(preditorCalls):
|
|
873
|
+
self.addSepNewline = True
|
|
874
|
+
|
|
858
875
|
if info and doHyperlink and not isConsolePrEdit:
|
|
859
876
|
fileStart = info.get("fileStart")
|
|
860
877
|
fileEnd = info.get("fileEnd")
|
|
@@ -139,8 +139,11 @@ class DragTabBar(QTabBar):
|
|
|
139
139
|
"""Used by the tab_menu to rename the tab at index `_context_menu_tab`."""
|
|
140
140
|
if self._context_menu_tab != -1:
|
|
141
141
|
current = self.tabText(self._context_menu_tab)
|
|
142
|
-
msg = 'Rename the {} tab to:'.format(current)
|
|
142
|
+
msg = 'Rename the {} tab to (new name must be unique):'.format(current)
|
|
143
|
+
|
|
143
144
|
name, success = QInputDialog.getText(self, 'Rename Tab', msg, text=current)
|
|
145
|
+
name = self.parent().get_next_available_tab_name(name)
|
|
146
|
+
|
|
144
147
|
if success:
|
|
145
148
|
self.setTabText(self._context_menu_tab, name)
|
|
146
149
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import absolute_import
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
import re
|
|
5
4
|
|
|
6
5
|
from Qt.QtCore import Qt
|
|
7
6
|
from Qt.QtGui import QIcon
|
|
@@ -46,6 +45,9 @@ class GroupTabWidget(OneTabWidget):
|
|
|
46
45
|
self.editor_cls = WorkboxTextEdit
|
|
47
46
|
self.core_name = core_name
|
|
48
47
|
self.setStyleSheet(DEFAULT_STYLE_SHEET)
|
|
48
|
+
|
|
49
|
+
self.default_title = 'Group01'
|
|
50
|
+
|
|
49
51
|
corner = QWidget(self)
|
|
50
52
|
lyt = QHBoxLayout(corner)
|
|
51
53
|
lyt.setSpacing(0)
|
|
@@ -69,7 +71,7 @@ class GroupTabWidget(OneTabWidget):
|
|
|
69
71
|
self.uiCornerBTN = corner
|
|
70
72
|
self.setCornerWidget(self.uiCornerBTN, Qt.Corner.TopRightCorner)
|
|
71
73
|
|
|
72
|
-
def add_new_tab(self, group, title=
|
|
74
|
+
def add_new_tab(self, group, title=None, prefs=None):
|
|
73
75
|
"""Adds a new tab to the requested group, creating the group if the group
|
|
74
76
|
doesn't exist.
|
|
75
77
|
|
|
@@ -80,9 +82,6 @@ class GroupTabWidget(OneTabWidget):
|
|
|
80
82
|
If True is passed, then the current group tab is used.
|
|
81
83
|
title (str, optional): The name to give the newly created tab inside
|
|
82
84
|
the group.
|
|
83
|
-
group_fmt(str, optional): If None is passed to group, this string is
|
|
84
|
-
used to search for existing tabs to calculate the last number
|
|
85
|
-
and generate the new group tab name.
|
|
86
85
|
|
|
87
86
|
Returns:
|
|
88
87
|
GroupedTabWidget: The tab group for this group.
|
|
@@ -90,21 +89,14 @@ class GroupTabWidget(OneTabWidget):
|
|
|
90
89
|
"""
|
|
91
90
|
parent = None
|
|
92
91
|
if not group:
|
|
93
|
-
|
|
94
|
-
group_fmt = r'Group {}'
|
|
95
|
-
last = 0
|
|
96
|
-
for i in range(self.count()):
|
|
97
|
-
match = re.match(group_fmt.format(r'(\d+)'), self.tabText(i))
|
|
98
|
-
if match:
|
|
99
|
-
last = max(last, int(match.group(1)))
|
|
100
|
-
group = group_fmt.format(last + 1)
|
|
92
|
+
group = self.get_next_available_tab_name(self.default_title)
|
|
101
93
|
elif group is True:
|
|
102
94
|
group = self.currentIndex()
|
|
103
95
|
if isinstance(group, int):
|
|
104
96
|
group_title = self.tabText(group)
|
|
105
97
|
parent = self.widget(group)
|
|
106
98
|
elif isinstance(group, str):
|
|
107
|
-
group_title = group
|
|
99
|
+
group_title = group.replace(" ", "_")
|
|
108
100
|
index = self.index_for_text(group)
|
|
109
101
|
if index != -1:
|
|
110
102
|
parent = self.widget(index)
|
|
@@ -146,7 +138,7 @@ class GroupTabWidget(OneTabWidget):
|
|
|
146
138
|
self,
|
|
147
139
|
'Close all editors under this tab?',
|
|
148
140
|
'Are you sure you want to close all tabs under the "{}" tab?'.format(
|
|
149
|
-
self.tabText(
|
|
141
|
+
self.tabText(index)
|
|
150
142
|
),
|
|
151
143
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.Cancel,
|
|
152
144
|
)
|
|
@@ -154,11 +146,11 @@ class GroupTabWidget(OneTabWidget):
|
|
|
154
146
|
# Clean up all temp files created by this group's editors if they
|
|
155
147
|
# are not using actual saved files.
|
|
156
148
|
tab_widget = self.widget(self.currentIndex())
|
|
157
|
-
for
|
|
158
|
-
editor = tab_widget.widget(
|
|
149
|
+
for editor_index in range(tab_widget.count()):
|
|
150
|
+
editor = tab_widget.widget(editor_index)
|
|
159
151
|
editor.__remove_tempfile__()
|
|
160
152
|
|
|
161
|
-
super(GroupTabWidget, self).close_tab(
|
|
153
|
+
super(GroupTabWidget, self).close_tab(index)
|
|
162
154
|
|
|
163
155
|
def current_groups_widget(self):
|
|
164
156
|
"""Returns the current widget of the currently selected group or None."""
|
|
@@ -166,7 +158,8 @@ class GroupTabWidget(OneTabWidget):
|
|
|
166
158
|
if editor_tab:
|
|
167
159
|
return editor_tab.currentWidget()
|
|
168
160
|
|
|
169
|
-
def default_tab(self, title=
|
|
161
|
+
def default_tab(self, title=None, prefs=None):
|
|
162
|
+
title = title or self.default_title
|
|
170
163
|
widget = GroupedTabWidget(
|
|
171
164
|
parent=self,
|
|
172
165
|
editor_kwargs=self.editor_kwargs,
|
|
@@ -223,6 +216,8 @@ class GroupTabWidget(OneTabWidget):
|
|
|
223
216
|
group_name = group['name']
|
|
224
217
|
tab_widget = None
|
|
225
218
|
|
|
219
|
+
group_name = self.get_next_available_tab_name(group_name)
|
|
220
|
+
|
|
226
221
|
for tab in group.get('tabs', []):
|
|
227
222
|
# Only add this tab if, there is data on disk to load. The user can
|
|
228
223
|
# open multiple instances of PrEditor using the same prefs. The
|
|
@@ -323,3 +318,31 @@ class GroupTabWidget(OneTabWidget):
|
|
|
323
318
|
tab_widget = self.currentWidget()
|
|
324
319
|
tab_widget.setCurrentIndex(editor)
|
|
325
320
|
return tab_widget.currentWidget()
|
|
321
|
+
|
|
322
|
+
def set_current_groups_from_workbox(self, workbox):
|
|
323
|
+
"""Make the specified workbox the current widget. If the workbox is not
|
|
324
|
+
found, the current widget is not changed.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
workbox (WorkboxMixin): The workbox to make current.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
success (bool): Whether the workbox was found and made the current
|
|
331
|
+
widget
|
|
332
|
+
"""
|
|
333
|
+
workbox_infos = self.all_widgets()
|
|
334
|
+
found_info = None
|
|
335
|
+
for workbox_info in workbox_infos:
|
|
336
|
+
if workbox_info[0] == workbox:
|
|
337
|
+
found_info = workbox_info
|
|
338
|
+
break
|
|
339
|
+
if found_info:
|
|
340
|
+
workbox = workbox_info[0]
|
|
341
|
+
group_idx = workbox_info[-2]
|
|
342
|
+
editor_idx = workbox_info[-1]
|
|
343
|
+
|
|
344
|
+
self.setCurrentIndex(group_idx)
|
|
345
|
+
tab_widget = self.currentWidget()
|
|
346
|
+
tab_widget.setCurrentIndex(editor_idx)
|
|
347
|
+
|
|
348
|
+
return bool(found_info)
|
|
@@ -27,7 +27,12 @@ class GroupedTabWidget(OneTabWidget):
|
|
|
27
27
|
self.uiCornerBTN.released.connect(lambda: self.add_new_editor())
|
|
28
28
|
self.setCornerWidget(self.uiCornerBTN, Qt.Corner.TopRightCorner)
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
self.default_title = "Workbox01"
|
|
31
|
+
|
|
32
|
+
def add_new_editor(self, title=None, prefs=None):
|
|
33
|
+
title = title or self.default_title
|
|
34
|
+
|
|
35
|
+
title = self.get_next_available_tab_name(title)
|
|
31
36
|
editor, title = self.default_tab(title)
|
|
32
37
|
index = self.addTab(editor, title)
|
|
33
38
|
self.setCurrentIndex(index)
|
|
@@ -45,11 +50,18 @@ class GroupedTabWidget(OneTabWidget):
|
|
|
45
50
|
self, 'Tab can not be closed.', msg, QMessageBox.StandardButton.Ok
|
|
46
51
|
)
|
|
47
52
|
return
|
|
53
|
+
|
|
54
|
+
workbox = self.widget(index)
|
|
55
|
+
name = workbox.__workbox_name__()
|
|
56
|
+
msg = (
|
|
57
|
+
f"Would you like to donate the contents of tab\n{name}\nto the "
|
|
58
|
+
"/dev/null fund for wayward code?"
|
|
59
|
+
)
|
|
60
|
+
|
|
48
61
|
ret = QMessageBox.question(
|
|
49
62
|
self,
|
|
50
63
|
'Donate to the cause?',
|
|
51
|
-
|
|
52
|
-
"for wayward code?",
|
|
64
|
+
msg,
|
|
53
65
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.Cancel,
|
|
54
66
|
)
|
|
55
67
|
if ret == QMessageBox.StandardButton.Yes:
|
|
@@ -59,7 +71,8 @@ class GroupedTabWidget(OneTabWidget):
|
|
|
59
71
|
|
|
60
72
|
super(GroupedTabWidget, self).close_tab(index)
|
|
61
73
|
|
|
62
|
-
def default_tab(self, title=
|
|
74
|
+
def default_tab(self, title=None, prefs=None):
|
|
75
|
+
title = title or self.default_title
|
|
63
76
|
kwargs = self.editor_kwargs if self.editor_kwargs else {}
|
|
64
77
|
editor = self.editor_cls(parent=self, core_name=self.core_name, **kwargs)
|
|
65
78
|
return editor, title
|
|
@@ -76,5 +89,14 @@ class GroupedTabWidget(OneTabWidget):
|
|
|
76
89
|
if hasattr(self.window(), "setWorkboxFontBasedOnConsole"):
|
|
77
90
|
self.window().setWorkboxFontBasedOnConsole()
|
|
78
91
|
|
|
92
|
+
def tab_widget(self):
|
|
93
|
+
"""Return the tab widget which contains this group tab
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
self._tab_widget (GroupTabWidget): The tab widget which contains
|
|
97
|
+
this workbox
|
|
98
|
+
"""
|
|
99
|
+
return self.parent().parent()
|
|
100
|
+
|
|
79
101
|
def update_closable_tabs(self):
|
|
80
102
|
self.setTabsClosable(self.count() != 1)
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
from __future__ import absolute_import
|
|
2
2
|
|
|
3
|
+
import re
|
|
4
|
+
|
|
3
5
|
from Qt.QtWidgets import QTabWidget
|
|
4
6
|
|
|
7
|
+
TAB_ITERATION_PATTERN = re.compile(r"(\d+)(?!.*\d)")
|
|
8
|
+
|
|
5
9
|
|
|
6
10
|
class OneTabWidget(QTabWidget):
|
|
7
11
|
"""A QTabWidget that shows the close button only if there is more than one
|
|
@@ -17,6 +21,44 @@ class OneTabWidget(QTabWidget):
|
|
|
17
21
|
super(OneTabWidget, self).__init__(*args, **kwargs)
|
|
18
22
|
self.tabCloseRequested.connect(self.close_tab)
|
|
19
23
|
|
|
24
|
+
def get_next_available_tab_name(self, name):
|
|
25
|
+
"""Get the next available tab name, incrementing an iteration if needed.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
name (str): The desired name
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
name (str): The name, or updated name if needed
|
|
32
|
+
"""
|
|
33
|
+
name = name.replace(" ", "_")
|
|
34
|
+
|
|
35
|
+
existing_names = [self.tabText(i) for i in range(self.count())]
|
|
36
|
+
|
|
37
|
+
# Use regex to find the last set of digits. If found, the base name is
|
|
38
|
+
# a slice of name minus the digits string. Otherwise, the base name is
|
|
39
|
+
# the full name and iteration is zero.
|
|
40
|
+
match = TAB_ITERATION_PATTERN.search(name)
|
|
41
|
+
if match:
|
|
42
|
+
# We found trailing digits, so slice to get base name, and convert
|
|
43
|
+
# iteration to int
|
|
44
|
+
iter_str = match.group()
|
|
45
|
+
base = name[: -len(iter_str)]
|
|
46
|
+
iteration = int(iter_str)
|
|
47
|
+
else:
|
|
48
|
+
# No trailing digits found, so base name is full name and iteration
|
|
49
|
+
# is zero.
|
|
50
|
+
base = name
|
|
51
|
+
iteration = 0
|
|
52
|
+
|
|
53
|
+
if name in existing_names:
|
|
54
|
+
for _ in range(99):
|
|
55
|
+
iteration += 1
|
|
56
|
+
new_iter_str = str(iteration).zfill(2)
|
|
57
|
+
name = base + new_iter_str
|
|
58
|
+
if name not in existing_names:
|
|
59
|
+
break
|
|
60
|
+
return name
|
|
61
|
+
|
|
20
62
|
def addTab(self, *args, **kwargs): # noqa: N802
|
|
21
63
|
ret = super(OneTabWidget, self).addTab(*args, **kwargs)
|
|
22
64
|
self.update_closable_tabs()
|
|
@@ -48,6 +48,7 @@ from .completer import CompleterMode
|
|
|
48
48
|
from .level_buttons import LoggingLevelButton
|
|
49
49
|
from .set_text_editor_path_dialog import SetTextEditorPathDialog
|
|
50
50
|
from .status_label import StatusLabel
|
|
51
|
+
from .workbox_mixin import WorkboxName
|
|
51
52
|
|
|
52
53
|
logger = logging.getLogger(__name__)
|
|
53
54
|
|
|
@@ -59,31 +60,6 @@ class WorkboxPages:
|
|
|
59
60
|
Workboxes = 1
|
|
60
61
|
|
|
61
62
|
|
|
62
|
-
class WorkboxName(str):
|
|
63
|
-
"""The joined name of a workbox `group/workbox` with access to its parts.
|
|
64
|
-
|
|
65
|
-
This subclass provides properties for the group and workbox values separately.
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
def __new__(cls, group, workbox):
|
|
69
|
-
txt = "/".join((group, workbox))
|
|
70
|
-
ret = super().__new__(cls, txt)
|
|
71
|
-
# Preserve the imitable nature of str's by using properties without setters.
|
|
72
|
-
ret._group = group
|
|
73
|
-
ret._workbox = workbox
|
|
74
|
-
return ret
|
|
75
|
-
|
|
76
|
-
@property
|
|
77
|
-
def group(self):
|
|
78
|
-
"""The tab name of the group tab that contains the workbox."""
|
|
79
|
-
return self._group
|
|
80
|
-
|
|
81
|
-
@property
|
|
82
|
-
def workbox(self):
|
|
83
|
-
"""The workbox of the tab for this workbox inside of the group."""
|
|
84
|
-
return self._workbox
|
|
85
|
-
|
|
86
|
-
|
|
87
63
|
class LoggerWindow(Window):
|
|
88
64
|
_instance = None
|
|
89
65
|
styleSheetChanged = Signal(str)
|
|
@@ -93,9 +69,7 @@ class LoggerWindow(Window):
|
|
|
93
69
|
self.name = name if name else get_core_name()
|
|
94
70
|
self._stylesheet = 'Bright'
|
|
95
71
|
|
|
96
|
-
|
|
97
|
-
self.statusTimer = QTimer()
|
|
98
|
-
self.statusTimer.setSingleShot(True)
|
|
72
|
+
self.setupStatusTimer()
|
|
99
73
|
|
|
100
74
|
# Store the previous time a font-resize wheel event was triggered to prevent
|
|
101
75
|
# rapid-fire WheelEvents. Initialize to the current time.
|
|
@@ -292,10 +266,9 @@ class LoggerWindow(Window):
|
|
|
292
266
|
|
|
293
267
|
self.dont_ask_again = []
|
|
294
268
|
|
|
295
|
-
# Load any plugins
|
|
296
|
-
self.
|
|
297
|
-
|
|
298
|
-
self.plugins[name] = plugin(self)
|
|
269
|
+
# Load any plugins, and set window title
|
|
270
|
+
self.loadPlugins()
|
|
271
|
+
self.setWindowTitle(self.defineWindowTitle())
|
|
299
272
|
|
|
300
273
|
self.restorePrefs()
|
|
301
274
|
|
|
@@ -308,17 +281,6 @@ class LoggerWindow(Window):
|
|
|
308
281
|
action.triggered.connect(partial(self.setStyleSheet, style_name))
|
|
309
282
|
|
|
310
283
|
self.uiConsoleTOOLBAR.show()
|
|
311
|
-
loggerName = QApplication.instance().translate(
|
|
312
|
-
'PrEditorWindow', DEFAULT_CORE_NAME
|
|
313
|
-
)
|
|
314
|
-
self.setWindowTitle(
|
|
315
|
-
'{} - {} - {} {}-bit'.format(
|
|
316
|
-
loggerName,
|
|
317
|
-
self.name,
|
|
318
|
-
'{}.{}.{}'.format(*sys.version_info[:3]),
|
|
319
|
-
osystem.getPointerSize(),
|
|
320
|
-
)
|
|
321
|
-
)
|
|
322
284
|
|
|
323
285
|
self.setWorkboxFontBasedOnConsole()
|
|
324
286
|
self.setEditorChooserFontBasedOnConsole()
|
|
@@ -359,6 +321,29 @@ class LoggerWindow(Window):
|
|
|
359
321
|
|
|
360
322
|
self.update_workbox_stack()
|
|
361
323
|
|
|
324
|
+
def loadPlugins(self):
|
|
325
|
+
"""Load any plugins that modify the LoggerWindow."""
|
|
326
|
+
self.plugins = {}
|
|
327
|
+
for name, plugin in plugins.loggerwindow():
|
|
328
|
+
if name not in self.plugins:
|
|
329
|
+
self.plugins[name] = plugin(self)
|
|
330
|
+
|
|
331
|
+
def defineWindowTitle(self):
|
|
332
|
+
"""Define the window title, including and info plugins may add."""
|
|
333
|
+
|
|
334
|
+
# Define the title
|
|
335
|
+
loggerName = QApplication.instance().translate(
|
|
336
|
+
'PrEditorWindow', DEFAULT_CORE_NAME
|
|
337
|
+
)
|
|
338
|
+
pyVersion = '{}.{}.{}'.format(*sys.version_info[:3])
|
|
339
|
+
size = osystem.getPointerSize()
|
|
340
|
+
title = f"{loggerName} - {self.name} - {pyVersion} {size}-bit"
|
|
341
|
+
|
|
342
|
+
# Add any info plugins may add to title
|
|
343
|
+
for _name, plugin in self.plugins.items():
|
|
344
|
+
title = plugin.updateWindowTitle(title)
|
|
345
|
+
return title
|
|
346
|
+
|
|
362
347
|
def comment_toggle(self):
|
|
363
348
|
self.current_workbox().__comment_toggle__()
|
|
364
349
|
|
|
@@ -815,6 +800,7 @@ class LoggerWindow(Window):
|
|
|
815
800
|
'uiStatusLbl_limit': self.uiStatusLBL.limit(),
|
|
816
801
|
'textEditorPath': self.textEditorPath,
|
|
817
802
|
'textEditorCmdTempl': self.textEditorCmdTempl,
|
|
803
|
+
'uiSeparateTracebackACT': self.uiSeparateTracebackACT.isChecked(),
|
|
818
804
|
'currentStyleSheet': self._stylesheet,
|
|
819
805
|
'flash_time': self.uiConsoleTXT.flash_time,
|
|
820
806
|
'find_files_regex': self.uiFindInWorkboxesWGT.uiRegexBTN.isChecked(),
|
|
@@ -967,6 +953,8 @@ class LoggerWindow(Window):
|
|
|
967
953
|
self.textEditorPath = pref.get('textEditorPath', defaultExePath)
|
|
968
954
|
self.textEditorCmdTempl = pref.get('textEditorCmdTempl', defaultCmd)
|
|
969
955
|
|
|
956
|
+
self.uiSeparateTracebackACT.setChecked(pref.get('uiSeparateTracebackACT', True))
|
|
957
|
+
|
|
970
958
|
self.uiWordWrapACT.setChecked(pref.get('wordWrap', True))
|
|
971
959
|
self.setWordWrap(self.uiWordWrapACT.isChecked())
|
|
972
960
|
self.uiClearBeforeRunningACT.setChecked(pref.get('clearBeforeRunning', False))
|
|
@@ -1041,16 +1029,24 @@ class LoggerWindow(Window):
|
|
|
1041
1029
|
self.uiStatusLBL.setText(txt)
|
|
1042
1030
|
self.uiMenuBar.adjustSize()
|
|
1043
1031
|
|
|
1032
|
+
def setupStatusTimer(self):
|
|
1033
|
+
# Create timer to autohide status messages
|
|
1034
|
+
self.statusTimer = QTimer()
|
|
1035
|
+
self.statusTimer.setSingleShot(True)
|
|
1036
|
+
self.statusTimer.setInterval(2000)
|
|
1037
|
+
self.statusTimer.timeout.connect(self.clearStatusText)
|
|
1038
|
+
|
|
1044
1039
|
def clearStatusText(self):
|
|
1045
1040
|
"""Clear any displayed status text"""
|
|
1046
1041
|
self.uiStatusLBL.clear()
|
|
1047
1042
|
self.uiMenuBar.adjustSize()
|
|
1048
1043
|
|
|
1049
1044
|
def autoHideStatusText(self):
|
|
1050
|
-
"""Set timer to automatically clear status text
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1045
|
+
"""Set timer to automatically clear status text.
|
|
1046
|
+
|
|
1047
|
+
If timer is already running, it will be automatically stopped first (We can't
|
|
1048
|
+
use static method QTimer.singleShot for this)
|
|
1049
|
+
"""
|
|
1054
1050
|
self.statusTimer.start()
|
|
1055
1051
|
|
|
1056
1052
|
def setStyleSheet(self, stylesheet, recordPrefs=True):
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
<x>0</x>
|
|
93
93
|
<y>0</y>
|
|
94
94
|
<width>796</width>
|
|
95
|
-
<height>
|
|
95
|
+
<height>22</height>
|
|
96
96
|
</rect>
|
|
97
97
|
</property>
|
|
98
98
|
<widget class="QMenu" name="uiDebugMENU">
|
|
@@ -193,6 +193,8 @@
|
|
|
193
193
|
<addaction name="uiSetFlashWindowIntervalACT"/>
|
|
194
194
|
<addaction name="separator"/>
|
|
195
195
|
<addaction name="uiErrorHyperlinksACT"/>
|
|
196
|
+
<addaction name="uiSeparateTracebackACT"/>
|
|
197
|
+
<addaction name="separator"/>
|
|
196
198
|
<addaction name="uiSetPreferredTextEditorPathACT"/>
|
|
197
199
|
<addaction name="uiSetWorkboxEditorACT"/>
|
|
198
200
|
</widget>
|
|
@@ -1003,6 +1005,14 @@ at the indicated line in the specified text editor.
|
|
|
1003
1005
|
<string>Highlight Exact Completion</string>
|
|
1004
1006
|
</property>
|
|
1005
1007
|
</action>
|
|
1008
|
+
<action name="uiSeparateTracebackACT">
|
|
1009
|
+
<property name="checkable">
|
|
1010
|
+
<bool>true</bool>
|
|
1011
|
+
</property>
|
|
1012
|
+
<property name="text">
|
|
1013
|
+
<string>Visually Separate PrEditor Traceback</string>
|
|
1014
|
+
</property>
|
|
1015
|
+
</action>
|
|
1006
1016
|
</widget>
|
|
1007
1017
|
<customwidgets>
|
|
1008
1018
|
<customwidget>
|
|
@@ -12,6 +12,44 @@ from Qt.QtWidgets import QStackedWidget
|
|
|
12
12
|
from ..prefs import prefs_path
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
class WorkboxName(str):
|
|
16
|
+
"""The joined name of a workbox `group/workbox` with access to its parts.
|
|
17
|
+
|
|
18
|
+
You may pass the group, workbox, or the fully formed workbox name:
|
|
19
|
+
examples:
|
|
20
|
+
workboxName = WorkboxName("Group01", "Workbox05")
|
|
21
|
+
workboxName = WorkboxName("Group01/Workbox05")
|
|
22
|
+
This subclass provides properties for the group and workbox values separately.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __new__(cls, name, sub_name=None):
|
|
26
|
+
if sub_name is not None:
|
|
27
|
+
txt = "/".join((name, sub_name))
|
|
28
|
+
else:
|
|
29
|
+
txt = name
|
|
30
|
+
try:
|
|
31
|
+
name, sub_name = txt.split("/")
|
|
32
|
+
except ValueError:
|
|
33
|
+
msg = "A fully formed name, or a group and name, must be passed in."
|
|
34
|
+
raise ValueError(msg) from None
|
|
35
|
+
|
|
36
|
+
ret = super().__new__(cls, txt)
|
|
37
|
+
# Preserve the imitable nature of str's by using properties without setters.
|
|
38
|
+
ret._group = name
|
|
39
|
+
ret._workbox = sub_name
|
|
40
|
+
return ret
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def group(self):
|
|
44
|
+
"""The tab name of the group tab that contains the workbox."""
|
|
45
|
+
return self._group
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def workbox(self):
|
|
49
|
+
"""The workbox of the tab for this workbox inside of the group."""
|
|
50
|
+
return self._workbox
|
|
51
|
+
|
|
52
|
+
|
|
15
53
|
class WorkboxMixin(object):
|
|
16
54
|
_warning_text = None
|
|
17
55
|
"""When a user is picking this Workbox class, show a warning with this text."""
|
|
@@ -26,6 +64,16 @@ class WorkboxMixin(object):
|
|
|
26
64
|
self._tempfile = tempfile
|
|
27
65
|
self.core_name = core_name
|
|
28
66
|
|
|
67
|
+
self._tab_widget = parent
|
|
68
|
+
|
|
69
|
+
def __tab_widget__(self):
|
|
70
|
+
"""Return the tab widget which contains this workbox
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
GroupedTabWidget: The tab widget which contains this workbox
|
|
74
|
+
"""
|
|
75
|
+
return self._tab_widget
|
|
76
|
+
|
|
29
77
|
def __auto_complete_enabled__(self):
|
|
30
78
|
raise NotImplementedError("Mixin method not overridden.")
|
|
31
79
|
|
|
@@ -84,8 +132,8 @@ class WorkboxMixin(object):
|
|
|
84
132
|
txt = '\n' * line + txt
|
|
85
133
|
|
|
86
134
|
# execute the code
|
|
87
|
-
|
|
88
|
-
ret, was_eval = self.__console__().executeString(txt, filename=
|
|
135
|
+
title = self.__workbox_trace_title__(selection=True)
|
|
136
|
+
ret, was_eval = self.__console__().executeString(txt, filename=title)
|
|
89
137
|
if was_eval:
|
|
90
138
|
# If the selected code was a statement print the result of the statement.
|
|
91
139
|
ret = repr(ret)
|
|
@@ -145,13 +193,63 @@ class WorkboxMixin(object):
|
|
|
145
193
|
|
|
146
194
|
return group, editor
|
|
147
195
|
|
|
148
|
-
def
|
|
196
|
+
def __workbox_trace_title__(self, selection=False):
|
|
149
197
|
title = "WorkboxSelection" if selection else "Workbox"
|
|
150
198
|
group, editor = self.__group_tab_index__()
|
|
151
199
|
if group == -1 or editor == -1:
|
|
152
200
|
return '<{}>'.format(title)
|
|
153
201
|
else:
|
|
154
|
-
|
|
202
|
+
name = self.__workbox_name__()
|
|
203
|
+
return '<{}>:{}'.format(title, name)
|
|
204
|
+
|
|
205
|
+
def __workbox_name__(self, workbox=None):
|
|
206
|
+
"""Returns the name for this workbox or a given workbox.
|
|
207
|
+
The name is the group tab text and the workbox tab text joined by a `/`"""
|
|
208
|
+
workboxTAB = self.window().uiWorkboxTAB
|
|
209
|
+
group_name = None
|
|
210
|
+
workbox_name = None
|
|
211
|
+
|
|
212
|
+
if workbox:
|
|
213
|
+
grouped_tab_widget = workbox.__tab_widget__()
|
|
214
|
+
for group_idx in range(workboxTAB.count()):
|
|
215
|
+
# If a previous iteration determine workbox_name, bust out
|
|
216
|
+
if workbox_name:
|
|
217
|
+
break
|
|
218
|
+
# Check if current group is the workboxes parent group
|
|
219
|
+
cur_group_widget = workboxTAB.widget(group_idx)
|
|
220
|
+
if cur_group_widget == grouped_tab_widget:
|
|
221
|
+
group_name = workboxTAB.tabText(group_idx)
|
|
222
|
+
|
|
223
|
+
# Found the group, now find workbox
|
|
224
|
+
for workbox_idx in range(cur_group_widget.count()):
|
|
225
|
+
cur_workbox_widget = cur_group_widget.widget(workbox_idx)
|
|
226
|
+
if cur_workbox_widget == workbox:
|
|
227
|
+
workbox_name = cur_group_widget.tabText(workbox_idx)
|
|
228
|
+
break
|
|
229
|
+
else:
|
|
230
|
+
grouped = self.__tab_widget__()
|
|
231
|
+
groupedTabBar = grouped.tabBar()
|
|
232
|
+
|
|
233
|
+
idx = -1
|
|
234
|
+
for idx in range(grouped.count()):
|
|
235
|
+
if grouped.widget(idx) == self:
|
|
236
|
+
break
|
|
237
|
+
workbox_name = groupedTabBar.tabText(idx)
|
|
238
|
+
|
|
239
|
+
group = grouped.tab_widget()
|
|
240
|
+
groupTabBar = group.tabBar()
|
|
241
|
+
idx = -1
|
|
242
|
+
for idx in range(group.count()):
|
|
243
|
+
if group.widget(idx) == grouped:
|
|
244
|
+
break
|
|
245
|
+
group_name = groupTabBar.tabText(idx)
|
|
246
|
+
|
|
247
|
+
# If both found, construct workbox name
|
|
248
|
+
if group_name and workbox_name:
|
|
249
|
+
name = WorkboxName(group_name, workbox_name)
|
|
250
|
+
else:
|
|
251
|
+
name = WorkboxName("", "")
|
|
252
|
+
return name
|
|
155
253
|
|
|
156
254
|
def __goto_line__(self, line):
|
|
157
255
|
raise NotImplementedError("Mixin method not overridden.")
|
|
@@ -57,8 +57,8 @@ class WorkboxTextEdit(WorkboxMixin, QTextEdit):
|
|
|
57
57
|
|
|
58
58
|
def __exec_all__(self):
|
|
59
59
|
txt = self.__text__().rstrip()
|
|
60
|
-
|
|
61
|
-
self.__console__().executeString(txt, filename=
|
|
60
|
+
title = self.__workbox_trace_title__()
|
|
61
|
+
self.__console__().executeString(txt, filename=title)
|
|
62
62
|
|
|
63
63
|
def __font__(self):
|
|
64
64
|
return self.font()
|