PrEditor 0.0.0.dev1__py2.py3-none-any.whl → 0.1.0__py2.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.

Potentially problematic release.


This version of PrEditor might be problematic. Click here for more details.

Files changed (363) hide show
  1. PrEditor-0.1.0.dist-info/LICENSE +165 -0
  2. PrEditor-0.1.0.dist-info/METADATA +212 -0
  3. PrEditor-0.1.0.dist-info/RECORD +149 -0
  4. {PrEditor-0.0.0.dev1.dist-info → PrEditor-0.1.0.dist-info}/WHEEL +1 -1
  5. PrEditor-0.1.0.dist-info/entry_points.txt +18 -0
  6. PrEditor-0.1.0.dist-info/top_level.txt +1 -0
  7. preditor/__init__.py +301 -0
  8. {blurdev → preditor}/__main__.py +13 -13
  9. preditor/about_module.py +166 -0
  10. preditor/cli.py +192 -0
  11. {blurdev → preditor}/contexts.py +119 -119
  12. preditor/cores/core.py +65 -0
  13. preditor/dccs/maya/PrEditor_maya.mod +2 -0
  14. preditor/dccs/maya/plug-ins/PrEditor_maya.py +108 -0
  15. preditor/debug.py +294 -0
  16. blurdev/scintilla/delayable_engine.py → preditor/delayable_engine/__init__.py +310 -299
  17. blurdev/scintilla/delayables/base.py → preditor/delayable_engine/delayables.py +85 -85
  18. {blurdev → preditor}/enum.py +728 -1003
  19. {blurdev → preditor}/gui/__init__.py +84 -125
  20. preditor/gui/app.py +159 -0
  21. {blurdev → preditor}/gui/codehighlighter.py +209 -219
  22. {blurdev → preditor}/gui/completer.py +226 -236
  23. {blurdev → preditor}/gui/console.py +801 -858
  24. {blurdev → preditor}/gui/dialog.py +200 -216
  25. preditor/gui/drag_tab_bar.py +190 -0
  26. preditor/gui/editor_chooser.py +57 -0
  27. {blurdev → preditor}/gui/errordialog.py +100 -97
  28. preditor/gui/fuzzy_search/fuzzy_search.py +93 -0
  29. preditor/gui/group_tab_widget/__init__.py +319 -0
  30. preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
  31. preditor/gui/group_tab_widget/grouped_tab_models.py +108 -0
  32. preditor/gui/group_tab_widget/grouped_tab_widget.py +75 -0
  33. preditor/gui/group_tab_widget/one_tab_widget.py +54 -0
  34. preditor/gui/level_buttons.py +349 -0
  35. {blurdev → preditor}/gui/logger_window_handler.py +46 -45
  36. {blurdev → preditor}/gui/loggerwindow.py +1205 -1417
  37. {blurdev → preditor}/gui/newtabwidget.py +69 -68
  38. {blurdev → preditor}/gui/redmine_login_dialog.py +63 -61
  39. {blurdev → preditor}/gui/set_text_editor_path_dialog.py +59 -57
  40. preditor/gui/ui/editor_chooser.ui +93 -0
  41. {blurdev → preditor}/gui/ui/errordialog.ui +81 -81
  42. {blurdev → preditor}/gui/ui/loggerwindow.ui +1030 -864
  43. {blurdev → preditor}/gui/ui/redmine_login_dialog.ui +124 -124
  44. {blurdev → preditor}/gui/ui/set_text_editor_path_dialog.ui +149 -149
  45. {blurdev → preditor}/gui/window.py +183 -199
  46. preditor/gui/workbox_mixin.py +357 -0
  47. preditor/gui/workbox_text_edit.py +117 -0
  48. preditor/gui/workboxwidget.py +276 -0
  49. preditor/logging_config.py +52 -0
  50. preditor/osystem.py +401 -0
  51. preditor/plugins.py +65 -0
  52. preditor/prefs.py +74 -0
  53. {blurdev → preditor}/resource/environment_variables.html +26 -38
  54. {blurdev → preditor}/resource/error_mail.html +85 -85
  55. {blurdev → preditor}/resource/error_mail_inline.html +41 -41
  56. preditor/resource/img/README.md +7 -0
  57. preditor/resource/img/arrow_forward.png +0 -0
  58. preditor/resource/img/check-bold.png +0 -0
  59. preditor/resource/img/chevron-down.png +0 -0
  60. preditor/resource/img/chevron-up.png +0 -0
  61. preditor/resource/img/close-thick.png +0 -0
  62. preditor/resource/img/comment-edit.png +0 -0
  63. preditor/resource/img/content-copy.png +0 -0
  64. preditor/resource/img/content-cut.png +0 -0
  65. preditor/resource/img/content-duplicate.png +0 -0
  66. preditor/resource/img/content-paste.png +0 -0
  67. preditor/resource/img/content-save.png +0 -0
  68. preditor/resource/img/debug_disabled.png +0 -0
  69. preditor/resource/img/eye-check.png +0 -0
  70. preditor/resource/img/file-plus.png +0 -0
  71. preditor/resource/img/file-remove.png +0 -0
  72. preditor/resource/img/format-align-left.png +0 -0
  73. preditor/resource/img/format-letter-case-lower.png +0 -0
  74. preditor/resource/img/format-letter-case-upper.png +0 -0
  75. preditor/resource/img/information.png +0 -0
  76. preditor/resource/img/logging_critical.png +0 -0
  77. preditor/resource/img/logging_custom.png +0 -0
  78. preditor/resource/img/logging_debug.png +0 -0
  79. preditor/resource/img/logging_error.png +0 -0
  80. preditor/resource/img/logging_info.png +0 -0
  81. preditor/resource/img/logging_not_set.png +0 -0
  82. preditor/resource/img/logging_warning.png +0 -0
  83. preditor/resource/img/marker.png +0 -0
  84. preditor/resource/img/play.png +0 -0
  85. preditor/resource/img/playlist-play.png +0 -0
  86. preditor/resource/img/plus-minus-variant.png +0 -0
  87. preditor/resource/img/preditor.ico +0 -0
  88. preditor/resource/img/preditor.png +0 -0
  89. preditor/resource/img/preditor.psd +0 -0
  90. preditor/resource/img/preditor.svg +44 -0
  91. preditor/resource/img/restart.svg +1 -0
  92. preditor/resource/img/skip-forward-outline.png +0 -0
  93. preditor/resource/img/skip-next-outline.png +0 -0
  94. preditor/resource/img/skip-next.png +0 -0
  95. preditor/resource/img/skip-previous.png +0 -0
  96. preditor/resource/img/subdirectory-arrow-right.png +0 -0
  97. preditor/resource/img/text-search-variant.png +0 -0
  98. {blurdev → preditor}/resource/lang/python.json +30 -30
  99. preditor/resource/settings.ini +25 -0
  100. {blurdev/resource/stylesheet/logger → preditor/resource/stylesheet}/Bright.css +56 -61
  101. {blurdev → preditor}/resource/stylesheet/Dark.css +190 -132
  102. {blurdev → preditor}/scintilla/__init__.py +22 -28
  103. preditor/scintilla/delayables/__init__.py +11 -0
  104. {blurdev → preditor}/scintilla/delayables/smart_highlight.py +94 -93
  105. {blurdev → preditor}/scintilla/delayables/spell_check.py +173 -172
  106. {blurdev → preditor}/scintilla/documenteditor.py +2039 -2115
  107. {blurdev → preditor}/scintilla/finddialog.py +68 -81
  108. {blurdev → preditor}/scintilla/lang/__init__.py +80 -93
  109. {blurdev → preditor}/scintilla/lang/config/bash.ini +15 -15
  110. {blurdev → preditor}/scintilla/lang/config/batch.ini +14 -14
  111. {blurdev → preditor}/scintilla/lang/config/cpp.ini +19 -19
  112. {blurdev → preditor}/scintilla/lang/config/css.ini +19 -19
  113. {blurdev → preditor}/scintilla/lang/config/eyeonscript.ini +17 -17
  114. {blurdev → preditor}/scintilla/lang/config/html.ini +21 -21
  115. {blurdev → preditor}/scintilla/lang/config/javascript.ini +24 -24
  116. {blurdev → preditor}/scintilla/lang/config/lua.ini +16 -16
  117. {blurdev → preditor}/scintilla/lang/config/maxscript.ini +20 -20
  118. {blurdev → preditor}/scintilla/lang/config/mel.ini +18 -18
  119. {blurdev → preditor}/scintilla/lang/config/mu.ini +22 -22
  120. {blurdev → preditor}/scintilla/lang/config/nsi.ini +5 -5
  121. {blurdev → preditor}/scintilla/lang/config/perl.ini +19 -19
  122. {blurdev → preditor}/scintilla/lang/config/puppet.ini +19 -19
  123. {blurdev → preditor}/scintilla/lang/config/python.ini +28 -28
  124. {blurdev → preditor}/scintilla/lang/config/ruby.ini +19 -19
  125. {blurdev → preditor}/scintilla/lang/config/sql.ini +7 -7
  126. {blurdev → preditor}/scintilla/lang/config/xml.ini +21 -21
  127. {blurdev → preditor}/scintilla/lang/config/yaml.ini +18 -18
  128. {blurdev → preditor}/scintilla/lang/language.py +240 -250
  129. preditor/scintilla/lexers/__init__.py +0 -0
  130. {blurdev → preditor}/scintilla/lexers/cpplexer.py +21 -30
  131. {blurdev → preditor}/scintilla/lexers/javascriptlexer.py +25 -34
  132. {blurdev → preditor}/scintilla/lexers/maxscriptlexer.py +234 -253
  133. {blurdev → preditor}/scintilla/lexers/mellexer.py +368 -376
  134. {blurdev → preditor}/scintilla/lexers/mulexer.py +32 -41
  135. {blurdev → preditor}/scintilla/lexers/pythonlexer.py +41 -50
  136. {blurdev → preditor}/scintilla/ui/finddialog.ui +160 -160
  137. preditor/settings.py +71 -0
  138. preditor/stream/__init__.py +80 -0
  139. preditor/stream/director.py +56 -0
  140. preditor/stream/manager.py +74 -0
  141. preditor/streamhandler_helper.py +46 -0
  142. preditor/utils/__init__.py +0 -0
  143. preditor/utils/cute.py +30 -0
  144. preditor/utils/stylesheets.py +54 -0
  145. {blurdev → preditor}/version.py +5 -5
  146. preditor/weakref.py +363 -0
  147. PrEditor-0.0.0.dev1.dist-info/METADATA +0 -51
  148. PrEditor-0.0.0.dev1.dist-info/RECORD +0 -279
  149. PrEditor-0.0.0.dev1.dist-info/top_level.txt +0 -1
  150. blurdev/__init__.py +0 -356
  151. blurdev/cores/__init__.py +0 -98
  152. blurdev/cores/application.py +0 -26
  153. blurdev/cores/core.py +0 -634
  154. blurdev/debug.py +0 -593
  155. blurdev/external.py +0 -391
  156. blurdev/gui/level_buttons.py +0 -585
  157. blurdev/gui/workboxwidget.py +0 -205
  158. blurdev/logger.py +0 -238
  159. blurdev/osystem.py +0 -813
  160. blurdev/prefs.py +0 -33
  161. blurdev/protocols/__init__.py +0 -71
  162. blurdev/protocols/write_std_output_handler.py +0 -83
  163. blurdev/resource/designer_plugins.xml +0 -9
  164. blurdev/resource/error_email_old.html +0 -41
  165. blurdev/resource/img/add.png +0 -0
  166. blurdev/resource/img/ajax-loader.gif +0 -0
  167. blurdev/resource/img/application.png +0 -0
  168. blurdev/resource/img/applications.png +0 -0
  169. blurdev/resource/img/assburner.png +0 -0
  170. blurdev/resource/img/assfreezer.png +0 -0
  171. blurdev/resource/img/bar.gif +0 -0
  172. blurdev/resource/img/blank.png +0 -0
  173. blurdev/resource/img/blurdev.png +0 -0
  174. blurdev/resource/img/calendar_disabled.png +0 -0
  175. blurdev/resource/img/calendar_enabled.png +0 -0
  176. blurdev/resource/img/cancel.png +0 -0
  177. blurdev/resource/img/custom.png +0 -0
  178. blurdev/resource/img/debug_high.png +0 -0
  179. blurdev/resource/img/debug_low.png +0 -0
  180. blurdev/resource/img/debug_mid.png +0 -0
  181. blurdev/resource/img/debug_off.png +0 -0
  182. blurdev/resource/img/django.png +0 -0
  183. blurdev/resource/img/doc.png +0 -0
  184. blurdev/resource/img/edit.png +0 -0
  185. blurdev/resource/img/elemental.png +0 -0
  186. blurdev/resource/img/explore.png +0 -0
  187. blurdev/resource/img/favorite.png +0 -0
  188. blurdev/resource/img/file.png +0 -0
  189. blurdev/resource/img/folder.png +0 -0
  190. blurdev/resource/img/ide/add.png +0 -0
  191. blurdev/resource/img/ide/add_note.png +0 -0
  192. blurdev/resource/img/ide/arrow_down.png +0 -0
  193. blurdev/resource/img/ide/arrow_up.png +0 -0
  194. blurdev/resource/img/ide/check.png +0 -0
  195. blurdev/resource/img/ide/class.png +0 -0
  196. blurdev/resource/img/ide/clean.png +0 -0
  197. blurdev/resource/img/ide/clearlog.png +0 -0
  198. blurdev/resource/img/ide/close.png +0 -0
  199. blurdev/resource/img/ide/comment_add.png +0 -0
  200. blurdev/resource/img/ide/comment_remove.png +0 -0
  201. blurdev/resource/img/ide/comment_toggle.png +0 -0
  202. blurdev/resource/img/ide/console.png +0 -0
  203. blurdev/resource/img/ide/copy.png +0 -0
  204. blurdev/resource/img/ide/copylstrip.png +0 -0
  205. blurdev/resource/img/ide/cut.png +0 -0
  206. blurdev/resource/img/ide/edit.png +0 -0
  207. blurdev/resource/img/ide/find.png +0 -0
  208. blurdev/resource/img/ide/find_replace.png +0 -0
  209. blurdev/resource/img/ide/findnext.png +0 -0
  210. blurdev/resource/img/ide/findprev.png +0 -0
  211. blurdev/resource/img/ide/folder_find.png +0 -0
  212. blurdev/resource/img/ide/function.png +0 -0
  213. blurdev/resource/img/ide/git-bash.png +0 -0
  214. blurdev/resource/img/ide/git-gui.png +0 -0
  215. blurdev/resource/img/ide/gitk.png +0 -0
  216. blurdev/resource/img/ide/goto.png +0 -0
  217. blurdev/resource/img/ide/goto_def.png +0 -0
  218. blurdev/resource/img/ide/help.png +0 -0
  219. blurdev/resource/img/ide/highlighter.png +0 -0
  220. blurdev/resource/img/ide/lowercase.png +0 -0
  221. blurdev/resource/img/ide/newfile.png +0 -0
  222. blurdev/resource/img/ide/newfolder.png +0 -0
  223. blurdev/resource/img/ide/newproject.png +0 -0
  224. blurdev/resource/img/ide/newwizard.png +0 -0
  225. blurdev/resource/img/ide/open.png +0 -0
  226. blurdev/resource/img/ide/paste.png +0 -0
  227. blurdev/resource/img/ide/pdb_continue.png +0 -0
  228. blurdev/resource/img/ide/pdb_down.png +0 -0
  229. blurdev/resource/img/ide/pdb_next.png +0 -0
  230. blurdev/resource/img/ide/pdb_step.png +0 -0
  231. blurdev/resource/img/ide/pdb_up.png +0 -0
  232. blurdev/resource/img/ide/plus_minus.png +0 -0
  233. blurdev/resource/img/ide/preferences.png +0 -0
  234. blurdev/resource/img/ide/project_find.png +0 -0
  235. blurdev/resource/img/ide/python.png +0 -0
  236. blurdev/resource/img/ide/pyular.png +0 -0
  237. blurdev/resource/img/ide/qt.png +0 -0
  238. blurdev/resource/img/ide/quit.png +0 -0
  239. blurdev/resource/img/ide/redo.png +0 -0
  240. blurdev/resource/img/ide/refresh.png +0 -0
  241. blurdev/resource/img/ide/remove.png +0 -0
  242. blurdev/resource/img/ide/ruler.png +0 -0
  243. blurdev/resource/img/ide/run.png +0 -0
  244. blurdev/resource/img/ide/runall.png +0 -0
  245. blurdev/resource/img/ide/runallclear.png +0 -0
  246. blurdev/resource/img/ide/runselected.png +0 -0
  247. blurdev/resource/img/ide/runselectedclear.png +0 -0
  248. blurdev/resource/img/ide/save.png +0 -0
  249. blurdev/resource/img/ide/saveas.png +0 -0
  250. blurdev/resource/img/ide/sdk.png +0 -0
  251. blurdev/resource/img/ide/separator.png +0 -0
  252. blurdev/resource/img/ide/tabbed.png +0 -0
  253. blurdev/resource/img/ide/tile.png +0 -0
  254. blurdev/resource/img/ide/toolbar.png +0 -0
  255. blurdev/resource/img/ide/undo.png +0 -0
  256. blurdev/resource/img/ide/uppercase.png +0 -0
  257. blurdev/resource/img/ide/view_as.png +0 -0
  258. blurdev/resource/img/ide/windowed.png +0 -0
  259. blurdev/resource/img/ide.ico +0 -0
  260. blurdev/resource/img/ide.png +0 -0
  261. blurdev/resource/img/ide48.png +0 -0
  262. blurdev/resource/img/info.png +0 -0
  263. blurdev/resource/img/legacy tool.png +0 -0
  264. blurdev/resource/img/library.png +0 -0
  265. blurdev/resource/img/logger/about.png +0 -0
  266. blurdev/resource/img/logger/arrow_forward.png +0 -0
  267. blurdev/resource/img/logger/clear.png +0 -0
  268. blurdev/resource/img/logger/close.png +0 -0
  269. blurdev/resource/img/logger/debug_disabled.png +0 -0
  270. blurdev/resource/img/logger/debug_high.png +0 -0
  271. blurdev/resource/img/logger/debug_low.png +0 -0
  272. blurdev/resource/img/logger/debug_mid.png +0 -0
  273. blurdev/resource/img/logger/down.png +0 -0
  274. blurdev/resource/img/logger/find.png +0 -0
  275. blurdev/resource/img/logger/logging_critical.png +0 -0
  276. blurdev/resource/img/logger/logging_debug.png +0 -0
  277. blurdev/resource/img/logger/logging_error.png +0 -0
  278. blurdev/resource/img/logger/logging_info.png +0 -0
  279. blurdev/resource/img/logger/logging_not_set.png +0 -0
  280. blurdev/resource/img/logger/logging_warning.png +0 -0
  281. blurdev/resource/img/logger/next.png +0 -0
  282. blurdev/resource/img/logger/play.png +0 -0
  283. blurdev/resource/img/logger/playlist_play.png +0 -0
  284. blurdev/resource/img/logger/previous.png +0 -0
  285. blurdev/resource/img/logger/return.png +0 -0
  286. blurdev/resource/img/logger/save.png +0 -0
  287. blurdev/resource/img/logger/subdirectory_arrow_right.png +0 -0
  288. blurdev/resource/img/logger/up.png +0 -0
  289. blurdev/resource/img/lovebar.png +0 -0
  290. blurdev/resource/img/new.png +0 -0
  291. blurdev/resource/img/new_selected.png +0 -0
  292. blurdev/resource/img/node.png +0 -0
  293. blurdev/resource/img/ok.png +0 -0
  294. blurdev/resource/img/options.png +0 -0
  295. blurdev/resource/img/packages.png +0 -0
  296. blurdev/resource/img/preview/add.png +0 -0
  297. blurdev/resource/img/preview/brush.png +0 -0
  298. blurdev/resource/img/preview/delete.png +0 -0
  299. blurdev/resource/img/preview/delte.png +0 -0
  300. blurdev/resource/img/preview/fill.png +0 -0
  301. blurdev/resource/img/preview/layers.png +0 -0
  302. blurdev/resource/img/preview/media.png +0 -0
  303. blurdev/resource/img/preview/navigate.png +0 -0
  304. blurdev/resource/img/preview/pencil.png +0 -0
  305. blurdev/resource/img/preview/select.png +0 -0
  306. blurdev/resource/img/preview/type.png +0 -0
  307. blurdev/resource/img/preview/visible.png +0 -0
  308. blurdev/resource/img/project.png +0 -0
  309. blurdev/resource/img/python_logger.ico +0 -0
  310. blurdev/resource/img/python_logger.png +0 -0
  311. blurdev/resource/img/refresh.png +0 -0
  312. blurdev/resource/img/remove.png +0 -0
  313. blurdev/resource/img/reset.png +0 -0
  314. blurdev/resource/img/richtext/font_bold.png +0 -0
  315. blurdev/resource/img/richtext/font_italic.png +0 -0
  316. blurdev/resource/img/richtext/link_image.png +0 -0
  317. blurdev/resource/img/richtext/spell_check.png +0 -0
  318. blurdev/resource/img/richtext/unordered_list.png +0 -0
  319. blurdev/resource/img/save.png +0 -0
  320. blurdev/resource/img/savesettings.png +0 -0
  321. blurdev/resource/img/settings.png +0 -0
  322. blurdev/resource/img/tool.png +0 -0
  323. blurdev/resource/img/toolbarHandleHorizontal.png +0 -0
  324. blurdev/resource/img/toolbarHandleVertical.png +0 -0
  325. blurdev/resource/img/trash.png +0 -0
  326. blurdev/resource/img/trax.png +0 -0
  327. blurdev/resource/img/tree.png +0 -0
  328. blurdev/resource/img/treegrunt.ico +0 -0
  329. blurdev/resource/img/treegrunt.png +0 -0
  330. blurdev/resource/img/treegruntedit.png +0 -0
  331. blurdev/resource/img/user interface.png +0 -0
  332. blurdev/resource/img/warning.png +0 -0
  333. blurdev/resource/img/watermark.png +0 -0
  334. blurdev/resource/sdk/blurdev.sdk +0 -3
  335. blurdev/resource/settings.ini +0 -82
  336. blurdev/resource/softimage/BlurApplication.dll +0 -0
  337. blurdev/resource/softimage/BlurApplication64.dll +0 -0
  338. blurdev/resource/stylesheet/Carbon.css +0 -35
  339. blurdev/resource/stylesheet/logger/Dark.css +0 -62
  340. blurdev/resource/templ/py_comment.templ +0 -1
  341. blurdev/resource/templ/py_debug_raise_error.templ +0 -7
  342. blurdev/resource/templ/py_doc_string.templ +0 -10
  343. blurdev/resource/templ/py_header.templ +0 -9
  344. blurdev/resource/templ/py_line_comment.templ +0 -1
  345. blurdev/resource/templ/py_log_to_file.templ +0 -22
  346. blurdev/resource/templ/py_module_path.templ +0 -1
  347. blurdev/resource/templ/py_pyqt_core.templ +0 -1
  348. blurdev/resource/templ/py_pyqt_gui.templ +0 -1
  349. blurdev/resource/templ/py_splashscreen.templ +0 -6
  350. blurdev/resource/templ/py_testing_note.templ +0 -1
  351. blurdev/resource/templ/py_testing_note_end.templ +0 -1
  352. blurdev/resource/tools_environments.json +0 -72
  353. blurdev/resource/tools_environments.xml +0 -11
  354. blurdev/resource/tools_environments_linux.xml +0 -11
  355. blurdev/resource/tools_environments_offline.xml +0 -7
  356. blurdev/runtimes/__init__.py +0 -2
  357. blurdev/runtimes/logger.py +0 -44
  358. blurdev/scintilla/delayables/__init__.py +0 -9
  359. blurdev/settings.py +0 -312
  360. blurdev/utils/error.py +0 -389
  361. {blurdev/scintilla/lexers → preditor/cores}/__init__.py +0 -0
  362. {blurdev/utils → preditor/gui/fuzzy_search}/__init__.py +0 -0
  363. {blurdev → preditor}/resource/img/warning-big.png +0 -0
@@ -0,0 +1,57 @@
1
+ from __future__ import absolute_import
2
+
3
+ from Qt.QtCore import Slot
4
+ from Qt.QtGui import QIcon
5
+ from Qt.QtWidgets import QWidget
6
+
7
+ from .. import plugins, resourcePath
8
+ from ..gui import loadUi
9
+
10
+
11
+ class EditorChooser(QWidget):
12
+ """A widget that lets the user choose from a a list of available editors."""
13
+
14
+ def __init__(self, parent=None, editor_name=None):
15
+ super(EditorChooser, self).__init__(parent=parent)
16
+ loadUi(__file__, self)
17
+ icon = QIcon(resourcePath('img/warning-big.png'))
18
+ self.uiWarningIconLBL.setPixmap(icon.pixmap(icon.availableSizes()[0]))
19
+ if editor_name:
20
+ self.set_editor_name(editor_name)
21
+
22
+ def editor_name(self):
23
+ return self.uiWorkboxEditorDDL.currentText()
24
+
25
+ def set_editor_name(self, name):
26
+ index = self.uiWorkboxEditorDDL.findText(name)
27
+ if index == -1:
28
+ self.uiWorkboxEditorDDL.addItem(name)
29
+ index = self.uiWorkboxEditorDDL.findText(name)
30
+ self.uiWorkboxEditorDDL.setCurrentIndex(index)
31
+
32
+ @Slot()
33
+ def refresh(self):
34
+ warning = "Choose an editor to enable Workboxs."
35
+ editor_name = self.editor_name()
36
+ if editor_name:
37
+ _, editor = plugins.editor(editor_name)
38
+ warning = editor._warning_text
39
+ self.uiWarningIconLBL.setVisible(bool(warning))
40
+ self.uiWarningTextLBL.setVisible(bool(warning))
41
+ self.uiWarningTextLBL.setText(warning)
42
+
43
+ def refresh_editors(self):
44
+ current = self.editor_name()
45
+ self.uiWorkboxEditorDDL.blockSignals(True)
46
+ self.uiWorkboxEditorDDL.clear()
47
+ for name, _ in sorted(plugins.editors()):
48
+ self.uiWorkboxEditorDDL.addItem(name)
49
+
50
+ self.uiWorkboxEditorDDL.setCurrentIndex(
51
+ self.uiWorkboxEditorDDL.findText(current)
52
+ )
53
+ self.uiWorkboxEditorDDL.blockSignals(False)
54
+
55
+ def showEvent(self, event): # noqa: N802
56
+ super(EditorChooser, self).showEvent(event)
57
+ self.refresh_editors()
@@ -1,97 +1,100 @@
1
- from __future__ import absolute_import
2
- import os
3
- import blurdev
4
- import traceback
5
- import getpass
6
-
7
- from blurdev.gui import Dialog
8
- from Qt.QtCore import Qt
9
- from Qt.QtGui import QPixmap
10
- from Qt.QtWidgets import QDialog
11
- from redminelib.exceptions import ImpersonateError
12
- from blurdev.gui.redmine_login_dialog import RedmineLoginDialog
13
-
14
-
15
- class ErrorDialog(Dialog):
16
-
17
- def __init__(self, parent):
18
- super(ErrorDialog, self).__init__(parent)
19
-
20
- blurdev.gui.loadUi(__file__, self)
21
-
22
- self.parent_ = parent
23
- self.requestPimpPID = None
24
- self.setWindowTitle('Error Occurred')
25
- self.errorLabel.setTextFormat(Qt.RichText)
26
- self.iconLabel.setPixmap(
27
- QPixmap(
28
- os.path.join(
29
- os.path.dirname(blurdev.__file__),
30
- 'resource',
31
- 'img',
32
- 'warning-big.png',
33
- )
34
- ).scaledToHeight(64, Qt.SmoothTransformation)
35
- )
36
-
37
- self.loggerButton.clicked.connect(self.showLogger)
38
- self.requestButton.clicked.connect(self.submitRequest)
39
- self.ignoreButton.clicked.connect(self.close)
40
-
41
- def setText(self, exc_info):
42
- from .console import ConsoleEdit
43
-
44
- self.traceback_msg = "".join(traceback.format_exception(*exc_info))
45
- msg = (
46
- 'The following error has occurred:<br>'
47
- '<br><font color=%(color)s>%(text)s</font>'
48
- )
49
- self.errorLabel.setText(
50
- msg
51
- % {
52
- 'text': self.traceback_msg.split('\n')[-2],
53
- 'color': ConsoleEdit._errorMessageColor.name(),
54
- }
55
- )
56
-
57
- def showLogger(self):
58
- inst = blurdev.gui.loggerwindow.LoggerWindow.instance()
59
- inst.show()
60
- self.close()
61
-
62
- def submitRequest(self):
63
- from blurdev.utils.errorEmail import buildErrorMessage
64
-
65
- subject, description = buildErrorMessage(self.traceback_msg, fmt='markdown')
66
- subject = self.traceback_msg.split('\n')[-2]
67
- from blurdev.actions.create_redmine_issue import CreateRedmineIssue
68
-
69
- kwargs = {
70
- 'subject': subject,
71
- 'description': description,
72
- 'screenshot': True,
73
- 'username': getpass.getuser(),
74
- }
75
-
76
- # Tryin a first connection impersonating the current user.
77
- try:
78
- CreateRedmineIssue(**kwargs)()
79
-
80
- # If that failed, we will use a dialog to prompt for credentials.
81
- except ImpersonateError:
82
- dialog = RedmineLoginDialog(parent=self)
83
- result = dialog.exec_()
84
- if result == QDialog.Accepted:
85
- kwargs.update(
86
- {
87
- 'username': dialog.username(),
88
- 'password': dialog.password(),
89
- 'redmine': dialog.redmine(),
90
- }
91
- )
92
-
93
- # The dialog can only return a successful connection.
94
- CreateRedmineIssue(**kwargs)()
95
- elif result == QDialog.Rejected:
96
- return
97
- self.close()
1
+ from __future__ import absolute_import
2
+
3
+ import getpass
4
+ import os
5
+ import traceback
6
+
7
+ from Qt.QtCore import Qt
8
+ from Qt.QtGui import QPixmap
9
+ from Qt.QtWidgets import QDialog
10
+ from redminelib.exceptions import ImpersonateError
11
+
12
+ from .. import __file__ as pfile
13
+ from . import Dialog, loadUi
14
+ from .redmine_login_dialog import RedmineLoginDialog
15
+
16
+
17
+ class ErrorDialog(Dialog):
18
+ def __init__(self, parent):
19
+ super(ErrorDialog, self).__init__(parent)
20
+
21
+ loadUi(__file__, self)
22
+
23
+ self.parent_ = parent
24
+ self.requestPimpPID = None
25
+ self.setWindowTitle('Error Occurred')
26
+ self.errorLabel.setTextFormat(Qt.RichText)
27
+ self.iconLabel.setPixmap(
28
+ QPixmap(
29
+ os.path.join(
30
+ os.path.dirname(pfile),
31
+ 'resource',
32
+ 'img',
33
+ 'warning-big.png',
34
+ )
35
+ ).scaledToHeight(64, Qt.SmoothTransformation)
36
+ )
37
+
38
+ self.loggerButton.clicked.connect(self.showLogger)
39
+ self.requestButton.clicked.connect(self.submitRequest)
40
+ self.ignoreButton.clicked.connect(self.close)
41
+
42
+ def setText(self, exc_info):
43
+ from .console import ConsolePrEdit
44
+
45
+ self.traceback_msg = "".join(traceback.format_exception(*exc_info))
46
+ msg = (
47
+ 'The following error has occurred:<br>'
48
+ '<br><font color=%(color)s>%(text)s</font>'
49
+ )
50
+ self.errorLabel.setText(
51
+ msg
52
+ % {
53
+ 'text': self.traceback_msg.split('\n')[-2],
54
+ 'color': ConsolePrEdit._errorMessageColor.name(),
55
+ }
56
+ )
57
+
58
+ def showLogger(self):
59
+ """Create/show the main PrEditor instance with the full traceback."""
60
+ from .. import launch
61
+
62
+ launch()
63
+ self.close()
64
+
65
+ def submitRequest(self):
66
+ from ..utils.errorEmail import buildErrorMessage
67
+
68
+ subject, description = buildErrorMessage(self.traceback_msg, fmt='markdown')
69
+ subject = self.traceback_msg.split('\n')[-2]
70
+ from ..actions.create_redmine_issue import CreateRedmineIssue
71
+
72
+ kwargs = {
73
+ 'subject': subject,
74
+ 'description': description,
75
+ 'screenshot': True,
76
+ 'username': getpass.getuser(),
77
+ }
78
+
79
+ # Tryin a first connection impersonating the current user.
80
+ try:
81
+ CreateRedmineIssue(**kwargs)()
82
+
83
+ # If that failed, we will use a dialog to prompt for credentials.
84
+ except ImpersonateError:
85
+ dialog = RedmineLoginDialog(parent=self)
86
+ result = dialog.exec_()
87
+ if result == QDialog.Accepted:
88
+ kwargs.update(
89
+ {
90
+ 'username': dialog.username(),
91
+ 'password': dialog.password(),
92
+ 'redmine': dialog.redmine(),
93
+ }
94
+ )
95
+
96
+ # The dialog can only return a successful connection.
97
+ CreateRedmineIssue(**kwargs)()
98
+ elif result == QDialog.Rejected:
99
+ return
100
+ self.close()
@@ -0,0 +1,93 @@
1
+ from __future__ import absolute_import
2
+
3
+ from functools import partial
4
+
5
+ from Qt.QtCore import QModelIndex, QPoint, Qt, Signal
6
+ from Qt.QtWidgets import QFrame, QLineEdit, QListView, QShortcut, QVBoxLayout
7
+
8
+ from ..group_tab_widget.grouped_tab_models import GroupTabFuzzyFilterProxyModel
9
+
10
+
11
+ class FuzzySearch(QFrame):
12
+ canceled = Signal("QModelIndex")
13
+ """Passes the original QModelIndex for the tab that was selected when the
14
+ widget was first shown. This lets you reset back to the orignal state."""
15
+ highlighted = Signal("QModelIndex")
16
+ """Emitted when the user navitages to the given index, but hasn't selected."""
17
+ selected = Signal("QModelIndex")
18
+ """Emitted when the user selects a item."""
19
+
20
+ def __init__(self, model, parent=None, **kwargs):
21
+ super(FuzzySearch, self).__init__(parent=parent, **kwargs)
22
+ self.y_offset = 100
23
+ self.setMinimumSize(400, 200)
24
+ self.uiCloseSCT = QShortcut(
25
+ Qt.Key_Escape, self, context=Qt.WidgetWithChildrenShortcut
26
+ )
27
+ self.uiCloseSCT.activated.connect(self._canceled)
28
+
29
+ self.uiUpSCT = QShortcut(Qt.Key_Up, self, context=Qt.WidgetWithChildrenShortcut)
30
+ self.uiUpSCT.activated.connect(partial(self.increment_selection, -1))
31
+ self.uiDownSCT = QShortcut(
32
+ Qt.Key_Down, self, context=Qt.WidgetWithChildrenShortcut
33
+ )
34
+ self.uiDownSCT.activated.connect(partial(self.increment_selection, 1))
35
+
36
+ lyt = QVBoxLayout(self)
37
+ self.uiLineEDIT = QLineEdit(parent=self)
38
+ self.uiLineEDIT.textChanged.connect(self.update_completer)
39
+ self.uiLineEDIT.returnPressed.connect(self.activated)
40
+ lyt.addWidget(self.uiLineEDIT)
41
+ self.uiResultsLIST = QListView(self)
42
+ self.uiResultsLIST.activated.connect(self.activated)
43
+ self.proxy_model = GroupTabFuzzyFilterProxyModel(self)
44
+ self.proxy_model.setSourceModel(model)
45
+ self.uiResultsLIST.setModel(self.proxy_model)
46
+ lyt.addWidget(self.uiResultsLIST)
47
+
48
+ self.original_model_index = model.original_model_index
49
+
50
+ def activated(self):
51
+ current = self.uiResultsLIST.currentIndex()
52
+ self.selected.emit(current)
53
+ self.hide()
54
+
55
+ def increment_selection(self, direction):
56
+ current = self.uiResultsLIST.currentIndex()
57
+ col = 0
58
+ row = 0
59
+ if current.isValid():
60
+ col = current.column()
61
+ row = current.row() + direction
62
+ new = self.uiResultsLIST.model().index(row, col)
63
+ self.uiResultsLIST.setCurrentIndex(new)
64
+ self.highlighted.emit(new)
65
+
66
+ def update_completer(self, wildcard):
67
+ if wildcard:
68
+ if not self.uiResultsLIST.currentIndex().isValid():
69
+ new = self.uiResultsLIST.model().index(0, 0)
70
+ self.uiResultsLIST.setCurrentIndex(new)
71
+ else:
72
+ self.uiResultsLIST.clearSelection()
73
+ self.uiResultsLIST.setCurrentIndex(QModelIndex())
74
+ self.proxy_model.setFuzzySearch(wildcard)
75
+ self.highlighted.emit(self.uiResultsLIST.currentIndex())
76
+
77
+ def _canceled(self):
78
+ # Restore the original tab as the user didn't choose the new tab
79
+ self.canceled.emit(self.original_model_index)
80
+ self.hide()
81
+
82
+ def reposition(self):
83
+ pgeo = self.parent().geometry()
84
+ geo = self.geometry()
85
+ center = QPoint(pgeo.width() // 2, 0)
86
+ geo.moveCenter(center)
87
+ geo.setY(self.y_offset)
88
+ self.setGeometry(geo)
89
+
90
+ def popup(self):
91
+ self.show()
92
+ self.reposition()
93
+ self.uiLineEDIT.setFocus(Qt.PopupFocusReason)
@@ -0,0 +1,319 @@
1
+ from __future__ import absolute_import
2
+
3
+ import os
4
+ import re
5
+
6
+ import six
7
+ from Qt.QtCore import Qt
8
+ from Qt.QtGui import QIcon
9
+ from Qt.QtWidgets import QHBoxLayout, QMessageBox, QToolButton, QWidget
10
+
11
+ from ... import resourcePath
12
+ from ...prefs import prefs_path
13
+ from ..drag_tab_bar import DragTabBar
14
+ from ..workbox_text_edit import WorkboxTextEdit
15
+ from .grouped_tab_menu import GroupTabMenu
16
+ from .grouped_tab_widget import GroupedTabWidget
17
+ from .one_tab_widget import OneTabWidget
18
+
19
+ DEFAULT_STYLE_SHEET = """
20
+ /* Make the two buttons in the GroupTabWidget take up the
21
+ same horizontal space as the GroupedTabWidget's buttons. */
22
+ GroupTabWidget>QTabBar::tab{
23
+ max-height: 1.5em;
24
+ }
25
+ /* We have an icon, no need to show the menu indicator */
26
+ #group_tab_widget_menu_btn::menu-indicator{
27
+ width: 0px;
28
+ }
29
+ /* The GroupedTabWidget has a single button, make it take
30
+ the same space as the GroupTabWidget buttons. */
31
+ GroupedTabWidget>QToolButton,GroupTabWidget>QWidget{
32
+ width: 3em;
33
+ }
34
+ """
35
+
36
+
37
+ class GroupTabWidget(OneTabWidget):
38
+ """A QTabWidget where each tab contains another tab widget, allowing users
39
+ to group code editors. It has a corner button to add a new tab, and a menu
40
+ allowing users to quickly focus on any tab in the entire group.
41
+ """
42
+
43
+ def __init__(self, editor_kwargs=None, core_name=None, *args, **kwargs):
44
+ super(GroupTabWidget, self).__init__(*args, **kwargs)
45
+ DragTabBar.install_tab_widget(self, 'group_tab_widget')
46
+ self.editor_kwargs = editor_kwargs
47
+ self.editor_cls = WorkboxTextEdit
48
+ self.core_name = core_name
49
+ self.setStyleSheet(DEFAULT_STYLE_SHEET)
50
+ corner = QWidget(self)
51
+ lyt = QHBoxLayout(corner)
52
+ lyt.setSpacing(0)
53
+ lyt.setContentsMargins(0, 0, 0, 0)
54
+
55
+ corner.uiNewTabBTN = QToolButton(corner)
56
+ corner.uiNewTabBTN.setObjectName('group_tab_widget_new_btn')
57
+ corner.uiNewTabBTN.setText('+')
58
+ corner.uiNewTabBTN.setIcon(QIcon(resourcePath('img/file-plus.png')))
59
+ corner.uiNewTabBTN.released.connect(lambda: self.add_new_tab(None))
60
+ lyt.addWidget(corner.uiNewTabBTN)
61
+
62
+ corner.uiMenuBTN = QToolButton(corner)
63
+ corner.uiMenuBTN.setIcon(QIcon(resourcePath('img/chevron-down.png')))
64
+ corner.uiMenuBTN.setObjectName('group_tab_widget_menu_btn')
65
+ corner.uiMenuBTN.setPopupMode(QToolButton.InstantPopup)
66
+ corner.uiCornerMENU = GroupTabMenu(self, parent=corner.uiMenuBTN)
67
+ corner.uiMenuBTN.setMenu(corner.uiCornerMENU)
68
+ lyt.addWidget(corner.uiMenuBTN)
69
+
70
+ self.uiCornerBTN = corner
71
+ self.setCornerWidget(self.uiCornerBTN, Qt.TopRightCorner)
72
+
73
+ def add_new_tab(self, group, title="Workbox"):
74
+ """Adds a new tab to the requested group, creating the group if the group
75
+ doesn't exist.
76
+
77
+ Args:
78
+ group: The group to add a new tab to. This can be an int index of an
79
+ existing tab, or the name of the group and it will create the group
80
+ if needed. If None is passed it will add a new tab `Group {last+1}`.
81
+ If True is passed, then the current group tab is used.
82
+
83
+ Returns:
84
+ GroupedTabWidget: The tab group for this group.
85
+ WorkboxMixin: The new text editor.
86
+ """
87
+ parent = None
88
+ if not group:
89
+ last = 0
90
+ for i in range(self.count()):
91
+ match = re.match(r'Group (\d+)', self.tabText(i))
92
+ if match:
93
+ last = max(last, int(match.group(1)))
94
+ group = "Group {}".format(last + 1)
95
+ elif group is True:
96
+ group = self.currentIndex()
97
+ if isinstance(group, int):
98
+ group_title = self.tabText(group)
99
+ parent = self.widget(group)
100
+ elif isinstance(group, six.string_types):
101
+ group_title = group
102
+ index = self.index_for_text(group)
103
+ if index != -1:
104
+ parent = self.widget(index)
105
+
106
+ if not parent:
107
+ parent, group_title = self.default_tab(group_title)
108
+ self.addTab(parent, group_title)
109
+
110
+ # Create the first editor tab and make it visible
111
+ editor = parent.add_new_editor(title)
112
+ self.setCurrentIndex(self.indexOf(parent))
113
+
114
+ return parent, editor
115
+
116
+ def all_widgets(self):
117
+ """A generator yielding information about every widget under every group.
118
+
119
+ Yields:
120
+ widget, group tab name, widget tab name, group tab index, widget tab index
121
+ """
122
+ for group_index in range(self.count()):
123
+ group_name = self.tabText(group_index)
124
+
125
+ tab_widget = self.widget(group_index)
126
+ for tab_index in range(tab_widget.count()):
127
+ tab_name = tab_widget.tabText(tab_index)
128
+ yield tab_widget.widget(
129
+ tab_index
130
+ ), group_name, tab_name, group_index, tab_index
131
+
132
+ def close_current_tab(self):
133
+ """Convenient method to close the currently open editor tab prompting
134
+ the user to confirm closing."""
135
+ editor_tab = self.currentWidget()
136
+ editor_tab.close_tab(editor_tab.currentIndex())
137
+
138
+ def close_tab(self, index):
139
+ ret = QMessageBox.question(
140
+ self,
141
+ 'Close all editors under this tab?',
142
+ 'Are you sure you want to close all tabs under the "{}" tab?'.format(
143
+ self.tabText(self.currentIndex())
144
+ ),
145
+ QMessageBox.Yes | QMessageBox.Cancel,
146
+ )
147
+ if ret == QMessageBox.Yes:
148
+ # Clean up all temp files created by this group's editors if they
149
+ # are not using actual saved files.
150
+ tab_widget = self.widget(self.currentIndex())
151
+ for index in range(tab_widget.count()):
152
+ editor = tab_widget.widget(index)
153
+ editor.__remove_tempfile__()
154
+
155
+ super(GroupTabWidget, self).close_tab(self.currentIndex())
156
+
157
+ def current_groups_widget(self):
158
+ """Returns the current widget of the currently selected group or None."""
159
+ editor_tab = self.currentWidget()
160
+ if editor_tab:
161
+ return editor_tab.currentWidget()
162
+
163
+ def default_tab(self, title='Group 1'):
164
+ widget = GroupedTabWidget(
165
+ parent=self,
166
+ editor_kwargs=self.editor_kwargs,
167
+ editor_cls=self.editor_cls,
168
+ core_name=self.core_name,
169
+ )
170
+ return widget, title
171
+
172
+ def restore_prefs(self, prefs):
173
+ """Adds tab groups and tabs, restoring the selected tabs. If a tab is
174
+ linked to a file that no longer exists, will not be added. Restores the
175
+ current tab for each group and the current group of tabs. If a current
176
+ tab is no longer valid, it will default to the first tab.
177
+
178
+ Preference schema:
179
+ ```json
180
+ {
181
+ "groups": [
182
+ {
183
+ // Name of the group tab. [Required]
184
+ "name": "My Group",
185
+ // This group should be the active group. First in list wins.
186
+ "current": true,
187
+ "tabs": [
188
+ {
189
+ // If filename is not null, this file is loaded
190
+ "filename": "C:\\temp\\invalid_asdfdfd.py",
191
+ // Name of the editor's tab [Optional]
192
+ "name": "invalid_asdfdfd.py",
193
+ "tempfile": null
194
+ },
195
+ {
196
+ // This tab should be active for the group.
197
+ "current": true,
198
+ "filename": null,
199
+ "name": "Workbox",
200
+ // If tempfile is not null, this file is loaded.
201
+ // Ignored if filename is not null.
202
+ "tempfile": "workbox_2yrwctco_a.py"
203
+ }
204
+ ]
205
+ }
206
+ ]
207
+ }
208
+ ```
209
+ """
210
+
211
+ self.clear()
212
+
213
+ workbox_dir = prefs_path('workboxes', core_name=self.core_name)
214
+ current_group = None
215
+ for group in prefs.get('groups', []):
216
+ current_tab = None
217
+ group_name = group['name']
218
+ tab_widget = None
219
+
220
+ for tab in group.get('tabs', []):
221
+ # Only add this tab if, there is data on disk to load. The user can
222
+ # open multiple instances of PrEditor using the same prefs. The
223
+ # json pref data represents the last time the prefs were saved.
224
+ # Each editor's contents are saved to individual files on disk.
225
+ # When a editor tab is closed, the temp file is removed, not on
226
+ # preferences save.
227
+ # By not restoring tabs for deleted files we prevent accidentally
228
+ # restoring a tab with empty text.
229
+ filename = tab.get('filename')
230
+ temp_name = tab.get('tempfile')
231
+ if filename:
232
+ if not os.path.exists(filename):
233
+ continue
234
+ if not temp_name:
235
+ continue
236
+ temp_name = os.path.join(workbox_dir, temp_name)
237
+ if not os.path.exists(temp_name):
238
+ continue
239
+
240
+ # There is a file on disk, add the tab, creating the group
241
+ # tab if it hasn't already been created.
242
+ name = tab['name']
243
+ tab_widget, editor = self.add_new_tab(group_name, name)
244
+ editor.__restore_prefs__(tab)
245
+
246
+ # If more than one tab in this group is listed as current, only
247
+ # respect the first
248
+ if current_tab is None and tab.get('current'):
249
+ current_tab = tab_widget.indexOf(editor)
250
+
251
+ # If there were no files to load, this tab was not added and there
252
+ # we don't need to restore the current tab for this group
253
+ if tab_widget is None:
254
+ continue
255
+
256
+ # Restore the current tab for this group
257
+ if current_tab is None:
258
+ # If there is no longer a current tab, default to the first tab
259
+ current_tab = 0
260
+ tab_widget.setCurrentIndex(current_tab)
261
+
262
+ # Which tab group is the active one? If more than one tab in this
263
+ # group is listed as current, only respect the first.
264
+ if current_group is None and group.get('current'):
265
+ current_group = self.indexOf(tab_widget)
266
+
267
+ # Restore the current group for this widget
268
+ if current_group is None:
269
+ # If there is no longer a current tab, default to the first tab
270
+ current_group = 0
271
+ self.setCurrentIndex(current_group)
272
+
273
+ def save_prefs(self, prefs=None):
274
+ groups = []
275
+ if prefs is None:
276
+ prefs = {}
277
+
278
+ prefs['groups'] = groups
279
+ current_group = self.currentIndex()
280
+ for i in range(self.count()):
281
+ tabs = []
282
+ group = {}
283
+ # Hopefully the alphabetical sorting of this dict is preserved in py3
284
+ # to make it easy to diff the json pref file if ever required.
285
+ if i == current_group:
286
+ group['current'] = True
287
+ group['name'] = self.tabText(i)
288
+ group['tabs'] = tabs
289
+
290
+ tab_widget = self.widget(i)
291
+ current_editor = tab_widget.currentIndex()
292
+ for j in range(tab_widget.count()):
293
+ current = True if j == current_editor else None
294
+ tabs.append(
295
+ tab_widget.widget(j).__save_prefs__(
296
+ name=tab_widget.tabText(j), current=current
297
+ )
298
+ )
299
+
300
+ groups.append(group)
301
+
302
+ return prefs
303
+
304
+ def set_current_groups_from_index(self, group, editor):
305
+ """Make the specified indexes the current widget and return it. If the
306
+ indexes are out of range the current widget is not changed.
307
+
308
+ Args:
309
+ group (int): The index of the group tab to make current.
310
+ editor (int): The index of the editor under the group tab to
311
+ make current.
312
+
313
+ Returns:
314
+ QWidget: The current widget after applying.
315
+ """
316
+ self.setCurrentIndex(group)
317
+ tab_widget = self.currentWidget()
318
+ tab_widget.setCurrentIndex(editor)
319
+ return tab_widget.currentWidget()