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.
- dcscope/__init__.py +17 -0
- dcscope/__main__.py +44 -0
- dcscope/_version.py +21 -0
- dcscope/extensions.py +250 -0
- dcscope/gui/__init__.py +2 -0
- dcscope/gui/analysis/__init__.py +10 -0
- dcscope/gui/analysis/ana_basins.py +110 -0
- dcscope/gui/analysis/ana_basins.ui +143 -0
- dcscope/gui/analysis/ana_filter.py +341 -0
- dcscope/gui/analysis/ana_filter.ui +364 -0
- dcscope/gui/analysis/ana_log.py +122 -0
- dcscope/gui/analysis/ana_log.ui +100 -0
- dcscope/gui/analysis/ana_meta.py +207 -0
- dcscope/gui/analysis/ana_meta.ui +141 -0
- dcscope/gui/analysis/ana_plot.py +638 -0
- dcscope/gui/analysis/ana_plot.ui +1060 -0
- dcscope/gui/analysis/ana_slot.py +504 -0
- dcscope/gui/analysis/ana_slot.ui +684 -0
- dcscope/gui/analysis/ana_tables.py +227 -0
- dcscope/gui/analysis/ana_tables.ui +195 -0
- dcscope/gui/analysis/ana_view.py +69 -0
- dcscope/gui/analysis/ana_view.ui +269 -0
- dcscope/gui/analysis/dlg_slot_reorder.py +55 -0
- dcscope/gui/analysis/dlg_slot_reorder.ui +138 -0
- dcscope/gui/bulk/__init__.py +2 -0
- dcscope/gui/bulk/bulk_emodulus.py +200 -0
- dcscope/gui/bulk/bulk_emodulus.ui +245 -0
- dcscope/gui/compute/__init__.py +3 -0
- dcscope/gui/compute/comp_lme4.py +115 -0
- dcscope/gui/compute/comp_lme4.ui +194 -0
- dcscope/gui/compute/comp_lme4_dataset.py +51 -0
- dcscope/gui/compute/comp_lme4_dataset.ui +92 -0
- dcscope/gui/compute/comp_lme4_results.py +120 -0
- dcscope/gui/compute/comp_lme4_results.ui +268 -0
- dcscope/gui/compute/comp_stats.py +223 -0
- dcscope/gui/compute/comp_stats.ui +187 -0
- dcscope/gui/dcor/__init__.py +304 -0
- dcscope/gui/dcor/dcor.ui +118 -0
- dcscope/gui/export/__init__.py +3 -0
- dcscope/gui/export/e2data.py +394 -0
- dcscope/gui/export/e2data.ui +367 -0
- dcscope/gui/export/e2filter.py +76 -0
- dcscope/gui/export/e2filter.ui +111 -0
- dcscope/gui/export/e2plot.py +94 -0
- dcscope/gui/export/e2plot.ui +175 -0
- dcscope/gui/main.py +1089 -0
- dcscope/gui/main.ui +579 -0
- dcscope/gui/matrix/__init__.py +4 -0
- dcscope/gui/matrix/block_matrix.py +141 -0
- dcscope/gui/matrix/block_matrix.ui +207 -0
- dcscope/gui/matrix/data_matrix.py +574 -0
- dcscope/gui/matrix/dm_dataset.py +116 -0
- dcscope/gui/matrix/dm_dataset.ui +348 -0
- dcscope/gui/matrix/dm_element.py +111 -0
- dcscope/gui/matrix/dm_element.ui +169 -0
- dcscope/gui/matrix/dm_filter.py +115 -0
- dcscope/gui/matrix/dm_filter.ui +287 -0
- dcscope/gui/matrix/plot_matrix.py +316 -0
- dcscope/gui/matrix/pm_element.py +39 -0
- dcscope/gui/matrix/pm_plot.py +86 -0
- dcscope/gui/matrix/pm_plot.ui +249 -0
- dcscope/gui/pipeline_plot.py +797 -0
- dcscope/gui/pipeline_plot.ui +66 -0
- dcscope/gui/preferences.py +380 -0
- dcscope/gui/preferences.ui +554 -0
- dcscope/gui/quick_view/__init__.py +1 -0
- dcscope/gui/quick_view/qv_main.py +1072 -0
- dcscope/gui/quick_view/qv_main.ui +1297 -0
- dcscope/gui/quick_view/qv_scatter.py +284 -0
- dcscope/gui/quick_view/qv_style.css +10 -0
- dcscope/gui/update.py +90 -0
- dcscope/gui/widgets/__init__.py +15 -0
- dcscope/gui/widgets/bg_thread.py +29 -0
- dcscope/gui/widgets/bulk_list.py +79 -0
- dcscope/gui/widgets/bulk_list.ui +95 -0
- dcscope/gui/widgets/double_spin_box_nan.py +75 -0
- dcscope/gui/widgets/feature_combobox.py +140 -0
- dcscope/gui/widgets/get_path.py +42 -0
- dcscope/gui/widgets/key_value_table_widget.css +12 -0
- dcscope/gui/widgets/key_value_table_widget.py +75 -0
- dcscope/gui/widgets/mdi_subwindow_wo_close.py +12 -0
- dcscope/gui/widgets/qrangeslider.py +262 -0
- dcscope/gui/widgets/rangecontrol.py +308 -0
- dcscope/gui/widgets/rangecontrol.ui +136 -0
- dcscope/gui/widgets/simple_image_view.py +55 -0
- dcscope/gui/widgets/simple_plot_widget.py +113 -0
- dcscope/gui/widgets/so_colorbaritem.py +29 -0
- dcscope/gui/widgets/wait_cursor.py +33 -0
- dcscope/idiom.py +26 -0
- dcscope/img/__init__.py +2 -0
- dcscope/img/icon-theme/breeze/COPYING-ICONS +209 -0
- dcscope/img/icon-theme/breeze/COPYING.LIB +510 -0
- dcscope/img/icon-theme/breeze/README +5 -0
- dcscope/img/icon-theme/breeze/actions/16/application-exit.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/16/code-context.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-cancel.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-close.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-messages.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-ok-apply.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/dialog-ok.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/document-open-folder.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/document-open.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/document-save.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/documentinfo.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/16/draw-watercolor.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/edit-clear-all.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/edit-clear.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/edit-paste.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/globe.svg +16 -0
- dcscope/img/icon-theme/breeze/actions/16/gtk-preferences.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/list-add.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/messagebox_warning.svg +20 -0
- dcscope/img/icon-theme/breeze/actions/16/object-columns.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/object-order-lower.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/object-rows.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/office-chart-line-stacked.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/office-chart-ring.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/office-chart-scatter.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/path-mode-polyline.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/preferences-activities.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/remove.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/16/search.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/show-grid.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/special_paste.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/tools-wizard.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/view-calendar-list.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/view-filter.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/view-list-tree.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/view-statistics.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/16/visibility.svg +21 -0
- dcscope/img/icon-theme/breeze/actions/22/application-exit.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/22/code-context.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-cancel.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-close.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-messages.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-ok-apply.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/dialog-ok.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/document-open-folder.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/document-open.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/document-save.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/documentinfo.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/draw-watercolor.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/edit-clear-all.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/edit-clear.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/edit-paste.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/globe.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/22/gtk-preferences.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/22/list-add.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/messagebox_warning.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/object-columns.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/object-order-lower.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/object-rows.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/office-chart-line-stacked.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/office-chart-ring.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/office-chart-scatter.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/path-mode-polyline.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/22/preferences-activities.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/remove.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/22/special_paste.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/tools-wizard.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/view-calendar-list.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/view-filter.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/view-list-tree.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/view-statistics.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/22/visibility.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/application-exit.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/code-context.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-cancel.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-close.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-messages.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-ok-apply.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/dialog-ok.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/document-open-folder.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/document-open.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/document-save.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/documentinfo.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/draw-watercolor.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/edit-clear-all.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/edit-clear.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/edit-paste.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/globe.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/24/gtk-preferences.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/24/list-add.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/messagebox_warning.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/24/object-columns.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/object-order-lower.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/object-rows.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/office-chart-line-stacked.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/office-chart-ring.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/office-chart-scatter.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/path-mode-polyline.svg +15 -0
- dcscope/img/icon-theme/breeze/actions/24/preferences-activities.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/24/remove.svg +10 -0
- dcscope/img/icon-theme/breeze/actions/24/special_paste.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/tools-wizard.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/view-calendar-list.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/view-filter.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/view-list-tree.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/view-statistics.svg +12 -0
- dcscope/img/icon-theme/breeze/actions/24/visibility.svg +14 -0
- dcscope/img/icon-theme/breeze/actions/32/application-exit.svg +8 -0
- dcscope/img/icon-theme/breeze/actions/32/dialog-cancel.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/32/dialog-messages.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/32/dialog-ok-apply.svg +1 -0
- dcscope/img/icon-theme/breeze/actions/32/dialog-ok.svg +1 -0
- dcscope/img/icon-theme/breeze/actions/32/document-open-folder.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/32/document-open.svg +13 -0
- dcscope/img/icon-theme/breeze/actions/32/document-save.svg +18 -0
- dcscope/img/icon-theme/breeze/actions/32/gtk-preferences.svg +17 -0
- dcscope/img/icon-theme/breeze/actions/32/object-order-lower.svg +18 -0
- dcscope/img/icon-theme/breeze/actions/32/view-filter.svg +18 -0
- dcscope/img/icon-theme/breeze/actions/32/view-list-tree.svg +18 -0
- dcscope/img/icon-theme/breeze/places/16/folder-cloud.svg +13 -0
- dcscope/img/icon-theme/breeze/places/16/folder.svg +13 -0
- dcscope/img/icon-theme/breeze/places/22/folder-cloud.svg +13 -0
- dcscope/img/icon-theme/breeze/places/22/folder.svg +13 -0
- dcscope/img/icon-theme/breeze/places/24/folder-cloud.svg +12 -0
- dcscope/img/icon-theme/breeze/places/24/folder.svg +12 -0
- dcscope/img/icon-theme/breeze/places/32/folder-cloud.svg +35 -0
- dcscope/img/icon-theme/breeze/places/32/folder.svg +30 -0
- dcscope/img/icon-theme/breeze/places/64/folder-cloud.svg +35 -0
- dcscope/img/icon-theme/breeze/places/64/folder.svg +30 -0
- dcscope/img/icon-theme/breeze/status/16/dialog-error.svg +9 -0
- dcscope/img/icon-theme/breeze/status/16/dialog-information.svg +9 -0
- dcscope/img/icon-theme/breeze/status/16/dialog-question.svg +7 -0
- dcscope/img/icon-theme/breeze/status/16/dialog-warning.svg +9 -0
- dcscope/img/icon-theme/breeze/status/22/dialog-error.svg +9 -0
- dcscope/img/icon-theme/breeze/status/22/dialog-information.svg +9 -0
- dcscope/img/icon-theme/breeze/status/22/dialog-question.svg +7 -0
- dcscope/img/icon-theme/breeze/status/22/dialog-warning.svg +9 -0
- dcscope/img/icon-theme/breeze/status/24/dialog-error.svg +13 -0
- dcscope/img/icon-theme/breeze/status/24/dialog-information.svg +13 -0
- dcscope/img/icon-theme/breeze/status/24/dialog-question.svg +9 -0
- dcscope/img/icon-theme/breeze/status/24/dialog-warning.svg +1 -0
- dcscope/img/icon-theme/breeze/status/64/dialog-error.svg +25 -0
- dcscope/img/icon-theme/breeze/status/64/dialog-information.svg +25 -0
- dcscope/img/icon-theme/breeze/status/64/dialog-question.svg +25 -0
- dcscope/img/icon-theme/breeze/status/64/dialog-warning.svg +25 -0
- dcscope/img/icon-theme/collect_icons.py +124 -0
- dcscope/img/icon-theme/dcscope/dcor.png +0 -0
- dcscope/img/icon-theme/dcscope/edit-copy-anew.svg +13 -0
- dcscope/img/icon-theme/dcscope/emodulus.svg +69 -0
- dcscope/img/icon-theme/dcscope/filter_ray.svg +54 -0
- dcscope/img/icon-theme/dcscope/region_channel.svg +86 -0
- dcscope/img/icon-theme/dcscope/region_reservoir.svg +89 -0
- dcscope/img/icon-theme/dcscope/rlang.svg +108 -0
- dcscope/img/icon-theme/dcscope/statistical_significance.svg +106 -0
- dcscope/img/icon-theme/index.theme +81 -0
- dcscope/img/icon.png +0 -0
- dcscope/img/icon.svg +73 -0
- dcscope/img/splash.png +0 -0
- dcscope/meta_tool.py +143 -0
- dcscope/pipeline/__init__.py +5 -0
- dcscope/pipeline/core.py +632 -0
- dcscope/pipeline/dataslot.py +270 -0
- dcscope/pipeline/filter.py +161 -0
- dcscope/pipeline/filter_ray.py +170 -0
- dcscope/pipeline/plot.py +187 -0
- dcscope/plot_cache.py +79 -0
- dcscope/session.py +379 -0
- dcscope/util.py +34 -0
- dcscope-2.22.1.dist-info/METADATA +95 -0
- dcscope-2.22.1.dist-info/RECORD +267 -0
- dcscope-2.22.1.dist-info/WHEEL +5 -0
- dcscope-2.22.1.dist-info/entry_points.txt +2 -0
- dcscope-2.22.1.dist-info/licenses/LICENSE +621 -0
- dcscope-2.22.1.dist-info/top_level.txt +1 -0
dcscope/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""GUI for analysis and visualization of deformability cytometry datasets
|
|
2
|
+
Copyright (C) 2019 Paul Müller
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify it
|
|
5
|
+
under the terms of the GNU General Public License as published by the
|
|
6
|
+
Free Software Foundation, either version 3 of the License, or (at your
|
|
7
|
+
option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful, but
|
|
10
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
11
|
+
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12
|
+
for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License along
|
|
15
|
+
with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
"""
|
|
17
|
+
from ._version import version as __version__ # noqa: F401
|
dcscope/__main__.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
def main(splash=True):
|
|
2
|
+
import importlib.resources
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from PyQt6.QtWidgets import QApplication
|
|
6
|
+
from PyQt6.QtCore import QEventLoop
|
|
7
|
+
# import before creating application
|
|
8
|
+
import pyqtgraph # noqa: F401
|
|
9
|
+
|
|
10
|
+
app = QApplication(sys.argv)
|
|
11
|
+
|
|
12
|
+
if splash:
|
|
13
|
+
from PyQt6.QtWidgets import QSplashScreen
|
|
14
|
+
from PyQt6.QtGui import QPixmap
|
|
15
|
+
ref = importlib.resources.files("dcscope.img") / "splash.png"
|
|
16
|
+
with importlib.resources.as_file(ref) as splash_path:
|
|
17
|
+
splash_pix = QPixmap(str(splash_path))
|
|
18
|
+
splash = QSplashScreen(splash_pix)
|
|
19
|
+
splash.setMask(splash_pix.mask())
|
|
20
|
+
splash.show()
|
|
21
|
+
# make sure Qt really displays the splash screen
|
|
22
|
+
app.processEvents(QEventLoop.ProcessEventsFlag.AllEvents, 300)
|
|
23
|
+
|
|
24
|
+
from PyQt6 import QtCore, QtGui
|
|
25
|
+
from .gui import DCscope
|
|
26
|
+
|
|
27
|
+
# Set Application Icon
|
|
28
|
+
ref = importlib.resources.files("dcscope.img") / "icon.png"
|
|
29
|
+
with importlib.resources.as_file(ref) as icon_path:
|
|
30
|
+
app.setWindowIcon(QtGui.QIcon(str(icon_path)))
|
|
31
|
+
|
|
32
|
+
# Use dots as decimal separators
|
|
33
|
+
QtCore.QLocale.setDefault(QtCore.QLocale(QtCore.QLocale.Language.C))
|
|
34
|
+
|
|
35
|
+
window = DCscope(*app.arguments()[1:])
|
|
36
|
+
|
|
37
|
+
if splash:
|
|
38
|
+
splash.finish(window)
|
|
39
|
+
|
|
40
|
+
sys.exit(app.exec())
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
main()
|
dcscope/_version.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
5
|
+
|
|
6
|
+
TYPE_CHECKING = False
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
11
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
12
|
+
else:
|
|
13
|
+
VERSION_TUPLE = object
|
|
14
|
+
|
|
15
|
+
version: str
|
|
16
|
+
__version__: str
|
|
17
|
+
__version_tuple__: VERSION_TUPLE
|
|
18
|
+
version_tuple: VERSION_TUPLE
|
|
19
|
+
|
|
20
|
+
__version__ = version = '2.22.1'
|
|
21
|
+
__version_tuple__ = version_tuple = (2, 22, 1)
|
dcscope/extensions.py
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import collections
|
|
2
|
+
import functools
|
|
3
|
+
import pathlib
|
|
4
|
+
import shutil
|
|
5
|
+
|
|
6
|
+
from dclab.util import hashfile
|
|
7
|
+
from dclab.rtdc_dataset.feat_anc_plugin import plugin_feature
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
SUPPORTED_FORMATS = [
|
|
11
|
+
".py",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ExtensionManager:
|
|
16
|
+
def __init__(self, store_path):
|
|
17
|
+
"""Extension manager
|
|
18
|
+
|
|
19
|
+
This class can be used to maintain a set of extensions
|
|
20
|
+
(plugin features or machine-learning features) at a
|
|
21
|
+
specific location `store_path` on the file system.
|
|
22
|
+
|
|
23
|
+
All extensions are loaded during instantiation. It is
|
|
24
|
+
possible to disable individual extensions (without
|
|
25
|
+
deleting them) on-the-fly.
|
|
26
|
+
"""
|
|
27
|
+
self.store_path = pathlib.Path(store_path)
|
|
28
|
+
self.store_path.mkdir(exist_ok=True, parents=True)
|
|
29
|
+
self.extension_hash_dict = collections.OrderedDict()
|
|
30
|
+
self.load_extensions_from_store()
|
|
31
|
+
|
|
32
|
+
def __contains__(self, key):
|
|
33
|
+
if isinstance(key, Extension):
|
|
34
|
+
key = key.hash
|
|
35
|
+
return key in self.extension_hash_dict
|
|
36
|
+
|
|
37
|
+
def __getitem__(self, key):
|
|
38
|
+
return self.get_extension_or_bust(key)
|
|
39
|
+
|
|
40
|
+
def __iter__(self):
|
|
41
|
+
for ahash in self.extension_hash_dict:
|
|
42
|
+
yield self.extension_hash_dict[ahash]
|
|
43
|
+
|
|
44
|
+
def __len__(self):
|
|
45
|
+
return len(self.extension_hash_dict)
|
|
46
|
+
|
|
47
|
+
def get_extension_or_bust(self, ext):
|
|
48
|
+
"""Return an Extension instance or raise ValueError
|
|
49
|
+
|
|
50
|
+
Parameter `ext` can be an instance of Extension, an
|
|
51
|
+
extension hash, or an index. If an Extension or a
|
|
52
|
+
hash is provided, this function checks whether the
|
|
53
|
+
extension is maintained by this manager and returns
|
|
54
|
+
the correct instance.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
ext: Extension
|
|
59
|
+
Extension instance
|
|
60
|
+
"""
|
|
61
|
+
if isinstance(ext, Extension):
|
|
62
|
+
the_hash = ext.hash
|
|
63
|
+
elif isinstance(ext, int):
|
|
64
|
+
the_hash = list(self.extension_hash_dict.keys())[ext]
|
|
65
|
+
else:
|
|
66
|
+
the_hash = ext
|
|
67
|
+
if the_hash in self.extension_hash_dict:
|
|
68
|
+
return self.extension_hash_dict[the_hash]
|
|
69
|
+
else:
|
|
70
|
+
raise ValueError(f"Extension not in {self.store_path}: {the_hash}")
|
|
71
|
+
|
|
72
|
+
def import_extension_from_path(self, path):
|
|
73
|
+
"""Import an extension file to `self.store_path`"""
|
|
74
|
+
ext = Extension(path)
|
|
75
|
+
if ext.hash not in self.extension_hash_dict:
|
|
76
|
+
new_name = f"ext_{ext.type}_{ext.hash}{ext.suffix}"
|
|
77
|
+
new_path = self.store_path / new_name
|
|
78
|
+
shutil.copy2(path, new_path)
|
|
79
|
+
ext.path = new_path
|
|
80
|
+
self.extension_load(ext)
|
|
81
|
+
return ext
|
|
82
|
+
|
|
83
|
+
def load_extensions_from_store(self):
|
|
84
|
+
"""Load all extensions from `self.store_path`
|
|
85
|
+
|
|
86
|
+
This function is called during initialization.
|
|
87
|
+
"""
|
|
88
|
+
failed = []
|
|
89
|
+
# load all (enabled) extensions
|
|
90
|
+
for pp in self.store_path.glob("ext_*"):
|
|
91
|
+
if pp.suffix in SUPPORTED_FORMATS:
|
|
92
|
+
ext = Extension(pp)
|
|
93
|
+
try:
|
|
94
|
+
self.extension_load(ext)
|
|
95
|
+
except BaseException:
|
|
96
|
+
failed.append(ext)
|
|
97
|
+
if failed:
|
|
98
|
+
raise ValueError(f"Could not load these extensions: {failed}")
|
|
99
|
+
|
|
100
|
+
def extension_load(self, ext):
|
|
101
|
+
"""Load a single extension
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
ext: Extension
|
|
106
|
+
Extension instance
|
|
107
|
+
"""
|
|
108
|
+
# add to hash dict first in case it gets disabled
|
|
109
|
+
self.extension_hash_dict[ext.hash] = ext
|
|
110
|
+
ext.load()
|
|
111
|
+
|
|
112
|
+
def extension_remove(self, ext):
|
|
113
|
+
"""Remove an extension from `self.store_path` and unload it
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
ext: Extension or str or int
|
|
118
|
+
Extension instance, its hash or its index in
|
|
119
|
+
ExtensionManager
|
|
120
|
+
"""
|
|
121
|
+
ext = self.get_extension_or_bust(ext)
|
|
122
|
+
self.extension_hash_dict.pop(ext.hash)
|
|
123
|
+
# re-instantiate ext to get the path right
|
|
124
|
+
ext.destroy()
|
|
125
|
+
|
|
126
|
+
def extension_set_enabled(self, ext, enabled):
|
|
127
|
+
"""Enable or disable an extension
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
ext: Extension or str or int
|
|
132
|
+
Extension instance, its hash or its index in
|
|
133
|
+
ExtensionManager
|
|
134
|
+
enabled: bool
|
|
135
|
+
Whether to enable the extension.
|
|
136
|
+
"""
|
|
137
|
+
ext = self.get_extension_or_bust(ext)
|
|
138
|
+
ext.set_enabled(enabled)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class Extension:
|
|
142
|
+
def __init__(self, path):
|
|
143
|
+
"""Helper class for managing individual extensions"""
|
|
144
|
+
self.path = pathlib.Path(path)
|
|
145
|
+
self.suffix = self.path.suffix
|
|
146
|
+
|
|
147
|
+
def __repr__(self):
|
|
148
|
+
return f"<DCscope Extension {self.path} at {hex(id(self))}>"
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def description(self):
|
|
152
|
+
"""Description of the extension"""
|
|
153
|
+
description = "No description provided."
|
|
154
|
+
if self.loaded:
|
|
155
|
+
if self.type == "feat_anc_plugin":
|
|
156
|
+
pfinst = self.get_plugin_feature_instances()[0]
|
|
157
|
+
info = pfinst.plugin_feature_info
|
|
158
|
+
description = info['long description']
|
|
159
|
+
return description
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def enabled(self):
|
|
163
|
+
"""Whether the extension is enabled"""
|
|
164
|
+
return not self.path_lock_disabled.exists()
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
@functools.lru_cache()
|
|
168
|
+
def hash(self):
|
|
169
|
+
"""MD5 hash of the extension"""
|
|
170
|
+
return hashfile(self.path)
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def loaded(self):
|
|
174
|
+
"""Whether the extension is currently loaded"""
|
|
175
|
+
if self.type == "feat_anc_plugin":
|
|
176
|
+
return bool(self.get_plugin_feature_instances())
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def path_lock_disabled(self):
|
|
180
|
+
return self.path.with_name(self.path.name + "_disabled")
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def title(self):
|
|
184
|
+
"""Descriptive title including version of the extension"""
|
|
185
|
+
title = self.path.name # fallback
|
|
186
|
+
if self.loaded:
|
|
187
|
+
if self.type == "feat_anc_plugin":
|
|
188
|
+
pfinst = self.get_plugin_feature_instances()[0]
|
|
189
|
+
info = pfinst.plugin_feature_info
|
|
190
|
+
title = f"{info['description']} " \
|
|
191
|
+
+ f"({info['version']}-{info['identifier'][:4]})"
|
|
192
|
+
return title
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
@functools.lru_cache()
|
|
196
|
+
def type(self):
|
|
197
|
+
"""Type of the extension (e.g. "feat_anc_plugin")"""
|
|
198
|
+
if self.path.suffix == ".py":
|
|
199
|
+
return "feat_anc_plugin"
|
|
200
|
+
else:
|
|
201
|
+
raise ValueError(f"Cannot determine extension type: {self.path}!")
|
|
202
|
+
|
|
203
|
+
def get_plugin_feature_instances(self):
|
|
204
|
+
"""Return a list of all PlugInFeature instances for this extension"""
|
|
205
|
+
pf_instances = []
|
|
206
|
+
for inst in plugin_feature.PlugInFeature.features:
|
|
207
|
+
if (isinstance(inst, plugin_feature.PlugInFeature)
|
|
208
|
+
and self.path.samefile(inst.plugin_path)):
|
|
209
|
+
pf_instances.append(inst)
|
|
210
|
+
return pf_instances
|
|
211
|
+
|
|
212
|
+
def set_enabled(self, enabled):
|
|
213
|
+
"""Set this extension to enabled (True) or disabled (False)
|
|
214
|
+
|
|
215
|
+
The extension is also loaded (True) or unloaded (False).
|
|
216
|
+
"""
|
|
217
|
+
if enabled:
|
|
218
|
+
# set enabled so that `load` works
|
|
219
|
+
self.path_lock_disabled.unlink(missing_ok=True)
|
|
220
|
+
self.load()
|
|
221
|
+
else:
|
|
222
|
+
self.unload()
|
|
223
|
+
self.path_lock_disabled.touch()
|
|
224
|
+
|
|
225
|
+
def load(self):
|
|
226
|
+
"""Load the extension if it is enabled and not loaded"""
|
|
227
|
+
if not self.enabled or self.loaded:
|
|
228
|
+
# do not load disabled extensions or extensions already loaded
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
if self.type == "feat_anc_plugin":
|
|
233
|
+
plugin_feature.load_plugin_feature(self.path)
|
|
234
|
+
except BaseException:
|
|
235
|
+
# If loading the extension fails, disable it and only then
|
|
236
|
+
# raise the exception.
|
|
237
|
+
self.set_enabled(False)
|
|
238
|
+
raise
|
|
239
|
+
|
|
240
|
+
def unload(self):
|
|
241
|
+
"""Unload the extension"""
|
|
242
|
+
if self.type == "feat_anc_plugin":
|
|
243
|
+
for inst in self.get_plugin_feature_instances():
|
|
244
|
+
plugin_feature.remove_plugin_feature(inst)
|
|
245
|
+
|
|
246
|
+
def destroy(self):
|
|
247
|
+
"""Unload and remove the extension"""
|
|
248
|
+
self.unload()
|
|
249
|
+
self.path_lock_disabled.unlink(missing_ok=True)
|
|
250
|
+
self.path.unlink(missing_ok=True)
|
dcscope/gui/__init__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# flake8: noqa: F401
|
|
2
|
+
from .dlg_slot_reorder import DlgSlotReorder
|
|
3
|
+
from .ana_basins import BasinsPanel
|
|
4
|
+
from .ana_filter import FilterPanel
|
|
5
|
+
from .ana_log import LogPanel
|
|
6
|
+
from .ana_meta import MetaPanel
|
|
7
|
+
from .ana_plot import PlotPanel
|
|
8
|
+
from .ana_slot import SlotPanel
|
|
9
|
+
from .ana_tables import TablesPanel
|
|
10
|
+
from .ana_view import AnalysisView
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import importlib.resources
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from pygments import highlight, lexers, formatters
|
|
5
|
+
from PyQt6 import uic, QtCore, QtWidgets
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BasinsPanel(QtWidgets.QWidget):
|
|
9
|
+
"""Tables panel widget
|
|
10
|
+
|
|
11
|
+
Visualizes tables stored in the .rtdc file
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, *args, **kwargs):
|
|
15
|
+
super(BasinsPanel, self).__init__(*args, **kwargs)
|
|
16
|
+
ref = importlib.resources.files(
|
|
17
|
+
"dcscope.gui.analysis") / "ana_basins.ui"
|
|
18
|
+
with importlib.resources.as_file(ref) as path_ui:
|
|
19
|
+
uic.loadUi(path_ui, self)
|
|
20
|
+
# current DCscope pipeline
|
|
21
|
+
self._pipeline = None
|
|
22
|
+
self.data_role = QtCore.Qt.ItemDataRole.UserRole + 2
|
|
23
|
+
self.treeWidget_basin_name.setColumnCount(1)
|
|
24
|
+
|
|
25
|
+
self.listWidget_dataset.currentRowChanged.connect(
|
|
26
|
+
self.on_select_dataset)
|
|
27
|
+
self.treeWidget_basin_name.currentItemChanged.connect(
|
|
28
|
+
self.on_select_basin)
|
|
29
|
+
self.update_content()
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def pipeline(self):
|
|
33
|
+
return self._pipeline
|
|
34
|
+
|
|
35
|
+
def add_basin_nodes(self, parent_widget, ds):
|
|
36
|
+
for bd in ds.basins_get_dicts():
|
|
37
|
+
# Get all basins
|
|
38
|
+
item = QtWidgets.QTreeWidgetItem(parent_widget)
|
|
39
|
+
item.setText(0, bd["name"])
|
|
40
|
+
item.setData(0, self.data_role, (ds, bd))
|
|
41
|
+
|
|
42
|
+
@QtCore.pyqtSlot(int)
|
|
43
|
+
def on_select_dataset(self, ds_idx):
|
|
44
|
+
"""Show the tables of the dataset in the right-hand list widget"""
|
|
45
|
+
self.treeWidget_basin_name.clear()
|
|
46
|
+
if ds_idx >= 0:
|
|
47
|
+
ds = self._pipeline.slots[ds_idx].get_dataset()
|
|
48
|
+
self.add_basin_nodes(parent_widget=self.treeWidget_basin_name,
|
|
49
|
+
ds=ds)
|
|
50
|
+
|
|
51
|
+
@QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem, QtWidgets.QTreeWidgetItem)
|
|
52
|
+
def on_select_basin(self, current, previous=None):
|
|
53
|
+
"""Show the tables of the dataset in the right-hand list widget"""
|
|
54
|
+
ds_idx = self.listWidget_dataset.currentRow()
|
|
55
|
+
if current is not None and ds_idx >= 0:
|
|
56
|
+
# Get the correct basin
|
|
57
|
+
ds, bd = current.data(0, self.data_role)
|
|
58
|
+
# try to access that basin in `ds`
|
|
59
|
+
for bn in ds.basins:
|
|
60
|
+
if bn.key == bd["key"]:
|
|
61
|
+
# We've got a match
|
|
62
|
+
loaded = True
|
|
63
|
+
available = bn.is_available()
|
|
64
|
+
break
|
|
65
|
+
else:
|
|
66
|
+
loaded = False
|
|
67
|
+
available = False
|
|
68
|
+
bn = None
|
|
69
|
+
|
|
70
|
+
# Display the basin information
|
|
71
|
+
self.label_status.setText(f"{loaded=}, {available=}")
|
|
72
|
+
self.label_id.setText(f"{bd.get('name')} ({bd['key']})")
|
|
73
|
+
self.textEdit_def.setText(
|
|
74
|
+
highlight(json.dumps(bd, sort_keys=True, indent=2),
|
|
75
|
+
lexers.JsonLexer(),
|
|
76
|
+
formatters.HtmlFormatter(full=True,
|
|
77
|
+
noclasses=True,
|
|
78
|
+
nobackground=True))
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if available and bn is not None and not current.childCount():
|
|
82
|
+
# Add child tree nodes
|
|
83
|
+
self.add_basin_nodes(parent_widget=current,
|
|
84
|
+
ds=bn.ds)
|
|
85
|
+
current.setExpanded(True)
|
|
86
|
+
else:
|
|
87
|
+
self.textEdit_def.clear()
|
|
88
|
+
self.label_status.setText("")
|
|
89
|
+
self.label_id.setText("")
|
|
90
|
+
|
|
91
|
+
def set_pipeline(self, pipeline):
|
|
92
|
+
self._pipeline = pipeline
|
|
93
|
+
|
|
94
|
+
def update_content(self, slot_index=None, **kwargs):
|
|
95
|
+
if self._pipeline and self._pipeline.slots:
|
|
96
|
+
self.setEnabled(True)
|
|
97
|
+
self.setUpdatesEnabled(False)
|
|
98
|
+
self.listWidget_dataset.clear()
|
|
99
|
+
self.treeWidget_basin_name.clear()
|
|
100
|
+
for slot in self._pipeline.slots:
|
|
101
|
+
self.listWidget_dataset.addItem(slot.name)
|
|
102
|
+
self.setUpdatesEnabled(True)
|
|
103
|
+
if slot_index is None or slot_index < 0:
|
|
104
|
+
slot_index = max(0, self.listWidget_dataset.currentRow())
|
|
105
|
+
slot_index = min(slot_index, self._pipeline.num_slots - 1)
|
|
106
|
+
self.listWidget_dataset.setCurrentRow(slot_index)
|
|
107
|
+
else:
|
|
108
|
+
self.setEnabled(False)
|
|
109
|
+
self.listWidget_dataset.clear()
|
|
110
|
+
self.treeWidget_basin_name.clear()
|
|
@@ -0,0 +1,143 @@
|
|
|
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>701</width>
|
|
10
|
+
<height>538</height>
|
|
11
|
+
</rect>
|
|
12
|
+
</property>
|
|
13
|
+
<property name="windowTitle">
|
|
14
|
+
<string>Form</string>
|
|
15
|
+
</property>
|
|
16
|
+
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1">
|
|
17
|
+
<item>
|
|
18
|
+
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
|
|
19
|
+
<item>
|
|
20
|
+
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
21
|
+
<item>
|
|
22
|
+
<widget class="QLabel" name="label">
|
|
23
|
+
<property name="text">
|
|
24
|
+
<string>Dataset</string>
|
|
25
|
+
</property>
|
|
26
|
+
</widget>
|
|
27
|
+
</item>
|
|
28
|
+
<item>
|
|
29
|
+
<widget class="QListWidget" name="listWidget_dataset">
|
|
30
|
+
<property name="minimumSize">
|
|
31
|
+
<size>
|
|
32
|
+
<width>200</width>
|
|
33
|
+
<height>0</height>
|
|
34
|
+
</size>
|
|
35
|
+
</property>
|
|
36
|
+
<property name="showDropIndicator" stdset="0">
|
|
37
|
+
<bool>false</bool>
|
|
38
|
+
</property>
|
|
39
|
+
<property name="alternatingRowColors">
|
|
40
|
+
<bool>true</bool>
|
|
41
|
+
</property>
|
|
42
|
+
<property name="selectionBehavior">
|
|
43
|
+
<enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
|
|
44
|
+
</property>
|
|
45
|
+
</widget>
|
|
46
|
+
</item>
|
|
47
|
+
</layout>
|
|
48
|
+
</item>
|
|
49
|
+
<item>
|
|
50
|
+
<layout class="QVBoxLayout" name="verticalLayout_3">
|
|
51
|
+
<item>
|
|
52
|
+
<widget class="QLabel" name="label_2">
|
|
53
|
+
<property name="text">
|
|
54
|
+
<string>Basins</string>
|
|
55
|
+
</property>
|
|
56
|
+
</widget>
|
|
57
|
+
</item>
|
|
58
|
+
<item>
|
|
59
|
+
<widget class="QTreeWidget" name="treeWidget_basin_name">
|
|
60
|
+
<property name="showDropIndicator" stdset="0">
|
|
61
|
+
<bool>false</bool>
|
|
62
|
+
</property>
|
|
63
|
+
<property name="alternatingRowColors">
|
|
64
|
+
<bool>true</bool>
|
|
65
|
+
</property>
|
|
66
|
+
<property name="autoExpandDelay">
|
|
67
|
+
<number>0</number>
|
|
68
|
+
</property>
|
|
69
|
+
<property name="uniformRowHeights">
|
|
70
|
+
<bool>true</bool>
|
|
71
|
+
</property>
|
|
72
|
+
<property name="headerHidden">
|
|
73
|
+
<bool>true</bool>
|
|
74
|
+
</property>
|
|
75
|
+
<column>
|
|
76
|
+
<property name="text">
|
|
77
|
+
<string notr="true">1</string>
|
|
78
|
+
</property>
|
|
79
|
+
</column>
|
|
80
|
+
</widget>
|
|
81
|
+
</item>
|
|
82
|
+
</layout>
|
|
83
|
+
</item>
|
|
84
|
+
</layout>
|
|
85
|
+
</item>
|
|
86
|
+
<item>
|
|
87
|
+
<widget class="Line" name="line">
|
|
88
|
+
<property name="orientation">
|
|
89
|
+
<enum>Qt::Orientation::Horizontal</enum>
|
|
90
|
+
</property>
|
|
91
|
+
</widget>
|
|
92
|
+
</item>
|
|
93
|
+
<item>
|
|
94
|
+
<layout class="QFormLayout" name="formLayout">
|
|
95
|
+
<item row="0" column="0">
|
|
96
|
+
<widget class="QLabel" name="label_3">
|
|
97
|
+
<property name="text">
|
|
98
|
+
<string>Basin</string>
|
|
99
|
+
</property>
|
|
100
|
+
</widget>
|
|
101
|
+
</item>
|
|
102
|
+
<item row="0" column="1">
|
|
103
|
+
<widget class="QLabel" name="label_id">
|
|
104
|
+
<property name="text">
|
|
105
|
+
<string/>
|
|
106
|
+
</property>
|
|
107
|
+
</widget>
|
|
108
|
+
</item>
|
|
109
|
+
<item row="1" column="0">
|
|
110
|
+
<widget class="QLabel" name="label_6">
|
|
111
|
+
<property name="text">
|
|
112
|
+
<string>Status</string>
|
|
113
|
+
</property>
|
|
114
|
+
</widget>
|
|
115
|
+
</item>
|
|
116
|
+
<item row="2" column="0">
|
|
117
|
+
<widget class="QLabel" name="label_5">
|
|
118
|
+
<property name="text">
|
|
119
|
+
<string>Definition</string>
|
|
120
|
+
</property>
|
|
121
|
+
</widget>
|
|
122
|
+
</item>
|
|
123
|
+
<item row="2" column="1">
|
|
124
|
+
<widget class="QTextEdit" name="textEdit_def">
|
|
125
|
+
<property name="readOnly">
|
|
126
|
+
<bool>true</bool>
|
|
127
|
+
</property>
|
|
128
|
+
</widget>
|
|
129
|
+
</item>
|
|
130
|
+
<item row="1" column="1">
|
|
131
|
+
<widget class="QLabel" name="label_status">
|
|
132
|
+
<property name="text">
|
|
133
|
+
<string/>
|
|
134
|
+
</property>
|
|
135
|
+
</widget>
|
|
136
|
+
</item>
|
|
137
|
+
</layout>
|
|
138
|
+
</item>
|
|
139
|
+
</layout>
|
|
140
|
+
</widget>
|
|
141
|
+
<resources/>
|
|
142
|
+
<connections/>
|
|
143
|
+
</ui>
|