68 return res |
68 return res |
69 |
69 |
70 def place_node(self, node): |
70 def place_node(self, node): |
71 best_child = None |
71 best_child = None |
72 known_best_match = 0 |
72 known_best_match = 0 |
|
73 potential_siblings = {} |
73 for child in self.children: |
74 for child in self.children: |
74 if child.path is not None: |
75 if child.path is not None: |
75 in_common = 0 |
76 in_common = 0 |
76 for child_path_item, node_path_item in izip(child.path, node.path): |
77 for child_path_item, node_path_item in izip(child.path, node.path): |
77 if child_path_item == node_path_item: |
78 if child_path_item == node_path_item: |
84 if in_common > known_best_match and \ |
85 if in_common > known_best_match and \ |
85 child.nodetype == "HMI_NODE" and \ |
86 child.nodetype == "HMI_NODE" and \ |
86 in_common == len(child.path) - 1: |
87 in_common == len(child.path) - 1: |
87 known_best_match = in_common |
88 known_best_match = in_common |
88 best_child = child |
89 best_child = child |
|
90 else: |
|
91 potential_siblings[child.path[ |
|
92 -2 if child.nodetype == "HMI_NODE" else -1]] = child |
89 if best_child is not None: |
93 if best_child is not None: |
90 best_child.place_node(node) |
94 if node.nodetype == "HMI_NODE" and best_child.path[:-1] == node.path[:-1]: |
|
95 return "Duplicate_HMI_NODE", best_child |
|
96 return best_child.place_node(node) |
91 else: |
97 else: |
|
98 candidate_name = node.path[-2 if node.nodetype == "HMI_NODE" else -1] |
|
99 if candidate_name in potential_siblings: |
|
100 return "Non_Unique", potential_siblings[candidate_name] |
|
101 |
|
102 if node.nodetype == "HMI_NODE" and len(self.children) > 0: |
|
103 prev = self.children[-1] |
|
104 if prev.path[:-1] == node.path[:-1]: |
|
105 return "Late_HMI_NODE",prev |
|
106 |
92 self.children.append(node) |
107 self.children.append(node) |
|
108 return None |
93 |
109 |
94 def etree(self, add_hash=False): |
110 def etree(self, add_hash=False): |
95 |
111 |
96 attribs = dict(name=self.name) |
112 attribs = dict(name=self.name) |
97 if self.path is not None: |
113 if self.path is not None: |
193 |
209 |
194 # take first HMI_NODE (placed as special node), make it root |
210 # take first HMI_NODE (placed as special node), make it root |
195 for i,v in enumerate(hmi_types_instances): |
211 for i,v in enumerate(hmi_types_instances): |
196 path = v["IEC_path"].split(".") |
212 path = v["IEC_path"].split(".") |
197 derived = v["derived"] |
213 derived = v["derived"] |
198 if derived == "HMI_NODE" and ['CONFIG', 'HEARTBEAT'] : |
214 if derived == "HMI_NODE": |
199 hmi_tree_root = HMITreeNode(path, "", derived, v["type"], v["vartype"], v["C_path"]) |
215 hmi_tree_root = HMITreeNode(path, "", derived, v["type"], v["vartype"], v["C_path"]) |
200 hmi_types_instances.pop(i) |
216 hmi_types_instances.pop(i) |
201 break |
217 break |
202 |
218 |
203 assert(hmi_tree_root is not None) |
219 assert(hmi_tree_root is not None) |
215 name = path[-2] |
231 name = path[-2] |
216 kwargs['hmiclass'] = path[-1] |
232 kwargs['hmiclass'] = path[-1] |
217 else: |
233 else: |
218 name = path[-1] |
234 name = path[-1] |
219 new_node = HMITreeNode(path, name, derived, v["type"], v["vartype"], v["C_path"], **kwargs) |
235 new_node = HMITreeNode(path, name, derived, v["type"], v["vartype"], v["C_path"], **kwargs) |
220 hmi_tree_root.place_node(new_node) |
236 placement_result = hmi_tree_root.place_node(new_node) |
|
237 if placement_result is not None: |
|
238 cause, problematic_node = placement_result |
|
239 if cause == "Non_Unique": |
|
240 message = _("HMI tree nodes paths are not unique.\nConflicting variable: {} {}").format( |
|
241 ".".join(problematic_node.path), |
|
242 ".".join(new_node.path)) |
|
243 |
|
244 last_FB = None |
|
245 for v in varlist: |
|
246 if v["vartype"] == "FB": |
|
247 last_FB = v |
|
248 if v["C_path"] == problematic_node: |
|
249 break |
|
250 if last_FB is not None: |
|
251 failing_parent = last_FB["type"] |
|
252 message += "\n" |
|
253 message += _("Solution: Add HMI_NODE at beginning of {}").format(failing_parent) |
|
254 |
|
255 elif cause in ["Late_HMI_NODE", "Duplicate_HMI_NODE"]: |
|
256 cause, problematic_node = placement_result |
|
257 message = _("There must be only one occurrence of HMI_NODE before any HMI_* variable in POU.\nConflicting variable: {} {}").format( |
|
258 ".".join(problematic_node.path), |
|
259 ".".join(new_node.path)) |
|
260 |
|
261 self.FatalError("SVGHMI : " + message) |
221 |
262 |
222 if on_hmitree_update is not None: |
263 if on_hmitree_update is not None: |
223 on_hmitree_update() |
264 on_hmitree_update() |
224 |
265 |
225 variable_decl_array = [] |
266 variable_decl_array = [] |