plugins/python/python.py
author laurent
Fri, 16 Dec 2011 22:55:13 +0100
changeset 654 9f6c091c316c
parent 430 5981ad8547f5
child 657 340c0b9caeca
permissions -rw-r--r--
Removing multiple definition of UndoBuffer
import wx
import os
import modules
from plugger import PlugTemplate, opjimg
from PLCControler import UndoBuffer
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")) 

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:
            open_pyeditor = True
            has_permissions = self.GetPlugRoot().CheckProjectPathPerm()
            if not has_permissions:
                dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame,
                                          _("You don't have write permissions.\nOpen PythonEditor anyway ?"),
                                          _("Open PythonEditor"),
                                          wx.YES_NO|wx.ICON_QUESTION)
                open_pyeditor = dialog.ShowModal() == wx.ID_YES
                dialog.Destroy()
            if open_pyeditor:
                def _onclose():
                    self._View = None
                if has_permissions:
                    def _onsave():
                        self.GetPlugRoot().SaveProject()
                else:
                    def _onsave():
                        pass
                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.encode("utf-8"))
        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.close()
        
        matiec_flags = '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath())
        
        return [(Gen_Pythonfile_path, matiec_flags)], "", True, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb"))