diff -r f1049e4df866 -r 0f41c1e2c121 svghmi/svghmi.py --- a/svghmi/svghmi.py Tue Mar 23 05:15:19 2021 +0100 +++ b/svghmi/svghmi.py Wed Mar 24 05:34:46 2021 +0100 @@ -2,15 +2,13 @@ # -*- coding: utf-8 -*- # This file is part of Beremiz -# Copyright (C) 2019: Edouard TISSERANT +# Copyright (C) 2021: Edouard TISSERANT # # See COPYING file for copyrights details. from __future__ import absolute_import import os import shutil -from itertools import izip, imap -from pprint import pformat import hashlib import weakref import shlex @@ -32,142 +30,11 @@ from editors.ConfTreeNodeEditor import ConfTreeNodeEditor from XSLTransform import XSLTransform from svghmi.i18n import EtreeToMessages, SaveCatalog, ReadTranslations, MatchTranslations, TranslationToEtree, open_pofile - -HMI_TYPES_DESC = { - "HMI_NODE":{}, - "HMI_STRING":{}, - "HMI_INT":{}, - "HMI_BOOL":{}, - "HMI_REAL":{} -} - -HMI_TYPES = HMI_TYPES_DESC.keys() +from svghmi.hmi_tree import HMI_TYPES, HMITreeNode, SPECIAL_NODES ScriptDirectory = paths.AbsDir(__file__) -class HMITreeNode(object): - def __init__(self, path, name, nodetype, iectype = None, vartype = None, cpath = None, hmiclass = None): - self.path = path - self.name = name - self.nodetype = nodetype - self.hmiclass = hmiclass - - if iectype is not None: - self.iectype = iectype - self.vartype = vartype - self.cpath = cpath - - if nodetype in ["HMI_NODE"]: - self.children = [] - - 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]) - res += "\n" - - return res - - 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 - for child_path_item, node_path_item in izip(child.path, node.path): - if child_path_item == node_path_item: - in_common +=1 - else: - break - # 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 - best_child = child - else: - 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) - 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): - - 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 - - if add_hash: - 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): - res.append(child_etree) - - return res - - @classmethod - 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 - """ - nodetype = enode.tag - 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(): - node.children.append(cls.from_etree(child)) - return node - - def traverse(self): - yield self - if hasattr(self, "children"): - for c in self.children: - for yoodl in c.traverse(): - yield yoodl - - - def hash(self): - """ Produce a hash, any change in HMI tree structure change that hash """ - s = hashlib.new('md5') - self._hash(s) - # limit size to HMI_HASH_SIZE as in svghmi.c - return map(ord,s.digest())[:8] - - def _hash(self, s): - s.update(str((self.name,self.nodetype))) - if hasattr(self, "children"): - for c in self.children: - c._hash(s) # module scope for HMITree root # so that CTN can use HMITree deduced in Library @@ -178,10 +45,6 @@ on_hmitree_update = None -SPECIAL_NODES = [("HMI_ROOT", "HMI_NODE"), - ("heartbeat", "HMI_INT")] - # ("current_page", "HMI_STRING")]) - class SVGHMILibrary(POULibrary): def GetLibraryPath(self): return paths.AbsNeighbourFile(__file__, "pous.xml")