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:
Laurent@1330: import os, re, 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:
laurent@656:
Laurent@1124: CODEFILE_NAME = "CodeFile"
Laurent@1124: SECTIONS_NAMES = []
Laurent@1124:
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"])
Laurent@1124:
Laurent@1315: self.CodeFileParser = GenerateParserFromXSDstring(
Laurent@1124: CODEFILE_XSD % sections_str)
Laurent@1315: self.CodeFileVariables = etree.XPath("variables/variable")
Laurent@1124:
Laurent@1096: filepath = self.CodeFileName()
lbessard@145:
lbessard@145: if os.path.isfile(filepath):
lbessard@145: xmlfile = open(filepath, 'r')
Laurent@1315: codefile_xml = xmlfile.read()
lbessard@145: xmlfile.close()
lbessard@145:
Laurent@1315: codefile_xml = codefile_xml.replace(
Laurent@1315: '<%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)
Laurent@1330:
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,
Laurent@1153: 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)
lbessard@145:
lbessard@145: def GetVariables(self):
lbessard@145: datas = []
Laurent@1315: for var in self.CodeFileVariables(self.CodeFile):
Laurent@1124: datas.append({"Name" : var.getname(),
Laurent@1124: "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)
Laurent@1124:
Laurent@1096: def GetTextParts(self):
Laurent@1315: return dict([(section, getattr(self.CodeFile, section).getanyText())
Laurent@1124: for section in self.SECTIONS_NAMES])
Laurent@1124:
Edouard@718: def CTNTestModified(self):
Laurent@1096: return self.ChangesToSave or not self.CodeFileIsSaved()
laurent@630:
Laurent@1061: def OnCTNSave(self, from_project_path=None):
Laurent@1096: filepath = self.CodeFileName()
lbessard@145:
lbessard@145: xmlfile = open(filepath,"w")
Laurent@1315: xmlfile.write(etree.tostring(
Laurent@1315: self.CodeFile,
Laurent@1315: pretty_print=True,
Laurent@1315: xml_declaration=True,
Laurent@1315: encoding='utf-8'))
lbessard@145: xmlfile.close()
lbessard@145:
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(),
Edouard@1448: 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))
lbessard@145:
lbessard@145: def StartBuffering(self):
lbessard@145: self.Buffering = True
lbessard@145:
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
lbessard@145:
Laurent@1096: def MarkCodeFileAsSaved(self):
laurent@651: self.EndBuffering()
Laurent@1096: self.CodeFileBuffer.CurrentSaved()
laurent@651:
Laurent@1096: def CodeFileIsSaved(self):
Laurent@1096: return self.CodeFileBuffer.IsCurrentSaved() and not self.Buffering
laurent@658:
lbessard@145: def LoadPrevious(self):
laurent@651: self.EndBuffering()
Laurent@1315: self.CodeFile = self.CodeFileParser.Loads(self.CodeFileBuffer.Previous())
lbessard@145:
lbessard@145: def LoadNext(self):
Laurent@1315: self.CodeFile = self.CodeFileParser.Loads(self.CodeFileBuffer.Next())
lbessard@145:
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
lbessard@145: