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