Quantum GIS API Documentation  1.7.4
src/core/qgsrunprocess.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           qgsrunprocess.cpp
00003 
00004  A class that runs an external program
00005 
00006                              -------------------
00007     begin                : Jan 2005
00008     copyright            : (C) 2005 by Gavin Macaulay
00009     email                : gavin at macaulay dot co dot nz
00010  ***************************************************************************/
00011 
00012 /***************************************************************************
00013  *                                                                         *
00014  *   This program is free software; you can redistribute it and/or modify  *
00015  *   it under the terms of the GNU General Public License as published by  *
00016  *   the Free Software Foundation; either version 2 of the License, or     *
00017  *   (at your option) any later version.                                   *
00018  *                                                                         *
00019  ***************************************************************************/
00020 /* $Id$ */
00021 
00022 #include "qgsrunprocess.h"
00023 
00024 #include "qgslogger.h"
00025 #include "qgsmessageoutput.h"
00026 #include <QProcess>
00027 #include <QMessageBox>
00028 
00029 QgsRunProcess::QgsRunProcess( const QString& action, bool capture )
00030     : mProcess( NULL ), mOutput( NULL )
00031 {
00032   // Make up a string from the command and arguments that we'll use
00033   // for display purposes
00034   QgsDebugMsg( "Running command: " + action );
00035 
00036   mCommand = action;
00037 
00038   mProcess = new QProcess;
00039 
00040   if ( capture )
00041   {
00042     connect( mProcess, SIGNAL( error( QProcess::ProcessError ) ), this, SLOT( processError( QProcess::ProcessError ) ) );
00043     connect( mProcess, SIGNAL( readyReadStandardOutput() ), this, SLOT( stdoutAvailable() ) );
00044     connect( mProcess, SIGNAL( readyReadStandardError() ), this, SLOT( stderrAvailable() ) );
00045     // We only care if the process has finished if we are capturing
00046     // the output from the process, hence this connect() call is
00047     // inside the capture if() statement.
00048     connect( mProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ), this, SLOT( processExit( int, QProcess::ExitStatus ) ) );
00049 
00050     // Use QgsMessageOutput for displaying output to user
00051     // It will delete itself when the dialog box is closed.
00052     mOutput = QgsMessageOutput::createMessageOutput();
00053     mOutput->setTitle( action );
00054     mOutput->setMessage( tr( "<b>Starting %1...</b>" ).arg( action ), QgsMessageOutput::MessageHtml );
00055     mOutput->showMessage( false ); // non-blocking
00056 
00057     // get notification of delete if it's derived from QObject
00058     QObject* mOutputObj = dynamic_cast<QObject *>( mOutput );
00059     if ( mOutputObj )
00060     {
00061       connect( mOutputObj, SIGNAL( destroyed() ), this, SLOT( dialogGone() ) );
00062     }
00063 
00064     // start the process!
00065     mProcess->start( action );
00066   }
00067   else
00068   {
00069     if ( ! mProcess->startDetached( action ) ) // let the program run by itself
00070     {
00071       QMessageBox::critical( 0, tr( "Action" ),
00072                              tr( "Unable to run command\n%1" ).arg( action ),
00073                              QMessageBox::Ok, Qt::NoButton );
00074     }
00075     // We're not capturing the output from the process, so we don't
00076     // need to exist anymore.
00077     die();
00078   }
00079 }
00080 
00081 QgsRunProcess::~QgsRunProcess()
00082 {
00083   delete mProcess;
00084 }
00085 
00086 void QgsRunProcess::die()
00087 {
00088   // safe way to do "delete this" for QObjects
00089   deleteLater();
00090 }
00091 
00092 void QgsRunProcess::stdoutAvailable()
00093 {
00094   QString line( mProcess->readAllStandardOutput() );
00095 
00096   // Add the new output to the dialog box
00097   mOutput->appendMessage( line );
00098 }
00099 
00100 void QgsRunProcess::stderrAvailable()
00101 {
00102   QString line( mProcess->readAllStandardError() );
00103 
00104   // Add the new output to the dialog box, but color it red
00105   mOutput->appendMessage( "<font color=red>" + line + "</font>" );
00106 }
00107 
00108 void QgsRunProcess::processExit( int, QProcess::ExitStatus )
00109 {
00110   // Because we catch the dialog box going (the dialogGone()
00111   // function), and delete this instance, control will only pass to
00112   // this function if the dialog box still exists when the process
00113   // exits, so it's always safe to use the pointer to the dialog box
00114   // (unless it was never created in the first case, which is what the
00115   // test against 0 is for).
00116 
00117   if ( mOutput != 0 )
00118   {
00119     mOutput->appendMessage( "<b>" + tr( "Done" ) + "</b>" );
00120   }
00121 
00122   // Since the dialog box takes care of deleting itself, and the
00123   // process has gone, there's no need for this instance to stay
00124   // around, so we disappear too.
00125   die();
00126 }
00127 
00128 void QgsRunProcess::dialogGone()
00129 {
00130   // The dialog has gone, so the user is no longer interested in the
00131   // output from the process. Since the process will run happily
00132   // without the QProcess object, this instance and its data can then
00133   // go too, but disconnect the signals to prevent further functions in this
00134   // class being called after it has been deleted (Qt seems not to be
00135   // disconnecting them itself)
00136 
00137   mOutput = 0;
00138 
00139   disconnect( mProcess, SIGNAL( error( QProcess::ProcessError ) ), this, SLOT( processError( QProcess::ProcessError ) ) );
00140   disconnect( mProcess, SIGNAL( readyReadStandardOutput() ), this, SLOT( stdoutAvailable() ) );
00141   disconnect( mProcess, SIGNAL( readyReadStandardError() ), this, SLOT( stderrAvailable() ) );
00142   disconnect( mProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ), this, SLOT( processExit( int, QProcess::ExitStatus ) ) );
00143 
00144   die();
00145 }
00146 
00147 void QgsRunProcess::processError( QProcess::ProcessError err )
00148 {
00149   if ( err == QProcess::FailedToStart )
00150   {
00151     QgsMessageOutput* output = mOutput ? mOutput : QgsMessageOutput::createMessageOutput();
00152     output->setMessage( tr( "Unable to run command %1" ).arg( mCommand ), QgsMessageOutput::MessageText );
00153     // Didn't work, so no need to hang around
00154     die();
00155   }
00156   else
00157   {
00158     QgsDebugMsg( "Got error: " + QString( "%d" ).arg( err ) );
00159   }
00160 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines