--- a/Beremiz.py Fri Feb 22 19:04:01 2008 +0100
+++ b/Beremiz.py Sun Feb 24 02:06:42 2008 +0100
@@ -36,8 +36,6 @@
from plugger import PluginsRoot
-from wxPopen import wxPopen3
WINDOW_COLOUR = wx.Colour(240,240,240)
TITLE_COLOUR = wx.Colour(200,200,220)
@@ -72,30 +70,14 @@
# Patch wx.lib.imageutils so that gray is supported on alpha images
+from wx.lib.imageutils import grayOut as old_grayOut
- Convert the given image (in place) to a grayed-out
- version, appropriate for a 'disabled' appearance.
- factor = 0.7 # 0 < f < 1. Higher is grayer.
- maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
AlphaData = anImage.GetAlphaData()
- data = map(ord, list(anImage.GetData()))
- for i in range(0, len(data), 3):
- pixel = (data[i], data[i+1], data[i+2])
- pixel = wx.lib.imageutils.makeGray(pixel, factor, maskColor)
- anImage.SetData(''.join(map(chr, data)))
if AlphaData is not None:
anImage.SetAlphaData(AlphaData)
@@ -136,22 +118,23 @@
""" Base class for file like objects to facilitate StdOut for the Shell."""
- def __init__(self, output = None):
+ def __init__(self, output): self.red_white = wx.TextAttr("RED", "WHITE")
self.red_yellow = wx.TextAttr("RED", "YELLOW")
self.black_white = wx.TextAttr("BLACK", "WHITE")
self.default_style = None
- def writelines(self, l):
def write(self, s, style = None):
- if not style : style=self.black_white
+ if style is None : style=self.black_white if self.default_style != style:
self.output.SetDefaultStyle(style)
self.default_style = style
- self.output.AppendText(s)
+ self.output.AppendText(s) + self.output.ScrollLines(s.count('\n')+1) + self.output.ShowPosition(self.output.GetLastPosition()) def write_warning(self, s):
self.write(s,self.red_white)
@@ -165,42 +148,6 @@
- def LogCommand(self, Command, sz_limit = 100, no_stdout=False):
- if self.errlen > sz_limit:
- self.write(Command + "\n")
- self.write_warning("exited with status %d (pid %d)\n"%(ecode,pid))
- p = wxPopen3(Command, input, output, errors, fin, self.output)
- return (self.exitcode, self.outdata, self.errdata)
[ID_BEREMIZ, ID_BEREMIZMAINSPLITTER,
ID_BEREMIZPLCCONFIG, ID_BEREMIZLOGCONSOLE,
] = [wx.NewId() for _init_ctrls in range(4)]
@@ -869,9 +816,15 @@
def GetButtonCallBackFunction(self, plugin, method):
+ """ Generate the callbackfunc for a given plugin method""" def OnButtonClick(event):
+ # Disable button to prevent re-entrant call + event.GetEventObject().Disable() getattr(plugin,method)(self.Log)
- #self.RefreshVariableLists()
+ event.GetEventObject().Enable() + # Trigger refresh on Idle wx.CallAfter(self.RefreshAll)
--- a/plugger.py Fri Feb 22 19:04:01 2008 +0100
+++ b/plugger.py Sun Feb 24 02:06:42 2008 +0100
@@ -8,13 +8,13 @@
from xml.dom import minidom
-import subprocess, ctypes, time, shutil
#Quick hack to be able to find Beremiz IEC tools. Should be config params.
base_folder = os.path.split(sys.path[0])[0]
sys.path.append(os.path.join(base_folder, "plcopeneditor"))
from xmlclass import GenerateClassesFromXSDstring
+from wxPopen import ProcessLogger _BaseParamsClass = GenerateClassesFromXSDstring("""<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
@@ -670,6 +670,9 @@
# copy PluginMethods so that it can be later customized
self.PluginMethods = [dic.copy() for dic in self.PluginMethods]
def HasProjectOpened(self):
@@ -860,7 +863,13 @@
logger.write("Compiling IEC Program in to C code...\n")
# Now compile IEC code into many C files
# files are listed to stdout, and errors to stderr.
- status, result, err_result = logger.LogCommand("%s \"%s\" -I \"%s\" \"%s\""%(iec2c_path, self._getIECcodepath(), ieclib_path, buildpath), no_stdout=True)
+ status, result, err_result = ProcessLogger( + "%s \"%s\" -I \"%s\" \"%s\""%( + self._getIECcodepath(), + ieclib_path, buildpath), logger.write_error("Error : IEC to C compiler returned %d\n"%status)
@@ -893,12 +902,16 @@
logger.write("Start build in %s\n" % buildpath)
+ self.EnableMethod("_Clean", True) + self.EnableMethod("_showIECcode", True) if not self._Generate_SoftPLC(logger):
logger.write_error("SoftPLC code generation failed !\n")
#logger.write("SoftPLC code generation successfull\n")
logger.write("Generating plugins code ...\n")
@@ -960,7 +973,13 @@
logger.write(" [CC] "+bn+" -> "+obn+"\n")
objectfilename = os.path.splitext(CFile)[0]+".o"
- status, result, err_result = logger.LogCommand("\"%s\" -c \"%s\" -o \"%s\" %s %s"%(compiler, CFile, objectfilename, _CFLAGS, CFLAGS))
+ status, result, err_result = ProcessLogger( + "\"%s\" -c \"%s\" -o \"%s\" %s %s"% + (compiler, CFile, objectfilename, _CFLAGS, CFLAGS) logger.write_error("Build failed\n")
@@ -972,7 +991,14 @@
exe_path = os.path.join(buildpath, exe)
logger.write(" [CC] " + ' '.join(obns)+" -> " + exe + "\n")
- status, result, err_result = logger.LogCommand("\"%s\" \"%s\" -o \"%s\" %s"%(linker, '" "'.join(objs), exe_path, ' '.join(LDFLAGS+[_LDFLAGS])))
+ status, result, err_result = ProcessLogger( + "\"%s\" \"%s\" -o \"%s\" %s"% + ' '.join(LDFLAGS+[_LDFLAGS])) logger.write_error("Build failed\n")
self.EnableMethod("_Run", False)
@@ -1034,24 +1060,42 @@
shutil.rmtree(os.path.join(self._getBuildPath()))
logger.write_error("Build directory already clean\n")
+ self.EnableMethod("_showIECcode", False) + self.EnableMethod("_Clean", False) + self.EnableMethod("_Run", False)
command_start_plc = os.path.join(self._getBuildPath(),self.GetProjectName() + exe_ext)
if os.path.isfile(command_start_plc):
- logger.write("\nStarting PLC\n")
- self.pid_plc = subprocess.Popen(command_start_plc).pid
+ logger.write("Starting PLC\n") + def this_plc_finish_callback(*args): + if self.runningPLC is not None: + self.runningPLC = ProcessLogger( + finish_callback = this_plc_finish_callback) + self.EnableMethod("_Clean", False) + self.EnableMethod("_Run", False) + self.EnableMethod("_Stop", True) + self.EnableMethod("_build", False) logger.write_error("%s doesn't exist\n" %command_start_plc)
+ def reset_finished(self): + self.EnableMethod("_Clean", True) + self.EnableMethod("_Run", True) + self.EnableMethod("_Stop", False) + self.EnableMethod("_build", True)
+ if self.runningPLC is not None: logger.write("Stopping PLC\n")
- handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.pid_plc)
- ctypes.windll.kernel32.TerminateProcess(handle, -1)
- ctypes.windll.kernel32.CloseHandle(handle)
+ was_runningPLC = self.runningPLC {"bitmap" : os.path.join("images", "editPLC"),
@@ -1078,10 +1122,10 @@
{"bitmap" : os.path.join("images", "ShowIECcode"),
"name" : "Show IEC code",
"tooltip" : "Show IEC code generated by PLCGenerator",
"method" : "_showIECcode"},
{"name" : "Edit raw IEC code",
"tooltip" : "Edit raw IEC code added to code generated by PLCGenerator",
"method" : "_editIECrawcode"}
--- a/wxPopen.py Fri Feb 22 19:04:01 2008 +0100
+++ b/wxPopen.py Sun Feb 24 02:06:42 2008 +0100
@@ -22,168 +22,128 @@
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-# based on wxPopen.py from boa-constructor
-from StringIO import StringIO
+import subprocess, ctypes - if wx.VERSION < (2, 6, 0):
- def Bind(self, event, function, id = None):
- event(self, id, function)
- def __init__(self, input, handler=None):
- handler.Bind(wx.EVT_IDLE, self.OnIdle)
- handler.Bind(wx.EVT_END_PROCESS, self.OnProcessEnded)
+class outputThread(threading.Thread): + Thread is used to print the output of a command to the stdout + def __init__(self, Proc, fd, callback=None, endcallback=None): + threading.Thread.__init__(self) + self.callback = callback + self.endcallback = endcallback - input.reverse() # so we can pop
+ self.retval = self.Proc.poll() + while not self.retval and not self.killed and not outeof: + outchunk = self.fd.readline() + if outchunk == '': outeof = True + wx.CallAfter(self.callback,outchunk) + self.retval=self.Proc.poll() + wx.CallAfter(self.endcallback, self.Proc.pid, self.retval)
- self.inputStream = None
- self.errorStream = None
- self.outputStream = None
- self.finishedFunc = None
+ def __init__(self, logger, Command, finish_callback=None, no_stdout=False, no_stderr=False): + self.finish_callback = finish_callback + self.no_stdout = no_stdout + self.no_stderr = no_stderr
- def execute(self, cmd):
- self.process = wx.Process(self.handler)
- self.process.Redirect()
+ self.Proc = subprocess.Popen(self.Command, + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + stderr = subprocess.STDOUT) +# stderr = subprocess.PIPE) + self.outt = outputThread( - self.pid = wx.Execute(cmd, wx.EXEC_ASYNC, self.process)
- self.inputStream = self.process.GetOutputStream()
- self.errorStream = self.process.GetErrorStream()
- self.outputStream = self.process.GetInputStream()
+# self.errt = outputThread(
- def setCallbacks(self, output, errors, finished):
- self.outputFunc = output
- self.errorsFunc = errors
- self.finishedFunc = finished
+ self.logger.write_warning(v)
- if self.process is not None:
- self.process.CloseOutput()
+ def finish(self, pid,ecode): + self.logger.write(self.Command + "\n") + self.logger.write_warning("exited with status %s (pid %s)\n"%(str(ecode),str(pid))) + if self.finish_callback is not None: + self.finish_callback(self,ecode,pid) - if self.process is not None:
- self.process.CloseOutput()
- if wx.Process.Kill(self.pid, wx.SIGTERM) != wx.KILL_OK:
- wx.Process.Kill(self.pid, wx.SIGKILL)
- def updateStream(self, stream, data):
- if stream and stream.CanRead():
+ self.outt.killed = True +# self.errt.killed = True + if wx.Platform == '__WXMSW__': + handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.Proc.pid) + ctypes.windll.kernel32.TerminateProcess(handle, -1) + ctypes.windll.kernel32.CloseHandle(handle)
- def updateInpStream(self, stream, input):
- def updateErrStream(self, stream, data):
- return self.updateStream(stream, data)
- def updateOutStream(self, stream, data):
- return self.updateStream(stream, data)
- def OnIdle(self, event=None):
- if self.process is not None:
- self.updateInpStream(self.inputStream, self.input)
- e = self.updateErrStream(self.errorStream, self.errors)
- if e is not None and self.errorsFunc is not None:
- wx.CallAfter(self.errorsFunc, e)
- o = self.updateOutStream(self.outputStream, self.output)
- if o is not None and self.outputFunc is not None:
- wx.CallAfter(self.outputFunc, o)
- def OnProcessEnded(self, event):
- pid,exitcode = event.GetPid(), event.GetExitCode()
- #self.handler.Disconnect(-1, wx.EVT_IDLE)
- wx.CallAfter(self.finishedFunc, pid, exitcode)
-class ProcessRunner(wx.EvtHandler, ProcessRunnerMix):
- def __init__(self, input):
- wx.EvtHandler.__init__(self)
- ProcessRunnerMix.__init__(self, input)
-def wxPopen3(cmd, input, output, errors, finish, handler=None):
- p = ProcessRunnerMix(input, handler)
- p.setCallbacks(output, errors, finish)
- f = wx.Frame(None, -1, 'asd')#, style=0)
+ def spin(self, timeout=None, out_limit=None, err_limit=None, keyword = None, kill_it = True): + while not self.finished: + if err_limit and self.errlen > err_limit: + if out_limit and self.outlen > out_limit: + if keyword and self.outdata.find(keyword)!=-1:
- p = wxPopen3('''c:\\python23\\python.exe -c "print '*'*5000"''',
- input, output, errors, fin, f)
+ if not self.outt.finished and kill_it:
+ return [self.exitcode, self.outdata, self.errdata] -if __name__ == '__main__':