dcscope 2.22.1__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.
Files changed (267) hide show
  1. dcscope/__init__.py +17 -0
  2. dcscope/__main__.py +44 -0
  3. dcscope/_version.py +21 -0
  4. dcscope/extensions.py +250 -0
  5. dcscope/gui/__init__.py +2 -0
  6. dcscope/gui/analysis/__init__.py +10 -0
  7. dcscope/gui/analysis/ana_basins.py +110 -0
  8. dcscope/gui/analysis/ana_basins.ui +143 -0
  9. dcscope/gui/analysis/ana_filter.py +341 -0
  10. dcscope/gui/analysis/ana_filter.ui +364 -0
  11. dcscope/gui/analysis/ana_log.py +122 -0
  12. dcscope/gui/analysis/ana_log.ui +100 -0
  13. dcscope/gui/analysis/ana_meta.py +207 -0
  14. dcscope/gui/analysis/ana_meta.ui +141 -0
  15. dcscope/gui/analysis/ana_plot.py +638 -0
  16. dcscope/gui/analysis/ana_plot.ui +1060 -0
  17. dcscope/gui/analysis/ana_slot.py +504 -0
  18. dcscope/gui/analysis/ana_slot.ui +684 -0
  19. dcscope/gui/analysis/ana_tables.py +227 -0
  20. dcscope/gui/analysis/ana_tables.ui +195 -0
  21. dcscope/gui/analysis/ana_view.py +69 -0
  22. dcscope/gui/analysis/ana_view.ui +269 -0
  23. dcscope/gui/analysis/dlg_slot_reorder.py +55 -0
  24. dcscope/gui/analysis/dlg_slot_reorder.ui +138 -0
  25. dcscope/gui/bulk/__init__.py +2 -0
  26. dcscope/gui/bulk/bulk_emodulus.py +200 -0
  27. dcscope/gui/bulk/bulk_emodulus.ui +245 -0
  28. dcscope/gui/compute/__init__.py +3 -0
  29. dcscope/gui/compute/comp_lme4.py +115 -0
  30. dcscope/gui/compute/comp_lme4.ui +194 -0
  31. dcscope/gui/compute/comp_lme4_dataset.py +51 -0
  32. dcscope/gui/compute/comp_lme4_dataset.ui +92 -0
  33. dcscope/gui/compute/comp_lme4_results.py +120 -0
  34. dcscope/gui/compute/comp_lme4_results.ui +268 -0
  35. dcscope/gui/compute/comp_stats.py +223 -0
  36. dcscope/gui/compute/comp_stats.ui +187 -0
  37. dcscope/gui/dcor/__init__.py +304 -0
  38. dcscope/gui/dcor/dcor.ui +118 -0
  39. dcscope/gui/export/__init__.py +3 -0
  40. dcscope/gui/export/e2data.py +394 -0
  41. dcscope/gui/export/e2data.ui +367 -0
  42. dcscope/gui/export/e2filter.py +76 -0
  43. dcscope/gui/export/e2filter.ui +111 -0
  44. dcscope/gui/export/e2plot.py +94 -0
  45. dcscope/gui/export/e2plot.ui +175 -0
  46. dcscope/gui/main.py +1089 -0
  47. dcscope/gui/main.ui +579 -0
  48. dcscope/gui/matrix/__init__.py +4 -0
  49. dcscope/gui/matrix/block_matrix.py +141 -0
  50. dcscope/gui/matrix/block_matrix.ui +207 -0
  51. dcscope/gui/matrix/data_matrix.py +574 -0
  52. dcscope/gui/matrix/dm_dataset.py +116 -0
  53. dcscope/gui/matrix/dm_dataset.ui +348 -0
  54. dcscope/gui/matrix/dm_element.py +111 -0
  55. dcscope/gui/matrix/dm_element.ui +169 -0
  56. dcscope/gui/matrix/dm_filter.py +115 -0
  57. dcscope/gui/matrix/dm_filter.ui +287 -0
  58. dcscope/gui/matrix/plot_matrix.py +316 -0
  59. dcscope/gui/matrix/pm_element.py +39 -0
  60. dcscope/gui/matrix/pm_plot.py +86 -0
  61. dcscope/gui/matrix/pm_plot.ui +249 -0
  62. dcscope/gui/pipeline_plot.py +797 -0
  63. dcscope/gui/pipeline_plot.ui +66 -0
  64. dcscope/gui/preferences.py +380 -0
  65. dcscope/gui/preferences.ui +554 -0
  66. dcscope/gui/quick_view/__init__.py +1 -0
  67. dcscope/gui/quick_view/qv_main.py +1072 -0
  68. dcscope/gui/quick_view/qv_main.ui +1297 -0
  69. dcscope/gui/quick_view/qv_scatter.py +284 -0
  70. dcscope/gui/quick_view/qv_style.css +10 -0
  71. dcscope/gui/update.py +90 -0
  72. dcscope/gui/widgets/__init__.py +15 -0
  73. dcscope/gui/widgets/bg_thread.py +29 -0
  74. dcscope/gui/widgets/bulk_list.py +79 -0
  75. dcscope/gui/widgets/bulk_list.ui +95 -0
  76. dcscope/gui/widgets/double_spin_box_nan.py +75 -0
  77. dcscope/gui/widgets/feature_combobox.py +140 -0
  78. dcscope/gui/widgets/get_path.py +42 -0
  79. dcscope/gui/widgets/key_value_table_widget.css +12 -0
  80. dcscope/gui/widgets/key_value_table_widget.py +75 -0
  81. dcscope/gui/widgets/mdi_subwindow_wo_close.py +12 -0
  82. dcscope/gui/widgets/qrangeslider.py +262 -0
  83. dcscope/gui/widgets/rangecontrol.py +308 -0
  84. dcscope/gui/widgets/rangecontrol.ui +136 -0
  85. dcscope/gui/widgets/simple_image_view.py +55 -0
  86. dcscope/gui/widgets/simple_plot_widget.py +113 -0
  87. dcscope/gui/widgets/so_colorbaritem.py +29 -0
  88. dcscope/gui/widgets/wait_cursor.py +33 -0
  89. dcscope/idiom.py +26 -0
  90. dcscope/img/__init__.py +2 -0
  91. dcscope/img/icon-theme/breeze/COPYING-ICONS +209 -0
  92. dcscope/img/icon-theme/breeze/COPYING.LIB +510 -0
  93. dcscope/img/icon-theme/breeze/README +5 -0
  94. dcscope/img/icon-theme/breeze/actions/16/application-exit.svg +17 -0
  95. dcscope/img/icon-theme/breeze/actions/16/code-context.svg +13 -0
  96. dcscope/img/icon-theme/breeze/actions/16/dialog-cancel.svg +13 -0
  97. dcscope/img/icon-theme/breeze/actions/16/dialog-close.svg +17 -0
  98. dcscope/img/icon-theme/breeze/actions/16/dialog-messages.svg +13 -0
  99. dcscope/img/icon-theme/breeze/actions/16/dialog-ok-apply.svg +13 -0
  100. dcscope/img/icon-theme/breeze/actions/16/dialog-ok.svg +13 -0
  101. dcscope/img/icon-theme/breeze/actions/16/document-open-folder.svg +13 -0
  102. dcscope/img/icon-theme/breeze/actions/16/document-open.svg +13 -0
  103. dcscope/img/icon-theme/breeze/actions/16/document-save.svg +13 -0
  104. dcscope/img/icon-theme/breeze/actions/16/documentinfo.svg +12 -0
  105. dcscope/img/icon-theme/breeze/actions/16/draw-watercolor.svg +13 -0
  106. dcscope/img/icon-theme/breeze/actions/16/edit-clear-all.svg +13 -0
  107. dcscope/img/icon-theme/breeze/actions/16/edit-clear.svg +13 -0
  108. dcscope/img/icon-theme/breeze/actions/16/edit-paste.svg +13 -0
  109. dcscope/img/icon-theme/breeze/actions/16/globe.svg +16 -0
  110. dcscope/img/icon-theme/breeze/actions/16/gtk-preferences.svg +13 -0
  111. dcscope/img/icon-theme/breeze/actions/16/list-add.svg +13 -0
  112. dcscope/img/icon-theme/breeze/actions/16/messagebox_warning.svg +20 -0
  113. dcscope/img/icon-theme/breeze/actions/16/object-columns.svg +13 -0
  114. dcscope/img/icon-theme/breeze/actions/16/object-order-lower.svg +13 -0
  115. dcscope/img/icon-theme/breeze/actions/16/object-rows.svg +13 -0
  116. dcscope/img/icon-theme/breeze/actions/16/office-chart-line-stacked.svg +13 -0
  117. dcscope/img/icon-theme/breeze/actions/16/office-chart-ring.svg +13 -0
  118. dcscope/img/icon-theme/breeze/actions/16/office-chart-scatter.svg +13 -0
  119. dcscope/img/icon-theme/breeze/actions/16/path-mode-polyline.svg +13 -0
  120. dcscope/img/icon-theme/breeze/actions/16/preferences-activities.svg +13 -0
  121. dcscope/img/icon-theme/breeze/actions/16/remove.svg +10 -0
  122. dcscope/img/icon-theme/breeze/actions/16/search.svg +13 -0
  123. dcscope/img/icon-theme/breeze/actions/16/show-grid.svg +13 -0
  124. dcscope/img/icon-theme/breeze/actions/16/special_paste.svg +13 -0
  125. dcscope/img/icon-theme/breeze/actions/16/tools-wizard.svg +13 -0
  126. dcscope/img/icon-theme/breeze/actions/16/view-calendar-list.svg +13 -0
  127. dcscope/img/icon-theme/breeze/actions/16/view-filter.svg +13 -0
  128. dcscope/img/icon-theme/breeze/actions/16/view-list-tree.svg +13 -0
  129. dcscope/img/icon-theme/breeze/actions/16/view-statistics.svg +13 -0
  130. dcscope/img/icon-theme/breeze/actions/16/visibility.svg +21 -0
  131. dcscope/img/icon-theme/breeze/actions/22/application-exit.svg +13 -0
  132. dcscope/img/icon-theme/breeze/actions/22/code-context.svg +14 -0
  133. dcscope/img/icon-theme/breeze/actions/22/dialog-cancel.svg +14 -0
  134. dcscope/img/icon-theme/breeze/actions/22/dialog-close.svg +10 -0
  135. dcscope/img/icon-theme/breeze/actions/22/dialog-messages.svg +14 -0
  136. dcscope/img/icon-theme/breeze/actions/22/dialog-ok-apply.svg +14 -0
  137. dcscope/img/icon-theme/breeze/actions/22/dialog-ok.svg +14 -0
  138. dcscope/img/icon-theme/breeze/actions/22/document-open-folder.svg +14 -0
  139. dcscope/img/icon-theme/breeze/actions/22/document-open.svg +14 -0
  140. dcscope/img/icon-theme/breeze/actions/22/document-save.svg +14 -0
  141. dcscope/img/icon-theme/breeze/actions/22/documentinfo.svg +14 -0
  142. dcscope/img/icon-theme/breeze/actions/22/draw-watercolor.svg +14 -0
  143. dcscope/img/icon-theme/breeze/actions/22/edit-clear-all.svg +14 -0
  144. dcscope/img/icon-theme/breeze/actions/22/edit-clear.svg +14 -0
  145. dcscope/img/icon-theme/breeze/actions/22/edit-paste.svg +14 -0
  146. dcscope/img/icon-theme/breeze/actions/22/globe.svg +12 -0
  147. dcscope/img/icon-theme/breeze/actions/22/gtk-preferences.svg +13 -0
  148. dcscope/img/icon-theme/breeze/actions/22/list-add.svg +14 -0
  149. dcscope/img/icon-theme/breeze/actions/22/messagebox_warning.svg +17 -0
  150. dcscope/img/icon-theme/breeze/actions/22/object-columns.svg +14 -0
  151. dcscope/img/icon-theme/breeze/actions/22/object-order-lower.svg +17 -0
  152. dcscope/img/icon-theme/breeze/actions/22/object-rows.svg +17 -0
  153. dcscope/img/icon-theme/breeze/actions/22/office-chart-line-stacked.svg +17 -0
  154. dcscope/img/icon-theme/breeze/actions/22/office-chart-ring.svg +17 -0
  155. dcscope/img/icon-theme/breeze/actions/22/office-chart-scatter.svg +17 -0
  156. dcscope/img/icon-theme/breeze/actions/22/path-mode-polyline.svg +17 -0
  157. dcscope/img/icon-theme/breeze/actions/22/preferences-activities.svg +14 -0
  158. dcscope/img/icon-theme/breeze/actions/22/remove.svg +10 -0
  159. dcscope/img/icon-theme/breeze/actions/22/special_paste.svg +14 -0
  160. dcscope/img/icon-theme/breeze/actions/22/tools-wizard.svg +14 -0
  161. dcscope/img/icon-theme/breeze/actions/22/view-calendar-list.svg +14 -0
  162. dcscope/img/icon-theme/breeze/actions/22/view-filter.svg +14 -0
  163. dcscope/img/icon-theme/breeze/actions/22/view-list-tree.svg +14 -0
  164. dcscope/img/icon-theme/breeze/actions/22/view-statistics.svg +14 -0
  165. dcscope/img/icon-theme/breeze/actions/22/visibility.svg +14 -0
  166. dcscope/img/icon-theme/breeze/actions/24/application-exit.svg +12 -0
  167. dcscope/img/icon-theme/breeze/actions/24/code-context.svg +12 -0
  168. dcscope/img/icon-theme/breeze/actions/24/dialog-cancel.svg +12 -0
  169. dcscope/img/icon-theme/breeze/actions/24/dialog-close.svg +10 -0
  170. dcscope/img/icon-theme/breeze/actions/24/dialog-messages.svg +12 -0
  171. dcscope/img/icon-theme/breeze/actions/24/dialog-ok-apply.svg +12 -0
  172. dcscope/img/icon-theme/breeze/actions/24/dialog-ok.svg +14 -0
  173. dcscope/img/icon-theme/breeze/actions/24/document-open-folder.svg +12 -0
  174. dcscope/img/icon-theme/breeze/actions/24/document-open.svg +12 -0
  175. dcscope/img/icon-theme/breeze/actions/24/document-save.svg +12 -0
  176. dcscope/img/icon-theme/breeze/actions/24/documentinfo.svg +14 -0
  177. dcscope/img/icon-theme/breeze/actions/24/draw-watercolor.svg +12 -0
  178. dcscope/img/icon-theme/breeze/actions/24/edit-clear-all.svg +14 -0
  179. dcscope/img/icon-theme/breeze/actions/24/edit-clear.svg +12 -0
  180. dcscope/img/icon-theme/breeze/actions/24/edit-paste.svg +12 -0
  181. dcscope/img/icon-theme/breeze/actions/24/globe.svg +14 -0
  182. dcscope/img/icon-theme/breeze/actions/24/gtk-preferences.svg +13 -0
  183. dcscope/img/icon-theme/breeze/actions/24/list-add.svg +12 -0
  184. dcscope/img/icon-theme/breeze/actions/24/messagebox_warning.svg +13 -0
  185. dcscope/img/icon-theme/breeze/actions/24/object-columns.svg +12 -0
  186. dcscope/img/icon-theme/breeze/actions/24/object-order-lower.svg +15 -0
  187. dcscope/img/icon-theme/breeze/actions/24/object-rows.svg +15 -0
  188. dcscope/img/icon-theme/breeze/actions/24/office-chart-line-stacked.svg +15 -0
  189. dcscope/img/icon-theme/breeze/actions/24/office-chart-ring.svg +15 -0
  190. dcscope/img/icon-theme/breeze/actions/24/office-chart-scatter.svg +15 -0
  191. dcscope/img/icon-theme/breeze/actions/24/path-mode-polyline.svg +15 -0
  192. dcscope/img/icon-theme/breeze/actions/24/preferences-activities.svg +13 -0
  193. dcscope/img/icon-theme/breeze/actions/24/remove.svg +10 -0
  194. dcscope/img/icon-theme/breeze/actions/24/special_paste.svg +12 -0
  195. dcscope/img/icon-theme/breeze/actions/24/tools-wizard.svg +12 -0
  196. dcscope/img/icon-theme/breeze/actions/24/view-calendar-list.svg +12 -0
  197. dcscope/img/icon-theme/breeze/actions/24/view-filter.svg +12 -0
  198. dcscope/img/icon-theme/breeze/actions/24/view-list-tree.svg +12 -0
  199. dcscope/img/icon-theme/breeze/actions/24/view-statistics.svg +12 -0
  200. dcscope/img/icon-theme/breeze/actions/24/visibility.svg +14 -0
  201. dcscope/img/icon-theme/breeze/actions/32/application-exit.svg +8 -0
  202. dcscope/img/icon-theme/breeze/actions/32/dialog-cancel.svg +13 -0
  203. dcscope/img/icon-theme/breeze/actions/32/dialog-messages.svg +13 -0
  204. dcscope/img/icon-theme/breeze/actions/32/dialog-ok-apply.svg +1 -0
  205. dcscope/img/icon-theme/breeze/actions/32/dialog-ok.svg +1 -0
  206. dcscope/img/icon-theme/breeze/actions/32/document-open-folder.svg +13 -0
  207. dcscope/img/icon-theme/breeze/actions/32/document-open.svg +13 -0
  208. dcscope/img/icon-theme/breeze/actions/32/document-save.svg +18 -0
  209. dcscope/img/icon-theme/breeze/actions/32/gtk-preferences.svg +17 -0
  210. dcscope/img/icon-theme/breeze/actions/32/object-order-lower.svg +18 -0
  211. dcscope/img/icon-theme/breeze/actions/32/view-filter.svg +18 -0
  212. dcscope/img/icon-theme/breeze/actions/32/view-list-tree.svg +18 -0
  213. dcscope/img/icon-theme/breeze/places/16/folder-cloud.svg +13 -0
  214. dcscope/img/icon-theme/breeze/places/16/folder.svg +13 -0
  215. dcscope/img/icon-theme/breeze/places/22/folder-cloud.svg +13 -0
  216. dcscope/img/icon-theme/breeze/places/22/folder.svg +13 -0
  217. dcscope/img/icon-theme/breeze/places/24/folder-cloud.svg +12 -0
  218. dcscope/img/icon-theme/breeze/places/24/folder.svg +12 -0
  219. dcscope/img/icon-theme/breeze/places/32/folder-cloud.svg +35 -0
  220. dcscope/img/icon-theme/breeze/places/32/folder.svg +30 -0
  221. dcscope/img/icon-theme/breeze/places/64/folder-cloud.svg +35 -0
  222. dcscope/img/icon-theme/breeze/places/64/folder.svg +30 -0
  223. dcscope/img/icon-theme/breeze/status/16/dialog-error.svg +9 -0
  224. dcscope/img/icon-theme/breeze/status/16/dialog-information.svg +9 -0
  225. dcscope/img/icon-theme/breeze/status/16/dialog-question.svg +7 -0
  226. dcscope/img/icon-theme/breeze/status/16/dialog-warning.svg +9 -0
  227. dcscope/img/icon-theme/breeze/status/22/dialog-error.svg +9 -0
  228. dcscope/img/icon-theme/breeze/status/22/dialog-information.svg +9 -0
  229. dcscope/img/icon-theme/breeze/status/22/dialog-question.svg +7 -0
  230. dcscope/img/icon-theme/breeze/status/22/dialog-warning.svg +9 -0
  231. dcscope/img/icon-theme/breeze/status/24/dialog-error.svg +13 -0
  232. dcscope/img/icon-theme/breeze/status/24/dialog-information.svg +13 -0
  233. dcscope/img/icon-theme/breeze/status/24/dialog-question.svg +9 -0
  234. dcscope/img/icon-theme/breeze/status/24/dialog-warning.svg +1 -0
  235. dcscope/img/icon-theme/breeze/status/64/dialog-error.svg +25 -0
  236. dcscope/img/icon-theme/breeze/status/64/dialog-information.svg +25 -0
  237. dcscope/img/icon-theme/breeze/status/64/dialog-question.svg +25 -0
  238. dcscope/img/icon-theme/breeze/status/64/dialog-warning.svg +25 -0
  239. dcscope/img/icon-theme/collect_icons.py +124 -0
  240. dcscope/img/icon-theme/dcscope/dcor.png +0 -0
  241. dcscope/img/icon-theme/dcscope/edit-copy-anew.svg +13 -0
  242. dcscope/img/icon-theme/dcscope/emodulus.svg +69 -0
  243. dcscope/img/icon-theme/dcscope/filter_ray.svg +54 -0
  244. dcscope/img/icon-theme/dcscope/region_channel.svg +86 -0
  245. dcscope/img/icon-theme/dcscope/region_reservoir.svg +89 -0
  246. dcscope/img/icon-theme/dcscope/rlang.svg +108 -0
  247. dcscope/img/icon-theme/dcscope/statistical_significance.svg +106 -0
  248. dcscope/img/icon-theme/index.theme +81 -0
  249. dcscope/img/icon.png +0 -0
  250. dcscope/img/icon.svg +73 -0
  251. dcscope/img/splash.png +0 -0
  252. dcscope/meta_tool.py +143 -0
  253. dcscope/pipeline/__init__.py +5 -0
  254. dcscope/pipeline/core.py +632 -0
  255. dcscope/pipeline/dataslot.py +270 -0
  256. dcscope/pipeline/filter.py +161 -0
  257. dcscope/pipeline/filter_ray.py +170 -0
  258. dcscope/pipeline/plot.py +187 -0
  259. dcscope/plot_cache.py +79 -0
  260. dcscope/session.py +379 -0
  261. dcscope/util.py +34 -0
  262. dcscope-2.22.1.dist-info/METADATA +95 -0
  263. dcscope-2.22.1.dist-info/RECORD +267 -0
  264. dcscope-2.22.1.dist-info/WHEEL +5 -0
  265. dcscope-2.22.1.dist-info/entry_points.txt +2 -0
  266. dcscope-2.22.1.dist-info/licenses/LICENSE +621 -0
  267. dcscope-2.22.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,66 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>Form</class>
4
+ <widget class="QWidget" name="Form">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>739</width>
10
+ <height>641</height>
11
+ </rect>
12
+ </property>
13
+ <property name="sizePolicy">
14
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
15
+ <horstretch>0</horstretch>
16
+ <verstretch>0</verstretch>
17
+ </sizepolicy>
18
+ </property>
19
+ <property name="windowTitle">
20
+ <string>Form</string>
21
+ </property>
22
+ <layout class="QHBoxLayout" name="horizontalLayout">
23
+ <property name="leftMargin">
24
+ <number>0</number>
25
+ </property>
26
+ <property name="topMargin">
27
+ <number>0</number>
28
+ </property>
29
+ <property name="rightMargin">
30
+ <number>0</number>
31
+ </property>
32
+ <property name="bottomMargin">
33
+ <number>0</number>
34
+ </property>
35
+ <item>
36
+ <widget class="GraphicsLayoutWidget" name="plot_layout" native="true">
37
+ <property name="sizePolicy">
38
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
39
+ <horstretch>0</horstretch>
40
+ <verstretch>0</verstretch>
41
+ </sizepolicy>
42
+ </property>
43
+ <property name="minimumSize">
44
+ <size>
45
+ <width>200</width>
46
+ <height>100</height>
47
+ </size>
48
+ </property>
49
+ <property name="styleSheet">
50
+ <string notr="true">background-color:#FFF</string>
51
+ </property>
52
+ </widget>
53
+ </item>
54
+ </layout>
55
+ </widget>
56
+ <customwidgets>
57
+ <customwidget>
58
+ <class>GraphicsLayoutWidget</class>
59
+ <extends>QWidget</extends>
60
+ <header>pyqtgraph</header>
61
+ <container>1</container>
62
+ </customwidget>
63
+ </customwidgets>
64
+ <resources/>
65
+ <connections/>
66
+ </ui>
@@ -0,0 +1,380 @@
1
+ import os.path as os_path
2
+ import pathlib
3
+ import traceback
4
+
5
+ import importlib.resources
6
+ import platform
7
+
8
+ from dclab.rtdc_dataset.fmt_dcor import access_token
9
+ from dclab.lme4 import rsetup
10
+ from PyQt6 import uic, QtCore, QtWidgets
11
+ from PyQt6.QtCore import QStandardPaths
12
+
13
+ from .widgets import show_wait_cursor
14
+ from ..extensions import ExtensionManager, SUPPORTED_FORMATS
15
+
16
+
17
+ class ExtensionErrorWrapper:
18
+ def __init__(self, ehash):
19
+ self.ehash = ehash
20
+
21
+ def __enter__(self):
22
+ return self
23
+
24
+ def __exit__(self, exc_type, exc_val, trc):
25
+ if exc_type is not None:
26
+ QtWidgets.QMessageBox.warning(
27
+ None,
28
+ f"Loading extension {self.ehash} failed!",
29
+ f"It was not possible to load the extension {self.ehash}! "
30
+ + "You might have to install additional software:\n\n"
31
+ + traceback.format_exc(),
32
+ )
33
+ return True # do not raise the exception
34
+
35
+
36
+ class Preferences(QtWidgets.QDialog):
37
+ """Preferences dialog to interact with QSettings"""
38
+ instances = {}
39
+ feature_changed = QtCore.pyqtSignal()
40
+
41
+ def __init__(self, parent, *args, **kwargs):
42
+ super(Preferences, self).__init__(parent=parent, *args, **kwargs)
43
+ ref = importlib.resources.files("dcscope.gui") / "preferences.ui"
44
+ with importlib.resources.as_file(ref) as path_ui:
45
+ uic.loadUi(path_ui, self)
46
+ self.settings = QtCore.QSettings()
47
+ self.parent = parent
48
+
49
+ # Get default R path
50
+ if rsetup.has_r():
51
+ rdefault = str(rsetup.get_r_path())
52
+ else:
53
+ rdefault = ""
54
+
55
+ #: configuration keys, corresponding widgets, and defaults
56
+ self.config_pairs = [
57
+ ["advanced/developer mode", self.advanced_developer_mode, "0"],
58
+ ["check for updates", self.general_check_for_updates, "1"],
59
+ ["dcor/api key", self.dcor_api_key, ""],
60
+ ["dcor/servers", self.dcor_servers, ["dcor.mpl.mpg.de"]],
61
+ ["dcor/use ssl", self.dcor_use_ssl, "1"],
62
+ ["lme4/r path", self.lme4_rpath, rdefault],
63
+ ["s3/endpoint url", self.lineEdit_s3_endpoint_url, ""],
64
+ ["s3/access key id", self.lineEdit_s3_access_key_id, ""],
65
+ ["s3/secret access key", self.lineEdit_s3_secret_access_key, ""],
66
+ ]
67
+
68
+ # extensions
69
+ store_path = os_path.join(
70
+ QStandardPaths.writableLocation(
71
+ QStandardPaths.StandardLocation.AppDataLocation), "extensions")
72
+ self.extensions = ExtensionManager(store_path)
73
+
74
+ self.tabWidget.setCurrentIndex(0)
75
+ self.reload()
76
+
77
+ # signals
78
+ self.btn_apply = self.buttonBox.button(
79
+ QtWidgets.QDialogButtonBox.StandardButton.Apply)
80
+ self.btn_apply.clicked.connect(self.on_settings_apply)
81
+ self.btn_cancel = self.buttonBox.button(
82
+ QtWidgets.QDialogButtonBox.StandardButton.Cancel)
83
+ self.btn_ok = self.buttonBox.button(
84
+ QtWidgets.QDialogButtonBox.StandardButton.Ok)
85
+ self.btn_ok.clicked.connect(self.on_settings_apply)
86
+ self.btn_restore = self.buttonBox.button(
87
+ QtWidgets.QDialogButtonBox.StandardButton.RestoreDefaults)
88
+ self.btn_restore.clicked.connect(self.on_settings_restore)
89
+ # DCOR
90
+ self.pushButton_enc_token.clicked.connect(self.on_dcor_enc_token)
91
+ # extension buttons
92
+ self.checkBox_ext_enabled.clicked.connect(self.on_ext_enabled)
93
+ self.pushButton_ext_load.clicked.connect(self.on_ext_load)
94
+ self.pushButton_ext_remove.clicked.connect(self.on_ext_remove)
95
+ self.listWidget_ext.currentRowChanged.connect(self.on_ext_selected)
96
+ self.listWidget_ext.itemChanged.connect(self.on_ext_modified)
97
+ # lme4 buttons
98
+ self.pushButton_lme4_install.clicked.connect(self.on_lme4_install)
99
+ self.pushButton_lme4_search.clicked.connect(self.on_lme4_search_r)
100
+ # tab changed
101
+ self.tabWidget.currentChanged.connect(self.on_tab_changed)
102
+
103
+ def reload(self):
104
+ """Read configuration or set default parameters"""
105
+ for key, widget, default in self.config_pairs:
106
+ value = self.settings.value(key, default)
107
+ value = value or default
108
+ if isinstance(widget, QtWidgets.QCheckBox):
109
+ widget.setChecked(bool(int(value)))
110
+ elif isinstance(widget, QtWidgets.QLineEdit):
111
+ widget.setText(value)
112
+ elif widget is self.dcor_servers:
113
+ self.dcor_servers.clear()
114
+ self.dcor_servers.addItems(value)
115
+ self.dcor_servers.setCurrentIndex(0)
116
+ else:
117
+ raise NotImplementedError("No rule for '{}'".format(key))
118
+
119
+ # peculiarities of developer mode
120
+ devmode = bool(int(self.settings.value("advanced/developer mode", 0)))
121
+ self.dcor_use_ssl.setVisible(devmode) # show "use ssl" in dev mode
122
+
123
+ if self.tabWidget.currentWidget() is self.tab_r:
124
+ self.reload_lme4()
125
+
126
+ self.reload_ext()
127
+
128
+ def reload_ext(self):
129
+ """Reload the list of extensions"""
130
+ # extensions
131
+ row = self.listWidget_ext.currentRow()
132
+ self.listWidget_ext.blockSignals(True)
133
+ self.listWidget_ext.clear()
134
+ have_extensions = bool(self.extensions)
135
+ self.widget_ext_controls.setVisible(have_extensions)
136
+ if have_extensions:
137
+ for ii, ext in enumerate(self.extensions):
138
+ lwitem = QtWidgets.QListWidgetItem(ext.title,
139
+ self.listWidget_ext)
140
+ lwitem.setFlags(QtCore.Qt.ItemFlag.ItemIsEditable
141
+ | QtCore.Qt.ItemFlag.ItemIsSelectable
142
+ | QtCore.Qt.ItemFlag.ItemIsEnabled
143
+ | QtCore.Qt.ItemFlag.ItemIsUserCheckable)
144
+ lwitem.setCheckState(QtCore.Qt.CheckState.Checked
145
+ if ext.enabled
146
+ else QtCore.Qt.CheckState.UnChecked)
147
+ lwitem.setData(100, ext.hash)
148
+ self.listWidget_ext.setCurrentRow(0)
149
+ if row + 1 > self.listWidget_ext.count() or row < 0:
150
+ row = 0
151
+ self.listWidget_ext.setCurrentRow(row)
152
+ self.listWidget_ext.blockSignals(False)
153
+ self.on_ext_selected()
154
+
155
+ @show_wait_cursor
156
+ def reload_lme4(self, install=False):
157
+ """Reload information about lme4, optionally installing it"""
158
+ # Before we do anything, we have to find a persistent writable
159
+ # location where we can install lme4 and set the environment variable
160
+ # R_LIBS_USER accordingly.
161
+ r_libs_user = self.settings.value("lme4/r libs user", None)
162
+ if r_libs_user is None or not pathlib.Path(r_libs_user).exists():
163
+ r_libs_user = pathlib.Path(
164
+ QStandardPaths.writableLocation(
165
+ QStandardPaths.StandardLocation.AppLocalDataLocation)
166
+ ) / "r-libs"
167
+ r_libs_user.mkdir(parents=True, exist_ok=True)
168
+ r_libs_user = str(r_libs_user)
169
+ self.settings.setValue("lme4/r libs user", r_libs_user)
170
+ rsetup.set_r_lib_path(r_libs_user)
171
+
172
+ # set the binary
173
+ binary = self.lme4_rpath.text()
174
+ if pathlib.Path(binary).is_file():
175
+ rsetup.set_r_path(binary)
176
+
177
+ # enable/disable lme4-install button
178
+ self.pushButton_lme4_install.setEnabled(rsetup.has_r())
179
+
180
+ # check lme4 package status
181
+ if not rsetup.has_r():
182
+ r_version = "unknown"
183
+ lme4_st = "unknown"
184
+ else:
185
+ r_version = rsetup.get_r_version()
186
+ if rsetup.has_lme4():
187
+ lme4_st = "installed"
188
+ else:
189
+ lme4_st = "not installed"
190
+
191
+ if install and lme4_st == "not installed":
192
+ self.setEnabled(False)
193
+ rsetup.require_lme4()
194
+ self.setEnabled(True)
195
+ # update interface with installed lme4
196
+ self.reload_lme4(install=False)
197
+ else:
198
+ # update user interface
199
+ self.pushButton_lme4_install.setVisible(lme4_st == "not installed")
200
+ self.label_r_version.setText(r_version)
201
+ self.label_lme4_installed.setText(lme4_st)
202
+
203
+ @QtCore.pyqtSlot()
204
+ def on_dcor_enc_token(self):
205
+ """Load an encrypted DCOR access token and store the certificate"""
206
+ # get path
207
+ path, _ = QtWidgets.QFileDialog.getOpenFileName(
208
+ parent=self,
209
+ caption="SSpecify encrypted DCOR access token",
210
+ directory=self.settings.value("paths/encrypted access token", ""),
211
+ filter="DCOR access token (*.dcor-access)")
212
+ if not path:
213
+ return
214
+ path = pathlib.Path(path)
215
+ self.settings.setValue("paths/encrypted access token",
216
+ str(path.parent))
217
+ # get password
218
+ pwd, cont = QtWidgets.QInputDialog.getText(
219
+ self,
220
+ "Password required",
221
+ f"Please enter the encryption password for {path.name}!",
222
+ QtWidgets.QLineEdit.EchoMode.Password)
223
+ pwd = pwd.strip()
224
+ if not pwd or not cont:
225
+ return
226
+ # get info
227
+ host = access_token.get_hostname(path, pwd)
228
+ api_key = access_token.get_api_key(path, pwd)
229
+ cert = access_token.get_certificate(path, pwd)
230
+ # write certificate to our global DCscope certs directory
231
+ ca_path = pathlib.Path(
232
+ QStandardPaths.writableLocation(
233
+ QStandardPaths.StandardLocation.AppDataLocation)
234
+ ) / "certificates"
235
+ (ca_path / f"{host}.cert").write_bytes(cert)
236
+ # store other metadata
237
+ self.settings.setValue("dcor/api key", api_key)
238
+
239
+ servers = self.settings.value("dcor/servers", ["dcor.mpl.mpg.de"])
240
+ if host in servers:
241
+ servers.remove(host)
242
+ servers.insert(0, host.strip("/"))
243
+ self.settings.setValue("dcor/servers", servers)
244
+ self.reload()
245
+
246
+ @QtCore.pyqtSlot(bool)
247
+ def on_ext_enabled(self, enabled):
248
+ """Enable or disable an extension (signal from checkbox widget)"""
249
+ item = self.listWidget_ext.currentItem()
250
+ ehash = item.data(100)
251
+ with ExtensionErrorWrapper(ehash):
252
+ self.extensions.extension_set_enabled(ehash, enabled)
253
+ self.reload_ext()
254
+ self.feature_changed.emit()
255
+
256
+ @QtCore.pyqtSlot()
257
+ def on_ext_load(self):
258
+ """Load an extension from the file system"""
259
+ format_string = " ".join(f"*{su}" for su in SUPPORTED_FORMATS)
260
+ paths, _ = QtWidgets.QFileDialog.getOpenFileNames(
261
+ parent=self,
262
+ caption="Select an extension file",
263
+ directory=self.settings.value("paths/extension", ""),
264
+ filter=f"Supported extension files ({format_string})")
265
+ if paths:
266
+ for pp in paths:
267
+ with ExtensionErrorWrapper(pp):
268
+ self.extensions.import_extension_from_path(pp)
269
+ self.reload_ext()
270
+ self.feature_changed.emit()
271
+
272
+ @QtCore.pyqtSlot()
273
+ def on_ext_remove(self):
274
+ """Remove an extension"""
275
+ ehash = self.listWidget_ext.currentItem().data(100)
276
+ self.extensions.extension_remove(ehash)
277
+ self.reload_ext()
278
+ self.feature_changed.emit()
279
+
280
+ @QtCore.pyqtSlot(QtWidgets.QListWidgetItem)
281
+ def on_ext_modified(self, item):
282
+ """Enable or disable an extension (signal from listWidget)"""
283
+ ehash = item.data(100)
284
+ enabled = bool(item.checkState())
285
+ with ExtensionErrorWrapper(ehash):
286
+ self.extensions.extension_set_enabled(ehash, enabled)
287
+ self.listWidget_ext.setCurrentItem(item)
288
+ self.reload_ext()
289
+ self.feature_changed.emit()
290
+
291
+ @QtCore.pyqtSlot()
292
+ def on_ext_selected(self):
293
+ """Display details for an extension (signal from listWidget)"""
294
+ item = self.listWidget_ext.currentItem()
295
+ if item is not None:
296
+ ehash = item.data(100)
297
+ ext = self.extensions[ehash]
298
+ self.checkBox_ext_enabled.blockSignals(True)
299
+ self.checkBox_ext_enabled.setChecked(ext.enabled)
300
+ self.checkBox_ext_enabled.blockSignals(False)
301
+ with ExtensionErrorWrapper(ehash):
302
+ if ext.enabled: # only load the extension if enabled
303
+ ext.load()
304
+ self.label_ext_name.setText(ext.title)
305
+ item.setText(ext.title)
306
+ self.label_ext_description.setText(ext.description)
307
+
308
+ @QtCore.pyqtSlot()
309
+ def on_lme4_install(self):
310
+ self.reload_lme4(install=True)
311
+
312
+ @QtCore.pyqtSlot()
313
+ def on_lme4_search_r(self):
314
+ if platform.system() == "Windows":
315
+ filters = "R executable (R.exe)"
316
+ else:
317
+ filters = "R executable (R)"
318
+ path, _ = QtWidgets.QFileDialog.getOpenFileName(
319
+ self, "Executable", ".", filters)
320
+ if path:
321
+ self.lme4_rpath.setText(path)
322
+
323
+ @QtCore.pyqtSlot()
324
+ def on_settings_apply(self):
325
+ """Save current changes made in UI to settings and reload UI"""
326
+ for key, widget, default in self.config_pairs:
327
+ if isinstance(widget, QtWidgets.QCheckBox):
328
+ value = int(widget.isChecked())
329
+ if key == "advanced/developer mode":
330
+ devmode = int(self.settings.value(
331
+ "advanced/developer mode", 0))
332
+ if devmode != value:
333
+ msg = QtWidgets.QMessageBox()
334
+ msg.setIcon(QtWidgets.QMessageBox.Icon.Information)
335
+ msg.setText("Please restart DCscope for the changes "
336
+ + "to take effect.")
337
+ msg.setWindowTitle("Restart DCscope")
338
+ msg.exec()
339
+ elif isinstance(widget, QtWidgets.QLineEdit):
340
+ value = widget.text().strip()
341
+ elif widget is self.dcor_servers:
342
+ curtext = self.dcor_servers.currentText()
343
+ items = self.settings.value(key, default)
344
+ if curtext in items:
345
+ # We do it again below to be on the safe side
346
+ items.remove(curtext)
347
+ for bad_start in ["https://", "http://"]:
348
+ if curtext.startswith(bad_start):
349
+ curtext = curtext[len(bad_start):]
350
+ if curtext in items:
351
+ # We do it again with the stripped version
352
+ items.remove(curtext)
353
+ items.insert(0, curtext)
354
+ value = items
355
+ else:
356
+ raise NotImplementedError("No rule for '{}'".format(key))
357
+ self.settings.setValue(key, value)
358
+
359
+ # reload UI to give visual feedback
360
+ self.reload()
361
+
362
+ @QtCore.pyqtSlot()
363
+ def on_settings_restore(self):
364
+ self.settings.clear()
365
+ self.reload()
366
+
367
+ @QtCore.pyqtSlot()
368
+ def on_tab_changed(self):
369
+ if self.tabWidget.currentWidget() is self.tab_extensions:
370
+ # Managing extensions has nothing to do with other settings.
371
+ enabled = False
372
+ else:
373
+ enabled = True
374
+
375
+ if self.tabWidget.currentWidget() is self.tab_r:
376
+ self.reload_lme4()
377
+
378
+ self.btn_apply.setEnabled(enabled)
379
+ self.btn_cancel.setEnabled(enabled)
380
+ self.btn_restore.setEnabled(enabled)