From fabc86f00f1c6cecfaf1d3a6e80da7dddeffb8cf Mon Sep 17 00:00:00 2001
From: Christoph Schmidt <christoph.,schmidt@tugraz.at>
Date: Wed, 3 Jan 2024 20:24:52 +0100
Subject: [PATCH] Updated to Version 1.1.3. Updated some examples and
 ConfigNode implementations.

---
 examples/example2/ApplicationConfig.py        | 57 +++++++++++
 examples/example2/LaserConfig.py              | 14 +++
 examples/example2/main.py                     | 96 +++++++++++++++++++
 examples/main.py                              |  6 +-
 src/confighandler/controller/CSignal.py       |  2 +-
 src/confighandler/controller/ConfigNode.py    |  2 +-
 src/confighandler/controller/Field.py         | 15 ++-
 .../view/fields/FieldViewList.py              | 25 ++---
 8 files changed, 200 insertions(+), 17 deletions(-)
 create mode 100644 examples/example2/ApplicationConfig.py
 create mode 100644 examples/example2/LaserConfig.py
 create mode 100644 examples/example2/main.py

diff --git a/examples/example2/ApplicationConfig.py b/examples/example2/ApplicationConfig.py
new file mode 100644
index 0000000..ea6b63a
--- /dev/null
+++ b/examples/example2/ApplicationConfig.py
@@ -0,0 +1,57 @@
+import logging
+import sys
+from pathlib import Path
+
+
+
+sys.path.append('../src/')
+
+import confighandler as cfg
+from confighandler.controller.SelectableList import SelectableList
+from LaserConfig import LaserConfig
+
+
+class ApplicationConfig(cfg.ConfigNode):
+
+    def __init__(self, internal_log=True, internal_log_level= logging.DEBUG) -> None:
+        super().__init__(internal_log=internal_log, internal_log_level=internal_log_level)
+
+        # self.output_directory: cfg.Field[Path] = cfg.Field(Path("C:\\{wafer_list1}"))
+        #
+        # self.wafer_version: cfg.Field[str] = cfg.Field("v1.0",
+        #                                                friendly_name="wafer_version",
+        #                                                description="The version of the wafer")
+        #
+        # self.wafer_number: cfg.Field[int] = cfg.Field(1,
+        #                                               friendly_name="wafer_number",
+        #                                               description="The version of the wafer")
+        #
+        # self.check: cfg.Field[bool] = cfg.Field(False, friendly_name="testcheck",
+        #                                               description="Testcheck")
+        #
+        #
+        # self.wafer_nr: cfg.Field[str] = cfg.Field("12345ABCD_{wafer_number}",
+        #                                           friendly_name="wafer_nr",
+        #                                           description="The version of the wafer")
+        #
+        # self.wafer_number2: cfg.Field[tuple] = cfg.Field((1, 2),
+        #                                                  friendly_name="wafer_number2",
+        #                                                  description="The version of the wafer")
+        #
+        # self.wafer_list: cfg.Field[list] = cfg.Field([1, 2],
+        #                                              friendly_name="wafer_list",
+        #                                              description="The version of the wafer")
+
+        self.wafer_list1: cfg.Field[list] = cfg.Field(SelectableList(
+            [6, 7, 8],
+            selected_index=0,
+            description='ms'
+        ),
+                                                     friendly_name="wafer_list1",
+                                                     description="The version of the wafer")
+
+        # self.laser_config: LaserConfig = LaserConfig(internal_log=internal_log,
+        #                                              internal_log_level=internal_log_level)
+
+
+        self.register()
diff --git a/examples/example2/LaserConfig.py b/examples/example2/LaserConfig.py
new file mode 100644
index 0000000..3d1956b
--- /dev/null
+++ b/examples/example2/LaserConfig.py
@@ -0,0 +1,14 @@
+import confighandler as cfg
+
+
+class LaserConfig(cfg.ConfigNode):
+
+    def __init__(self, internal_log, internal_log_level) -> None:
+        super().__init__(internal_log=internal_log, internal_log_level=internal_log_level)
+        self.wavelength_range = cfg.Field(850)
+        self.velocity = cfg.Field(2.0)
+        self.acceleration = cfg.Field(1.0)
+        self.deceleration = cfg.Field(1.0)
+        self.port = cfg.Field("USB 0")
+
+        self.register()
diff --git a/examples/example2/main.py b/examples/example2/main.py
new file mode 100644
index 0000000..28e27f6
--- /dev/null
+++ b/examples/example2/main.py
@@ -0,0 +1,96 @@
+import logging
+import sys
+import time
+
+from PySide6 import QtWidgets
+from PySide6.QtCore import Signal, QObject
+from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QTreeWidget
+from rich.logging import RichHandler
+
+from ApplicationConfig import ApplicationConfig
+
+class TestClass:
+
+    def _decorator(foo):
+        def magic(self):
+            print("start magic")
+            foo(self)
+            print("end magic")
+
+        return magic
+    def __init__(self, config: ApplicationConfig):
+        self.config = config
+        self._wafer = 0
+
+    @property
+    def wafer(self):
+        return self._wafer
+
+    @wafer.setter
+    def wafer(self, value):
+        self._wafer = value
+        self.config.wafer_list1.set(value)
+        print("Wafer changed to", value)
+        #self.signal.emit(value)
+
+def test(*args, **kwargs):
+    print(f"test: {args}, {kwargs}")
+
+if __name__ == "__main__":
+    app = QApplication(sys.argv)
+
+    # setup the logging module
+
+    config = ApplicationConfig()
+    testclass = TestClass(config)
+    time.sleep(1)
+    #config.autosave(enable=True, path='./configs_autosave')
+    config.load('./configs/ApplicationConfig.yaml')
+    config.autosave(enable=True, path='./')
+    #print(config.wafer_version)
+    #config.wafer_version.get()
+    #config.wafer_number.get()
+    #print(config.wafer_version)
+
+    window = QMainWindow()
+    wdg = QWidget()
+    grd = QtWidgets.QGridLayout()
+    wdg.setLayout(grd)
+    grd.addWidget(config.view.widget(), 0, 0)
+    #grd.addWidget(config.view.widget(), 1, 0)
+
+    tree = QTreeWidget()
+
+
+    tree.setColumnCount(3)
+    tree.setHeaderLabels(["Name", "Type", "asdf"])
+    tree.addTopLevelItem(config.view.ui_tree_widget_item(tree))
+    grd.addWidget(tree, 2, 0)
+
+    btn_set = QtWidgets.QPushButton("Set Wafer Number to 123")
+    btn_set.clicked.connect(lambda: config.wafer_nr.set("123"))
+    grd.addWidget(btn_set, 3, 0)
+
+    btn_save = QtWidgets.QPushButton("Save Config")
+    btn_save.clicked.connect(lambda: config.save('./configs/ApplicationConfig.yaml'))
+    grd.addWidget(btn_save, 4, 0)
+
+    # Add a new combo box
+    combo = QtWidgets.QComboBox()
+    grd.addWidget(combo, 5, 0)
+    config.wafer_list1.view.add_new_view(combo)
+
+
+    config.wafer_list1.connect(test)
+    
+    window.setCentralWidget(wdg)
+    #print(config.load('config.yaml'))
+
+
+    window.show()
+
+    sys.exit(app.exec())
+    # config.wafer_nr = "1234"
+
+    # config.save("test.yaml")
+
diff --git a/examples/main.py b/examples/main.py
index 2fd56e6..e27cf9c 100644
--- a/examples/main.py
+++ b/examples/main.py
@@ -3,13 +3,14 @@ import sys
 import time
 
 from PySide6 import QtWidgets
+from PySide6.QtCore import Signal
 from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QTreeWidget
 from rich.logging import RichHandler
 
 from ApplicationConfig import ApplicationConfig
 
 class TestClass:
-
+    signal = Signal(int)
     def __init__(self):
         self._wafer = 0
 
@@ -21,6 +22,7 @@ class TestClass:
     def wafer(self, value):
         self._wafer = value
         print("Wafer changed to", value)
+        self.signal.emit(value)
 
 
 if __name__ == "__main__":
@@ -65,6 +67,8 @@ if __name__ == "__main__":
     combo = QtWidgets.QComboBox()
     grd.addWidget(combo, 5, 0)
     config.wafer_list1.view.add_new_view(combo)
+
+
     config.wafer_list1.connect_property(testclass, TestClass.wafer)
     
     window.setCentralWidget(wdg)
diff --git a/src/confighandler/controller/CSignal.py b/src/confighandler/controller/CSignal.py
index a1d4494..ee30a58 100644
--- a/src/confighandler/controller/CSignal.py
+++ b/src/confighandler/controller/CSignal.py
@@ -12,7 +12,7 @@ class CSignal:
 
     def emit(self, *args, **kwargs):
         for connection in self.connections:
-            connection()
+            connection(*args, **kwargs)
 
     def connect(self, func: callable):
         self.connections.append(func)
diff --git a/src/confighandler/controller/ConfigNode.py b/src/confighandler/controller/ConfigNode.py
index 6fb02ba..b96ef09 100644
--- a/src/confighandler/controller/ConfigNode.py
+++ b/src/confighandler/controller/ConfigNode.py
@@ -191,7 +191,7 @@ class ConfigNode(CObject):
     # ==================================================================================================================
     # Functions that happens on a change
     # ==================================================================================================================
-    def _on_field_changed(self):
+    def _on_field_changed(self, *args, **kwargs):
         # Emit that a field has changed, thus the keywords have changed
        # print(f"Field changed {self.keywords}")
         for attr, val in self.fields.items():
diff --git a/src/confighandler/controller/Field.py b/src/confighandler/controller/Field.py
index 09a174c..d7f02bc 100644
--- a/src/confighandler/controller/Field.py
+++ b/src/confighandler/controller/Field.py
@@ -11,6 +11,8 @@ import re
 from pathlib import Path
 from typing import Generic, T, TypeVar
 
+from PySide6.QtCore import Signal
+
 import confighandler
 from confighandler.controller.CObject import CObject
 from confighandler.controller.CSignal import CSignal
@@ -23,12 +25,12 @@ class FieldData(object):
         self.value = [value, friendly_name, description]
 
 
-
 T = TypeVar('T')
 
 
 class Field(Generic[T], CObject):
 
+    changed = CSignal()
     def __init__(self, value: T, friendly_name: str = None, description: str = None,
                  internal_log=True, internal_log_level=logging.INFO):
         super().__init__()
@@ -88,8 +90,13 @@ class Field(Generic[T], CObject):
         self.props.append((instance, prop))
 
     def _set_all_props(self, value):
+        # deactivate the set function since this can trigger an infinite loop
+        bset = self.set
+        self.set = lambda *args, **kwargs: None
         for inst, prop in self.props:
             prop.fset(inst, value)
+        # Reactive the set function
+        self.set = bset
 
     # ==================================================================================================================
     # Register the field to a configuration
@@ -104,7 +111,6 @@ class Field(Generic[T], CObject):
         :param csig_field_changed: The signal that is emitted when the keywords are changed
         """
 
-
         self.name = name
         self.owner = owner
         formatter = logging.Formatter(f'%(name)s [{self.name}] %(message)s')
@@ -186,8 +192,12 @@ class Field(Generic[T], CObject):
             self.set_keywords()
             # self.view.value_changed.emit(self.value)
             # This emits a function that notifies the owner that the field has been set
+            self.changed.emit(value)
             self.csig_field_changed.emit()
 
+    def connect(self, func):
+        self.changed.connect(func)
+
     # ==================================================================================================================
     # Things that should happen when the value is changed
     # ==================================================================================================================
@@ -209,4 +219,3 @@ class Field(Generic[T], CObject):
 
     def __repr__(self):
         return str(f"{self.__class__.__name__}")
-
diff --git a/src/confighandler/view/fields/FieldViewList.py b/src/confighandler/view/fields/FieldViewList.py
index c5a8e95..7678c2e 100644
--- a/src/confighandler/view/fields/FieldViewList.py
+++ b/src/confighandler/view/fields/FieldViewList.py
@@ -8,7 +8,7 @@ Description:
 
 from PySide6 import QtWidgets
 from PySide6.QtCore import Signal
-from PySide6.QtWidgets import QWidget, QLineEdit
+from PySide6.QtWidgets import QWidget, QLineEdit, QComboBox
 
 from confighandler.view.FieldView import FieldView
 
@@ -17,24 +17,27 @@ class FieldViewList(FieldView):
 
     value_changed = Signal(tuple)
 
-    def __init__(self, parent_field: 'FieldTuple'):
+    def __init__(self, parent_field: 'FieldList'):
         super().__init__(parent_field)
 
-    def ui_field(self, view: QLineEdit = None) -> QLineEdit:
+    def ui_field(self, view: QLineEdit | QComboBox = None) -> QLineEdit:
         """
 
         """
         if view is None:
             le = QLineEdit(str(self.parent_field.value))
-        else:
-            le: QLineEdit = view
         le.setToolTip(f"({self.parent_field.name}) {self.parent_field._description}")
-        self.ui_edit_fields.append(le)
-        self.ui_edit_fields[-1].textEdited.connect(self._on_text_edited)
-        # self.ui_edit_fields[-1] : QtWidgets.QLineEdit
-        self.ui_edit_fields[-1].editingFinished.connect(self._on_edited_finished)
-        # new
-        return self.ui_edit_fields[-1]
+        if isinstance(view, QLineEdit):
+            le: QLineEdit = view
+
+            self.ui_edit_fields.append(le)
+            self.ui_edit_fields[-1].textEdited.connect(self._on_text_edited)
+            # self.ui_edit_fields[-1] : QtWidgets.QLineEdit
+            self.ui_edit_fields[-1].editingFinished.connect(self._on_edited_finished)
+            # new
+            return self.ui_edit_fields[-1]
+        elif isinstance(view, QComboBox):
+            cb: QComboBox = view
 
     def _on_text_edited(self, value):
         self.parent_field.set(value)
-- 
GitLab