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.
- MDANSE_GUI/BackEnd.py +108 -0
- MDANSE_GUI/DataViewModel/ActionsHolder.py +135 -0
- MDANSE_GUI/DataViewModel/JobHolder.py +175 -0
- MDANSE_GUI/DataViewModel/JobStatusQt.py +65 -0
- MDANSE_GUI/DataViewModel/TrajectoryHolder.py +143 -0
- MDANSE_GUI/DataViewModel/__init__.py +15 -0
- MDANSE_GUI/ElementsDatabaseEditor.py +254 -0
- MDANSE_GUI/Icons/__init__.py +34 -0
- MDANSE_GUI/Icons/about.png +0 -0
- MDANSE_GUI/Icons/api.png +0 -0
- MDANSE_GUI/Icons/atom.png +0 -0
- MDANSE_GUI/Icons/bug.png +0 -0
- MDANSE_GUI/Icons/clock.png +0 -0
- MDANSE_GUI/Icons/element.png +0 -0
- MDANSE_GUI/Icons/empty_data.png +0 -0
- MDANSE_GUI/Icons/first.png +0 -0
- MDANSE_GUI/Icons/help.png +0 -0
- MDANSE_GUI/Icons/hourglass.png +0 -0
- MDANSE_GUI/Icons/last.png +0 -0
- MDANSE_GUI/Icons/load.png +0 -0
- MDANSE_GUI/Icons/log.png +0 -0
- MDANSE_GUI/Icons/logfile.png +0 -0
- MDANSE_GUI/Icons/minus.png +0 -0
- MDANSE_GUI/Icons/old_mdanse.png +0 -0
- MDANSE_GUI/Icons/pause.png +0 -0
- MDANSE_GUI/Icons/periodic_table.png +0 -0
- MDANSE_GUI/Icons/play.png +0 -0
- MDANSE_GUI/Icons/plot.png +0 -0
- MDANSE_GUI/Icons/plus.png +0 -0
- MDANSE_GUI/Icons/preferences.png +0 -0
- MDANSE_GUI/Icons/quit.png +0 -0
- MDANSE_GUI/Icons/registry.png +0 -0
- MDANSE_GUI/Icons/run.png +0 -0
- MDANSE_GUI/Icons/shell.png +0 -0
- MDANSE_GUI/Icons/stop.png +0 -0
- MDANSE_GUI/Icons/template.png +0 -0
- MDANSE_GUI/Icons/units.png +0 -0
- MDANSE_GUI/Icons/user.png +0 -0
- MDANSE_GUI/Icons/user_definitions.png +0 -0
- MDANSE_GUI/Icons/web.png +0 -0
- MDANSE_GUI/Icons/working_directory.png +0 -0
- MDANSE_GUI/InputWidgets/AseInputFileWidget.py +95 -0
- MDANSE_GUI/InputWidgets/AtomMappingWidget.py +222 -0
- MDANSE_GUI/InputWidgets/AtomSelectionWidget.py +363 -0
- MDANSE_GUI/InputWidgets/AtomTransmutationWidget.py +64 -0
- MDANSE_GUI/InputWidgets/BackupWidget.py +48 -0
- MDANSE_GUI/InputWidgets/BooleanWidget.py +57 -0
- MDANSE_GUI/InputWidgets/ComboWidget.py +64 -0
- MDANSE_GUI/InputWidgets/DummyWidget.py +54 -0
- MDANSE_GUI/InputWidgets/FloatWidget.py +83 -0
- MDANSE_GUI/InputWidgets/FramesWidget.py +99 -0
- MDANSE_GUI/InputWidgets/HDFTrajectoryWidget.py +66 -0
- MDANSE_GUI/InputWidgets/InputDirectoryWidget.py +28 -0
- MDANSE_GUI/InputWidgets/InputFileWidget.py +95 -0
- MDANSE_GUI/InputWidgets/InstrumentResolutionWidget.py +145 -0
- MDANSE_GUI/InputWidgets/IntegerWidget.py +79 -0
- MDANSE_GUI/InputWidgets/InterpolationOrderWidget.py +81 -0
- MDANSE_GUI/InputWidgets/MoleculeWidget.py +72 -0
- MDANSE_GUI/InputWidgets/MultipleCombosWidget.py +70 -0
- MDANSE_GUI/InputWidgets/OutputDirectoryWidget.py +29 -0
- MDANSE_GUI/InputWidgets/OutputFilesWidget.py +173 -0
- MDANSE_GUI/InputWidgets/OutputTrajectoryWidget.py +135 -0
- MDANSE_GUI/InputWidgets/ProjectionWidget.py +83 -0
- MDANSE_GUI/InputWidgets/QVectorsWidget.py +122 -0
- MDANSE_GUI/InputWidgets/RangeWidget.py +100 -0
- MDANSE_GUI/InputWidgets/RunningModeWidget.py +83 -0
- MDANSE_GUI/InputWidgets/StringWidget.py +67 -0
- MDANSE_GUI/InputWidgets/VectorWidget.py +51 -0
- MDANSE_GUI/InputWidgets/WidgetBase.py +145 -0
- MDANSE_GUI/InputWidgets/__init__.py +41 -0
- MDANSE_GUI/MolecularViewer/AtomProperties.py +201 -0
- MDANSE_GUI/MolecularViewer/ColourManager.py +93 -0
- MDANSE_GUI/MolecularViewer/Contents.py +72 -0
- MDANSE_GUI/MolecularViewer/Controls.py +333 -0
- MDANSE_GUI/MolecularViewer/Dummy.py +38 -0
- MDANSE_GUI/MolecularViewer/MolecularViewer.py +767 -0
- MDANSE_GUI/MolecularViewer/__init__.py +15 -0
- MDANSE_GUI/MolecularViewer/database/__init__.py +36 -0
- MDANSE_GUI/MolecularViewer/database/chemical_elements.yml +1081 -0
- MDANSE_GUI/MolecularViewer/database/residues.yml +33 -0
- MDANSE_GUI/MolecularViewer/readers/__init__.py +46 -0
- MDANSE_GUI/MolecularViewer/readers/hdf5wrapper.py +48 -0
- MDANSE_GUI/MolecularViewer/readers/i_reader.py +266 -0
- MDANSE_GUI/MolecularViewer/readers/reader_registry.py +25 -0
- MDANSE_GUI/PeriodicTableViewer.py +426 -0
- MDANSE_GUI/Plotter/__init__.py +15 -0
- MDANSE_GUI/Plotter/dialogs/__init__.py +15 -0
- MDANSE_GUI/Plotter/dialogs/about_dialog.py +88 -0
- MDANSE_GUI/Plotter/dialogs/cross_viewer_dialog.py +539 -0
- MDANSE_GUI/Plotter/dialogs/data_viewer_1d_dialog.py +139 -0
- MDANSE_GUI/Plotter/dialogs/data_viewer_nd_dialog.py +140 -0
- MDANSE_GUI/Plotter/dialogs/inspect_data_dialog.py +449 -0
- MDANSE_GUI/Plotter/dialogs/plot_1d_axis_settings_dialog.py +268 -0
- MDANSE_GUI/Plotter/dialogs/plot_1d_general_settings_dialog.py +262 -0
- MDANSE_GUI/Plotter/dialogs/plot_1d_lines_settings_dialog.py +280 -0
- MDANSE_GUI/Plotter/dialogs/plot_2d_general_settings_dialog.py +65 -0
- MDANSE_GUI/Plotter/dialogs/plot_2d_image_settings_dialog.py +171 -0
- MDANSE_GUI/Plotter/dialogs/plot_nd_axis_settings_dialog.py +332 -0
- MDANSE_GUI/Plotter/dialogs/plot_nd_general_settings_dialog.py +78 -0
- MDANSE_GUI/Plotter/dialogs/plot_nd_image_settings_dialog.py +122 -0
- MDANSE_GUI/Plotter/dialogs/slice_viewer_dialog.py +465 -0
- MDANSE_GUI/Plotter/dialogs/units_editor_dialog.py +193 -0
- MDANSE_GUI/Plotter/dialogs/viewer_1d_dialog.py +33 -0
- MDANSE_GUI/Plotter/handlers/__init__.py +15 -0
- MDANSE_GUI/Plotter/handlers/logger_popup.py +33 -0
- MDANSE_GUI/Plotter/handlers/logger_widget.py +65 -0
- MDANSE_GUI/Plotter/models/__init__.py +15 -0
- MDANSE_GUI/Plotter/models/data_list_model.py +101 -0
- MDANSE_GUI/Plotter/models/data_tree_model.py +598 -0
- MDANSE_GUI/Plotter/models/plot_1d_model.py +941 -0
- MDANSE_GUI/Plotter/models/plot_2d_model.py +435 -0
- MDANSE_GUI/Plotter/models/plot_nd_model.py +1043 -0
- MDANSE_GUI/Plotter/utils/__init__.py +15 -0
- MDANSE_GUI/Plotter/utils/numeric.py +781 -0
- MDANSE_GUI/Plotter/utils/sorted_dict.py +804 -0
- MDANSE_GUI/Plotter/utils/sorted_list.py +2604 -0
- MDANSE_GUI/Plotter/utils/sorted_set.py +724 -0
- MDANSE_GUI/Plotter/views/__init__.py +15 -0
- MDANSE_GUI/Plotter/views/table_views.py +24 -0
- MDANSE_GUI/Plotter/widgets/__init__.py +15 -0
- MDANSE_GUI/Plotter/widgets/actions_widget.py +97 -0
- MDANSE_GUI/Plotter/widgets/data_widget.py +158 -0
- MDANSE_GUI/Plotter/widgets/datasets_widget.py +90 -0
- MDANSE_GUI/Plotter/widgets/logger_widget.py +58 -0
- MDANSE_GUI/Plotter/widgets/main_window.py +267 -0
- MDANSE_GUI/Plotter/widgets/plot_1d_widget.py +243 -0
- MDANSE_GUI/Plotter/widgets/plot_2d_widget.py +139 -0
- MDANSE_GUI/Plotter/widgets/plot_actions_widget.py +68 -0
- MDANSE_GUI/Plotter/widgets/plot_nd_widget.py +204 -0
- MDANSE_GUI/Plotter/widgets/preview_widget.py +53 -0
- MDANSE_GUI/Plotter/widgets/range_slider.py +277 -0
- MDANSE_GUI/RegistryViewer.py +304 -0
- MDANSE_GUI/Resources.py +49 -0
- MDANSE_GUI/Scripts/__init__.py +15 -0
- MDANSE_GUI/Scripts/mdanse_elements_database.py +32 -0
- MDANSE_GUI/Scripts/mdanse_gui.py +27 -0
- MDANSE_GUI/Scripts/mdanse_periodic_table.py +29 -0
- MDANSE_GUI/Scripts/mdanse_plotter.py +30 -0
- MDANSE_GUI/Scripts/mdanse_units_editor.py +29 -0
- MDANSE_GUI/Session/LocalSession.py +58 -0
- MDANSE_GUI/Session/Logger.py +52 -0
- MDANSE_GUI/Session/__init__.py +15 -0
- MDANSE_GUI/SubclassViewer.py +134 -0
- MDANSE_GUI/Subprocess/JobState.py +242 -0
- MDANSE_GUI/Subprocess/JobStatusProcess.py +86 -0
- MDANSE_GUI/Subprocess/Subprocess.py +47 -0
- MDANSE_GUI/Subprocess/__init__.py +15 -0
- MDANSE_GUI/TabbedWindow.py +291 -0
- MDANSE_GUI/Tabs/ConverterTab.py +139 -0
- MDANSE_GUI/Tabs/GeneralTab.py +97 -0
- MDANSE_GUI/Tabs/JobTab.py +168 -0
- MDANSE_GUI/Tabs/Layouts/DoublePanel.py +141 -0
- MDANSE_GUI/Tabs/Layouts/SinglePanel.py +110 -0
- MDANSE_GUI/Tabs/Layouts/TriplePanel.py +30 -0
- MDANSE_GUI/Tabs/Layouts/__init__.py +15 -0
- MDANSE_GUI/Tabs/LoggingTab.py +94 -0
- MDANSE_GUI/Tabs/Models/GeneralModel.py +73 -0
- MDANSE_GUI/Tabs/Models/JobHolder.py +247 -0
- MDANSE_GUI/Tabs/Models/JobTree.py +123 -0
- MDANSE_GUI/Tabs/Models/__init__.py +15 -0
- MDANSE_GUI/Tabs/RunTab.py +109 -0
- MDANSE_GUI/Tabs/Settings/LocalSettings.py +25 -0
- MDANSE_GUI/Tabs/Settings/__init__.py +15 -0
- MDANSE_GUI/Tabs/TrajectoryTab.py +112 -0
- MDANSE_GUI/Tabs/Views/ActionsTree.py +124 -0
- MDANSE_GUI/Tabs/Views/RunTable.py +155 -0
- MDANSE_GUI/Tabs/Views/TrajectoryView.py +80 -0
- MDANSE_GUI/Tabs/Views/__init__.py +15 -0
- MDANSE_GUI/Tabs/Visualisers/Action.py +280 -0
- MDANSE_GUI/Tabs/Visualisers/AnalysisInfo.py +61 -0
- MDANSE_GUI/Tabs/Visualisers/TextInfo.py +47 -0
- MDANSE_GUI/Tabs/Visualisers/TrajectoryInfo.py +69 -0
- MDANSE_GUI/Tabs/Visualisers/View3D.py +50 -0
- MDANSE_GUI/Tabs/Visualisers/__init__.py +15 -0
- MDANSE_GUI/Tabs/__init__.py +15 -0
- MDANSE_GUI/UnitsEditor.py +208 -0
- MDANSE_GUI/Widgets/ConvertDialog.py +118 -0
- MDANSE_GUI/Widgets/ConvertWizard.py +483 -0
- MDANSE_GUI/Widgets/GeneralWidgets.py +659 -0
- MDANSE_GUI/Widgets/Generator.py +78 -0
- MDANSE_GUI/Widgets/LoaderButton.py +70 -0
- MDANSE_GUI/Widgets/Oscillator.py +76 -0
- MDANSE_GUI/Widgets/StyleDialog.py +153 -0
- MDANSE_GUI/Widgets/TrajectoryViewer.py +70 -0
- MDANSE_GUI/Widgets/__init__.py +14 -0
- MDANSE_GUI/__init__.py +26 -0
- MDANSE_GUI/main.py +57 -0
- MDANSE_GUI-0.1.0a1.dist-info/AUTHORS +18 -0
- MDANSE_GUI-0.1.0a1.dist-info/LICENSE +675 -0
- MDANSE_GUI-0.1.0a1.dist-info/METADATA +808 -0
- MDANSE_GUI-0.1.0a1.dist-info/RECORD +194 -0
- MDANSE_GUI-0.1.0a1.dist-info/WHEEL +5 -0
- MDANSE_GUI-0.1.0a1.dist-info/entry_points.txt +7 -0
- 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
|
+
#
|