wxPopen.py
changeset 48 6b30cfee163e
child 70 2767bc85aa9a
equal deleted inserted replaced
47:fd45c291fed0 48:6b30cfee163e
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 #This file is part of Beremiz, a Integrated Development Environment for
       
     5 #programming IEC 61131-3 automates supporting plcopen standard and CanFestival. 
       
     6 #
       
     7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
       
     8 #
       
     9 #See COPYING file for copyrights details.
       
    10 #
       
    11 #This library is free software; you can redistribute it and/or
       
    12 #modify it under the terms of the GNU General Public
       
    13 #License as published by the Free Software Foundation; either
       
    14 #version 2.1 of the License, or (at your option) any later version.
       
    15 #
       
    16 #This library is distributed in the hope that it will be useful,
       
    17 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    19 #General Public License for more details.
       
    20 #
       
    21 #You should have received a copy of the GNU General Public
       
    22 #License along with this library; if not, write to the Free Software
       
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    24 
       
    25 #
       
    26 # based on wxPopen.py from boa-constructor
       
    27 #
       
    28 
       
    29 import time
       
    30 from StringIO import StringIO
       
    31 
       
    32 from wxPython.wx import *
       
    33 
       
    34 class ProcessRunnerMix:
       
    35     def __init__(self, input, handler=None):
       
    36         if handler is None:
       
    37             handler = self
       
    38         self.handler = handler    
       
    39         EVT_IDLE(handler, self.OnIdle)
       
    40         EVT_END_PROCESS(handler, -1, self.OnProcessEnded)
       
    41 
       
    42         input.reverse() # so we can pop
       
    43         self.input = input
       
    44         
       
    45         self.reset()
       
    46 
       
    47     def reset(self):
       
    48         self.process = None
       
    49         self.pid = -1
       
    50         self.output = []
       
    51         self.errors = []
       
    52         self.inputStream = None
       
    53         self.errorStream = None
       
    54         self.outputStream = None
       
    55         self.outputFunc = None
       
    56         self.errorsFunc = None
       
    57         self.finishedFunc = None
       
    58         self.finished = false
       
    59         self.responded = false
       
    60 
       
    61     def execute(self, cmd):
       
    62         self.process = wxProcess(self.handler)
       
    63         self.process.Redirect()
       
    64 
       
    65         self.pid = wxExecute(cmd, wxEXEC_NOHIDE, self.process)
       
    66 
       
    67         self.inputStream = self.process.GetOutputStream()
       
    68         self.errorStream = self.process.GetErrorStream()
       
    69         self.outputStream = self.process.GetInputStream()
       
    70 
       
    71         #self.OnIdle()
       
    72         wxWakeUpIdle()
       
    73     
       
    74     def setCallbacks(self, output, errors, finished):
       
    75         self.outputFunc = output
       
    76         self.errorsFunc = errors
       
    77         self.finishedFunc = finished
       
    78 
       
    79     def detach(self):
       
    80         if self.process is not None:
       
    81             self.process.CloseOutput()
       
    82             self.process.Detach()
       
    83             self.process = None
       
    84 
       
    85     def kill(self):
       
    86         if self.process is not None:
       
    87             self.process.CloseOutput()
       
    88             if wxProcess_Kill(self.pid, wxSIGTERM) != wxKILL_OK:
       
    89                 wxProcess_Kill(self.pid, wxSIGKILL)
       
    90             self.process = None
       
    91 
       
    92     def updateStream(self, stream, data):
       
    93         if stream and stream.CanRead():
       
    94             if not self.responded:
       
    95                 self.responded = true
       
    96             text = stream.read()
       
    97             data.append(text)
       
    98             return text
       
    99         else:
       
   100             return None
       
   101 
       
   102     def updateInpStream(self, stream, input):
       
   103         if stream and input:
       
   104             line = input.pop()
       
   105             stream.write(line)
       
   106 
       
   107     def updateErrStream(self, stream, data):
       
   108         return self.updateStream(stream, data)
       
   109 
       
   110     def updateOutStream(self, stream, data):
       
   111         return self.updateStream(stream, data)
       
   112 
       
   113     def OnIdle(self, event=None):
       
   114         if self.process is not None:
       
   115             self.updateInpStream(self.inputStream, self.input)
       
   116             e = self.updateErrStream(self.errorStream, self.errors)
       
   117             if e is not None and self.errorsFunc is not None:
       
   118                 wxCallAfter(self.errorsFunc, e)
       
   119             o = self.updateOutStream(self.outputStream, self.output)
       
   120             if o is not None and self.outputFunc is not None:
       
   121                 wxCallAfter(self.outputFunc, o)
       
   122 
       
   123             #wxWakeUpIdle()
       
   124             #time.sleep(0.001)
       
   125 
       
   126     def OnProcessEnded(self, event):
       
   127         self.OnIdle()
       
   128         pid,exitcode = event.GetPid(), event.GetExitCode()
       
   129         if self.process:
       
   130             self.process.Destroy()
       
   131             self.process = None
       
   132 
       
   133         self.finished = true
       
   134         
       
   135         # XXX doesn't work ???
       
   136         #self.handler.Disconnect(-1, wxEVT_IDLE)
       
   137         
       
   138         if self.finishedFunc:
       
   139             wxCallAfter(self.finishedFunc, pid, exitcode)
       
   140 
       
   141 class ProcessRunner(wxEvtHandler, ProcessRunnerMix):
       
   142     def __init__(self, input):
       
   143         wxEvtHandler.__init__(self)
       
   144         ProcessRunnerMix.__init__(self, input)
       
   145 
       
   146 def wxPopen3(cmd, input, output, errors, finish, handler=None):
       
   147     p = ProcessRunnerMix(input, handler)
       
   148     p.setCallbacks(output, errors, finish)
       
   149     p.execute(cmd)
       
   150     return p
       
   151     
       
   152