plugger.py
changeset 17 ee8cb104dbe0
parent 16 b2c02ca6271e
child 18 0fac6d621a24
--- a/plugger.py	Wed Aug 29 07:58:49 2007 +0200
+++ b/plugger.py	Fri Aug 31 15:11:30 2007 +0200
@@ -3,18 +3,20 @@
 """
 
 import os
+import plugins
 import types
 import shutil
 from xml.dom import minidom
-import plugins
 from xmlclass import GenerateClassesFromXSDstring
 
+from PLCControler import PLCControler
+
 _BaseParamsClass = GenerateClassesFromXSDstring("""<?xml version="1.0" encoding="ISO-8859-1" ?>
         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
           <xsd:element name="BaseParams">
             <xsd:complexType>
               <xsd:attribute name="Name" type="xsd:string" use="required"/>
-              <xsd:attribute name="IEC_Channel" type="xsd:integer" use="required"  default="-1"/>
+              <xsd:attribute name="IEC_Channel" type="xsd:integer" use="required"/>
               <xsd:attribute name="Enabled" type="xsd:boolean" use="required" default="true"/>
             </xsd:complexType>
           </xsd:element>
@@ -35,18 +37,22 @@
     def _AddParamsMembers(self):
         Classes = GenerateClassesFromXSDstring(self.XSD)[0]
         self.PlugParams = []
-        for name, XSDclass in Classes.items():
-            if XSDclass.IsBaseClass:
-                obj = XSDclass()
-                self.PlugParams.append( (name, obj) )
-                setattr(self, name, obj)
-
-    def __init__(self, PlugPath):
+        Classes = [(name, XSDclass) for name, XSDclass in Classes.items() if XSDclass.IsBaseClass]
+        if len(Classes) == 1:
+            name, XSDclass = Classes[0]
+            obj = XSDclass()
+            self.PlugParams = (name, obj)
+            setattr(self, name, obj)
+
+    def __init__(self):
         # Create BaseParam 
         self.BaseParams = _BaseParamsClass()
-        self.MandatoryParams = [("BaseParams", self.BaseParams)]
+        self.MandatoryParams = ("BaseParams", self.BaseParams)
         self._AddParamsMembers()
         self.PluggedChilds = {}
+
+    def PluginBaseXmlFilePath(self, PlugName=None):
+        return os.path.join(self.PlugPath(PlugName), "baseplugin.xml")
     
     def PluginXmlFilePath(self, PlugName=None):
         return os.path.join(self.PlugPath(PlugName), "plugin.xml")
@@ -62,26 +68,50 @@
     def OnPlugSave(self):
         return True
 
+    def GetPlugParamsAttributes(self):
+        return self.PlugParams[1].getElementAttributes()
+    
+    def SetPlugParamsAttribute(self, name, value):
+        attr = getattr(self.PlugParams[1], name, None)
+        if isinstance(attr, types.ClassType):
+            attr.SetValue(value)
+        else:
+            setattr(self.PlugParams[1], name, value)
+
     def PlugRequestSave(self):
         # If plugin do not have corresponding directory
-        if not os.path.isdir(self.PlugPath(PlugName)):
+        plugpath = self.PlugPath()
+        if not os.path.isdir(plugpath):
             # Create it
-            os.mkdir(self.PlugPath(PlugName))
-
-        # generate XML for all XML parameters controllers of the plugin
-        XMLString = '<?xml version="1.0" encoding="UTF-8"?>'
-        for nodeName, XMLController in self.PlugParams + self.MandatoryParams:
-            XMLString += XMLController.generateXMLTextMethod(self, nodeName, 0)
-        XMLFile = open(self.PluginXmlFilePath(PlugName),'w')
-        XMLFile.write(XMLString)
-        XMLFile.close()
+            os.mkdir(plugpath)
+
+        # generate XML for base XML parameters controller of the plugin
+        basexmlfilepath = self.PluginBaseXmlFilePath()
+        if basexmlfilepath:
+            BaseXMLFile = open(basexmlfilepath,'w')
+            BaseXMLFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+            BaseXMLFile.write(self.MandatoryParams[1].generateXMLText(self.MandatoryParams[0], 0))
+            BaseXMLFile.close()
+        
+        # generate XML for XML parameters controller of the plugin
+        xmlfilepath = self.PluginXmlFilePath()
+        if xmlfilepath:
+            XMLFile = open(xmlfilepath,'w')
+            XMLFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+            XMLFile.write(self.PlugParams[1].generateXMLText(self.PlugParams[0], 0))
+            XMLFile.close()
         
         # Call the plugin specific OnPlugSave method
-        self.OnPlugSave()
+        result = self.OnPlugSave()
+        if not result:
+            return "Error while saving \"%s\""%self.PlugPath()
         
         # go through all childs and do the same
         for PlugChild in self.IterChilds():
-            PlugChild.PlugRequestSave()
+            result = PlugChild.PlugRequestSave()
+            if result:
+                return result
+        return None
     
     def PlugImport(self, src_PlugPath):
         shutil.copytree(src_PlugPath, self.PlugPath)
@@ -92,7 +122,7 @@
         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_loc, IEC_Direction IEC_Type, Name)]\
+            [(IEC_loc, IEC_Direction, IEC_Type, Name)]\
             ex: [((0,0,4,5),'I','STRING','__IX_0_0_4_5'),...]
         """
         return [],""
@@ -132,7 +162,7 @@
     
     def _GetChildBySomething(self, sep, something, matching):
         toks = matching.split(sep,1)
-        for PlugInstance in self.IterChilds:
+        for PlugInstance in self.IterChilds():
             # if match component of the name
             if getattr(PlugInstance.BaseParams, something) == toks[0]:
                 # if Name have other components
@@ -150,6 +180,12 @@
     def GetChildByIECLocation(self, Location):
         return self._GetChildBySomething('_',"IEC_Channel", Name)
     
+    def GetPlugInfos(self):
+        childs = []
+        for child in self.IterChilds():
+            childs.append(child.GetPlugInfos())
+        return {"name" : self.BaseParams.getName(), "type" : None, "values" : childs}
+    
     def FindNewIEC_Channel(self, DesiredChannel):
         """
         Changes IEC Channel number to DesiredChannel if available, nearest available if not.
@@ -217,10 +253,10 @@
             PlugClass = PlugClass()
         
         # Eventualy Initialize child instance list for this class of plugin
-        PluggedChildsWithSameClass = self.PluggedChilds.setdefault(PlugType,list())
+        PluggedChildsWithSameClass = self.PluggedChilds.setdefault(PlugType, list())
         # Check count
-        if PlugClass.MaxCount and len(PluggedChildsWithSameClass) >= PlugClass.MaxCount:
-            raise Exception, "Max count (%d) reached for this plugin of type %s "%(PlugClass.MaxCount, PlugType)
+        if getattr(PlugClass, "PlugMaxCount", None) and len(PluggedChildsWithSameClass) >= PlugClass.PlugMaxCount:
+            raise Exception, "Max count (%d) reached for this plugin of type %s "%(PlugClass.PlugMaxCount, PlugType)
         
         # create the final class, derived of provided plugin and template
         class FinalPlugClass(PlugClass, PlugTemplate):
@@ -239,21 +275,25 @@
                 # If dir have already be made, and file exist
                 if os.path.isdir(_self.PlugPath(PlugName)) and os.path.isfile(_self.PluginXmlFilePath(PlugName)):
                     #Load the plugin.xml file into parameters members
-                    _self.LoadXMLParams()
+                    _self.LoadXMLParams(PlugName)
                     # Check that IEC_Channel is not already in use.
                     self.FindNewIEC_Channel(self.BaseParams.getIEC_Channel())
                     # Call the plugin real __init__
-                    PlugClass.__init__(_self)
+                    if getattr(PlugClass, "__init__", None):
+                        PlugClass.__init__(_self)
                     #Load and init all the childs
                     _self.LoadChilds()
                 else:
                     # If plugin do not have corresponding file/dirs - they will be created on Save
                     # Set plugin name
                     _self.BaseParams.setName(PlugName)
+                    os.mkdir(_self.PlugPath())
                     # Find an IEC number
                     _self.FindNewIEC_Channel(0)
                     # Call the plugin real __init__
-                    PlugClass.__init__(_self)
+                    if getattr(PlugClass, "__init__", None):
+                        PlugClass.__init__(_self)
+                    _self.PlugRequestSave()
 
         # Create the object out of the resulting class
         newPluginOpj = FinalPlugClass()
@@ -263,39 +303,50 @@
         return newPluginOpj
             
 
-    def LoadXMLParams(self):
-        # PlugParams have been filled, make a local dict to work with
-        PlugParams = dict(self.PlugParams + self.MandatoryParams)
+    def LoadXMLParams(self, PlugName = None, test = True):
+        # Get the base xml tree
+        basexmlfilepath = self.PluginBaseXmlFilePath(PlugName)
+        if basexmlfilepath:
+            basexmlfile = open(basexmlfilepath, 'r')
+            basetree = minidom.parse(basexmlfile)
+            self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0])
+            basexmlfile.close()
+        
         # Get the xml tree
-        xmlfile = open(self.PluginXmlFilePath(PlugName), 'r')
-        tree = minidom.parse(xmlfile)
-        xmlfile.close()
-        # for each root elements
-        for subtree in tree.childNodes:
-            # if a plugin specific parameter set
-            if subtree.nodeName in PlugParams:
-                #Load into associated xmlclass.
-                PlugParams[subtree.nodeName].loadXMLTree(subtree)
-        
-        # Basic check. Better to fail immediately.
-        if(self.BaseParams.getName() != PlugName):
-            raise Exception, "Project tree layout do not match plugin.xml %s!=%s "%(PlugName,self.BaseParams.getName())
-        # Now, self.PlugPath() should be OK
+        xmlfilepath = self.PluginXmlFilePath(PlugName)
+        if xmlfilepath:
+            xmlfile = open(xmlfilepath, 'r')
+            tree = minidom.parse(xmlfile)
+            self.PlugParams[1].loadXMLTree(tree.childNodes[0])
+            xmlfile.close()
+        
+        if test:
+            # Basic check. Better to fail immediately.
+            if not PlugName:
+                PlugName = os.path.split(self.PlugPath())[1].split(NameTypeSeparator)[0]
+            if (self.BaseParams.getName() != PlugName):
+                raise Exception, "Project tree layout do not match plugin.xml %s!=%s "%(PlugName, self.BaseParams.getName())
+            # Now, self.PlugPath() should be OK
 
     def LoadChilds(self):
         # Iterate over all PlugName@PlugType in plugin directory, and try to open them
         for PlugDir in os.listdir(self.PlugPath()):
-            if os.path.isdir(os.path.join(self.PlugPath(),PlugDir)) and \
+            if os.path.isdir(os.path.join(self.PlugPath(), PlugDir)) and \
                PlugDir.count(NameTypeSeparator) == 1:
                 try:
-                    self.PlugAddChild(*PlugDir.split[NameTypeSeparator])
+                    self.PlugAddChild(*PlugDir.split(NameTypeSeparator))
                 except Exception, e:
                     print e
 
+def _GetClassFunction(name):
+    def GetRootClass():
+        return getattr(__import__("plugins." + name), name).RootClass
+    return GetRootClass
+
 class PluginsRoot(PlugTemplate):
 
     # For root object, available Childs Types are modules of the plugin packages.
-    PlugChildsTypes = [(name,lambda : getattr(__import__("plugins." + name), name).RootClass) for name in plugins.__all__]
+    PlugChildsTypes = [(name, _GetClassFunction(name)) for name in plugins.__all__]
 
     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
@@ -314,33 +365,33 @@
                 <xsd:element name="Win32">
                   <xsd:complexType>
                     <xsd:attribute name="ToolChain" type="ppx:Win32Compiler" use="required" default="MinGW"/>
-                    <xsd:attribute name="Priority" type="xsd:integer" use="required" default="0"/>
+                    <xsd:attribute name="Priority" type="xsd:integer" use="required"/>
                   </xsd:complexType>
                 </xsd:element>
                 <xsd:element name="Linux">
                   <xsd:complexType>
                     <xsd:attribute name="Compiler" type="xsd:string" use="required" default="gcc"/>
-                    <xsd:attribute name="Nice" type="xsd:integer" use="required" default="0"/>
+                    <xsd:attribute name="Nice" type="xsd:integer" use="required"/>
                   </xsd:complexType>
                 </xsd:element>
                 <xsd:element name="Xenomai">
                   <xsd:complexType>
                     <xsd:attribute name="xeno-config" type="xsd:string" use="required" default="/usr/xenomai/"/>
-                    <xsd:attribute name="Compiler" type="xsd:string" use="required" default="0"/>
-                    <xsd:attribute name="Priority" type="xsd:integer" use="required" default="0"/>
+                    <xsd:attribute name="Compiler" type="xsd:string" use="required"/>
+                    <xsd:attribute name="Priority" type="xsd:integer" use="required"/>
                   </xsd:complexType>
                 </xsd:element>
                 <xsd:element name="RTAI">
                   <xsd:complexType>
-                    <xsd:attribute name="xeno-config" type="xsd:string" use="required" default="0"/>
-                    <xsd:attribute name="Compiler" type="xsd:string" use="required" default="0"/>
-                    <xsd:attribute name="Priority" type="xsd:integer" use="required" default="0"/>
+                    <xsd:attribute name="xeno-config" type="xsd:string" use="required"/>
+                    <xsd:attribute name="Compiler" type="xsd:string" use="required"/>
+                    <xsd:attribute name="Priority" type="xsd:integer" use="required"/>
                   </xsd:complexType>
                 </xsd:element>
                 <xsd:element name="Library">
                   <xsd:complexType>
-                    <xsd:attribute name="Dynamic" type="xsd:boolean" default="true"/>
-                    <xsd:attribute name="Compiler" type="xsd:string" use="required" default="0"/>
+                    <xsd:attribute name="Dynamic" type="xsd:boolean" use="required" default="true"/>
+                    <xsd:attribute name="Compiler" type="xsd:string" use="required"/>
                   </xsd:complexType>
                 </xsd:element>
               </xsd:choice>
@@ -351,29 +402,120 @@
     </xsd:schema>
     """
 
-    def __init__(self, ProjectPath):
+    def __init__(self):
+        PlugTemplate.__init__(self)
         # self is the parent
         self.PlugParent = None
         # Keep track of the plugin type name
         self.PlugType = "Beremiz"
-        # Keep track of the root plugin (i.e. project path)
-        self.ProjectPath = ProjectPath
+        
+        self.ProjectPath = ""
+        self.PLCManager = None
+    
+    def HasProjectOpened(self):
+        """
+        Return if a project is actually opened
+        """
+        return self.ProjectPath != ""
+    
+    def GetProjectPath(self):
+        return self.ProjectPath
+    
+    def GetTargetTypes(self):
+        return self.BeremizRoot.TargetType.getChoices().keys()
+    
+    def ChangeTargetType(self, target_type):
+        self.BeremizRoot.TargetType.addContent(target_type)
+        
+    def GetTargetAttributes(self):
+        content = self.BeremizRoot.TargetType.getContent()
+        if content:
+            return content["value"].getElementAttributes()
+        else:
+            return []
+        
+    def SetTargetAttribute(self, name, value):
+        content = self.BeremizRoot.TargetType.getContent()
+        if content:
+            attr = getattr(content["value"], name, None)
+            if isinstance(attr, types.ClassType):
+                attr.SetValue(value)
+            else:
+                setattr(content["value"], name, value)
+    
+    def GetTargetType(self):
+        content = self.BeremizRoot.TargetType.getContent()
+        if content:
+            return content["name"]
+        else:
+            return ""
+    
+    def NewProject(self, ProjectPath, PLCParams):
+        """
+        Create a new project in an empty folder
+        @param ProjectPath: path of the folder where project have to be created
+        @param PLCParams: properties of the PLCOpen program created
+        """
+        # Verify that choosen folder is empty
+        if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0:
+            return "Folder choosen isn't empty. You can't use it for a new project!"
+        # Create Controler for PLCOpen program
+        self.PLCManager = PLCControler()
+        self.PLCManager.CreateNewProject(PLCParams.pop("projectName"))
+        self.PLCManager.SetProjectProperties(properties = PLCParams)
         # Change XSD into class members
         self._AddParamsMembers()
         self.PluggedChilds = {}
         # No IEC channel, name, etc...
         self.MandatoryParams = []
+        # Keep track of the root plugin (i.e. project path)
+        self.ProjectPath = ProjectPath
+        self.BaseParams.setName(os.path.split(ProjectPath)[1])
+        return None
+        
+    def LoadProject(self, ProjectPath):
+        """
+        Load a project contained in a folder
+        @param ProjectPath: path of the project folder
+        """
+        # Verify that project contains a PLCOpen program
+        plc_file = os.path.join(ProjectPath, "plc.xml")
+        if not os.path.isfile(plc_file):
+            return "Folder choosen doesn't contain a program. It's not a valid project!"
+        # Create Controler for PLCOpen program
+        self.PLCManager = PLCControler()
+        # Load PLCOpen file
+        result = self.PLCManager.OpenXMLFile(plc_file)
+        if result:
+            return result
+        # Change XSD into class members
+        self._AddParamsMembers()
+        self.PluggedChilds = {}
+        # No IEC channel, name, etc...
+        self.MandatoryParams = None
+        # Keep track of the root plugin (i.e. project path)
+        self.ProjectPath = ProjectPath
         # If dir have already be made, and file exist
-        if os.path.isdir(_self.PlugPath(PlugName)) and os.path.isfile(_self.PluginXmlFilePath(PlugName)):
+        if os.path.isdir(self.PlugPath()) and os.path.isfile(self.PluginXmlFilePath()):
             #Load the plugin.xml file into parameters members
-            _self.LoadXMLParams()
+            result = self.LoadXMLParams(test = False)
+            if result:
+                return result
             #Load and init all the childs
-            _self.LoadChilds()
-
-    def PlugPath(self,PlugName=None):
+            self.LoadChilds()
+        self.BaseParams.setName(os.path.split(ProjectPath)[1])
+        return None
+    
+    def SaveProject(self):
+        if not self.PLCManager.SaveXMLFile():
+            self.PLCManager.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
+        self.PlugRequestSave()
+    
+    def PlugPath(self, PlugName=None):
         return self.ProjectPath
-        
+    
+    def PluginBaseXmlFilePath(self, PlugName=None):
+        return None
+    
     def PluginXmlFilePath(self, PlugName=None):
         return os.path.join(self.PlugPath(PlugName), "beremiz.xml")
-    
-