コード例 #1
0
 def _getItemsList(self):
     result = self.DbConnector.getItems(False)
     listItems = QStringList()
     if result is None or len(result) == 0:
         return listItems
     for element in result:
         listItems.append(element[1])
     return listItems
コード例 #2
0
def ensure_QStringList(args):
    if type(args) == type([]):
        arguments = QStringList()
        for arg in args:
            arguments.append(arg)
        args = arguments
    assert isinstance(args, QStringList) # fails if caller passes the wrong thing
    return args
コード例 #3
0
def ensure_QStringList(args):
    if type(args) == type([]):
        arguments = QStringList()
        for arg in args:
            arguments.append(arg)
        args = arguments
    assert isinstance(args,
                      QStringList)  # fails if caller passes the wrong thing
    return args
コード例 #4
0
 def _setLang(self):
     LangList = QStringList()
     LangList.append(u'English')
     LangList.append(u'Русский')
     LangList.append(u'Română')
     self.window.cmbx_lang.addItems(LangList)
     name = self.defaultLanguage
     index = self.window.cmbx_lang.findText(name)
     self.window.cmbx_lang.setCurrentIndex(index)
     self._setLangIcons()
コード例 #5
0
 def run_command(self, program, args):
     if debug_run():
         print "will run this command:", program, args
     from PyQt4.Qt import QStringList, QProcess, QObject, SIGNAL, QDir
     # modified from runSim.py
     arguments = QStringList()
     if sys.platform == 'win32':
         program = "\"%s\"" % program # Double quotes needed by Windows. ###@@@ test this
     ### try it with blanks in output file name and in program name, once it works ###@@@
     for arg in [program] + args:
         if arg:
             arguments.append(arg)
     self.simProcess = simProcess = QProcess()
     simProcess.setArguments(arguments)
     simProcess.setWorkingDirectory(QDir(self.working_directory)) # in case it writes random files
     if 1:
         # report stdout/stderr
         def blabout():
             print "stdout:", simProcess.readStdout()
             ##e should also mention its existence in history, but don't copy it all there in case a lot
         def blaberr():
             text = str(simProcess.readStderr()) # str since it's QString (i hope it can't be unicode)
             print "stderr:", text
             env.history.message(redmsg("%s stderr: " % self.plugin_name + quote_html(text)))
             # examples from CoNTub/bin/HJ:
             # stderr: BAD INPUT
             # stderr: Error: Indices of both tubes coincide
         QObject.connect(simProcess, SIGNAL("readyReadStdout()"), blabout)
         QObject.connect(simProcess, SIGNAL("readyReadStderr()"), blaberr)
     started = simProcess.start() ###k what is this code? i forget if true means ok or error
     if debug_run():
         print "qprocess started:",started
     while 1:
         ###e need to make it abortable! from which abort button? ideally, one on the dialog; maybe cancel button??
         # on exception: simProcess.kill()
         if simProcess.isRunning():
             if debug_run():
                 print "still running"
                 time.sleep(1)
             else:
                 time.sleep(0.1)
         else:
             break
     if debug_run():
         print "process done i guess: normalExit = %r, (if normal) exitStatus = %r" % \
               (simProcess.normalExit(), simProcess.exitStatus())
     if 1:
         QObject.disconnect(simProcess, SIGNAL("readyReadStdout()"), blabout)
         QObject.disconnect(simProcess, SIGNAL("readyReadStderr()"), blaberr)
     if simProcess.normalExit():
         return simProcess.exitStatus()
     else:
         return -1
コード例 #6
0
ファイル: ADC_scope.py プロジェクト: ChimeraTK/AD16
    def openDevice(self):
        
        if self.ad16 != None:
            QtGui.QMessageBox.information(self, 'Error', 'Device already open. Close first!')
        
        # create open device dialog
        dlg = QFileDialog(self)
        dlg.setAcceptMode(QFileDialog.AcceptOpen)
        dlg.setWindowTitle('Open DMAP file')
        dlg.setViewMode( QtGui.QFileDialog.Detail )
        dlg.setNameFilters( ['DMAP Files (*.dmap)', 'All Files (*)'] )
        dlg.setDefaultSuffix('dmap')
        
        # show dialog, open only if user did not cancel
        if dlg.exec_() :
            # file name must be converted into standard python string
            name = str(dlg.selectedFiles()[0])
            
            # open file and extract entries
            devNames = QStringList()
            f = open(name,'r')
            for line in f:
                x = line.split(' ',1)
                devNames.append(x[0])
            
            # create dialog to choose the right device
            devName = QInputDialog.getItem(self, 'Open device in DMAP file', 'Device:', devNames,0,False)

            # open AD16 device
            if(devName[1]) :
                myad16 = libad16.ad16()
                mtca4u.set_dmap_location(name)
                print 'DMAP file location is set to: '+mtca4u.get_dmap_location()
                try:
                    myad16.open(str(devName[0]))
                except libad16.ad16Exception as e:
                    QtGui.QMessageBox.information(self, 'Error', e.what)
                    return
                except Exception as e:
                    QtGui.QMessageBox.information(self, 'Error', 'Device cannot be opened: '+str(e))
                    return
                myad16.setTriggerMode(libad16.trigger.PERIODIC,1)
                self.ad16 = myad16
        
            # update start button
            self.startStopButton.setText("Start")
            self.startStopButton.setEnabled(True)
コード例 #7
0
    def setup(self, selectedServer):
        self.server_listview.clear()
        self.items = []

        servers = self.servers[:]
        servers.reverse()
        for s in servers:
            item = QStringList()
            item.append(s.server_id)
            item.append(s.item)
            self.server_listview.addItems(item)
            #item = QListViewItem(self.server_listview, str(s.server_id), s.engine)
            self.items += [item]
            if s == selectedServer:
                selectedItem = item
        self.items.reverse()
        self.server_listview.setCurrentIndex(selectedItem)

        self._fillServerProperties(selectedServer)
        return
コード例 #8
0
ファイル: ServerManager.py プロジェクト: vcsrc/nanoengineer
    def setup(self, selectedServer):
        self.server_listview.clear()
        self.items = []

        servers = self.servers[:]
        servers.reverse()
        for s in servers:
            item = QStringList()
            item.append(s.server_id)
            item.append(s.item)
            self.server_listview.addItems(item)
            #item = QListViewItem(self.server_listview, str(s.server_id), s.engine)
            self.items += [item]
            if s == selectedServer:
                selectedItem = item
        self.items.reverse()
        self.server_listview.setCurrentIndex(selectedItem)

        self._fillServerProperties(selectedServer)
        return
コード例 #9
0
ファイル: GamessJob.py プロジェクト: ematvey/NanoEngineer-1
    def _launch_pcgamess(self):
        """
        Run PC GAMESS (Windows only).
        PC GAMESS creates 2 output files:
          - the DAT file, called "PUNCH", is written to the directory from which
            PC GAMESS is started.  This is why we chdir to the Gamess temp directory
            before we run PC GAMESS.
          - the OUT file (aka the log file), which we name jigname.out.
        Returns: 0 = Success
                       1 = Cancelled
                       2 = Failed
        """
        oldir = os.getcwd() # Save current directory
        
        jobDir = os.path.dirname(self.job_batfile)
        os.chdir(jobDir) # Change directory to the GAMESS temp directory.
##        print "Current directory is: ", jobDir
        
        DATfile = os.path.join(jobDir, "PUNCH")
        if os.path.exists(DATfile): # Remove any previous DAT (PUNCH) file.
            print "run_pcgamess: Removing DAT file: ", DATfile
            os.remove(DATfile)
        
        # Hours wasted testing this undocumented tripe.  Here's the deal: When using spawnv
        # on Windows, any args that might have spaces must be delimited by double quotes.
        # Mark 050530.
        
        #program = "\"" + self.job_batfile + "\""
        #args = [program, ]
        
        # Here's the infuriating part.  The 2nd arg to spawnv cannot have double quotes, but the
        # first arg in args (the program name) must have the double quotes if there is a space in
        # self.gms_program.
        
        #print  "program = ", program
        #print  "Spawnv args are %r" % (args,) # this %r remains (see above)
        #os.spawnv(os.P_WAIT, self.job_batfile, args)
        
        arg_list = ['-i', self.job_inputfile, '-o', self.job_outputfile]
        args = QStringList()        
        for s in arg_list:
            args.append(str(s))          
            
        process = QProcess()
        process.start(self.server.program, args)
        # Blocks for n millisconds until the process has started and started() 
        # signal is emitted. Returns true if the process was started successfullly. 
        if not process.waitForStarted(2000): 
            print "The process can't be started."
            return 2
        progressDialog = self.showProgress()
        progressDialog.show()
        i = 55
        pInc = True
        while process.state() == QProcess.Running:
            env.call_qApp_processEvents() #bruce 050908 replaced qApp.processEvents()
            if progressDialog.wasCanceled():
                process.kill()
                os.chdir(oldir)
                return 1 # Job cancelled.
                           
            progressDialog.setValue(i)
            if pInc:
                if i < 75: i += 1
                else: pInc = False
            else:
                if i > 55:  i -= 1
                else: pInc = True
            # Do sth here
            time.sleep(0.05)
            if not process.state() == QProcess.Running:
                 break
              
        progressDialog.setValue(100)
        progressDialog.accept()
        
        os.chdir(oldir)
        self.gamessJig.outputfile = self.job_outputfile
        
        return 0 # Success
コード例 #10
0
    def _launch_pcgamess(self):
        """
        Run PC GAMESS (Windows only).
        PC GAMESS creates 2 output files:
          - the DAT file, called "PUNCH", is written to the directory from which
            PC GAMESS is started.  This is why we chdir to the Gamess temp directory
            before we run PC GAMESS.
          - the OUT file (aka the log file), which we name jigname.out.
        Returns: 0 = Success
                       1 = Cancelled
                       2 = Failed
        """
        oldir = os.getcwd()  # Save current directory

        jobDir = os.path.dirname(self.job_batfile)
        os.chdir(jobDir)  # Change directory to the GAMESS temp directory.
        ##        print "Current directory is: ", jobDir

        DATfile = os.path.join(jobDir, "PUNCH")
        if os.path.exists(DATfile):  # Remove any previous DAT (PUNCH) file.
            print "run_pcgamess: Removing DAT file: ", DATfile
            os.remove(DATfile)

        # Hours wasted testing this undocumented tripe.  Here's the deal: When using spawnv
        # on Windows, any args that might have spaces must be delimited by double quotes.
        # Mark 050530.

        #program = "\"" + self.job_batfile + "\""
        #args = [program, ]

        # Here's the infuriating part.  The 2nd arg to spawnv cannot have double quotes, but the
        # first arg in args (the program name) must have the double quotes if there is a space in
        # self.gms_program.

        #print  "program = ", program
        #print  "Spawnv args are %r" % (args,) # this %r remains (see above)
        #os.spawnv(os.P_WAIT, self.job_batfile, args)

        arg_list = ['-i', self.job_inputfile, '-o', self.job_outputfile]
        args = QStringList()
        for s in arg_list:
            args.append(str(s))

        process = QProcess()
        process.start(self.server.program, args)
        # Blocks for n millisconds until the process has started and started()
        # signal is emitted. Returns true if the process was started successfullly.
        if not process.waitForStarted(2000):
            print "The process can't be started."
            return 2
        progressDialog = self.showProgress()
        progressDialog.show()
        i = 55
        pInc = True
        while process.state() == QProcess.Running:
            env.call_qApp_processEvents(
            )  #bruce 050908 replaced qApp.processEvents()
            if progressDialog.wasCanceled():
                process.kill()
                os.chdir(oldir)
                return 1  # Job cancelled.

            progressDialog.setValue(i)
            if pInc:
                if i < 75: i += 1
                else: pInc = False
            else:
                if i > 55: i -= 1
                else: pInc = True
            # Do sth here
            time.sleep(0.05)
            if not process.state() == QProcess.Running:
                break

        progressDialog.setValue(100)
        progressDialog.accept()

        os.chdir(oldir)
        self.gamessJig.outputfile = self.job_outputfile

        return 0  # Success
コード例 #11
0
ファイル: qutemol.py プロジェクト: ematvey/NanoEngineer-1
def launch_qutemol(pdb_file):
    """
    Launch and load QuteMolX with the PDB file I{pdb_file}.
    
    @param pdb_file: the PDB filename to load
    @type  pdb_file: string
    
    @return: (errorcode, errortext)
             where errorcode is one of the following: ###k
                 0 = successful
                 8 = QuteMolX failed for an unknown reason.
    @rtype:  int, text
    """
    
    plugin_name = "QuteMolX"
    plugin_prefs_keys = (qutemol_enabled_prefs_key, qutemol_path_prefs_key)
            
    errorcode, errortext_or_path = \
             checkPluginPreferences(plugin_name, plugin_prefs_keys,
                                    insure_executable = True)
    if errorcode:
        return errorcode, errortext_or_path
    
    program_path = errortext_or_path
    
    workdir, junk_exe = os.path.split(program_path)
    
    # This provides a way to tell NE1 which version of QuteMolX is installed.
    if debug_pref("QuteMol 0.4.1 or later", 
                  Choice_boolean_True, 
                  prefs_key = True):
        version = "0.4.1"
    else:
        version = "0.4.0"
    
    # Start QuteMolX.
    try:
        args = [pdb_file]
        if env.debug():
            print "Debug: Launching", plugin_name, \
                  "\n  working directory=", workdir, \
                  "\n  program_path=", program_path,  \
                  "\n  args are %r" % (args,)
        
        arguments = QStringList()
        for arg in args:
            if arg != "":
                arguments.append(arg)
        
        p = Process()
        
        # QuteMolX must run from the directory its executable lives. Otherwise,  
        # it has serious problems (but still runs). Mark 2007-06-02.
        p.setWorkingDirectory(QString(workdir))
        
        # Tried p.startDetached() so that QuteMolX would be its own process and 
        # continue to live even if NE1 exits. Unfortunately, 
        # setWorkingDirectory() doesn't work. Seems like a Qt bug to me. 
        # Mark 2007-06-02
        p.start(program_path, arguments)
        
    except:
        print_compact_traceback( "exception in launch_qutemol(): " )
        return 8, "%s failed for an unknown reason." % plugin_name
    
    # set an appropriate exitcode and msg
    if p.exitStatus() == QProcess.NormalExit:
        exitcode = p.exitStatus()
        if not exitcode:
            msg = plugin_name + " launched."
        else:
            msg = plugin_name + " had exitcode %r" % exitcode
    else:
        exitcode = p.exitStatus()
        exitcode = -1
        msg = "Abnormal exit (or failure to launch)"
        
    if exitcode:
        return 8, "Error: " + msg 
        # this breaks the convention of the other error returns
            
    return 0, plugin_name + " launched." # from launch_qutemol
コード例 #12
0
ファイル: povray.py プロジェクト: ongzyphysics/NanoEngineer-1
def launch_povray_or_megapov(
        win, info,
        povray_ini):  #bruce 060707/11 revised this extensively for Mac A8
    """
    Try to launch POV-Ray or MegaPOV, as specified in <info> (as returned from decode_povray_prefs, assumed already checked),
    on the given <povray_ini> file (which should already exist), and running in the directory of that file
    (this is required, since it may contain relative pathnames).
    <win> must be the main window object (used for .glpane.is_animating).
       Returns (errorcode, errortext), where errorcode is one of the following: ###k
        0 = successful
        8 = POV-Ray or MegaPOV failed for an unknown reason.
    """
    (program_nickname, program_path,
     include_dir) = info  #e rename this arg renderer_info?

    exit = ''
    program = program_path

    if sys.platform == 'win32':
        program = "\"" + program + "\""  # Double quotes needed by Windows. Mark 060602.
        if program_nickname == 'POV-Ray':
            exit = "/EXIT"

    # Later we'll cd to the POV-Ray's INI file directory and use tmp_ini in the POV-Ray command-line.
    # This helps us get around POV-Ray's I/O Restrictions. Mark 060529.
    workdir, tmp_ini = os.path.split(povray_ini)

    # Render scene.
    try:
        args = [tmp_ini]
        if exit:
            args += [exit]
        if env.debug():
            ## use env.history.message(_graymsg(msg)) ?
            print "debug: Launching %s: \n" % program_nickname,\
                  "working directory=",workdir,"\n  program_path=", program_path,  "\n  args are %r" % (args,)

        arguments = QStringList()
        for arg in args:
            if arg != "":
                arguments.append(arg)

        from processes.Process import Process
        p = Process()
        #bruce 060707: this doesn't take advantage of anything not in QProcess,
        # unless it matters that it reads and discards stdout/stderr
        # (eg so large output would not block -- unlikely that this matters).
        # It doesn't echo stdout/stderr. See also blabout/blaberr in other files. Maybe fix this? ###@@@
        p.setWorkingDirectory(workdir)
        p.start(program, arguments)

        # Put up hourglass cursor to indicate we are busy. Restore the cursor below. Mark 060621.
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

        win.glpane.is_animating = True  # This disables selection [do you mean highlighting? #k] while rendering the image.

        import time
        msg = "Rendering image"
        while p.state() == QProcess.Running:
            # Display a message on the status bar that POV-Ray/MegaPOV is rendering.
            # I'd much rather display a progressbar and stop button by monitoring the size of the output file.
            # This would require the output file to be written in PPM or BMP format, but not PNG format, since
            # I don't believe a PNG's final filesize can be predicted.
            # Check out monitor_progress_by_file_growth() in runSim.py, which does this. [mark]
            time.sleep(0.25)
            env.history.statusbar_msg(msg)
            env.call_qApp_processEvents()
            if 1:
                # Update the statusbar message while rendering.
                if len(
                        msg
                ) > 40:  #bruce changed 100 -> 40 in case of short statusbar
                    msg = "Rendering image"
                else:
                    #msg = msg + "."
                    msg += "."

    except:
        #bruce 060707 moved print_compact_traceback earlier, and its import to toplevel (after Windows A8, before Linux/Mac A8)
        print_compact_traceback("exception in launch_povray_or_megapov(): ")
        QApplication.restoreOverrideCursor()
        win.glpane.is_animating = False
        return 8, "%s failed for an unknown reason." % program_nickname

    #bruce 060707 moved the following outside the above try clause, and revised it (after Windows A8, before Linux/Mac A8)
    QApplication.restoreOverrideCursor()  # Restore the cursor. Mark 060621.
    ## env.history.statusbar_msg("Rendering finished!") # this is wrong if it was not a normal exit. [bruce 060707 removed it]
    win.glpane.is_animating = False

    if 1:
        #bruce 060707 added this (after Windows A8, before Linux/Mac A8):
        # set an appropriate exitcode and msg
        if p.exitStatus() == QProcess.NormalExit:
            exitcode = p.exitStatus()
            if not exitcode:
                msg = "Rendering finished!"
            else:
                msg = "Rendering program had exitcode %r" % exitcode
                # e.g. 126 for Mac failure; same as shell exitcode, which says "cannot execute binary file";
                # but /usr/bin/open helps, so we'll try that above (but not in this commit, which is just to
                # improve error reporting). ###@@@
                # [bruce 060707]
        else:
            exitcode = p.exitStatus()
            exitcode = -1
            msg = "Abnormal exit (or failure to launch)"
        if exitcode or env.debug():
            print msg
        env.history.statusbar_msg(msg)
        ##        if env.debug():
        ##            env.history.message(_graymsg(msg)) # not needed, caller prints it
        if exitcode:
            return 8, "Error: " + msg  # this breaks the convention of the other error returns
        pass

    # Display image in separate window here. [Actually I think this is done in the caller -- bruce 060707 comment]

    return 0, "Rendering finished"  # from launch_povray_or_megapov
コード例 #13
0
def launch_qutemol(pdb_file):
    """
    Launch and load QuteMolX with the PDB file I{pdb_file}.
    
    @param pdb_file: the PDB filename to load
    @type  pdb_file: string
    
    @return: (errorcode, errortext)
             where errorcode is one of the following: ###k
                 0 = successful
                 8 = QuteMolX failed for an unknown reason.
    @rtype:  int, text
    """

    plugin_name = "QuteMolX"
    plugin_prefs_keys = (qutemol_enabled_prefs_key, qutemol_path_prefs_key)

    errorcode, errortext_or_path = \
             checkPluginPreferences(plugin_name, plugin_prefs_keys,
                                    insure_executable = True)
    if errorcode:
        return errorcode, errortext_or_path

    program_path = errortext_or_path

    workdir, junk_exe = os.path.split(program_path)

    # This provides a way to tell NE1 which version of QuteMolX is installed.
    if debug_pref("QuteMol 0.4.1 or later",
                  Choice_boolean_True,
                  prefs_key=True):
        version = "0.4.1"
    else:
        version = "0.4.0"

    # Start QuteMolX.
    try:
        args = [pdb_file]
        if env.debug():
            print "Debug: Launching", plugin_name, \
                  "\n  working directory=", workdir, \
                  "\n  program_path=", program_path,  \
                  "\n  args are %r" % (args,)

        arguments = QStringList()
        for arg in args:
            if arg != "":
                arguments.append(arg)

        p = Process()

        # QuteMolX must run from the directory its executable lives. Otherwise,
        # it has serious problems (but still runs). Mark 2007-06-02.
        p.setWorkingDirectory(QString(workdir))

        # Tried p.startDetached() so that QuteMolX would be its own process and
        # continue to live even if NE1 exits. Unfortunately,
        # setWorkingDirectory() doesn't work. Seems like a Qt bug to me.
        # Mark 2007-06-02
        p.start(program_path, arguments)

    except:
        print_compact_traceback("exception in launch_qutemol(): ")
        return 8, "%s failed for an unknown reason." % plugin_name

    # set an appropriate exitcode and msg
    if p.exitStatus() == QProcess.NormalExit:
        exitcode = p.exitStatus()
        if not exitcode:
            msg = plugin_name + " launched."
        else:
            msg = plugin_name + " had exitcode %r" % exitcode
    else:
        exitcode = p.exitStatus()
        exitcode = -1
        msg = "Abnormal exit (or failure to launch)"

    if exitcode:
        return 8, "Error: " + msg
        # this breaks the convention of the other error returns

    return 0, plugin_name + " launched."  # from launch_qutemol
コード例 #14
0
ファイル: povray.py プロジェクト: foulowl/nanoengineer
def launch_povray_or_megapov(win, info, povray_ini): #bruce 060707/11 revised this extensively for Mac A8
    """
    Try to launch POV-Ray or MegaPOV, as specified in <info> (as returned from decode_povray_prefs, assumed already checked),
    on the given <povray_ini> file (which should already exist), and running in the directory of that file
    (this is required, since it may contain relative pathnames).
    <win> must be the main window object (used for .glpane.is_animating).
       Returns (errorcode, errortext), where errorcode is one of the following: ###k
        0 = successful
        8 = POV-Ray or MegaPOV failed for an unknown reason.
    """
    (program_nickname, program_path, include_dir) = info #e rename this arg renderer_info?

    exit = ''
    program = program_path

    if sys.platform == 'win32':
        program = "\""+program+"\"" # Double quotes needed by Windows. Mark 060602.
        if program_nickname == 'POV-Ray':
            exit = "/EXIT"

    # Later we'll cd to the POV-Ray's INI file directory and use tmp_ini in the POV-Ray command-line.
    # This helps us get around POV-Ray's I/O Restrictions. Mark 060529.
    workdir, tmp_ini = os.path.split(povray_ini)

    # Render scene.
    try:
        args = [tmp_ini]
        if exit:
            args += [exit]
        if env.debug():
            ## use env.history.message(_graymsg(msg)) ?
            print "debug: Launching %s: \n" % program_nickname,\
                  "working directory=",workdir,"\n  program_path=", program_path,  "\n  args are %r" % (args,)

        arguments = QStringList()
        for arg in args:
            if arg != "":
                arguments.append(arg)

        from processes.Process import Process
        p = Process()
            #bruce 060707: this doesn't take advantage of anything not in QProcess,
            # unless it matters that it reads and discards stdout/stderr
            # (eg so large output would not block -- unlikely that this matters).
            # It doesn't echo stdout/stderr. See also blabout/blaberr in other files. Maybe fix this? ###@@@
        p.setWorkingDirectory(workdir)
        p.start(program, arguments)

        # Put up hourglass cursor to indicate we are busy. Restore the cursor below. Mark 060621.
        QApplication.setOverrideCursor( QCursor(Qt.WaitCursor) )

        win.glpane.is_animating = True # This disables selection [do you mean highlighting? #k] while rendering the image.

        import time
        msg = "Rendering image"
        while p.state() == QProcess.Running:
            # Display a message on the status bar that POV-Ray/MegaPOV is rendering.
            # I'd much rather display a progressbar and stop button by monitoring the size of the output file.
            # This would require the output file to be written in PPM or BMP format, but not PNG format, since
            # I don't believe a PNG's final filesize can be predicted.
            # Check out monitor_progress_by_file_growth() in runSim.py, which does this. [mark]
            time.sleep(0.25)
            env.history.statusbar_msg(msg)
            env.call_qApp_processEvents()
            if 1:
                # Update the statusbar message while rendering.
                if len(msg) > 40: #bruce changed 100 -> 40 in case of short statusbar
                    msg = "Rendering image"
                else:
                    #msg = msg + "."
                    msg += "."

    except:
        #bruce 060707 moved print_compact_traceback earlier, and its import to toplevel (after Windows A8, before Linux/Mac A8)
        print_compact_traceback( "exception in launch_povray_or_megapov(): " )
        QApplication.restoreOverrideCursor()
        win.glpane.is_animating = False
        return 8, "%s failed for an unknown reason." % program_nickname

    #bruce 060707 moved the following outside the above try clause, and revised it (after Windows A8, before Linux/Mac A8)
    QApplication.restoreOverrideCursor() # Restore the cursor. Mark 060621.
    ## env.history.statusbar_msg("Rendering finished!") # this is wrong if it was not a normal exit. [bruce 060707 removed it]
    win.glpane.is_animating = False

    if 1:
        #bruce 060707 added this (after Windows A8, before Linux/Mac A8):
        # set an appropriate exitcode and msg
        if p.exitStatus() == QProcess.NormalExit:
            exitcode = p.exitStatus()
            if not exitcode:
                msg = "Rendering finished!"
            else:
                msg = "Rendering program had exitcode %r" % exitcode
                    # e.g. 126 for Mac failure; same as shell exitcode, which says "cannot execute binary file";
                    # but /usr/bin/open helps, so we'll try that above (but not in this commit, which is just to
                    # improve error reporting). ###@@@
                    # [bruce 060707]
        else:
            exitcode = p.exitStatus()
            exitcode = -1
            msg = "Abnormal exit (or failure to launch)"
        if exitcode or env.debug():
            print msg
        env.history.statusbar_msg(msg)
##        if env.debug():
##            env.history.message(_graymsg(msg)) # not needed, caller prints it
        if exitcode:
            return 8, "Error: " + msg # this breaks the convention of the other error returns
        pass

    # Display image in separate window here. [Actually I think this is done in the caller -- bruce 060707 comment]

    return 0, "Rendering finished" # from launch_povray_or_megapov