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
blurdev/cores/core.py DELETED
@@ -1,634 +0,0 @@
1
- from __future__ import print_function
2
- from __future__ import absolute_import
3
- import sys
4
- import time
5
- import os
6
- import glob
7
-
8
- from Qt.QtCore import QDateTime, QEvent, QObject, Qt, Signal
9
- from Qt.QtWidgets import (
10
- QApplication,
11
- QDialog,
12
- QMainWindow,
13
- QSplashScreen,
14
- )
15
- import sentry_bootstrap
16
-
17
- import blurdev
18
- import blurdev.debug
19
- import blurdev.osystem
20
- import blurdev.cores.application
21
- import blurdev.settings
22
- from blurdev.utils.error import sentry_before_send_callback
23
-
24
-
25
- class Core(QObject):
26
- """
27
- The Core class provides all the main shared functionality and signals that need to
28
- be distributed between different pacakges.
29
- """
30
-
31
- # ----------------------------------------------------------------
32
- # blurdev signals
33
- aboutToClearPaths = Signal() # Emitted before environment is changed or reloaded
34
- styleSheetChanged = Signal(str)
35
-
36
- # ----------------------------------------------------------------
37
-
38
- def __init__(self, hwnd=0, objectName=None):
39
- QObject.__init__(self)
40
- if objectName is None:
41
- objectName = 'blurdev'
42
- QObject.setObjectName(self, objectName)
43
-
44
- # create custom properties
45
- self._protectedModules = []
46
- self._hwnd = hwnd
47
- self._logger = None
48
- self._stylesheet = None
49
- self._headless = False
50
- self._useAppUserModelID = None
51
- self._rootWindow = None
52
-
53
- # Applications like 3ds Max 2018 use stylesheets, when blurdev installs custom
54
- # stylesheets it will automatically add this to the start of that stylesheet.
55
- # This makes it so we don't have to include that stylesheet info into our
56
- # stylesheets, but still don't cause horrible eye gouging things to happen to
57
- # the application.
58
- self._defaultStyleSheet = ''
59
-
60
- # Paths in this variable will be removed in
61
- # blurdev.osystem.subprocessEnvironment
62
- self._removeFromPATHEnv = set()
63
- self.environment_override_filepath = os.environ.get(
64
- 'BDEV_ENVIRONMENT_OVERRIDE_FILEPATH', ''
65
- )
66
-
67
- def aboutBlurdev(self):
68
- """Useful info about blurdev and its dependencies as a string."""
69
- from Qt import (
70
- __binding__,
71
- __binding_version__,
72
- __version__ as qtpy_version,
73
- __qt_version__,
74
- )
75
-
76
- msg = [
77
- 'blurdev: {} ({})'.format(blurdev.__version__, self.objectName()),
78
- ' {}'.format(os.path.dirname(blurdev.__file__)),
79
- ]
80
-
81
- msg.append('Qt: {}'.format(__qt_version__))
82
- msg.append(' Qt.py: {}, binding: {}'.format(qtpy_version, __binding__))
83
-
84
- try:
85
- # QtSiteConfig is optional
86
- import QtSiteConfig
87
-
88
- msg.append(' QtSiteConfig: {}'.format(QtSiteConfig.__version__))
89
- except (ImportError, AttributeError):
90
- pass
91
-
92
- # Legacy Qt 4 support
93
- if __binding__ not in ('PyQt5', 'PySide2'):
94
- msg.append(
95
- ' {qt}: {qtver}'.format(qt=__binding__, qtver=__binding_version__)
96
- )
97
- # Add info for all Qt5 bindings that have been imported somewhere
98
- if 'PyQt5.QtCore' in sys.modules:
99
- msg.append(
100
- ' PyQt5: {}'.format(sys.modules['PyQt5.QtCore'].PYQT_VERSION_STR)
101
- )
102
- if 'PySide2.QtCore' in sys.modules:
103
- msg.append(
104
- ' PySide2: {}'.format(sys.modules['PySide2.QtCore'].qVersion())
105
- )
106
-
107
- # Include the python version info
108
- msg.append('Python:')
109
- msg.append(' {}'.format(sys.version))
110
-
111
- return '\n'.join(msg)
112
-
113
- def defaultStyle(self):
114
- """The default style name used when setting up the QApplication.
115
-
116
- In Qt4 this is Plastique, in Qt5 this is Fusion.
117
- """
118
- from Qt import IsPyQt4, IsPySide
119
-
120
- if IsPyQt4 or IsPySide:
121
- return 'Plastique'
122
- return 'Fusion'
123
-
124
- def flashWindow(self, window=None, dwFlags=None, count=1, timeout=0, hwnd=None):
125
- """Flashes the application depending on the os.
126
-
127
- On Windows this calls FlashWindowEx. See this documentation.
128
- http://docs.activestate.com/activepython/2.7/pywin32/win32gui__FlashWindowEx_meth.html
129
- https://msdn.microsoft.com/en-us/library/ms679348(v=vs.85).aspx
130
-
131
- Args: window (QWidget|None): This widget will be flashed. Attempts to get the
132
- hwnd from this widget. Note: This is ignored if hwnd is passed in.
133
-
134
- dwFlags (blurdev.osystem.FlashTimes): A enum value used to control the
135
- flashing behavior. See
136
- https://msdn.microsoft.com/en-us/library/ms679348(v=vs.85).aspx for more
137
- details. Defaults to FLASHW_TIMERNOFG.
138
-
139
- count (int): The number of times to flash the window. Defaults to 1.
140
-
141
- timeout (int): The rate at which the window is to be flashed in
142
- milliseconds. if zero is passed, the default cursor blink rate is used.
143
-
144
- hwnd (int or None): Flash this hwnd. If None(default) it will flash window
145
- if provided, otherwise it will flash blurdev.core.rootWindow().
146
-
147
- Returns:
148
- bool: Was anything attempted. On windows this always returns True.
149
- """
150
- if blurdev.settings.OS_TYPE == 'Windows':
151
- import ctypes
152
-
153
- if dwFlags is None:
154
- dwFlags = blurdev.osystem.FlashTimes.FLASHW_TIMERNOFG
155
- if hwnd is None:
156
- if window is None:
157
- hwnd = self.rootWindow().winId().__int__()
158
- else:
159
- hwnd = window.winId().__int__()
160
-
161
- ctypes.windll.user32.FlashWindow(hwnd, int(dwFlags), count, timeout)
162
- return True
163
- return False
164
-
165
- def errorCoreText(self):
166
- """Returns text that is included in the error email for the active core.
167
- Override in subclasses to provide extra data. If a empty string is returned
168
- this line will not be shown in the error email.
169
- """
170
- return ''
171
-
172
- def shouldReportException(self, exc_type, exc_value, exc_traceback, actions=None):
173
- """
174
- Allow core to control how exceptions are handled. Currently being used
175
- by `BlurExcepthook`, informing which excepthooks should or should not
176
- be executed.
177
-
178
- Args:
179
- exc_type (type): exception type class object
180
- exc_value (Exception): class instance of exception parameter
181
- exc_traceback (traceback): encapsulation of call stack for exception
182
- actions (dict, optional): default values for the returned dict. A copy
183
- of this dict is returned with standard defaults applied.
184
-
185
- Returns:
186
- dict: Boolean values representing whether to perform excepthook
187
- action, keyed to the name of the excepthook
188
- """
189
- if actions is None:
190
- actions = {}
191
- # Create a shallow copy so we don't modify the passed in dict and don't
192
- # need to use a default value of None
193
- actions = actions.copy()
194
-
195
- # provide the expected default values
196
- actions.setdefault('email', True)
197
- # If blurdev is running headless, there is no way to show a gui prompt
198
- actions.setdefault('prompt', not self.headless)
199
- return actions
200
-
201
- def init(self):
202
- """Initializes the core system"""
203
- ret = self.initCore()
204
- return ret
205
-
206
- def initCore(self):
207
- """Work method to initialize the core system -- breaking the initialization
208
- apart allows the gui-dependant initialization to be delayed in applications
209
- where that is necessary by overloading init().
210
- """
211
- # register protected modules
212
- # do not want to affect this module during environment switching
213
- self.protectModule('blurdev')
214
- # we should never remove main. If we do in specific cases it will prevent
215
- # external tools from running if they use "if __name__ == '__main__':" as
216
- # __name__ will return None
217
- self.protectModule('__main__')
218
- # Pillar is used by blurdev so reloading it breaks blurdev. Devs may have pillar
219
- # in their tools virtualenv to aid in installing other pip packages.
220
- self.protectModule('pillar')
221
- # pkg_resources is found in the tools virtualenv and we use it when switching
222
- self.protectModule('pkg_resources')
223
-
224
- # initialize sentry client
225
- sentry_bootstrap.init_sentry(force=True)
226
- sentry_bootstrap.add_external_callback(sentry_before_send_callback)
227
-
228
- # Gets the override filepath, it is defined this way, instead of
229
- # being defined in the class definition, so that we can change this
230
- # path, or remove it entirely for offline installs.
231
- # self.environment_override_filepath = os.environ.get(
232
- # 'BDEV_ENVIRONMENT_OVERRIDE_FILEPATH', '')
233
-
234
- # initialize the application
235
- app = QApplication.instance()
236
- output = None
237
-
238
- if not app:
239
- # create a new application
240
- from blurdev.cores.application import CoreApplication, Application
241
-
242
- # Check for headless environment's
243
- if blurdev.settings.OS_TYPE == 'Linux':
244
- if os.environ.get('DISPLAY') is None:
245
- output = CoreApplication([])
246
- self._headless = True
247
- if output is None:
248
- output = Application([])
249
-
250
- self.updateApplicationName(output)
251
-
252
- return output
253
-
254
- @property
255
- def headless(self):
256
- """If true, no Qt gui elements should be used because python is running a
257
- QCoreApplication.
258
- """
259
- return self._headless
260
-
261
- def hwnd(self):
262
- if self.objectName() == 'assfreezer':
263
- return int(self.rootWindow().winId())
264
- return self._hwnd
265
-
266
- def logger(self, parent=None):
267
- """Creates and returns the logger instance"""
268
- from blurdev.gui.loggerwindow import LoggerWindow
269
-
270
- return LoggerWindow.instance(parent)
271
-
272
- def protectModule(self, moduleName):
273
- """
274
- Registers the inputed module name for protection from tools environment
275
- switching
276
- """
277
- key = str(moduleName)
278
- if key not in self._protectedModules:
279
- self._protectedModules.append(str(moduleName))
280
-
281
- def protectedModules(self):
282
- """
283
- Returns the modules that should not be affected when a tools environment changes
284
- """
285
- return self._protectedModules
286
-
287
- def rootWindow(self):
288
- """
289
- Returns the currently active window
290
- """
291
- if self._rootWindow is not None:
292
- return self._rootWindow
293
-
294
- if QApplication.instance():
295
- self._rootWindow = QApplication.instance().activeWindow()
296
- # Ignore QSplashScreen's, they should never be considered the root window.
297
- if isinstance(self._rootWindow, QSplashScreen):
298
- self._rootWindow = None
299
- # If the application does not have focus try to find A top level widget
300
- # that doesn't have a parent and is a QMainWindow or QDialog
301
- if self._rootWindow is None:
302
- windows = []
303
- dialogs = []
304
- for w in QApplication.instance().topLevelWidgets():
305
- if w.parent() is None:
306
- if isinstance(w, QMainWindow):
307
- windows.append(w)
308
- elif isinstance(w, QDialog):
309
- dialogs.append(w)
310
- if windows:
311
- self._rootWindow = windows[0]
312
- elif dialogs:
313
- self._rootWindow = dialogs[0]
314
-
315
- # grab the root window
316
- if self._rootWindow:
317
- while self._rootWindow.parent():
318
- parent = self._rootWindow.parent()
319
- if isinstance(parent, QSplashScreen):
320
- return self._rootWindow
321
- else:
322
- self._rootWindow = parent
323
- return self._rootWindow
324
-
325
- def setHwnd(self, hwnd):
326
- self._hwnd = hwnd
327
-
328
- def emailAddressMd5Hash(self, text, address=None):
329
- """Turns the text into a md5 string and inserts it in the address.
330
-
331
- This is useful for controlling how messages are threaded into conversations on
332
- gmail.
333
-
334
- Args:
335
- text (str): This text will be converted into a md5 hash.
336
-
337
- address (str or None): The md5 hash will be inserted using str.format on the
338
- "hash" key. If None, it will use the value stored in the BDEV_ERROR_EMAIL
339
- environment variable.
340
-
341
- Returns:
342
- str: The formatted address.
343
-
344
- """
345
- import hashlib
346
-
347
- m = hashlib.md5()
348
- m.update(text.encode('utf-8'))
349
- if address is None:
350
- address = os.environ.get('BDEV_ERROR_EMAIL')
351
- return address.format(hash=m.hexdigest())
352
-
353
- def sendEmail(
354
- self, sender, targets, subject, message, attachments=None, refId=None
355
- ):
356
- """Sends an email.
357
- Args:
358
- sender (str): The source email address.
359
-
360
- targets (str or list): A single email string, or a list of email address(s)
361
- to send the email to.
362
-
363
- subject (str): The subject of the email.
364
- message (str): The body of the message. Treated as html
365
- attachments (list or None): File paths for files to be attached.
366
-
367
- refId (str or None): If not None "X-Entity-Ref-ID" is added to the header
368
- with this value. For gmail passing a empty string appears to be the same
369
- as passing real data.
370
- """
371
- try:
372
- from email import Encoders
373
- from email.MIMEText import MIMEText
374
- from email.MIMEMultipart import MIMEMultipart
375
- from email.MIMEBase import MIMEBase
376
- except ImportError:
377
- from email.mime.text import MIMEText
378
- from email.mime.multipart import MIMEMultipart
379
- from email.mime.base import MIMEBase
380
-
381
- import smtplib
382
-
383
- output = MIMEMultipart()
384
- output['Subject'] = str(subject)
385
- output['From'] = str(sender)
386
- if refId is not None:
387
- output['X-Entity-Ref-ID'] = refId
388
-
389
- # convert to string
390
- if isinstance(targets, (tuple, list)):
391
- output['To'] = ', '.join(targets)
392
- else:
393
- output['To'] = str(targets)
394
-
395
- output['Date'] = (
396
- QDateTime.currentDateTime().toUTC().toString('ddd, d MMM yyyy hh:mm:ss')
397
- )
398
- output['Content-type'] = 'Multipart/mixed'
399
- output.preamble = 'This is a multi-part message in MIME format.'
400
- output.epilogue = ''
401
-
402
- # Build Body
403
- msgText = MIMEText(str(message), 'html')
404
- msgText['Content-type'] = 'text/html'
405
-
406
- output.attach(msgText)
407
-
408
- # Include Attachments
409
- if attachments:
410
- for a in attachments:
411
- fp = open(str(a), 'rb')
412
- txt = MIMEBase('application', 'octet-stream')
413
- txt.set_payload(fp.read())
414
- fp.close()
415
-
416
- Encoders.encode_base64(txt)
417
- txt.add_header(
418
- 'Content-Disposition',
419
- 'attachment; filename="%s"' % os.path.basename(a),
420
- )
421
- output.attach(txt)
422
-
423
- try:
424
- smtp = smtplib.SMTP('mail.blur.com', timeout=1)
425
- # smtp.starttls()
426
- # smtp.connect(os.environ.get('BDEV_SEND_EMAIL_SERVER', 'mail.blur.com'))
427
- smtp.sendmail(str(sender), output['To'].split(','), output.as_string())
428
- smtp.close()
429
- except Exception:
430
- # TODO: Proper logging
431
-
432
- import inspect
433
-
434
- frame = inspect.stack()[1]
435
- module = inspect.getmodule(frame[0])
436
-
437
- import traceback
438
-
439
- traceback.print_exc()
440
-
441
- print(
442
- 'Module {0} @ {1} failed to send email\n{2}\n{3}\n{4}\n{5}'.format(
443
- module.__name__, module.__file__, sender, targets, subject, message
444
- )
445
- )
446
-
447
- raise
448
-
449
- def readStyleSheet(self, stylesheet='', path=None):
450
- """Returns the contents of the requested stylesheet.
451
-
452
- Args:
453
-
454
- stylesheet (str): the name of the stylesheet. Attempt to load stylesheet.css
455
- shipped with blurdev. Ignored if path is provided.
456
-
457
- path (str): Return the contents of this file path.
458
-
459
- Returns:
460
- str: The contents of stylesheet or blank if stylesheet was not found.
461
- valid: A stylesheet was found and loaded.
462
- """
463
- if path is None:
464
- path = os.path.join(
465
- os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
466
- 'resource',
467
- 'stylesheet',
468
- '{}.css'.format(stylesheet),
469
- )
470
- if os.path.isfile(path):
471
- with open(path) as f:
472
- return f.read(), True
473
- return '', False
474
-
475
- def setStyleSheet(self, stylesheet, recordPrefs=True):
476
- """Accepts the name of a stylesheet included with blurdev, or a full
477
- path to any stylesheet. If given None, it will remove the
478
- stylesheet.
479
- """
480
-
481
- def mergeDefaultStyleSheet(newSheet):
482
- """If the core has backed up a stylesheet, always include it."""
483
- return self._defaultStyleSheet + newSheet
484
-
485
- app = QApplication.instance()
486
- if app and isinstance(
487
- app, QApplication
488
- ): # Don't set stylesheet if QCoreApplication
489
- if stylesheet is None or stylesheet == 'None':
490
- app.setStyleSheet(mergeDefaultStyleSheet(''))
491
- self._stylesheet = None
492
- elif os.path.isfile(stylesheet):
493
- with open(stylesheet) as f:
494
- app.setStyleSheet(mergeDefaultStyleSheet(f.read()))
495
- self._stylesheet = stylesheet
496
- else:
497
- # Try to find an installed stylesheet with the given name
498
- sheet, valid = self.readStyleSheet(stylesheet)
499
- if valid:
500
- self._stylesheet = stylesheet
501
- app.setStyleSheet(mergeDefaultStyleSheet(sheet))
502
- path = self.styleSheetPath(stylesheet)
503
- if os.path.isfile(path):
504
- with open(path) as f:
505
- app.setStyleSheet(mergeDefaultStyleSheet(f.read()))
506
- self._stylesheet = stylesheet
507
-
508
- if self.objectName() != 'blurdev':
509
- # Storing the stylesheet as an environment variable for other external
510
- # tools.
511
- os.environ['BDEV_STYLESHEET'] = str(stylesheet)
512
-
513
- # Notify widgets of the stylesheet change
514
- self.styleSheetChanged.emit(str(stylesheet))
515
-
516
- def styleSheetPath(self, styleSheet, subFolder=None):
517
- if not styleSheet or styleSheet == 'None':
518
- return ''
519
- components = [
520
- os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
521
- 'resource',
522
- 'stylesheet',
523
- ]
524
- if subFolder is not None:
525
- components.append(subFolder)
526
- components.append('{}.css'.format(styleSheet))
527
- return os.path.join(*components)
528
-
529
- def styleSheet(self):
530
- """Returns the name of the current stylesheet."""
531
- return self._stylesheet
532
-
533
- def styleSheets(self, subFolder=None):
534
- """Returns a list of installed stylesheet names.
535
-
536
- Args:
537
- subFolder (str or None, optional): Use this to access sub-folders of
538
- the stylesheet resource directory.
539
-
540
- Returns:
541
- list: A list .css file paths in the target directory.
542
- """
543
- components = [
544
- os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
545
- 'resource',
546
- 'stylesheet',
547
- ]
548
- if subFolder is not None:
549
- components.append(subFolder)
550
- cssdir = os.path.join(*components)
551
- cssfiles = sorted(glob.glob(os.path.join(cssdir, '*.css')))
552
- # Only return the filename without the .css extension
553
- return [os.path.splitext(os.path.basename(fp))[0] for fp in cssfiles]
554
-
555
- def shutdown(self):
556
- if QApplication.instance():
557
- QApplication.instance().closeAllWindows()
558
- QApplication.instance().quit()
559
-
560
- def showLogger(self):
561
- """
562
- Creates the python logger and displays it
563
- """
564
- logger = self.logger()
565
- logger.show()
566
- logger.activateWindow()
567
- logger.raise_()
568
- logger.console().setFocus()
569
-
570
- def unprotectModule(self, moduleName):
571
- """
572
- Removes the inputed module name from protection from tools environment switching
573
- """
574
- key = str(moduleName)
575
- while key in self._protectedModules:
576
- self._protectedModules.remove(key)
577
-
578
- def updateApplicationName(self, application=None, name=None):
579
- """Sets the application name based on the environment.
580
-
581
- Args:
582
- application (
583
- Qt.QtCore.QCoreApplication or Qt.QtWidgets.QApplication, optional):
584
- The Qt application that should have its name set to match the
585
- BDEV_APPLICATION_NAME environment variable. This env variable is
586
- removed by calling this function so it is not passed to child
587
- subprocesses. If None is provided, then blurdev.application is used.
588
-
589
- Returns:
590
- bool: If the application name was set. This could be because the
591
- application was None.
592
- """
593
- if application is None:
594
- application = blurdev.application
595
- if application is None:
596
- return False
597
- # Remove the BDEV_APPLICATION_NAME variable if defined so it is not
598
- # passed to child processes.
599
- appName = os.environ.pop('BDEV_APPLICATION_NAME', None)
600
- if name is not None:
601
- # If a name was passed in, use it instead of the env variable, but still
602
- # remove the env variable so it doesn't affect child subprocesses.
603
- appName = name
604
- if application and appName:
605
- # This name can be used in filePaths, so remove the invalid separator
606
- # used by older tools.
607
- appName = appName.replace('::', '_')
608
- # If a application name was passed, update the QApplication's
609
- # application name.
610
- application.setApplicationName(appName)
611
- return True
612
- return False
613
-
614
- def uuid(self):
615
- """Application specific unique identifier
616
-
617
- Returns:
618
- None:
619
- """
620
- return None
621
-
622
- def useAppUserModelID(self):
623
- """Returns a boolean value controlling if calling blurdev.setAppUserModelID
624
- will do anyting."""
625
- # Core subclasses Can simply set _useAppUserModelID to True or False if they
626
- # want to blanket enable or disable setAppUserModelID.
627
- if self._useAppUserModelID is None:
628
- # By default allow all core names. If a specific core name needs to be
629
- # excluded, it should be added to this list.
630
- return self.objectName() not in ('assfreezer', 'designer')
631
- return self._useAppUserModelID
632
-
633
- def setUseAppUserModelID(self, value):
634
- self._useAppUserModelID = value