--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/python/python.py Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,280 @@
+import wx
+import os
+import modules
+from plugger import PlugTemplate, opjimg
+from PythonEditor import PythonEditorFrame
+
+from xml.dom import minidom
+from xmlclass import *
+import cPickle
+
+PythonClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "python_xsd.xsd"))
+
+#-------------------------------------------------------------------------------
+# Undo Buffer for PythonCode
+#-------------------------------------------------------------------------------
+
+# Length of the buffer
+UNDO_BUFFER_LENGTH = 20
+
+"""
+Class implementing a buffer of changes made on the current editing model
+"""
+class UndoBuffer:
+
+ # Constructor initialising buffer
+ def __init__(self, currentstate, issaved = False):
+ self.Buffer = []
+ self.CurrentIndex = -1
+ self.MinIndex = -1
+ self.MaxIndex = -1
+ # if current state is defined
+ if currentstate:
+ self.CurrentIndex = 0
+ self.MinIndex = 0
+ self.MaxIndex = 0
+ # Initialising buffer with currentstate at the first place
+ for i in xrange(UNDO_BUFFER_LENGTH):
+ if i == 0:
+ self.Buffer.append(currentstate)
+ else:
+ self.Buffer.append(None)
+ # Initialising index of state saved
+ if issaved:
+ self.LastSave = 0
+ else:
+ self.LastSave = -1
+
+ # Add a new state in buffer
+ def Buffering(self, currentstate):
+ self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
+ self.Buffer[self.CurrentIndex] = currentstate
+ # Actualising buffer limits
+ self.MaxIndex = self.CurrentIndex
+ if self.MinIndex == self.CurrentIndex:
+ # If the removed state was the state saved, there is no state saved in the buffer
+ if self.LastSave == self.MinIndex:
+ self.LastSave = -1
+ self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH
+ self.MinIndex = max(self.MinIndex, 0)
+
+ # Return current state of buffer
+ def Current(self):
+ return self.Buffer[self.CurrentIndex]
+
+ # Change current state to previous in buffer and return new current state
+ def Previous(self):
+ if self.CurrentIndex != self.MinIndex:
+ self.CurrentIndex = (self.CurrentIndex - 1) % UNDO_BUFFER_LENGTH
+ return self.Buffer[self.CurrentIndex]
+ return None
+
+ # Change current state to next in buffer and return new current state
+ def Next(self):
+ if self.CurrentIndex != self.MaxIndex:
+ self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
+ return self.Buffer[self.CurrentIndex]
+ return None
+
+ # Return True if current state is the first in buffer
+ def IsFirst(self):
+ return self.CurrentIndex == self.MinIndex
+
+ # Return True if current state is the last in buffer
+ def IsLast(self):
+ return self.CurrentIndex == self.MaxIndex
+
+ # Note that current state is saved
+ def CurrentSaved(self):
+ self.LastSave = self.CurrentIndex
+
+ # Return True if current state is saved
+ def IsCurrentSaved(self):
+ return self.LastSave == self.CurrentIndex
+
+class PythonCodeTemplate:
+
+ def __init__(self):
+
+ self.PluginMethods.insert(0,
+ {"bitmap" : opjimg("editPYTHONcode"),
+ "name" : _("Edit Python File"),
+ "tooltip" : _("Edit Python File"),
+ "method" : "_OpenView"},
+ )
+
+ filepath = self.PythonFileName()
+
+ self.Buffering = False
+ self.PythonCode = PythonClasses["Python"]()
+ self.PythonBuffer = UndoBuffer(self.Copy(self.PythonCode), False)
+ if os.path.isfile(filepath):
+ xmlfile = open(filepath, 'r')
+ tree = minidom.parse(xmlfile)
+ xmlfile.close()
+
+ for child in tree.childNodes:
+ if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "Python":
+ self.PythonCode.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"])
+ self.PythonBuffer = UndoBuffer(self.Copy(self.PythonCode), True)
+ else:
+ self.OnPlugSave()
+
+ def PluginPath(self):
+ return os.path.join(self.PlugParent.PluginPath(), "modules", self.PlugType)
+
+ def PythonFileName(self):
+ return os.path.join(self.PlugPath(), "python.xml")
+
+ def GetFilename(self):
+ if self.PythonBuffer.IsCurrentSaved():
+ return "python"
+ else:
+ return "~python~"
+
+ def SetPythonCode(self, text):
+ self.PythonCode.settext(text)
+
+ def GetPythonCode(self):
+ return self.PythonCode.gettext()
+
+ _View = None
+ def _OpenView(self):
+ if not self._View:
+ def _onclose():
+ self._View = None
+ def _onsave():
+ self.GetPlugRoot().SaveProject()
+ self._View = PythonEditorFrame(self.GetPlugRoot().AppFrame, self)
+ self._View._onclose = _onclose
+ self._View._onsave = _onsave
+ self._View.Show()
+
+ def OnPlugSave(self):
+ filepath = self.PythonFileName()
+
+ text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ extras = {"xmlns":"http://www.w3.org/2001/XMLSchema",
+ "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
+ "xsi:schemaLocation" : "python_xsd.xsd"}
+ text += self.PythonCode.generateXMLText("Python", 0, extras)
+
+ xmlfile = open(filepath,"w")
+ xmlfile.write(text)
+ xmlfile.close()
+
+ self.PythonBuffer.CurrentSaved()
+ return True
+
+#-------------------------------------------------------------------------------
+# Current Buffering Management Functions
+#-------------------------------------------------------------------------------
+
+ """
+ Return a copy of the project
+ """
+ def Copy(self, model):
+ return cPickle.loads(cPickle.dumps(model))
+
+ def BufferPython(self):
+ self.PythonBuffer.Buffering(self.Copy(self.PythonCode))
+
+ def StartBuffering(self):
+ self.PythonBuffer.Buffering(self.PythonCode)
+ self.Buffering = True
+
+ def EndBuffering(self):
+ if self.Buffering:
+ self.PythonCode = self.Copy(self.PythonCode)
+ self.Buffering = False
+
+ def PythonCodeIsSaved(self):
+ if self.PythonBuffer:
+ return self.PythonBuffer.IsCurrentSaved()
+ else:
+ return True
+
+ def LoadPrevious(self):
+ self.PythonCode = self.Copy(self.PythonBuffer.Previous())
+
+ def LoadNext(self):
+ self.PythonCode = self.Copy(self.PythonBuffer.Next())
+
+ def GetBufferState(self):
+ first = self.PythonBuffer.IsFirst()
+ last = self.PythonBuffer.IsLast()
+ return not first, not last
+
+def _GetClassFunction(name):
+ def GetRootClass():
+ __import__("plugins.python.modules." + name)
+ return getattr(modules, name).RootClass
+ return GetRootClass
+
+class RootClass(PythonCodeTemplate):
+
+ # For root object, available Childs Types are modules of the modules packages.
+ PlugChildsTypes = [(name, _GetClassFunction(name), help) for name, help in zip(modules.__all__,modules.helps)]
+
+ def PluginPath(self):
+ return os.path.join(self.PlugParent.PluginPath(), self.PlugType)
+
+ def PlugGenerate_C(self, buildpath, locations):
+ """
+ Generate C code
+ @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
+ @param locations: List of complete variables locations \
+ [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
+ "NAME" : name of the variable (generally "__IW0_1_2" style)
+ "DIR" : direction "Q","I" or "M"
+ "SIZE" : size "X", "B", "W", "D", "L"
+ "LOC" : tuple of interger for IEC location (0,1,2,...)
+ }, ...]
+ @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
+ """
+ current_location = self.GetCurrentLocation()
+ # define a unique name for the generated C file
+ location_str = "_".join(map(lambda x:str(x), current_location))
+
+ plugin_root = self.GetPlugRoot()
+ plugin_root.GetIECProgramsAndVariables()
+
+ plc_python_filepath = os.path.join(os.path.split(__file__)[0], "plc_python.c")
+ plc_python_file = open(plc_python_filepath, 'r')
+ plc_python_code = plc_python_file.read()
+ plc_python_file.close()
+ python_eval_fb_list = []
+ for v in plugin_root._VariablesList :
+ if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL","PYTHON_POLL"]:
+ python_eval_fb_list.append(v)
+ python_eval_fb_count = max(1, len(python_eval_fb_list))
+
+ # prepare python code
+ plc_python_code = plc_python_code % {
+ "python_eval_fb_count": python_eval_fb_count,
+ "location": location_str}
+
+ Gen_Pythonfile_path = os.path.join(buildpath, "python_%s.c"%location_str)
+ pythonfile = open(Gen_Pythonfile_path,'w')
+ pythonfile.write(plc_python_code)
+ pythonfile.close()
+
+ runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str)
+ runtimefile = open(runtimefile_path, 'w')
+ runtimefile.write(self.GetPythonCode())
+ runtimefile.write("""
+def _runtime_%(location)s_begin():
+ print "runtime_begin"
+
+def _runtime_%(location)s_cleanup():
+ print "runtime_cleanup"
+
+""" % {"location": location_str})
+ runtimefile.close()
+
+ if wx.Platform == '__WXMSW__':
+ matiec_flags = " -I../../matiec/lib"
+ else:
+ matiec_flags = " -I../matiec/lib"
+
+ return [(Gen_Pythonfile_path, matiec_flags)], "", True, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb"))