andrej@1511: #!/usr/bin/env python andrej@1511: # -*- coding: utf-8 -*- andrej@1511: andrej@1511: # This file is part of Beremiz, a Integrated Development Environment for andrej@1511: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. andrej@1511: # andrej@1511: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD andrej@1511: # andrej@1511: # See COPYING file for copyrights details. andrej@1511: # andrej@1511: # This program is free software; you can redistribute it and/or andrej@1511: # modify it under the terms of the GNU General Public License andrej@1511: # as published by the Free Software Foundation; either version 2 andrej@1511: # of the License, or (at your option) any later version. andrej@1511: # andrej@1511: # This program is distributed in the hope that it will be useful, andrej@1511: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1511: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1511: # GNU General Public License for more details. andrej@1511: # andrej@1511: # You should have received a copy of the GNU General Public License andrej@1511: # along with this program; if not, write to the Free Software andrej@1511: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. andrej@1511: andrej@1511: andrej@1732: import os andrej@1732: import re andrej@1732: import traceback Laurent@1315: Laurent@1315: from copy import deepcopy Laurent@1315: from lxml import etree Laurent@1315: from xmlclass import GenerateParserFromXSDstring laurent@401: Laurent@1096: from PLCControler import UndoBuffer Laurent@1330: from ConfigTreeNode import XSDSchemaErrorMessage laurent@630: Laurent@1124: CODEFILE_XSD = """ Laurent@1315: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: %(includes_section)s Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Edouard@1448: Edouard@1448: Edouard@1448: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: %(sections)s Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Formatted text according to parts of XHTML 1.1 Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: Laurent@1124: """ Laurent@1124: Laurent@1124: SECTION_TAG_ELEMENT = "" lbessard@145: Laurent@1096: class CodeFile: andrej@1730: Laurent@1124: CODEFILE_NAME = "CodeFile" Laurent@1124: SECTIONS_NAMES = [] andrej@1730: etisserant@31: def __init__(self): Laurent@1124: sections_str = {"codefile_name": self.CODEFILE_NAME} Laurent@1124: if "includes" in self.SECTIONS_NAMES: Laurent@1124: sections_str["includes_section"] = SECTION_TAG_ELEMENT % "includes" Laurent@1124: else: Laurent@1124: sections_str["includes_section"] = "" Laurent@1124: sections_str["sections"] = "\n".join( Laurent@1124: [SECTION_TAG_ELEMENT % name Laurent@1124: for name in self.SECTIONS_NAMES if name != "includes"]) andrej@1730: Laurent@1315: self.CodeFileParser = GenerateParserFromXSDstring( Laurent@1124: CODEFILE_XSD % sections_str) Laurent@1315: self.CodeFileVariables = etree.XPath("variables/variable") andrej@1730: Laurent@1096: filepath = self.CodeFileName() andrej@1730: lbessard@145: if os.path.isfile(filepath): lbessard@145: xmlfile = open(filepath, 'r') Laurent@1315: codefile_xml = xmlfile.read() lbessard@145: xmlfile.close() andrej@1730: Laurent@1315: codefile_xml = codefile_xml.replace( andrej@1730: '<%s>' % self.CODEFILE_NAME, Laurent@1315: '<%s xmlns:xhtml="http://www.w3.org/1999/xhtml">' % self.CODEFILE_NAME) Laurent@1315: for cre, repl in [ Laurent@1315: (re.compile("(?)(?:)(?!)"), "]]>")]: Laurent@1315: codefile_xml = cre.sub(repl, codefile_xml) andrej@1730: Laurent@1330: try: Laurent@1330: self.CodeFile, error = self.CodeFileParser.LoadXMLString(codefile_xml) Laurent@1330: if error is not None: andrej@1581: (fname, lnum, src) = ((self.CODEFILE_NAME,) + error) andrej@1581: self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1 = fname, a2 = lnum, a3 = src)) Laurent@1330: self.CreateCodeFileBuffer(True) Laurent@1330: except Exception, exc: andrej@1581: msg = _("Couldn't load confnode parameters {a1} :\n {a2}").format(a1 = CTNName, a2 = unicode(exc)) andrej@1581: self.GetCTRoot().logger.write_error(msg) Laurent@1330: self.GetCTRoot().logger.write_error(traceback.format_exc()) lbessard@145: else: Laurent@1315: self.CodeFile = self.CodeFileParser.CreateRoot() Laurent@1096: self.CreateCodeFileBuffer(False) Edouard@718: self.OnCTNSave() lbessard@145: lbessard@145: def GetBaseTypes(self): Edouard@718: return self.GetCTRoot().GetBaseTypes() lbessard@145: Laurent@1096: def GetDataTypes(self, basetypes = False): Laurent@1096: return self.GetCTRoot().GetDataTypes(basetypes=basetypes) lbessard@145: Laurent@1146: def GenerateNewName(self, format, start_idx): Laurent@1146: return self.GetCTRoot().GenerateNewName( Laurent@1146: None, None, format, start_idx, andrej@1730: dict([(var.getname().upper(), True) Laurent@1146: for var in self.CodeFile.variables.getvariable()])) Laurent@1146: lbessard@145: def SetVariables(self, variables): Laurent@1096: self.CodeFile.variables.setvariable([]) lbessard@145: for var in variables: Laurent@1315: variable = self.CodeFileParser.CreateElement("variable", "variables") lbessard@145: variable.setname(var["Name"]) lbessard@145: variable.settype(var["Type"]) Laurent@1096: variable.setinitial(var["Initial"]) Edouard@1448: variable.setdesc(var["Description"]) Edouard@1448: variable.setonchange(var["OnChange"]) Edouard@1448: variable.setopts(var["Options"]) Laurent@1096: self.CodeFile.variables.appendvariable(variable) andrej@1730: lbessard@145: def GetVariables(self): lbessard@145: datas = [] Laurent@1315: for var in self.CodeFileVariables(self.CodeFile): andrej@1730: datas.append({"Name" : var.getname(), andrej@1730: "Type" : var.gettype(), Edouard@1448: "Initial" : var.getinitial(), Edouard@1448: "Description" : var.getdesc(), Edouard@1448: "OnChange" : var.getonchange(), Edouard@1448: "Options" : var.getopts(), Edouard@1448: }) lbessard@145: return datas lbessard@145: Laurent@1096: def SetTextParts(self, parts): Laurent@1124: for section in self.SECTIONS_NAMES: Laurent@1124: section_code = parts.get(section) Laurent@1124: if section_code is not None: Laurent@1315: getattr(self.CodeFile, section).setanyText(section_code) andrej@1730: Laurent@1096: def GetTextParts(self): Laurent@1315: return dict([(section, getattr(self.CodeFile, section).getanyText()) Laurent@1124: for section in self.SECTIONS_NAMES]) andrej@1730: Edouard@718: def CTNTestModified(self): andrej@1730: return self.ChangesToSave or not self.CodeFileIsSaved() laurent@630: Laurent@1061: def OnCTNSave(self, from_project_path=None): Laurent@1096: filepath = self.CodeFileName() andrej@1730: lbessard@145: xmlfile = open(filepath,"w") Laurent@1315: xmlfile.write(etree.tostring( andrej@1730: self.CodeFile, andrej@1730: pretty_print=True, andrej@1730: xml_declaration=True, Laurent@1315: encoding='utf-8')) lbessard@145: xmlfile.close() andrej@1730: Laurent@1096: self.MarkCodeFileAsSaved() etisserant@31: return True etisserant@31: Laurent@1095: def CTNGlobalInstances(self): Edouard@1448: variables = self.CodeFileVariables(self.CodeFile) Edouard@1448: ret = [(variable.getname(), Laurent@1096: variable.gettype(), andrej@1730: variable.getinitial()) Edouard@1448: for variable in variables] Edouard@1448: ret.extend([("On"+variable.getname()+"Change", "python_poll", "") Edouard@1448: for variable in variables Edouard@1448: if variable.getonchange()]) Edouard@1448: return ret laurent@656: lbessard@145: #------------------------------------------------------------------------------- lbessard@145: # Current Buffering Management Functions lbessard@145: #------------------------------------------------------------------------------- lbessard@145: lbessard@145: """ Laurent@1096: Return a copy of the codefile model lbessard@145: """ lbessard@145: def Copy(self, model): Laurent@1315: return deepcopy(model) lbessard@145: Laurent@1096: def CreateCodeFileBuffer(self, saved): laurent@658: self.Buffering = False Laurent@1315: self.CodeFileBuffer = UndoBuffer(self.CodeFileParser.Dumps(self.CodeFile), saved) laurent@651: Laurent@1096: def BufferCodeFile(self): Laurent@1315: self.CodeFileBuffer.Buffering(self.CodeFileParser.Dumps(self.CodeFile)) andrej@1730: lbessard@145: def StartBuffering(self): lbessard@145: self.Buffering = True andrej@1730: lbessard@145: def EndBuffering(self): lbessard@145: if self.Buffering: Laurent@1315: self.CodeFileBuffer.Buffering(self.CodeFileParser.Dumps(self.CodeFile)) lbessard@145: self.Buffering = False andrej@1730: Laurent@1096: def MarkCodeFileAsSaved(self): laurent@651: self.EndBuffering() Laurent@1096: self.CodeFileBuffer.CurrentSaved() andrej@1730: Laurent@1096: def CodeFileIsSaved(self): Laurent@1096: return self.CodeFileBuffer.IsCurrentSaved() and not self.Buffering andrej@1730: lbessard@145: def LoadPrevious(self): laurent@651: self.EndBuffering() Laurent@1315: self.CodeFile = self.CodeFileParser.Loads(self.CodeFileBuffer.Previous()) andrej@1730: lbessard@145: def LoadNext(self): Laurent@1315: self.CodeFile = self.CodeFileParser.Loads(self.CodeFileBuffer.Next()) andrej@1730: lbessard@145: def GetBufferState(self): Laurent@1096: first = self.CodeFileBuffer.IsFirst() and not self.Buffering Laurent@1096: last = self.CodeFileBuffer.IsLast() lbessard@145: return not first, not last