merge svghmi
authorEdouard Tisserant
Thu, 14 May 2020 09:24:09 +0200
branchsvghmi
changeset 2966 7349063b19d8
parent 2965 8f928cee01e5 (diff)
parent 2963 113e2f2e324d (current diff)
child 2967 fc5fbf087b93
merge
--- a/ConfigTreeNode.py	Wed May 13 22:25:22 2020 +0200
+++ b/ConfigTreeNode.py	Thu May 14 09:24:09 2020 +0200
@@ -678,6 +678,7 @@
 
         raise UserAddressedException(message)
 
+# Exception type for problems that user has to take action in order to fix
 class UserAddressedException(Exception):
     pass
 
--- a/POULibrary.py	Wed May 13 22:25:22 2020 +0200
+++ b/POULibrary.py	Thu May 14 09:24:09 2020 +0200
@@ -26,6 +26,7 @@
 from __future__ import absolute_import
 from weakref import ref
 
+from ConfigTreeNode import UserAddressedException
 
 class POULibrary(object):
     def __init__(self, CTR, LibName, TypeStack):
@@ -59,6 +60,11 @@
         # Pure python or IEC libs doesn't produce C code
         return ((""), [], False), ""
 
+    def FatalError(self, message):
+        """ Raise an exception that will trigger error message intended to 
+            the user, but without backtrace since it is not a software error """
+
+        raise UserAddressedException(message)
 
 def SimplePOULibraryFactory(path):
     class SimplePOULibrary(POULibrary):
--- a/svghmi/svghmi.py	Wed May 13 22:25:22 2020 +0200
+++ b/svghmi/svghmi.py	Thu May 14 09:24:09 2020 +0200
@@ -70,6 +70,7 @@
     def place_node(self, node):
         best_child = None
         known_best_match = 0
+        potential_siblings = {}
         for child in self.children:
             if child.path is not None:
                 in_common = 0
@@ -86,10 +87,25 @@
                    in_common == len(child.path) - 1:
                     known_best_match = in_common
                     best_child = child
+                else:
+                    potential_siblings[child.path[
+                        -2 if child.nodetype == "HMI_NODE" else -1]] = child
         if best_child is not None:
-            best_child.place_node(node)
+            if node.nodetype == "HMI_NODE" and best_child.path[:-1] == node.path[:-1]:
+                return "Duplicate_HMI_NODE", best_child
+            return best_child.place_node(node)
         else:
+            candidate_name = node.path[-2 if node.nodetype == "HMI_NODE" else -1]
+            if candidate_name in potential_siblings:
+                return "Non_Unique", potential_siblings[candidate_name]
+
+            if node.nodetype == "HMI_NODE" and len(self.children) > 0:
+                prev = self.children[-1]
+                if prev.path[:-1] == node.path[:-1]:
+                    return "Late_HMI_NODE",prev
+
             self.children.append(node)
+            return None
 
     def etree(self, add_hash=False):
 
@@ -195,7 +211,7 @@
         for i,v in enumerate(hmi_types_instances):
             path = v["IEC_path"].split(".")
             derived = v["derived"]
-            if derived == "HMI_NODE" and ['CONFIG', 'HEARTBEAT'] :
+            if derived == "HMI_NODE":
                 hmi_tree_root = HMITreeNode(path, "", derived, v["type"], v["vartype"], v["C_path"])
                 hmi_types_instances.pop(i)
                 break
@@ -217,7 +233,32 @@
             else:
                 name = path[-1]
             new_node = HMITreeNode(path, name, derived, v["type"], v["vartype"], v["C_path"], **kwargs)
-            hmi_tree_root.place_node(new_node)
+            placement_result = hmi_tree_root.place_node(new_node)
+            if placement_result is not None:
+                cause, problematic_node = placement_result
+                if cause == "Non_Unique":
+                    message = _("HMI tree nodes paths are not unique.\nConflicting variable: {} {}").format(
+                        ".".join(problematic_node.path),
+                        ".".join(new_node.path))
+
+                    last_FB = None 
+                    for v in varlist:
+                        if v["vartype"] == "FB":
+                            last_FB = v 
+                        if v["C_path"] == problematic_node:
+                            break
+                    if last_FB is not None:
+                        failing_parent = last_FB["type"]
+                        message += "\n"
+                        message += _("Solution: Add HMI_NODE at beginning of {}").format(failing_parent)
+
+                elif cause in ["Late_HMI_NODE", "Duplicate_HMI_NODE"]:
+                    cause, problematic_node = placement_result
+                    message = _("There must be only one occurrence of HMI_NODE before any HMI_* variable in POU.\nConflicting variable: {} {}").format(
+                        ".".join(problematic_node.path),
+                        ".".join(new_node.path))
+
+                self.FatalError("SVGHMI : " + message)
 
         if on_hmitree_update is not None:
             on_hmitree_update()