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