mirror of
https://github.com/nqrduck/nqrduck-spectrometer.git
synced 2024-12-22 00:10:26 +00:00
Implemented loading and saving of settings.
This commit is contained in:
parent
9187ffb9ec
commit
6496ec6824
4 changed files with 133 additions and 18 deletions
|
@ -1,5 +1,6 @@
|
||||||
"""Base class for all spectrometer controllers."""
|
"""Base class for all spectrometer controllers."""
|
||||||
|
|
||||||
|
import ast
|
||||||
from nqrduck.module.module_controller import ModuleController
|
from nqrduck.module.module_controller import ModuleController
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,6 +11,47 @@ class BaseSpectrometerController(ModuleController):
|
||||||
"""Initializes the spectrometer controller."""
|
"""Initializes the spectrometer controller."""
|
||||||
super().__init__(module)
|
super().__init__(module)
|
||||||
|
|
||||||
|
def save_settings(self, path: str) -> None:
|
||||||
|
"""Saves the settings of the spectrometer."""
|
||||||
|
# We get the different settings objects from the model
|
||||||
|
settings = self.module.model.settings
|
||||||
|
|
||||||
|
json = {}
|
||||||
|
json["name"] = self.module.model.name
|
||||||
|
|
||||||
|
for category in settings.keys():
|
||||||
|
for setting in settings[category]:
|
||||||
|
json[setting.name] = setting.value
|
||||||
|
|
||||||
|
with open(path, "w") as f:
|
||||||
|
f.write(str(json))
|
||||||
|
|
||||||
|
def load_settings(self, path: str) -> None:
|
||||||
|
"""Loads the settings of the spectrometer."""
|
||||||
|
with open(path, "r") as f:
|
||||||
|
json = f.read()
|
||||||
|
|
||||||
|
# string to dict
|
||||||
|
json = ast.literal_eval(json)
|
||||||
|
|
||||||
|
module_name = self.module.model.name
|
||||||
|
json_name = json["name"]
|
||||||
|
|
||||||
|
# For some reason the notification is shown twice
|
||||||
|
if module_name != json_name:
|
||||||
|
message = f"Module: {module_name} not compatible with module specified in settings file: {json_name}. Did you select the correct settings file?"
|
||||||
|
self.module.nqrduck_signal.emit("notification", ["Error", message])
|
||||||
|
return
|
||||||
|
|
||||||
|
settings = self.module.model.settings
|
||||||
|
for category in settings.keys():
|
||||||
|
for setting in settings[category]:
|
||||||
|
if setting.name in json:
|
||||||
|
setting.value = json[setting.name]
|
||||||
|
else:
|
||||||
|
message = f"Setting {setting.name} not found in settings file. A change in settings might have broken compatibility."
|
||||||
|
self.module.nqrduck_signal.emit("notification", ["Error", message])
|
||||||
|
|
||||||
def start_measurement(self):
|
def start_measurement(self):
|
||||||
"""Starts the measurement.
|
"""Starts the measurement.
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ class BaseSpectrometerModel(ModuleModel):
|
||||||
pulse_parameter_options (OrderedDict) : The pulse parameter options of the spectrometer
|
pulse_parameter_options (OrderedDict) : The pulse parameter options of the spectrometer
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
SETTING_FILE_EXTENSION = "setduck"
|
||||||
|
|
||||||
settings: OrderedDict
|
settings: OrderedDict
|
||||||
pulse_parameter_options: OrderedDict
|
pulse_parameter_options: OrderedDict
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from PyQt6.QtWidgets import (
|
||||||
QSizePolicy,
|
QSizePolicy,
|
||||||
QSpacerItem,
|
QSpacerItem,
|
||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
|
QPushButton,
|
||||||
)
|
)
|
||||||
from nqrduck.module.module_view import ModuleView
|
from nqrduck.module.module_view import ModuleView
|
||||||
from nqrduck.assets.icons import Logos
|
from nqrduck.assets.icons import Logos
|
||||||
|
@ -82,7 +83,7 @@ class BaseSpectrometerView(ModuleView):
|
||||||
layout.addWidget(edit_widget)
|
layout.addWidget(edit_widget)
|
||||||
layout.addStretch(1)
|
layout.addStretch(1)
|
||||||
layout.addWidget(icon_label)
|
layout.addWidget(icon_label)
|
||||||
|
|
||||||
# Add the layout to the vertical layout of the widget
|
# Add the layout to the vertical layout of the widget
|
||||||
category_layout.addLayout(layout)
|
category_layout.addLayout(layout)
|
||||||
|
|
||||||
|
@ -91,3 +92,43 @@ class BaseSpectrometerView(ModuleView):
|
||||||
|
|
||||||
# Push all the settings to the top of the widget
|
# Push all the settings to the top of the widget
|
||||||
self._ui_form.verticalLayout.addStretch(1)
|
self._ui_form.verticalLayout.addStretch(1)
|
||||||
|
|
||||||
|
# Now we add a save and load button to the widget
|
||||||
|
self.button_layout = QHBoxLayout()
|
||||||
|
self.save_button = QPushButton("Save Settings")
|
||||||
|
self.save_button.setIcon(Logos.Save16x16())
|
||||||
|
#self.save_button.setIconSize(self.save_button.size())
|
||||||
|
self.save_button.clicked.connect(self.on_save_button_clicked)
|
||||||
|
self.button_layout.addWidget(self.save_button)
|
||||||
|
|
||||||
|
self.load_button = QPushButton("Load Settings")
|
||||||
|
self.load_button.setIcon(Logos.Load16x16())
|
||||||
|
#self.load_button.setIconSize(self.load_button.size())
|
||||||
|
self.load_button.clicked.connect(self.on_load_button_clicked)
|
||||||
|
self.button_layout.addWidget(self.load_button)
|
||||||
|
|
||||||
|
self._ui_form.verticalLayout.addLayout(self.button_layout)
|
||||||
|
|
||||||
|
|
||||||
|
def on_save_button_clicked(self):
|
||||||
|
"""This method is called when the save button is clicked."""
|
||||||
|
logger.debug("Save button clicked")
|
||||||
|
# Open a dialog to save the settings to a file
|
||||||
|
file_manager = self.FileManager(
|
||||||
|
extension=self.module.model.SETTING_FILE_EXTENSION, parent=self
|
||||||
|
)
|
||||||
|
path = file_manager.saveFileDialog()
|
||||||
|
if path:
|
||||||
|
self.module.controller.save_settings(path)
|
||||||
|
|
||||||
|
def on_load_button_clicked(self):
|
||||||
|
"""This method is called when the load button is clicked."""
|
||||||
|
logger.debug("Load button clicked")
|
||||||
|
# Open a dialog to load the settings from a file
|
||||||
|
file_manager = self.FileManager(
|
||||||
|
extension=self.module.model.SETTING_FILE_EXTENSION, parent=self
|
||||||
|
)
|
||||||
|
path = file_manager.loadFileDialog()
|
||||||
|
self.module.controller.load_settings(path)
|
||||||
|
if path:
|
||||||
|
self.module.controller.load_settings(path)
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Setting(QObject):
|
||||||
description (str): A description of the setting.
|
description (str): A description of the setting.
|
||||||
default: The default value of the setting.
|
default: The default value of the setting.
|
||||||
"""
|
"""
|
||||||
|
self.widget = None
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.name = name
|
self.name = name
|
||||||
self.description = description
|
self.description = description
|
||||||
|
@ -81,34 +82,41 @@ class Setting(QObject):
|
||||||
lambda x=widget, s=self: s.on_value_changed(x.text())
|
lambda x=widget, s=self: s.on_value_changed(x.text())
|
||||||
)
|
)
|
||||||
return widget
|
return widget
|
||||||
|
|
||||||
class NumericalSetting(Setting):
|
class NumericalSetting(Setting):
|
||||||
"""A setting that is a numerical value.
|
"""A setting that is a numerical value.
|
||||||
|
|
||||||
It can additionally have a minimum and maximum value.
|
It can additionally have a minimum and maximum value.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name: str, description: str, default, min_value = None, max_value = None ) -> None:
|
|
||||||
|
def __init__(
|
||||||
|
self, name: str, description: str, default, min_value=None, max_value=None
|
||||||
|
) -> None:
|
||||||
"""Create a new numerical setting."""
|
"""Create a new numerical setting."""
|
||||||
super().__init__(name, self.description_limit_info(description, min_value, max_value), default)
|
super().__init__(
|
||||||
|
name,
|
||||||
|
self.description_limit_info(description, min_value, max_value),
|
||||||
|
default,
|
||||||
|
)
|
||||||
|
|
||||||
def description_limit_info(self, description: str, min_value, max_value) -> str:
|
def description_limit_info(self, description: str, min_value, max_value) -> str:
|
||||||
"""Updates the description with the limits of the setting if there are any.
|
"""Updates the description with the limits of the setting if there are any.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
description (str): The description of the setting.
|
description (str): The description of the setting.
|
||||||
min_value: The minimum value of the setting.
|
min_value: The minimum value of the setting.
|
||||||
max_value: The maximum value of the setting.
|
max_value: The maximum value of the setting.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The description of the setting with the limits.
|
str: The description of the setting with the limits.
|
||||||
"""
|
"""
|
||||||
if min_value is not None and max_value is not None:
|
if min_value is not None and max_value is not None:
|
||||||
description += (f"\n (min: {min_value}, max: {max_value})")
|
description += f"\n (min: {min_value}, max: {max_value})"
|
||||||
elif min_value is not None:
|
elif min_value is not None:
|
||||||
description += (f"\n (min: {min_value})")
|
description += f"\n (min: {min_value})"
|
||||||
elif max_value is not None:
|
elif max_value is not None:
|
||||||
description += (f"\n (max: {max_value})")
|
description += f"\n (max: {max_value})"
|
||||||
|
|
||||||
return description
|
return description
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,7 +129,7 @@ class FloatSetting(NumericalSetting):
|
||||||
description (str) : A description of the setting
|
description (str) : A description of the setting
|
||||||
min_value : The minimum value of the setting
|
min_value : The minimum value of the setting
|
||||||
max_value : The maximum value of the setting
|
max_value : The maximum value of the setting
|
||||||
spin_box : A tuple with two booleans that determine if a spin box is used if the second value is True, a slider will be created as well.
|
spin_box : A tuple with two booleans that determine if a spin box is used if the second value is True, a slider will be created as well.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_LENGTH = 100
|
DEFAULT_LENGTH = 100
|
||||||
|
@ -133,13 +141,19 @@ class FloatSetting(NumericalSetting):
|
||||||
description: str,
|
description: str,
|
||||||
min_value: float = None,
|
min_value: float = None,
|
||||||
max_value: float = None,
|
max_value: float = None,
|
||||||
spin_box: tuple = (False, False)
|
spin_box: tuple = (False, False),
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create a new float setting."""
|
"""Create a new float setting."""
|
||||||
|
self.spin_box = spin_box
|
||||||
super().__init__(name, description, default, min_value, max_value)
|
super().__init__(name, description, default, min_value, max_value)
|
||||||
|
|
||||||
if spin_box[0]:
|
if spin_box[0]:
|
||||||
self.widget = DuckSpinBox(min_value=min_value, max_value=max_value, slider=spin_box[1], double_box=True)
|
self.widget = DuckSpinBox(
|
||||||
|
min_value=min_value,
|
||||||
|
max_value=max_value,
|
||||||
|
slider=spin_box[1],
|
||||||
|
double_box=True,
|
||||||
|
)
|
||||||
self.widget.spin_box.setValue(default)
|
self.widget.spin_box.setValue(default)
|
||||||
else:
|
else:
|
||||||
self.widget = DuckFloatEdit(min_value=min_value, max_value=max_value)
|
self.widget = DuckFloatEdit(min_value=min_value, max_value=max_value)
|
||||||
|
@ -169,6 +183,12 @@ class FloatSetting(NumericalSetting):
|
||||||
self._value = float(value)
|
self._value = float(value)
|
||||||
self.settings_changed.emit()
|
self.settings_changed.emit()
|
||||||
|
|
||||||
|
if self.widget:
|
||||||
|
if self.spin_box[0]:
|
||||||
|
self.widget.spin_box.setValue(self._value)
|
||||||
|
else:
|
||||||
|
self.widget.setText(str(self._value))
|
||||||
|
|
||||||
|
|
||||||
class IntSetting(NumericalSetting):
|
class IntSetting(NumericalSetting):
|
||||||
"""A setting that is an Integer.
|
"""A setting that is an Integer.
|
||||||
|
@ -189,13 +209,15 @@ class IntSetting(NumericalSetting):
|
||||||
description: str,
|
description: str,
|
||||||
min_value=None,
|
min_value=None,
|
||||||
max_value=None,
|
max_value=None,
|
||||||
spin_box: tuple = (False, False)
|
spin_box: tuple = (False, False),
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create a new int setting."""
|
"""Create a new int setting."""
|
||||||
|
self.spin_box = spin_box
|
||||||
super().__init__(name, description, default, min_value, max_value)
|
super().__init__(name, description, default, min_value, max_value)
|
||||||
|
if self.spin_box[0]:
|
||||||
if spin_box[0]:
|
self.widget = DuckSpinBox(
|
||||||
self.widget = DuckSpinBox(min_value=min_value, max_value=max_value, slider=spin_box[1])
|
min_value=min_value, max_value=max_value, slider=spin_box[1]
|
||||||
|
)
|
||||||
self.widget.spin_box.setValue(default)
|
self.widget.spin_box.setValue(default)
|
||||||
else:
|
else:
|
||||||
self.widget = DuckIntEdit(min_value=min_value, max_value=max_value)
|
self.widget = DuckIntEdit(min_value=min_value, max_value=max_value)
|
||||||
|
@ -225,7 +247,11 @@ class IntSetting(NumericalSetting):
|
||||||
value = int(float(value))
|
value = int(float(value))
|
||||||
self._value = value
|
self._value = value
|
||||||
self.settings_changed.emit()
|
self.settings_changed.emit()
|
||||||
|
if self.widget:
|
||||||
|
if self.spin_box[0]:
|
||||||
|
self.widget.spin_box.setValue(value)
|
||||||
|
else:
|
||||||
|
self.widget.setText(str(value))
|
||||||
|
|
||||||
|
|
||||||
class BooleanSetting(Setting):
|
class BooleanSetting(Setting):
|
||||||
|
@ -253,6 +279,8 @@ class BooleanSetting(Setting):
|
||||||
def value(self, value):
|
def value(self, value):
|
||||||
try:
|
try:
|
||||||
self._value = bool(value)
|
self._value = bool(value)
|
||||||
|
if self.widget:
|
||||||
|
self.widget.setChecked(self._value)
|
||||||
self.settings_changed.emit()
|
self.settings_changed.emit()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError("Value must be a bool")
|
raise ValueError("Value must be a bool")
|
||||||
|
@ -307,6 +335,8 @@ class SelectionSetting(Setting):
|
||||||
try:
|
try:
|
||||||
if value in self.options:
|
if value in self.options:
|
||||||
self._value = value
|
self._value = value
|
||||||
|
if self.widget:
|
||||||
|
self.widget.setCurrentText(value)
|
||||||
self.settings_changed.emit()
|
self.settings_changed.emit()
|
||||||
else:
|
else:
|
||||||
raise ValueError("Value must be one of the options")
|
raise ValueError("Value must be one of the options")
|
||||||
|
|
Loading…
Reference in a new issue