# HG changeset patch # User Edouard Tisserant # Date 1589374132 -7200 # Node ID 8f928cee01e536bdefeb7986274f83197de49ad8 # Parent a7b11c9f468e245a78b8f34f4896e6b613f7662a SVGHMI: Makes error when HMI tree is not well formed. Prevents multiple and non-first HMI_NODE, and ensure that all paths in HMI tree are unique. diff -r a7b11c9f468e -r 8f928cee01e5 svghmi/svghmi.py --- a/svghmi/svghmi.py Wed May 13 14:47:17 2020 +0200 +++ b/svghmi/svghmi.py Wed May 13 14:48:52 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()