--- a/PLCControler.py Fri Aug 30 10:59:06 2013 +0200
+++ b/PLCControler.py Fri Aug 30 18:10:30 2013 +0200
@@ -25,12 +25,12 @@
from xml.dom import minidom
from types import StringType, UnicodeType, TupleType
import cPickle
+from copy import deepcopy
import os,sys,re
import datetime
from time import localtime
-from plcopen import PLCOpenParser, LoadProject, SaveProject, QualifierList, rect
-from plcopen.structures import *
+from plcopen import*
from graphics.GraphicCommons import *
from PLCGenerator import *
@@ -247,7 +247,7 @@
self.CreateProjectBuffer(False)
self.ProgramChunks = []
self.ProgramOffset = 0
- self.NextCompiledProject = self.Project #self.Copy(self.Project)
+ self.NextCompiledProject = self.Copy(self.Project)
self.CurrentCompiledProject = None
self.Buffering = False
@@ -758,7 +758,7 @@
if self.Project is not None:
try:
self.ProgramChunks = GenerateCurrentProgram(self, self.Project, errors, warnings)
- self.NextCompiledProject = self.Project #self.Copy(self.Project)
+ self.NextCompiledProject = self.Copy(self.Project)
program_text = "".join([item[0] for item in self.ProgramChunks])
if filepath is not None:
programfile = open(filepath, "w")
@@ -844,7 +844,7 @@
if self.Project is not None:
pou = self.Project.getpou(pou_name)
if pou is not None:
- return pou.generateXMLText('pou', 0)
+ return pou.tostring()
return None
def PastePou(self, pou_type, pou_xml):
@@ -852,47 +852,40 @@
Adds the POU defined by 'pou_xml' to the current project with type 'pou_type'
'''
try:
- tree = minidom.parseString(pou_xml.encode("utf-8"))
- root = tree.childNodes[0]
+ new_pou = LoadPou(pou_xml)
except:
return _("Couldn't paste non-POU object.")
-
- if root.nodeName == "pou":
- new_pou = plcopen.pous_pou()
- new_pou.loadXMLTree(root)
-
- name = new_pou.getname()
+
+ name = new_pou.getname()
+
+ idx = 0
+ new_name = name
+ while self.Project.getpou(new_name):
+ # a POU with that name already exists.
+ # make a new name and test if a POU with that name exists.
+ # append an incrementing numeric suffix to the POU name.
+ idx += 1
+ new_name = "%s%d" % (name, idx)
- idx = 0
- new_name = name
- while self.Project.getpou(new_name):
- # a POU with that name already exists.
- # make a new name and test if a POU with that name exists.
- # append an incrementing numeric suffix to the POU name.
- idx += 1
- new_name = "%s%d" % (name, idx)
-
- # we've found a name that does not already exist, use it
- new_pou.setname(new_name)
+ # we've found a name that does not already exist, use it
+ new_pou.setname(new_name)
+
+ if pou_type is not None:
+ orig_type = new_pou.getpouType()
+
+ # prevent violations of POU content restrictions:
+ # function blocks cannot be pasted as functions,
+ # programs cannot be pasted as functions or function blocks
+ if orig_type == 'functionBlock' and pou_type == 'function' or \
+ orig_type == 'program' and pou_type in ['function', 'functionBlock']:
+ return _('''%s "%s" can't be pasted as a %s.''') % (orig_type, name, pou_type)
- if pou_type is not None:
- orig_type = new_pou.getpouType()
-
- # prevent violations of POU content restrictions:
- # function blocks cannot be pasted as functions,
- # programs cannot be pasted as functions or function blocks
- if orig_type == 'functionBlock' and pou_type == 'function' or \
- orig_type == 'program' and pou_type in ['function', 'functionBlock']:
- return _('''%s "%s" can't be pasted as a %s.''') % (orig_type, name, pou_type)
-
- new_pou.setpouType(pou_type)
-
- self.Project.insertpou(-1, new_pou)
- self.BufferProject()
-
- return self.ComputePouName(new_name),
- else:
- return _("Couldn't paste non-POU object.")
+ new_pou.setpouType(pou_type)
+
+ self.Project.insertpou(-1, new_pou)
+ self.BufferProject()
+
+ return self.ComputePouName(new_name),
# Remove a Pou from project
def ProjectRemovePou(self, pou_name):
@@ -2170,22 +2163,28 @@
def GetEditedElementCopy(self, tagname, debug = False):
element = self.GetEditedElement(tagname, debug)
if element is not None:
- name = element.__class__.__name__
- return element.generateXMLText(name.split("_")[-1], 0)
+ return element.tostring()
return ""
def GetEditedElementInstancesCopy(self, tagname, blocks_id = None, wires = None, debug = False):
element = self.GetEditedElement(tagname, debug)
text = ""
if element is not None:
- wires = dict([(wire, True) for wire in wires if wire[0] in blocks_id and wire[1] in blocks_id])
+ wires = dict([(wire, True)
+ for wire in wires
+ if wire[0] in blocks_id and wire[1] in blocks_id])
+ copy_body = PLCOpenParser.CreateElement("body", "pou")
+ element.append(copy_body)
+ copy_body.setcontent(
+ PLCOpenParser.CreateElement(element.getbodyType(), "body"))
for id in blocks_id:
instance = element.getinstance(id)
if instance is not None:
- instance_copy = self.Copy(instance)
+ copy_body.appendcontentInstance(self.Copy(instance))
+ instance_copy = copy_body.getcontentInstance(id)
instance_copy.filterConnections(wires)
- name = instance_copy.__class__.__name__
- text += instance_copy.generateXMLText(name.split("_")[-1], 0)
+ text += instance_copy.tostring()
+ element.remove(copy_body)
return text
def GenerateNewName(self, tagname, name, format, start_idx=0, exclude={}, debug=False):
@@ -2227,10 +2226,6 @@
i += 1
return name
- CheckPasteCompatibility = {"SFC": lambda name: True,
- "LD": lambda name: not name.startswith("sfcObjects"),
- "FBD": lambda name: name.startswith("fbdObjects") or name.startswith("commonObjects")}
-
def PasteEditedElementInstances(self, tagname, text, new_pos, middle=False, debug=False):
element = self.GetEditedElement(tagname, debug)
element_name, element_type = self.GetEditedElementType(tagname, debug)
@@ -2248,62 +2243,46 @@
used_id = dict([(instance.getlocalId(), True) for instance in element.getinstances()])
new_id = {}
- text = "<paste>%s</paste>"%text
-
try:
- tree = minidom.parseString(text.encode("utf-8"))
+ instances = LoadPouInstances(text.encode("utf-8"), bodytype)
+ if len(instances) == 0:
+ raise ValueError
except:
return _("Invalid plcopen element(s)!!!")
- instances = []
+
exclude = {}
- for root in tree.childNodes:
- if root.nodeType == tree.ELEMENT_NODE and root.nodeName == "paste":
- for child in root.childNodes:
- if child.nodeType == tree.ELEMENT_NODE:
- if not child.nodeName in plcopen.ElementNameToClass:
- return _("\"%s\" element can't be pasted here!!!")%child.nodeName
-
- classname = plcopen.ElementNameToClass[child.nodeName]
- if not self.CheckPasteCompatibility[bodytype](classname):
- return _("\"%s\" element can't be pasted here!!!")%child.nodeName
-
- classobj = getattr(plcopen, classname, None)
- if classobj is not None:
- instance = classobj()
- instance.loadXMLTree(child)
- if child.nodeName == "block":
- blockname = instance.getinstanceName()
- if blockname is not None:
- blocktype = instance.gettypeName()
- if element_type == "function":
- return _("FunctionBlock \"%s\" can't be pasted in a Function!!!")%blocktype
- blockname = self.GenerateNewName(tagname,
- blockname,
- "%s%%d"%blocktype,
- debug=debug)
- exclude[blockname] = True
- instance.setinstanceName(blockname)
- self.AddEditedElementPouVar(tagname, blocktype, blockname)
- elif child.nodeName == "step":
- stepname = self.GenerateNewName(tagname,
- instance.getname(),
- "Step%d",
- exclude=exclude,
- debug=debug)
- exclude[stepname] = True
- instance.setname(stepname)
- localid = instance.getlocalId()
- if not used_id.has_key(localid):
- new_id[localid] = True
- instances.append((child.nodeName, instance))
-
- if len(instances) == 0:
- return _("Invalid plcopen element(s)!!!")
+ for instance in instances:
+ element.addinstance(instance)
+ instance_type = instance.getLocalTag()
+ if instance_type == "block":
+ blockname = instance.getinstanceName()
+ if blockname is not None:
+ blocktype = instance.gettypeName()
+ if element_type == "function":
+ return _("FunctionBlock \"%s\" can't be pasted in a Function!!!")%blocktype
+ blockname = self.GenerateNewName(tagname,
+ blockname,
+ "%s%%d"%blocktype,
+ debug=debug)
+ exclude[blockname] = True
+ instance.setinstanceName(blockname)
+ self.AddEditedElementPouVar(tagname, blocktype, blockname)
+ elif instance_type == "step":
+ stepname = self.GenerateNewName(tagname,
+ instance.getname(),
+ "Step%d",
+ exclude=exclude,
+ debug=debug)
+ exclude[stepname] = True
+ instance.setname(stepname)
+ localid = instance.getlocalId()
+ if not used_id.has_key(localid):
+ new_id[localid] = True
idx = 1
translate_id = {}
- bbox = plcopen.rect()
- for name, instance in instances:
+ bbox = rect()
+ for instance in instances:
localId = instance.getlocalId()
bbox.union(instance.getBoundingBox())
if used_id.has_key(localId):
@@ -2336,12 +2315,11 @@
diff = (new_pos[0] - x, new_pos[1] - y)
connections = {}
- for name, instance in instances:
+ for instance in instances:
connections.update(instance.updateConnectionsId(translate_id))
if getattr(instance, "setexecutionOrderId", None) is not None:
instance.setexecutionOrderId(0)
instance.translate(*diff)
- element.addinstance(name, instance)
return new_id, connections
@@ -3131,7 +3109,7 @@
self.CreateProjectBuffer(True)
self.ProgramChunks = []
self.ProgramOffset = 0
- self.NextCompiledProject = self.Project ## self.Copy(self.Project)
+ self.NextCompiledProject = self.Copy(self.Project)
self.CurrentCompiledProject = None
self.Buffering = False
self.CurrentElementEditing = None
@@ -3175,7 +3153,7 @@
Return a copy of the project
"""
def Copy(self, model):
- return cPickle.loads(cPickle.dumps(model))
+ return deepcopy(model)
def CreateProjectBuffer(self, saved):
if self.ProjectBufferEnabled:
--- a/plcopen/plcopen.py Fri Aug 30 10:59:06 2013 +0200
+++ b/plcopen/plcopen.py Fri Aug 30 18:10:30 2013 +0200
@@ -125,6 +125,38 @@
PLCOpenParser = GenerateParserFromXSD(os.path.join(os.path.split(__file__)[0], "tc6_xml_v201.xsd"))
+LOAD_POU_PROJECT_TEMPLATE = """
+<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns="http://www.plcopen.org/xml/tc6_0201">
+ <fileHeader companyName="" productName="" productVersion=""
+ creationDateTime="1970-01-01T00:00:00"/>
+ <contentHeader name="paste_project">
+ <coordinateInfo>
+ <fbd><scaling x="0" y="0"/></fbd>
+ <ld><scaling x="0" y="0"/></ld>
+ <sfc><scaling x="0" y="0"/></sfc>
+ </coordinateInfo>
+ </contentHeader>
+ <types>
+ <dataTypes/>
+ <pous>%s</pous>
+ </types>
+ <instances>
+ <configurations/>
+ </instances>
+</project>
+"""
+
+def LOAD_POU_INSTANCES_PROJECT_TEMPLATE(body_type):
+ return LOAD_POU_PROJECT_TEMPLATE % """
+<pou name="paste_pou" pouType="program">
+ <body>
+ <%(body_type)s>%%s</%(body_type)s>
+ </body>
+</pou>""" % locals()
+
def LoadProject(filepath):
project_file = open(filepath)
project_xml = project_file.read().replace(
@@ -138,6 +170,22 @@
return etree.fromstring(project_xml, PLCOpenParser)
+def LoadPou(xml_string):
+ root = etree.fromstring(
+ LOAD_POU_PROJECT_TEMPLATE % xml_string,
+ PLCOpenParser)
+ return root.xpath(
+ "/ppx:project/ppx:types/ppx:pous/ppx:pou",
+ namespaces=PLCOpenParser.NSMAP)[0]
+
+def LoadPouInstances(xml_string, body_type):
+ root = etree.fromstring(
+ LOAD_POU_INSTANCES_PROJECT_TEMPLATE(body_type) % xml_string,
+ PLCOpenParser)
+ return root.xpath(
+ "/ppx:project/ppx:types/ppx:pous/ppx:pou[@name='paste_pou']/ppx:body/ppx:%s/*" % body_type,
+ namespaces=PLCOpenParser.NSMAP)
+
def SaveProject(project, filepath):
project_file = open(filepath, 'w')
project_file.write(etree.tostring(
@@ -2409,7 +2457,7 @@
def getconditionConnection(self):
if self.condition is not None:
content = self.condition.getcontent()
- if content.getLocalTag() == "connection":
+ if content.getLocalTag() == "connectionPointIn":
return content
return None
setattr(cls, "getconditionConnection", getconditionConnection)
@@ -2425,7 +2473,7 @@
def translate(self, dx, dy):
_translateSingle(self, dx, dy)
condition_connection = self.getconditionConnection()
- if condition_connection:
+ if condition_connection is not None:
_translateConnections(condition_connection, dx, dy)
setattr(cls, "translate", translate)