# This file is part of Beremiz
# Copyright (C) 2021: Edouard TISSERANT
# See COPYING file for copyrights details.
from __future__ import absolute_import
from itertools import izip, imap
from pprint import pformat
HMI_TYPES = HMI_TYPES_DESC.keys()
class HMITreeNode(object):
def __init__(self, path, name, nodetype, iectype = None, vartype = None, cpath = None, hmiclass = None):
if nodetype in ["HMI_NODE"]:
def pprint(self, indent = 0):
res = ">"*indent + pformat(self.__dict__, indent = indent, depth = 1) + "\n"
if hasattr(self, "children"):
res += "\n".join([child.pprint(indent = indent + 1)
for child in self.children])
def place_node(self, node):
for child in self.children:
if child.path is not None:
for child_path_item, node_path_item in izip(child.path, node.path):
if child_path_item == node_path_item:
# Match can only be HMI_NODE, and the whole path of node
# must match candidate node (except for name part)
# since candidate would become child of that node
if in_common > known_best_match and \
child.nodetype == "HMI_NODE" and \
in_common == len(child.path) - 1:
known_best_match = in_common
potential_siblings[child.path[
-2 if child.nodetype == "HMI_NODE" else -1]] = child
if best_child is not None:
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)
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:
if prev.path[:-1] == node.path[:-1]:
return "Late_HMI_NODE",prev
node.parent = weakref.ref(self)
self.children.append(node)
def etree(self, add_hash=False):
attribs = dict(name=self.name)
if self.path is not None:
attribs["path"] = ".".join(self.path)
if self.hmiclass is not None:
attribs["class"] = self.hmiclass
attribs["hash"] = ",".join(map(str,self.hash()))
res = etree.Element(self.nodetype, **attribs)
if hasattr(self, "children"):
for child_etree in imap(lambda c:c.etree(), self.children):
def from_etree(cls, enode):
alternative constructor, restoring HMI Tree from XML backup
note: all C-related information is gone,
this restore is only for tree display and widget picking
attributes = enode.attrib
name = attributes["name"]
path = attributes["path"].split('.') if "path" in attributes else None
hmiclass = attributes.get("class", None)
# hash is computed on demand
node = cls(path, name, nodetype, hmiclass=hmiclass)
for child in enode.iterchildren():
newnode = cls.from_etree(child)
newnode.parent = weakref.ref(node)
node.children.append(newnode)
if hasattr(self, "children"):
for yoodl in c.traverse():
return p.hmi_path() + "/" + self.name
""" Produce a hash, any change in HMI tree structure change that hash """
# limit size to HMI_HASH_SIZE as in svghmi.c
return map(ord,s.digest())[:8]
s.update(str((self.name,self.nodetype)))
if hasattr(self, "children"):
SPECIAL_NODES = [("HMI_ROOT", "HMI_NODE"),
("heartbeat", "HMI_INT")]