Quantum GIS API Documentation
1.7.4
|
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 }