Skip to content

Commit

Permalink
Add user settings to the GUI
Browse files Browse the repository at this point in the history
  • Loading branch information
MBartkowiakSTFC committed Nov 13, 2023
1 parent 81a9098 commit 34e4dc8
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 2 deletions.
23 changes: 21 additions & 2 deletions MDANSE/Src/Framework/Session/Settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class CascadingSettings:
def __init__(self, *args, **kwargs):
self._parent = None
self._settings = {}
self._current_filename = None

def __getitem__(self, key: str):
value = self._settings.get(key, None)
Expand Down Expand Up @@ -57,13 +58,31 @@ def parent(self):
def serialize(self, fname: str):
with open(fname, "w") as target:
json.dump(self._settings, target)
self.currentFilename = fname

def load_from_file(self, fname: str):
with open(fname, "r") as source:
contents = json.load(source)
self._settings = contents
try:
contents = json.load(source)
except json.JSONDecodeError:
self._settings = {}
else:
self._settings = contents
self.currentFilename = fname

def writeChanges(self):
if self.currentFilename is not None:
self.serialize(self.currentFilename)

def produce_child(self):
child = CascadingSettings()
child._parent = self
return child

@property
def currentFilename(self):
return self._current_filename

@currentFilename.setter
def currentFilename(self, fname: str):
self._current_filename = fname
Binary file added MDANSE_GUI/Src/PyQtGUI/Icons/basic_gradient.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions MDANSE_GUI/Src/PyQtGUI/MainWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
QTreeView,
)

from MDANSE.Framework.Session.Settings import CascadingSettings

from MDANSE_GUI.PyQtGUI.BackEnd import BackEnd
from MDANSE_GUI.PyQtGUI.DataViewModel.TrajectoryHolder import DataTreeItem
from MDANSE_GUI.PyQtGUI.Widgets.Generator import WidgetGenerator
Expand All @@ -67,6 +69,7 @@
from MDANSE_GUI.PyQtGUI.MolecularViewer.Controls import ViewerControls
from MDANSE_GUI.PyQtGUI.Widgets.StyleDialog import StyleDialog, StyleDatabase
from MDANSE_GUI.PyQtGUI.pygenplot.widgets.main_window import MainWindow
from MDANSE_GUI.PyQtGUI.SettingsEditor import SettingsEditor


class LoaderButton(QToolButton):
Expand Down Expand Up @@ -131,6 +134,7 @@ def __init__(self, *args, parent=None, title="MDANSE", settings=None, **kwargs):
self._actions = []
self._toolbar_buttons = [] # list of (widget, icon_key:str) pairs
self._style_database = StyleDatabase(self)
self._mdanse_settings = CascadingSettings()
self.setWindowTitle(title)
self.wid_gen = WidgetGenerator()
self.resources = Resources()
Expand All @@ -147,6 +151,21 @@ def __init__(self, *args, parent=None, title="MDANSE", settings=None, **kwargs):
if state:
self.restoreState(state)
settings.endGroup()
settings.beginGroup("MDANSE")
fname = settings.value("config_file")
settings.endGroup()
if fname is None:
self._mdanse_settings.currentFilename = os.path.join(
self.workdir, ".mdanse_gui_settings.txt"
)
else:
try:
self._mdanse_settings.load_from_file(fname)
except:
self._mdanse_settings._settings = {}
self._mdanse_settings.currentFilename = os.path.join(
self.workdir, ".mdanse_gui_settings.txt"
)
self.settings_timer = QTimer()
self.settings_timer.timeout.connect(self.saveSettings)
self.settings_timer.setInterval(2000)
Expand Down Expand Up @@ -220,6 +239,13 @@ def launchUnitsEditor(self):
dialog_instance.show()
result = dialog_instance.exec()

@Slot()
def launchSettingsEditor(self):
dialog = SettingsEditor
dialog_instance = dialog(self, settings=self._mdanse_settings)
dialog_instance.show()
result = dialog_instance.exec()

@Slot()
def launchStyleSelector(self):
dialog = StyleDialog
Expand Down Expand Up @@ -294,6 +320,7 @@ def setupToolbar(self):
("periodic_table", self.launchPeriodicTable),
("element", self.launchElementsEditor),
("units", self.launchUnitsEditor),
("basic_gradient", self.launchSettingsEditor),
("user", self.launchStyleSelector),
]
for key, slot in valid_keys:
Expand Down Expand Up @@ -356,6 +383,9 @@ def saveSettings(self):
self.settings.setValue("geometry", self.saveGeometry())
self.settings.setValue("state", self.saveState())
self.settings.endGroup()
self.settings.beginGroup("MDANSE")
self.settings.setValue("config_file", self._mdanse_settings.currentFilename)
self.settings.endGroup()

def onMyToolBarButtonClick(self, s):
print("click", s)
160 changes: 160 additions & 0 deletions MDANSE_GUI/Src/PyQtGUI/SettingsEditor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# **************************************************************************
#
# MDANSE: Molecular Dynamics Analysis for Neutron Scattering Experiments
#
# @file Src/PyQtGUI/UnitsEditor.py
# @brief Shows the physical unit editor. Can run standalone.
#
# @homepage https://mdanse.org
# @license GNU General Public License v3 or higher (see LICENSE)
# @copyright Institut Laue Langevin 2013-now
# @copyright ISIS Neutron and Muon Source, STFC, UKRI 2021-now
# @authors Scientific Computing Group at ILL (see AUTHORS)
#
# **************************************************************************

import collections
import copy

from icecream import ic

from qtpy.QtWidgets import (
QDialog,
QPushButton,
QFrame,
QGridLayout,
QVBoxLayout,
QWidget,
QLabel,
QApplication,
QSizePolicy,
QMenu,
QLineEdit,
QTableView,
)
from qtpy.QtCore import (
Signal,
Slot,
Qt,
QPoint,
QSize,
QSortFilterProxyModel,
QModelIndex,
)
from qtpy.QtGui import (
QFont,
QEnterEvent,
QStandardItem,
QStandardItemModel,
QDoubleValidator,
)

from MDANSE import LOGGER
from MDANSE.Framework.Session.Settings import CascadingSettings

from MDANSE_GUI.PyQtGUI.Widgets.GeneralWidgets import InputVariable, InputDialog


class SettingsVisualiser(QFrame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

layout = QGridLayout(self)
self.setLayout(layout)

components = ["factor", "kg", "m", "s", "K", "mol", "A", "cd", "rad", "sr"]
self.lines = {}

validator = QDoubleValidator()

for n, item in enumerate(components):
label = QLabel(item, self)
entry = QLineEdit("0", self)
entry.setValidator(validator)
layout.addWidget(label, n, 0)
layout.addWidget(entry, n, 1)
self.lines[item] = entry

@Slot(dict)
def newValues(self, val_dict: dict):
for key, value in val_dict.items():
entry = self.lines[key]
entry.setReadOnly(False)
entry.setText(str(value))
entry.setReadOnly(True)


class SettingsModel(QStandardItemModel):
unit_info = Signal(dict)

def __init__(self, *args, **kwargs):
self.settings = kwargs.pop("settings", None)
self.filename = kwargs.pop("filename", None)
super().__init__()

if self.settings is None:
self.settings = CascadingSettings()
ic(
"SettingsModel received no CascadingSettings. Creating a fresh instance."
)
if self.filename is not None:
self.settings.load_from_file(self.filename)

self.populateList()
self.dataChanged.connect(self.updateSettings)

def populateList(self):
for key, value in self.settings._settings.items():
item = [QStandardItem(str(key)), QStandardItem(str(value))]
self.appendRow(item)

@Slot()
def addLine(self):
item = [QStandardItem("entry"), QStandardItem("value")]
self.appendRow(item)

@Slot()
def updateSettings(self):
for n in range(self.rowCount()):
key, value = self.item(n, 0).text(), self.item(n, 1).text()
self.settings[key] = value
ic(f"SettingsModel updated values. Got {self.settings._settings.items()}")
self.settings.writeChanges()


class SettingsEditor(QDialog):
def __init__(self, *args, **kwargs):
ic(f"kwargs of SettingsEditor: {kwargs}")
settings_object = kwargs.pop("settings", None)
super().__init__(*args, **kwargs)

self.setWindowTitle("MDANSE Settings Editor")
ic(f"settings_object is {settings_object}")
self.model = SettingsModel(*args, **{"settings": settings_object})

layout = QGridLayout(self)
self.setLayout(layout)

self.view = QTableView(self)
self.view.setModel(self.model)

# self.visualiser = SettingsVisualiser(self)

# self.view.clicked.connect(self.model.passValue)
# self.model.unit_info.connect(self.visualiser.newValues)

new_unit_button = QPushButton("New entry", self)
new_unit_button.clicked.connect(self.model.addLine)

layout.addWidget(self.view, 0, 0)
# layout.addWidget(self.visualiser, 0, 1)
layout.addWidget(new_unit_button, 1, 0)


if __name__ == "__main__":
import sys

app = QApplication(sys.argv)
root = SettingsEditor()
root.show()
app.exec()

0 comments on commit 34e4dc8

Please sign in to comment.