MDANSE-GUI 0.1.0a1__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 (194) hide show
  1. MDANSE_GUI/BackEnd.py +108 -0
  2. MDANSE_GUI/DataViewModel/ActionsHolder.py +135 -0
  3. MDANSE_GUI/DataViewModel/JobHolder.py +175 -0
  4. MDANSE_GUI/DataViewModel/JobStatusQt.py +65 -0
  5. MDANSE_GUI/DataViewModel/TrajectoryHolder.py +143 -0
  6. MDANSE_GUI/DataViewModel/__init__.py +15 -0
  7. MDANSE_GUI/ElementsDatabaseEditor.py +254 -0
  8. MDANSE_GUI/Icons/__init__.py +34 -0
  9. MDANSE_GUI/Icons/about.png +0 -0
  10. MDANSE_GUI/Icons/api.png +0 -0
  11. MDANSE_GUI/Icons/atom.png +0 -0
  12. MDANSE_GUI/Icons/bug.png +0 -0
  13. MDANSE_GUI/Icons/clock.png +0 -0
  14. MDANSE_GUI/Icons/element.png +0 -0
  15. MDANSE_GUI/Icons/empty_data.png +0 -0
  16. MDANSE_GUI/Icons/first.png +0 -0
  17. MDANSE_GUI/Icons/help.png +0 -0
  18. MDANSE_GUI/Icons/hourglass.png +0 -0
  19. MDANSE_GUI/Icons/last.png +0 -0
  20. MDANSE_GUI/Icons/load.png +0 -0
  21. MDANSE_GUI/Icons/log.png +0 -0
  22. MDANSE_GUI/Icons/logfile.png +0 -0
  23. MDANSE_GUI/Icons/minus.png +0 -0
  24. MDANSE_GUI/Icons/old_mdanse.png +0 -0
  25. MDANSE_GUI/Icons/pause.png +0 -0
  26. MDANSE_GUI/Icons/periodic_table.png +0 -0
  27. MDANSE_GUI/Icons/play.png +0 -0
  28. MDANSE_GUI/Icons/plot.png +0 -0
  29. MDANSE_GUI/Icons/plus.png +0 -0
  30. MDANSE_GUI/Icons/preferences.png +0 -0
  31. MDANSE_GUI/Icons/quit.png +0 -0
  32. MDANSE_GUI/Icons/registry.png +0 -0
  33. MDANSE_GUI/Icons/run.png +0 -0
  34. MDANSE_GUI/Icons/shell.png +0 -0
  35. MDANSE_GUI/Icons/stop.png +0 -0
  36. MDANSE_GUI/Icons/template.png +0 -0
  37. MDANSE_GUI/Icons/units.png +0 -0
  38. MDANSE_GUI/Icons/user.png +0 -0
  39. MDANSE_GUI/Icons/user_definitions.png +0 -0
  40. MDANSE_GUI/Icons/web.png +0 -0
  41. MDANSE_GUI/Icons/working_directory.png +0 -0
  42. MDANSE_GUI/InputWidgets/AseInputFileWidget.py +95 -0
  43. MDANSE_GUI/InputWidgets/AtomMappingWidget.py +222 -0
  44. MDANSE_GUI/InputWidgets/AtomSelectionWidget.py +363 -0
  45. MDANSE_GUI/InputWidgets/AtomTransmutationWidget.py +64 -0
  46. MDANSE_GUI/InputWidgets/BackupWidget.py +48 -0
  47. MDANSE_GUI/InputWidgets/BooleanWidget.py +57 -0
  48. MDANSE_GUI/InputWidgets/ComboWidget.py +64 -0
  49. MDANSE_GUI/InputWidgets/DummyWidget.py +54 -0
  50. MDANSE_GUI/InputWidgets/FloatWidget.py +83 -0
  51. MDANSE_GUI/InputWidgets/FramesWidget.py +99 -0
  52. MDANSE_GUI/InputWidgets/HDFTrajectoryWidget.py +66 -0
  53. MDANSE_GUI/InputWidgets/InputDirectoryWidget.py +28 -0
  54. MDANSE_GUI/InputWidgets/InputFileWidget.py +95 -0
  55. MDANSE_GUI/InputWidgets/InstrumentResolutionWidget.py +145 -0
  56. MDANSE_GUI/InputWidgets/IntegerWidget.py +79 -0
  57. MDANSE_GUI/InputWidgets/InterpolationOrderWidget.py +81 -0
  58. MDANSE_GUI/InputWidgets/MoleculeWidget.py +72 -0
  59. MDANSE_GUI/InputWidgets/MultipleCombosWidget.py +70 -0
  60. MDANSE_GUI/InputWidgets/OutputDirectoryWidget.py +29 -0
  61. MDANSE_GUI/InputWidgets/OutputFilesWidget.py +173 -0
  62. MDANSE_GUI/InputWidgets/OutputTrajectoryWidget.py +135 -0
  63. MDANSE_GUI/InputWidgets/ProjectionWidget.py +83 -0
  64. MDANSE_GUI/InputWidgets/QVectorsWidget.py +122 -0
  65. MDANSE_GUI/InputWidgets/RangeWidget.py +100 -0
  66. MDANSE_GUI/InputWidgets/RunningModeWidget.py +83 -0
  67. MDANSE_GUI/InputWidgets/StringWidget.py +67 -0
  68. MDANSE_GUI/InputWidgets/VectorWidget.py +51 -0
  69. MDANSE_GUI/InputWidgets/WidgetBase.py +145 -0
  70. MDANSE_GUI/InputWidgets/__init__.py +41 -0
  71. MDANSE_GUI/MolecularViewer/AtomProperties.py +201 -0
  72. MDANSE_GUI/MolecularViewer/ColourManager.py +93 -0
  73. MDANSE_GUI/MolecularViewer/Contents.py +72 -0
  74. MDANSE_GUI/MolecularViewer/Controls.py +333 -0
  75. MDANSE_GUI/MolecularViewer/Dummy.py +38 -0
  76. MDANSE_GUI/MolecularViewer/MolecularViewer.py +767 -0
  77. MDANSE_GUI/MolecularViewer/__init__.py +15 -0
  78. MDANSE_GUI/MolecularViewer/database/__init__.py +36 -0
  79. MDANSE_GUI/MolecularViewer/database/chemical_elements.yml +1081 -0
  80. MDANSE_GUI/MolecularViewer/database/residues.yml +33 -0
  81. MDANSE_GUI/MolecularViewer/readers/__init__.py +46 -0
  82. MDANSE_GUI/MolecularViewer/readers/hdf5wrapper.py +48 -0
  83. MDANSE_GUI/MolecularViewer/readers/i_reader.py +266 -0
  84. MDANSE_GUI/MolecularViewer/readers/reader_registry.py +25 -0
  85. MDANSE_GUI/PeriodicTableViewer.py +426 -0
  86. MDANSE_GUI/Plotter/__init__.py +15 -0
  87. MDANSE_GUI/Plotter/dialogs/__init__.py +15 -0
  88. MDANSE_GUI/Plotter/dialogs/about_dialog.py +88 -0
  89. MDANSE_GUI/Plotter/dialogs/cross_viewer_dialog.py +539 -0
  90. MDANSE_GUI/Plotter/dialogs/data_viewer_1d_dialog.py +139 -0
  91. MDANSE_GUI/Plotter/dialogs/data_viewer_nd_dialog.py +140 -0
  92. MDANSE_GUI/Plotter/dialogs/inspect_data_dialog.py +449 -0
  93. MDANSE_GUI/Plotter/dialogs/plot_1d_axis_settings_dialog.py +268 -0
  94. MDANSE_GUI/Plotter/dialogs/plot_1d_general_settings_dialog.py +262 -0
  95. MDANSE_GUI/Plotter/dialogs/plot_1d_lines_settings_dialog.py +280 -0
  96. MDANSE_GUI/Plotter/dialogs/plot_2d_general_settings_dialog.py +65 -0
  97. MDANSE_GUI/Plotter/dialogs/plot_2d_image_settings_dialog.py +171 -0
  98. MDANSE_GUI/Plotter/dialogs/plot_nd_axis_settings_dialog.py +332 -0
  99. MDANSE_GUI/Plotter/dialogs/plot_nd_general_settings_dialog.py +78 -0
  100. MDANSE_GUI/Plotter/dialogs/plot_nd_image_settings_dialog.py +122 -0
  101. MDANSE_GUI/Plotter/dialogs/slice_viewer_dialog.py +465 -0
  102. MDANSE_GUI/Plotter/dialogs/units_editor_dialog.py +193 -0
  103. MDANSE_GUI/Plotter/dialogs/viewer_1d_dialog.py +33 -0
  104. MDANSE_GUI/Plotter/handlers/__init__.py +15 -0
  105. MDANSE_GUI/Plotter/handlers/logger_popup.py +33 -0
  106. MDANSE_GUI/Plotter/handlers/logger_widget.py +65 -0
  107. MDANSE_GUI/Plotter/models/__init__.py +15 -0
  108. MDANSE_GUI/Plotter/models/data_list_model.py +101 -0
  109. MDANSE_GUI/Plotter/models/data_tree_model.py +598 -0
  110. MDANSE_GUI/Plotter/models/plot_1d_model.py +941 -0
  111. MDANSE_GUI/Plotter/models/plot_2d_model.py +435 -0
  112. MDANSE_GUI/Plotter/models/plot_nd_model.py +1043 -0
  113. MDANSE_GUI/Plotter/utils/__init__.py +15 -0
  114. MDANSE_GUI/Plotter/utils/numeric.py +781 -0
  115. MDANSE_GUI/Plotter/utils/sorted_dict.py +804 -0
  116. MDANSE_GUI/Plotter/utils/sorted_list.py +2604 -0
  117. MDANSE_GUI/Plotter/utils/sorted_set.py +724 -0
  118. MDANSE_GUI/Plotter/views/__init__.py +15 -0
  119. MDANSE_GUI/Plotter/views/table_views.py +24 -0
  120. MDANSE_GUI/Plotter/widgets/__init__.py +15 -0
  121. MDANSE_GUI/Plotter/widgets/actions_widget.py +97 -0
  122. MDANSE_GUI/Plotter/widgets/data_widget.py +158 -0
  123. MDANSE_GUI/Plotter/widgets/datasets_widget.py +90 -0
  124. MDANSE_GUI/Plotter/widgets/logger_widget.py +58 -0
  125. MDANSE_GUI/Plotter/widgets/main_window.py +267 -0
  126. MDANSE_GUI/Plotter/widgets/plot_1d_widget.py +243 -0
  127. MDANSE_GUI/Plotter/widgets/plot_2d_widget.py +139 -0
  128. MDANSE_GUI/Plotter/widgets/plot_actions_widget.py +68 -0
  129. MDANSE_GUI/Plotter/widgets/plot_nd_widget.py +204 -0
  130. MDANSE_GUI/Plotter/widgets/preview_widget.py +53 -0
  131. MDANSE_GUI/Plotter/widgets/range_slider.py +277 -0
  132. MDANSE_GUI/RegistryViewer.py +304 -0
  133. MDANSE_GUI/Resources.py +49 -0
  134. MDANSE_GUI/Scripts/__init__.py +15 -0
  135. MDANSE_GUI/Scripts/mdanse_elements_database.py +32 -0
  136. MDANSE_GUI/Scripts/mdanse_gui.py +27 -0
  137. MDANSE_GUI/Scripts/mdanse_periodic_table.py +29 -0
  138. MDANSE_GUI/Scripts/mdanse_plotter.py +30 -0
  139. MDANSE_GUI/Scripts/mdanse_units_editor.py +29 -0
  140. MDANSE_GUI/Session/LocalSession.py +58 -0
  141. MDANSE_GUI/Session/Logger.py +52 -0
  142. MDANSE_GUI/Session/__init__.py +15 -0
  143. MDANSE_GUI/SubclassViewer.py +134 -0
  144. MDANSE_GUI/Subprocess/JobState.py +242 -0
  145. MDANSE_GUI/Subprocess/JobStatusProcess.py +86 -0
  146. MDANSE_GUI/Subprocess/Subprocess.py +47 -0
  147. MDANSE_GUI/Subprocess/__init__.py +15 -0
  148. MDANSE_GUI/TabbedWindow.py +291 -0
  149. MDANSE_GUI/Tabs/ConverterTab.py +139 -0
  150. MDANSE_GUI/Tabs/GeneralTab.py +97 -0
  151. MDANSE_GUI/Tabs/JobTab.py +168 -0
  152. MDANSE_GUI/Tabs/Layouts/DoublePanel.py +141 -0
  153. MDANSE_GUI/Tabs/Layouts/SinglePanel.py +110 -0
  154. MDANSE_GUI/Tabs/Layouts/TriplePanel.py +30 -0
  155. MDANSE_GUI/Tabs/Layouts/__init__.py +15 -0
  156. MDANSE_GUI/Tabs/LoggingTab.py +94 -0
  157. MDANSE_GUI/Tabs/Models/GeneralModel.py +73 -0
  158. MDANSE_GUI/Tabs/Models/JobHolder.py +247 -0
  159. MDANSE_GUI/Tabs/Models/JobTree.py +123 -0
  160. MDANSE_GUI/Tabs/Models/__init__.py +15 -0
  161. MDANSE_GUI/Tabs/RunTab.py +109 -0
  162. MDANSE_GUI/Tabs/Settings/LocalSettings.py +25 -0
  163. MDANSE_GUI/Tabs/Settings/__init__.py +15 -0
  164. MDANSE_GUI/Tabs/TrajectoryTab.py +112 -0
  165. MDANSE_GUI/Tabs/Views/ActionsTree.py +124 -0
  166. MDANSE_GUI/Tabs/Views/RunTable.py +155 -0
  167. MDANSE_GUI/Tabs/Views/TrajectoryView.py +80 -0
  168. MDANSE_GUI/Tabs/Views/__init__.py +15 -0
  169. MDANSE_GUI/Tabs/Visualisers/Action.py +280 -0
  170. MDANSE_GUI/Tabs/Visualisers/AnalysisInfo.py +61 -0
  171. MDANSE_GUI/Tabs/Visualisers/TextInfo.py +47 -0
  172. MDANSE_GUI/Tabs/Visualisers/TrajectoryInfo.py +69 -0
  173. MDANSE_GUI/Tabs/Visualisers/View3D.py +50 -0
  174. MDANSE_GUI/Tabs/Visualisers/__init__.py +15 -0
  175. MDANSE_GUI/Tabs/__init__.py +15 -0
  176. MDANSE_GUI/UnitsEditor.py +208 -0
  177. MDANSE_GUI/Widgets/ConvertDialog.py +118 -0
  178. MDANSE_GUI/Widgets/ConvertWizard.py +483 -0
  179. MDANSE_GUI/Widgets/GeneralWidgets.py +659 -0
  180. MDANSE_GUI/Widgets/Generator.py +78 -0
  181. MDANSE_GUI/Widgets/LoaderButton.py +70 -0
  182. MDANSE_GUI/Widgets/Oscillator.py +76 -0
  183. MDANSE_GUI/Widgets/StyleDialog.py +153 -0
  184. MDANSE_GUI/Widgets/TrajectoryViewer.py +70 -0
  185. MDANSE_GUI/Widgets/__init__.py +14 -0
  186. MDANSE_GUI/__init__.py +26 -0
  187. MDANSE_GUI/main.py +57 -0
  188. MDANSE_GUI-0.1.0a1.dist-info/AUTHORS +18 -0
  189. MDANSE_GUI-0.1.0a1.dist-info/LICENSE +675 -0
  190. MDANSE_GUI-0.1.0a1.dist-info/METADATA +808 -0
  191. MDANSE_GUI-0.1.0a1.dist-info/RECORD +194 -0
  192. MDANSE_GUI-0.1.0a1.dist-info/WHEEL +5 -0
  193. MDANSE_GUI-0.1.0a1.dist-info/entry_points.txt +7 -0
  194. MDANSE_GUI-0.1.0a1.dist-info/top_level.txt +1 -0
MDANSE_GUI/BackEnd.py ADDED
@@ -0,0 +1,108 @@
1
+ # This file is part of MDANSE_GUI.
2
+ #
3
+ # MDANSE_GUI is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+ #
16
+
17
+ import copy
18
+ from icecream import ic
19
+ from qtpy.QtCore import Slot, QObject, QMutex, Signal
20
+
21
+ from MDANSE.Framework.Jobs.IJob import IJob
22
+ from MDANSE.Framework.Converters.Converter import Converter
23
+ from MDANSE.Framework.InstrumentResolutions.IInstrumentResolution import (
24
+ IInstrumentResolution,
25
+ )
26
+ from MDANSE.Framework.Configurators.IConfigurator import IConfigurator
27
+ from MDANSE.Framework.Formats.IFormat import IFormat
28
+ from MDANSE.Framework.Handlers.IHandler import IHandler
29
+ from MDANSE.Framework.InputData.IInputData import IInputData
30
+ from MDANSE.Framework.OutputVariables.IOutputVariable import IOutputVariable
31
+ from MDANSE.Framework.Projectors.IProjector import IProjector
32
+ from MDANSE.Framework.QVectors.IQVectors import IQVectors
33
+
34
+
35
+ from MDANSE_GUI.DataViewModel.TrajectoryHolder import DataTreeModel
36
+ from MDANSE_GUI.DataViewModel.JobHolder import JobHolder
37
+ from MDANSE_GUI.DataViewModel.ActionsHolder import ActionsSuperModel
38
+
39
+
40
+ class BackEnd(QObject):
41
+ """The main window of the MDANSE GUI,
42
+ inherits QMainWindow.
43
+
44
+ Args:
45
+ QMainWindow - the base class.
46
+ """
47
+
48
+ new_trajectory = Signal(str)
49
+ all_converters = Signal(object)
50
+ selected_converter = Signal(object)
51
+ selected_action = Signal(object)
52
+
53
+ def __init__(self, parent=None):
54
+ super().__init__(parent)
55
+
56
+ self.lock = QMutex()
57
+ self.data_holders = {}
58
+ self.createTrajectoryHolder()
59
+ self.createJobHolder()
60
+ self.createActionsHolder()
61
+
62
+ def createTrajectoryHolder(self):
63
+ self.trajectory_holder = DataTreeModel(parent=self)
64
+ self.data_holders["trajectory"] = self.trajectory_holder
65
+ self.new_trajectory.connect(self.trajectory_holder.acceptNewTrajectory)
66
+
67
+ def createActionsHolder(self):
68
+ self.actions_holder = ActionsSuperModel(parent=self)
69
+ self.actions_holder.buildModels(
70
+ [
71
+ IJob,
72
+ Converter,
73
+ IInstrumentResolution,
74
+ IConfigurator,
75
+ IFormat,
76
+ IHandler,
77
+ IInputData,
78
+ IOutputVariable,
79
+ IProjector,
80
+ IQVectors,
81
+ ]
82
+ )
83
+
84
+ def createJobHolder(self):
85
+ self.job_holder = JobHolder(parent=self)
86
+ self.data_holders["jobs"] = self.job_holder
87
+
88
+ @Slot(str)
89
+ def loadFile(self, fname: str):
90
+ ic(f"LoadFile triggered in BackEnd. File name is {fname}.")
91
+ if len(fname) < 2:
92
+ ic(f"Strangely short file name - not proceeding.")
93
+ return None
94
+ self.new_trajectory.emit(fname)
95
+
96
+ @Slot(str)
97
+ def returnActions(self, key: str):
98
+ """This slot will make Backend emit a signal that will
99
+ create a Dialog for a specific trajectory converter.
100
+ The type of the converter is chosen by the 'key' input
101
+ parameter.
102
+
103
+ Arguments:
104
+ key -- a string specifying which converter is needed.
105
+ """
106
+ ic("returnActions has been triggered in BackEnd")
107
+ thing = self._reverse_actions[str(key).split()[-1]]
108
+ self.selected_action.emit(thing)
@@ -0,0 +1,135 @@
1
+ # This file is part of MDANSE_GUI.
2
+ #
3
+ # MDANSE_GUI is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+ #
16
+
17
+ import typing
18
+
19
+ from icecream import ic
20
+ from qtpy.QtGui import QStandardItemModel, QStandardItem
21
+ from qtpy.QtCore import QObject, Slot, Qt, QMutex
22
+ from qtpy.QtWidgets import QTreeView
23
+
24
+ from MDANSE.Framework.Jobs.IJob import IJob
25
+
26
+ from MDANSE_GUI.SubclassViewer import JobTree
27
+ from MDANSE_GUI.DataViewModel.TrajectoryHolder import DataTreeItem
28
+
29
+
30
+ class ActionsHolder(QStandardItemModel):
31
+ def __init__(self, parent=None):
32
+ super().__init__(parent)
33
+
34
+ self.mutex = QMutex()
35
+ self._node_numbers = []
36
+ self._nodes = {}
37
+ self._next_number = 1
38
+ # the nodes used for structuring the data tree
39
+ # will be kept here
40
+ self._sections = {}
41
+ self._section_names = []
42
+
43
+ @Slot(object)
44
+ def append_object(self, thing):
45
+ self.mutex.lock()
46
+ self._nodes[self._next_number] = thing
47
+ self._node_numbers.append(self._next_number)
48
+ retval = int(self._next_number)
49
+ self._next_number += 1
50
+ self.mutex.unlock()
51
+ return retval
52
+
53
+
54
+ class ActionsSuperModel(QObject):
55
+ """This object will create and store all the possible
56
+ tree models of actions. These will be assigned to the
57
+ ActionsTree widget, depending on which data object
58
+ has been selected."""
59
+
60
+ def __init__(
61
+ self,
62
+ viewer: typing.Optional["QTreeView"] = None,
63
+ parent: typing.Optional["QObject"] = None,
64
+ ) -> None:
65
+ super().__init__(parent)
66
+
67
+ self.viewer = viewer
68
+ self.models = {}
69
+ self.currentItem = None
70
+ self.currentModel = None
71
+
72
+ def setViewer(self, viewer):
73
+ self.viewer = viewer
74
+
75
+ @Slot(DataTreeItem)
76
+ def switchModel(self, item: DataTreeItem):
77
+ """Changes the model behind the viewer to match
78
+ the item selected in the DataView.
79
+
80
+ Arguments:
81
+ ancestor -- name of the MDANSE object type
82
+ selected in the DataView.
83
+ """
84
+ ic("received item:", item)
85
+ ancestor = item.ancestors()[-1]
86
+ try:
87
+ current_model = self.models[ancestor]
88
+ except KeyError:
89
+ current_model = JobTree()
90
+ self.viewer.setModel(current_model)
91
+ self.current_model = current_model
92
+ self.currentItem = item
93
+
94
+ def buildModels(self, parent_classes: list):
95
+ """Creates several subtrees out of the registry tree.
96
+ Each tree will only contain nodes that share the same
97
+ ancestor.
98
+
99
+ Arguments:
100
+ registry -- an existing RegistryTree instance
101
+ which has been used to scan the MDANSE registry
102
+ """
103
+ for parent_class in parent_classes:
104
+ model = JobTree()
105
+ model.populateTree(parent_class=parent_class)
106
+ self.models[parent_class.__name__] = model
107
+ ic("Build the following models:", self.models.keys())
108
+ self.current_model = self.models["IJob"]
109
+
110
+ def copyNodeIntoModel(self, thing: typing.Any, model: ActionsHolder):
111
+ node_parents = thing.category
112
+ rootnode = None
113
+ for name in node_parents:
114
+ if name not in model._section_names:
115
+ section_node = QStandardItem()
116
+ section_node.setText(name)
117
+ if rootnode is None:
118
+ model.appendRow(section_node)
119
+ else:
120
+ rootnode.appendRow(section_node)
121
+ model._section_names.append(name)
122
+ model._sections[name] = section_node
123
+ rootnode = section_node
124
+ else:
125
+ rootnode = model._sections[name]
126
+ node_text = thing.label
127
+ node_number = model.append_object(thing)
128
+ ic(node_number)
129
+ newitem = QStandardItem()
130
+ newitem.setText(node_text)
131
+ newitem.setData(node_number)
132
+ if rootnode is None:
133
+ model.appendRow(newitem)
134
+ else:
135
+ rootnode.appendRow(newitem)
@@ -0,0 +1,175 @@
1
+ # This file is part of MDANSE_GUI.
2
+ #
3
+ # MDANSE_GUI is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+ #
16
+
17
+ from icecream import ic
18
+
19
+ from qtpy.QtGui import QStandardItemModel, QStandardItem
20
+ from qtpy.QtCore import QObject, Slot, Signal, QProcess, QThread, QMutex
21
+
22
+ from MDANSE_GUI.DataViewModel.JobStatusQt import JobStatusQt
23
+
24
+
25
+ class JobThread(QThread):
26
+ """A wrapper object for a single MDANSE analysis job.
27
+ It is created to run a single instance of the job,
28
+ and exits once the job has completed processing."""
29
+
30
+ job_failure = Signal(str)
31
+
32
+ def __init__(self, *args, command=None, parameters={}):
33
+ super().__init__(*args)
34
+ ic("JobThread starts init")
35
+ self._command = command
36
+ self._parameters = parameters
37
+ ic(f"JobThread.run will create a job instance of command {command}")
38
+ if isinstance(self._command, type):
39
+ self._job = self._command()
40
+ else:
41
+ self._job = self._command
42
+ self._job.build_configuration()
43
+ ic(f"JobThread._parameters: {self._parameters}")
44
+ # here we try to create and connect a JobStatusQt
45
+ status = JobStatusQt(parent=self)
46
+ self._job._status = status
47
+ self._status = status
48
+ ic("JobThread finished init")
49
+
50
+ def run(self):
51
+ try:
52
+ self._job.run(self._parameters)
53
+ except Exception as inst:
54
+ ic("JobThread has entered exception handling!")
55
+ error_message = ""
56
+ error_message += str(type(inst))
57
+ error_message += str(inst.args) # arguments stored in .args
58
+ error_message += str(inst) # __str__ allows args to be printed directly,
59
+ ic("JobThread is about to emit the failure message")
60
+ self.job_failure.emit(error_message)
61
+ else:
62
+ ic("JobThread.run did not raise an exception. JobThread.run will exit now")
63
+ self.exec() # this starts event handling - will it help?
64
+
65
+
66
+ class JobEntry(QObject):
67
+ """This coordinates all the objects that make up one line on the list
68
+ of current jobs. It is used for reporting the task progress to the GUI."""
69
+
70
+ def __init__(self, *args, command=None):
71
+ super().__init__(*args)
72
+ self._command = command
73
+ self._parameters = {}
74
+ self.has_started = False
75
+ self.has_finished = False
76
+ self.success = None
77
+ self.percent_complete = 0
78
+ self._output = None
79
+ self.reference = None
80
+ self.total_steps = 99
81
+ self._prog_item = QStandardItem()
82
+ self._stat_item = QStandardItem()
83
+
84
+ @property
85
+ def parameters(self):
86
+ return self._parameters
87
+
88
+ @parameters.setter
89
+ def set_parameters(self, input: dict):
90
+ self._parameters = input
91
+
92
+ def update_fields(self):
93
+ self._prog_item.setText(f"{self.percent_complete} percent complete")
94
+
95
+ @Slot(bool)
96
+ def on_finished(self, success: bool):
97
+ print("Item received on_finished!")
98
+ self.success = success
99
+ self.has_finished = True
100
+ self._stat_item.setText("Stopped")
101
+ if success:
102
+ self.percent_complete = 100
103
+ self._stat_item.setText("Completed!")
104
+ self.update_fields()
105
+
106
+ @Slot(int)
107
+ def on_started(self, target_steps: int):
108
+ print("Item received on_started!")
109
+ self.total_steps = target_steps
110
+ self.has_started = True
111
+ self._stat_item.setText("Starting")
112
+ self.update_fields()
113
+
114
+ @Slot(int)
115
+ def on_update(self, completed_steps: int):
116
+ print("Item received on_update!")
117
+ self.percent_complete = completed_steps / self.total_steps * 99
118
+ self._stat_item.setText("Running")
119
+ self.update_fields()
120
+
121
+ @Slot()
122
+ def on_oscillate(self):
123
+ """For jobs with unknown duration, the progress bar will bounce."""
124
+
125
+
126
+ class JobHolder(QStandardItemModel):
127
+ """All the job INSTANCES that are started by the GUI
128
+ are added to this model."""
129
+
130
+ def __init__(self, parent: QObject = None):
131
+ super().__init__(parent=parent)
132
+ self.lock = QMutex()
133
+ self.existing_threads = []
134
+ self.existing_jobs = []
135
+
136
+ @Slot(str)
137
+ def reportError(self, err: str):
138
+ ic(err)
139
+
140
+ @Slot(object)
141
+ def addItem(self, new_entry: QProcess):
142
+ traj = JobEntry(new_entry.basename, trajectory=new_entry)
143
+ self.appendRow([traj])
144
+
145
+ @Slot(list)
146
+ def startThread(self, job_vars: list):
147
+ try:
148
+ th_ref = JobThread(command=job_vars[0], parameters=job_vars[1])
149
+ except:
150
+ ic(f"Failed to create JobThread using {job_vars}")
151
+ return
152
+ th_ref.job_failure.connect(self.reportError)
153
+ item_th = JobEntry(command=job_vars[0])
154
+ th_ref._status._communicator.target.connect(item_th.on_started) # int
155
+ th_ref._status._communicator.progress.connect(item_th.on_update) # int
156
+ th_ref._status._communicator.finished.connect(item_th.on_finished) # bool
157
+ th_ref._status._communicator.oscillate.connect(item_th.on_oscillate) # nothing
158
+ ic("Thread ready to start!")
159
+ try:
160
+ task_name = str(job_vars[0].__name__)
161
+ except AttributeError:
162
+ task_name = str(job_vars[0].__class__.__name__)
163
+ self.appendRow(
164
+ [
165
+ QStandardItem(task_name),
166
+ item_th._prog_item,
167
+ item_th._stat_item,
168
+ ]
169
+ )
170
+ # nrows = self.rowCount()
171
+ # index = self.indexFromItem(item_th._item)
172
+ # print(f"Index: {index}")
173
+ th_ref.start()
174
+ self.existing_threads.append(th_ref)
175
+ self.existing_jobs.append(item_th)
@@ -0,0 +1,65 @@
1
+ # This file is part of MDANSE_GUI.
2
+ #
3
+ # MDANSE_GUI is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+ #
16
+
17
+ from icecream import ic
18
+ from qtpy.QtCore import QObject, Slot, Signal, QProcess, QThread, QMutex
19
+
20
+ from MDANSE.Framework.Status import Status
21
+
22
+
23
+ class JobCommunicator(QObject):
24
+ target = Signal(int)
25
+ progress = Signal(int)
26
+ finished = Signal(bool)
27
+ oscillate = Signal()
28
+
29
+
30
+ class JobStatusQt(Status):
31
+ def __init__(self, *args, **kwargs):
32
+ qparent = kwargs.pop("parent", None)
33
+ super().__init__()
34
+ self._state = {} # for compatibility with JobStatus
35
+ self._progress_meter = 0
36
+ self._mutex = QMutex()
37
+ self._communicator = JobCommunicator(parent=qparent)
38
+
39
+ @property
40
+ def state(self):
41
+ return self._state
42
+
43
+ def finish_status(self):
44
+ ic()
45
+ self._communicator.finished.emit(True)
46
+
47
+ def start_status(self):
48
+ ic()
49
+ try:
50
+ temp = int(self._nSteps)
51
+ except:
52
+ self._communicator.oscillate.emit()
53
+ else:
54
+ self._communicator.target.emit(temp)
55
+
56
+ def stop_status(self):
57
+ ic()
58
+ self._communicator.finished.emit(False)
59
+
60
+ def update_status(self):
61
+ self._mutex.lock()
62
+ self._progress_meter += 1
63
+ temp = int(self._progress_meter)
64
+ self._mutex.unlock()
65
+ self._communicator.progress.emit(temp)
@@ -0,0 +1,143 @@
1
+ # This file is part of MDANSE_GUI.
2
+ #
3
+ # MDANSE_GUI is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+ #
16
+
17
+ import hashlib
18
+ import os
19
+
20
+ from icecream import ic
21
+ from qtpy.QtGui import QStandardItemModel, QStandardItem
22
+ from qtpy.QtCore import QObject, Slot
23
+
24
+ from MDANSE.Framework.InputData import InputFileData
25
+ from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
26
+
27
+ # class TrajectoryItem(QStandardItem):
28
+
29
+ # def __init__(self, *args, trajectory = None):
30
+ # super().__init__(*args)
31
+ # self._trajectory = trajectory
32
+
33
+
34
+ # class TrajectoryHolder(QStandardItemModel):
35
+
36
+ # def __init__(self, parent: QObject = None):
37
+ # super().__init__(parent=parent)
38
+
39
+ # @Slot(object)
40
+ # def addItem(self, new_entry: InputFileData):
41
+ # traj = TrajectoryItem(new_entry.basename, trajectory = new_entry)
42
+ # self.appendRow([traj])
43
+
44
+ # @Slot(object)
45
+ # def acceptNewTrajectory(self, new_trajectory):
46
+
47
+
48
+ class FileObject:
49
+ def __init__(self, hash_function=hashlib.sha256):
50
+ self.filename = ""
51
+ self.absolute_path = ""
52
+ self.extension = ".*"
53
+ self.relative_path = "."
54
+ self.hash_function = hash_function
55
+ self.hash = -1
56
+
57
+ def setFilename(self, fname: str):
58
+ abspath, filename = os.path.split(fname)
59
+ self.extension = str(filename).split(".")[-1]
60
+ self.filename = filename
61
+ self.absolute_path = abspath
62
+ self.hash = self.calculateHash(fname)
63
+
64
+ def calculateHash(self, fname, chunk_size=1024 * 512):
65
+ hash_object = self.hash_function()
66
+ with open(fname, "br") as source:
67
+ while chunk := source.read(chunk_size):
68
+ hash_object.update(chunk)
69
+ return hash_object.hexdigest()
70
+
71
+
72
+ class DataTreeItem(QStandardItem):
73
+ def __init__(self, *args, **kwargs):
74
+ new_kwargs = {}
75
+ for key, val in kwargs.items():
76
+ if key not in ["mdanse_tag"]:
77
+ new_kwargs[key] = val
78
+ super().__init__(*args, **new_kwargs)
79
+
80
+ self.mdanse_tag = kwargs.get("mdanse_tag", "unknown")
81
+
82
+ self.original_input = []
83
+ self.processing_used = ""
84
+ self.processing_parameters = {}
85
+
86
+ def showHistory(self):
87
+ history = ";".join(self.ancestors())
88
+ return history
89
+
90
+ def ancestors(self):
91
+ parent = self.parent()
92
+ if parent is None:
93
+ return [self.mdanse_tag]
94
+ else:
95
+ return parent.ancestors() + [self.mdanse_tag]
96
+
97
+
98
+ class TrajectoryItem(DataTreeItem):
99
+ def __init__(self, *args, **kwargs):
100
+ new_kwargs = {}
101
+ for key, val in kwargs.items():
102
+ if key not in ["fname", "trajectory"]:
103
+ new_kwargs[key] = val
104
+ super().__init__(*args, **new_kwargs)
105
+
106
+ self.filename = kwargs.get("fname", "NULL")
107
+ self.trajectory = kwargs.get("trajectory", None)
108
+ self.original_input = []
109
+ self.processing_used = ""
110
+ self.processing_parameters = {}
111
+ self.file_info = FileObject()
112
+
113
+ if self.filename != "NULL":
114
+ self.file_info.setFilename(self.filename)
115
+ self.setText(os.path.split(self.filename)[1])
116
+
117
+
118
+ class AnalysisItem(DataTreeItem):
119
+ def __init__(self, *args, **kwargs):
120
+ super().__init__(*args, **kwargs)
121
+
122
+
123
+ class DataTreeModel(QStandardItemModel):
124
+ def __init__(self, parent: QObject = None):
125
+ super().__init__(parent=parent)
126
+ self._trajectory_objects = {}
127
+
128
+ @Slot(object)
129
+ def addItem(self, new_entry: InputFileData):
130
+ traj = TrajectoryItem(new_entry.basename, trajectory=new_entry)
131
+ self.appendRow([traj])
132
+
133
+ @Slot(str)
134
+ def acceptNewTrajectory(self, fname: str):
135
+ ic(f"Received {fname}")
136
+ data = HDFTrajectoryInputData(fname)
137
+ ic()
138
+ item = TrajectoryItem(fname=fname, trajectory=data, mdanse_tag="hdf_trajectory")
139
+ ic("Created TrajectoryItem")
140
+ self.appendRow(item)
141
+ tkey = item.file_info.hash
142
+ self._trajectory_objects[tkey] = data
143
+ ic("assigned new trajectory to the dictionary")
@@ -0,0 +1,15 @@
1
+ # This file is part of MDANSE_GUI.
2
+ #
3
+ # MDANSE_GUI is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+ #