--- a/plugins/c_ext/c_ext.py Tue May 06 15:22:18 2008 +0200
+++ b/plugins/c_ext/c_ext.py Fri May 23 10:31:26 2008 +0200
@@ -1,16 +1,106 @@
import wx
-import wx.stc as stc
-import os, sys, shutil
-from CppSTC import CppSTC
+import os
from plugger import PlugTemplate
-import tempfile
+from CFileEditor import CFileEditor
+
+from xml.dom import minidom
+from xmlclass import *
+import cPickle
+
+CFileClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "cext_xsd.xsd"))
+
+#-------------------------------------------------------------------------------
+# Undo Buffer for CFile
+#-------------------------------------------------------------------------------
+
+# 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
+
+
+TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L",
+ "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L",
+ "STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"}
class _Cfile:
XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="C_Extension">
+ <xsd:element name="CExtension">
<xsd:complexType>
- <xsd:attribute name="C_Files" type="xsd:string" use="optional" default="myfile.c"/>
<xsd:attribute name="CFLAGS" type="xsd:string" use="required"/>
<xsd:attribute name="LDFLAGS" type="xsd:string" use="required"/>
</xsd:complexType>
@@ -18,105 +108,117 @@
</xsd:schema>
"""
def __init__(self):
- self.CheckCFilesExist()
-
- def CheckCFilesExist(self):
- for CFile in self.CFileNames():
- if not os.path.isfile(CFile):
- f = open(CFile, 'w')
- f.write("/*Empty*/")
- f.close()
-
- def CFileBaseNames(self):
- """
- Returns list of C files base names, out of C_Extension.C_Files, coma separated list
- """
- return map(str.strip,str(self.C_Extension.getC_Files()).split(','))
-
- def CFileName(self, fn):
- return os.path.join(self.PlugPath(),fn)
-
- def CFileNames(self):
- """
- Returns list of full C files paths, out of C_Extension.C_Files, coma separated list
- """
- return map(self.CFileName, self.CFileBaseNames())
-
- def SetParamsAttribute(self, path, value, logger):
- """
- Take actions if C_Files changed
- """
- # Get a C files list before changes
- oldnames = self.CFileNames()
- # Apply changes
- res = PlugTemplate.SetParamsAttribute(self, path, value, logger)
- # If changes was about C files,
- if path == "C_Extension.C_Files":
- # Create files if did not exist
- self.CheckCFilesExist()
- # Get new list
- newnames = self.CFileNames()
- # Move unused files into trash (temporary directory)
- for oldfile in oldnames:
- if oldfile not in newnames:
- # define new "trash" name
- trashname = os.path.join(tempfile.gettempdir(),os.path.basename(oldfile))
- # move the file
- shutil.move(oldfile, trashname)
- # warn user
- logger.write_warning("\"%s\" moved to \"%s\"\n"%(oldfile, trashname))
- return value, False
- return res
-
- _Views = {}
+ filepath = self.CFileName()
+
+ self.Buffering = False
+ self.CFile = CFileClasses["CFile"]()
+ self.CFileBuffer = UndoBuffer(self.Copy(self.CFile), 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 == "CFile":
+ self.CFile.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"])
+ self.CFileBuffer = UndoBuffer(self.Copy(self.CFile), True)
+ else:
+ self.OnPlugSave()
+
+ def CFileName(self):
+ return os.path.join(self.PlugPath(), "cfile.xml")
+
+ def GetFilename(self):
+ if self.CFileBuffer.IsCurrentSaved():
+ return "cfile"
+ else:
+ return "~cfile~"
+
+ def GetBaseTypes(self):
+ return self.GetPlugRoot().GetBaseTypes()
+
+ def GetDataTypes(self, basetypes = False):
+ return self.GetPlugRoot().GetDataTypes(basetypes = basetypes)
+
+ def GetSizeOfType(self, type):
+ return TYPECONVERSION[self.GetPlugRoot().GetBaseType(type)]
+
+ def SetVariables(self, variables):
+ self.CFile.variables.setvariable([])
+ for var in variables:
+ variable = CFileClasses["variables_variable"]()
+ variable.setname(var["Name"])
+ variable.settype(var["Type"])
+ variable.setclass(var["Class"])
+ self.CFile.variables.appendvariable(variable)
+
+ def GetVariables(self):
+ datas = []
+ for var in self.CFile.variables.getvariable():
+ datas.append({"Name" : var.getname(), "Type" : var.gettype(), "Class" : var.getclass()})
+ return datas
+
+ def SetPartText(self, name, text):
+ if name == "Includes":
+ self.CFile.includes.settext(text)
+ elif name == "Globals":
+ self.CFile.globals.settext(text)
+ elif name == "Init":
+ self.CFile.initFunction.settext(text)
+ elif name == "CleanUp":
+ self.CFile.cleanUpFunction.settext(text)
+ elif name == "Retrieve":
+ self.CFile.retrieveFunction.settext(text)
+ elif name == "Publish":
+ self.CFile.publishFunction.settext(text)
+
+ def GetPartText(self, name):
+ if name == "Includes":
+ return self.CFile.includes.gettext()
+ elif name == "Globals":
+ return self.CFile.globals.gettext()
+ elif name == "Init":
+ return self.CFile.initFunction.gettext()
+ elif name == "CleanUp":
+ return self.CFile.cleanUpFunction.gettext()
+ elif name == "Retrieve":
+ return self.CFile.retrieveFunction.gettext()
+ elif name == "Publish":
+ return self.CFile.publishFunction.gettext()
+ return ""
+
+ _View = None
def _OpenView(self, logger):
- lst = self.CFileBaseNames()
-
- dlg = wx.MultiChoiceDialog( self.GetPlugRoot().AppFrame,
- "Choose C files to Edit :",
- "Edit", lst)
-
- if (dlg.ShowModal() == wx.ID_OK):
- selections = dlg.GetSelections()
- for selected in [lst[x] for x in selections]:
- if selected not in self._Views:
- # keep track of selected name as static for later close
- def _onclose(evt, sel = selected):
- self.SaveCView(sel)
- self._Views.pop(sel)
- evt.Skip()
- New_View = wx.Frame(self.GetPlugRoot().AppFrame,-1,selected)
- New_View.Bind(wx.EVT_CLOSE, _onclose)
- ed = CppSTC(New_View, wx.NewId())
- ed.SetText(open(self.CFileName(selected)).read())
- ed.EmptyUndoBuffer()
- ed.Colourise(0, -1)
- ed.SetMarginType(1, stc.STC_MARGIN_NUMBER)
- ed.SetMarginWidth(1, 25)
- New_View.ed = ed
- New_View.Show()
- self._Views[selected] = New_View
-
- dlg.Destroy()
-
+ if not self._View:
+ def _onclose():
+ self._View = None
+ def _onsave():
+ self.GetPlugRoot().SaveProject()
+ self._View = CFileEditor(self.GetPlugRoot().AppFrame, self)
+ self._View._onclose = _onclose
+ self._View._onsave = _onsave
+ self._View.Show()
PluginMethods = [
{"name" : "Edit C File",
"tooltip" : "Edit C File",
"method" : "_OpenView"},
- {"name" : "Import C File",
- "tooltip" : "Import C File",
- "method" : "_OpenView"}
]
- def SaveCView(self, name):
- f = open(self.CFileName(name),'w')
- f.write(self._Views[name].ed.GetText())
- f.close()
-
def OnPlugSave(self):
- for name in self._Views:
- self.SaveCView(name)
+ filepath = self.CFileName()
+
+ 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" : "cext_xsd.xsd"}
+ text += self.CFile.generateXMLText("CFile", 0, extras)
+
+ xmlfile = open(filepath,"w")
+ xmlfile.write(text)
+ xmlfile.close()
+
+ self.CFileBuffer.CurrentSaved()
return True
def PlugGenerate_C(self, buildpath, locations, logger):
@@ -135,26 +237,126 @@
current_location = self.GetCurrentLocation()
# define a unique name for the generated C file
location_str = "_".join(map(lambda x:str(x), current_location))
- res = []
- for CFile in self.CFileBaseNames():
- Gen_Cfile_path = os.path.join(buildpath, "CFile_%s_%s.c"%(location_str, os.path.splitext(CFile)[0]))
- f = open(Gen_Cfile_path,'w')
- f.write("/* Header generated by Beremiz c_ext plugin */\n")
- f.write("#include \"iec_std_lib.h\"\n")
- f.write("#define EXT_C_INIT __init_%s\n"%location_str)
- f.write("#define EXT_C_CLEANUP __init_%s\n"%location_str)
- f.write("#define EXT_C_PUBLISH __init_%s\n"%location_str)
- f.write("#define EXT_C_RETRIEVE __init_%s\n"%location_str)
- for loc in locations:
- f.write(loc["IEC_TYPE"]+" "+loc["NAME"]+";\n")
- f.write("/* End of header generated by Beremiz c_ext plugin */\n\n")
- src_file = open(self.CFileName(CFile),'r')
- f.write(src_file.read())
- src_file.close()
- f.close()
- res.append((Gen_Cfile_path,str(self.C_Extension.getCFLAGS())))
- return res,str(self.C_Extension.getLDFLAGS()),True
-
+
+ text = "/* Code generated by Beremiz c_ext plugin */\n\n"
+
+ # Adding includes
+ text += "/* User includes */\n"
+ text += self.CFile.includes.gettext()
+ text += "\n"
+
+ text += """/* Beremiz c_ext plugin includes */
+#ifdef _WINDOWS_H
+ #include "iec_types.h"
+#else
+ #include "iec_std_lib.h"
+#endif
+
+"""
+
+ # Adding variables
+ vars = []
+ inputs = outputs = 0
+ for variable in self.CFile.variables.variable:
+ var = {"Name" : variable.getname(), "Type" : variable.gettype()}
+ if variable.getclass() == "input":
+ var["location"] = "__I%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, inputs)
+ inputs += 1
+ else:
+ var["location"] = "__Q%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, outputs)
+ outputs += 1
+ vars.append(var)
+ text += "/* Beremiz c_ext plugin user variables definition */\n"
+ text += "#ifdef _WINDOWS_H\n"
+ base_types = self.GetPlugRoot().GetBaseTypes()
+ for var in vars:
+ if var["Type"] in base_types:
+ prefix = "IEC_"
+ else:
+ prefix = ""
+ text += "%s%s %s;\n"%(prefix, var["Type"], var["location"])
+ text += "#else\n"
+ for var in vars:
+ text += "%s %s;\n"%(var["Type"], var["location"])
+ text += "#endif\n\n"
+ text += "/* User variables reference */\n"
+ for var in vars:
+ text += "#define %s %s;\n"%(var["Name"], var["location"])
+ text += "\n"
+
+ # Adding user global variables and routines
+ text += "/* User internal user variables and routines */\n"
+ text += self.CFile.globals.gettext()
+
+ # Adding Beremiz plugin functions
+ text += "/* Beremiz plugin functions */\n"
+ text += "int __init_%s(int argc,char **argv)\n{\n"%location_str
+ text += self.CFile.initFunction.gettext()
+ text += "\n}\n\n"
+
+ text += "void __cleanup_%s()\n{\n"%location_str
+ text += self.CFile.cleanUpFunction.gettext()
+ text += "\n}\n\n"
+
+ text += "void __retrieve_%s()\n{\n"%location_str
+ text += self.CFile.retrieveFunction.gettext()
+ text += "\n}\n\n"
+
+ text += "void __publish_%s()\n{\n"%location_str
+ text += self.CFile.publishFunction.gettext()
+ text += "\n}\n\n"
+
+ Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c"%location_str)
+ cfile = open(Gen_Cfile_path,'w')
+ cfile.write(text)
+ cfile.close()
+
+ if wx.Platform == '__WXMSW__':
+ matiec_flags = " -I../../matiec/lib"
+ else:
+ matiec_flags = " -I../matiec/lib"
+
+ return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_flags))],str(self.CExtension.getLDFLAGS()),True
+
+#-------------------------------------------------------------------------------
+# Current Buffering Management Functions
+#-------------------------------------------------------------------------------
+
+ """
+ Return a copy of the project
+ """
+ def Copy(self, model):
+ return cPickle.loads(cPickle.dumps(model))
+
+ def BufferCFile(self):
+ self.CFileBuffer.Buffering(self.Copy(self.CFile))
+
+ def StartBuffering(self):
+ self.CFileBuffer.Buffering(self.CFile)
+ self.Buffering = True
+
+ def EndBuffering(self):
+ if self.Buffering:
+ self.CFile = self.Copy(self.CFile)
+ self.Buffering = False
+
+ def CFileIsSaved(self):
+ if self.CFileBuffer:
+ return self.CFileBuffer.IsCurrentSaved()
+ else:
+ return True
+
+ def LoadPrevious(self):
+ self.CFile = self.Copy(self.CFileBuffer.Previous())
+
+ def LoadNext(self):
+ self.CFile = self.Copy(self.CFileBuffer.Next())
+
+ def GetBufferState(self):
+ first = self.CFileBuffer.IsFirst()
+ last = self.CFileBuffer.IsLast()
+ return not first, not last
+
class RootClass:
PlugChildsTypes = [("C_File",_Cfile, "C file")]