Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsrunprocess.h 3 : : 4 : : A class that runs an external program 5 : : 6 : : ------------------- 7 : : begin : Jan 2005 8 : : copyright : (C) 2005 by Gavin Macaulay 9 : : email : gavin at macaulay dot co dot nz 10 : : ***************************************************************************/ 11 : : 12 : : /*************************************************************************** 13 : : * * 14 : : * This program is free software; you can redistribute it and/or modify * 15 : : * it under the terms of the GNU General Public License as published by * 16 : : * the Free Software Foundation; either version 2 of the License, or * 17 : : * (at your option) any later version. * 18 : : * * 19 : : ***************************************************************************/ 20 : : 21 : : #ifndef QGSRUNPROCESS_H 22 : : #define QGSRUNPROCESS_H 23 : : 24 : : #include <QObject> 25 : : #if QT_CONFIG(process) 26 : : #include <QProcess> 27 : : #endif 28 : : 29 : : #include <QThread> 30 : : 31 : : #include "qgis_core.h" 32 : : #include "qgis_sip.h" 33 : : 34 : : class QgsFeedback; 35 : : class QgsMessageOutput; 36 : : 37 : : /** 38 : : * \ingroup core 39 : : * \brief A class that executes an external program/script. 40 : : * 41 : : * It can optionally capture the standard output and error from the 42 : : * process and displays them in a dialog box. 43 : : * 44 : : * On some platforms (e.g. iOS) , the process execution is skipped 45 : : * https://lists.qt-project.org/pipermail/development/2015-July/022205.html 46 : : */ 47 : : class CORE_EXPORT QgsRunProcess: public QObject SIP_NODEFAULTCTORS 48 : : { 49 : 0 : Q_OBJECT 50 : : 51 : : public: 52 : : // This class deletes itself, so to ensure that it is only created 53 : : // using new, the Named Constructor Idiom is used, and one needs to 54 : : // use the create() static function to get an instance of this class. 55 : : 56 : : // The action argument contains string with the command. 57 : : // If capture is true, the standard output and error from the process 58 : : // will be sent to QgsMessageOutput - usually a dialog box. 59 : 0 : static QgsRunProcess *create( const QString &action, bool capture ) SIP_FACTORY 60 : 0 : { return new QgsRunProcess( action, capture ); } 61 : : 62 : : /** 63 : : * Splits the string \a command into a list of tokens, and returns 64 : : * the list. 65 : : * 66 : : * Tokens with spaces can be surrounded by double quotes; three 67 : : * consecutive double quotes represent the quote character itself. 68 : : * 69 : : * \since QGIS 3.18 70 : : */ 71 : : static QStringList splitCommand( const QString &command ); 72 : : 73 : : private: 74 : : QgsRunProcess( const QString &action, bool capture ) SIP_FORCE; 75 : : ~QgsRunProcess() override SIP_FORCE; 76 : : 77 : : #if QT_CONFIG(process) 78 : : // Deletes the instance of the class 79 : : void die(); 80 : : 81 : : QProcess *mProcess = nullptr; 82 : : QgsMessageOutput *mOutput = nullptr; 83 : : QString mCommand; 84 : : 85 : : public slots: 86 : : void stdoutAvailable(); 87 : : void stderrAvailable(); 88 : : void processError( QProcess::ProcessError ); 89 : : void processExit( int, QProcess::ExitStatus ); 90 : : void dialogGone(); 91 : : #endif // !(QT_CONFIG(process) 92 : : }; 93 : : 94 : : #if QT_CONFIG(process) 95 : : 96 : : /** 97 : : * \brief A thread safe class for performing blocking (sync) execution of external processes. 98 : : * 99 : : * This class should be used whenever a blocking process run is required. Unlike implementations 100 : : * which rely on QApplication::processEvents() or creation of a QEventLoop, this class is completely 101 : : * thread safe and can be used on either the main thread or background threads without issue. 102 : : * 103 : : * Not available on some platforms (e.g. iOS) 104 : : * https://lists.qt-project.org/pipermail/development/2015-July/022205.html 105 : : * 106 : : * \ingroup core 107 : : * \since QGIS 3.18 108 : : */ 109 : : class CORE_EXPORT QgsBlockingProcess : public QObject 110 : : { 111 : : Q_OBJECT 112 : : 113 : : public: 114 : : 115 : : /** 116 : : * Constructor for the given \a program, with the specified list of \a arguments. 117 : : * 118 : : * After construction, call run() to start the process execution. 119 : : */ 120 : : QgsBlockingProcess( const QString &program, const QStringList &arguments ); 121 : : 122 : : #ifndef SIP_RUN 123 : : 124 : : /** 125 : : * Sets a \a handler function to call whenever content is written by the process to stdout. 126 : : */ 127 : : void setStdOutHandler( const std::function< void( const QByteArray & ) > &handler ) { mStdoutHandler = handler; } 128 : : #else 129 : : 130 : : /** 131 : : * Sets a handler function to call whenever content is written by the process to stdout. 132 : : */ 133 : : void setStdOutHandler( SIP_PYCALLABLE / AllowNone / ); 134 : : % MethodCode 135 : : Py_BEGIN_ALLOW_THREADS 136 : : 137 : : sipCpp->setStdOutHandler( [a0]( const QByteArray &arg ) 138 : : { 139 : : SIP_BLOCK_THREADS 140 : : Py_XDECREF( sipCallMethod( NULL, a0, "D", &arg, sipType_QByteArray, NULL ) ); 141 : : SIP_UNBLOCK_THREADS 142 : : } ); 143 : : 144 : : Py_END_ALLOW_THREADS 145 : : % End 146 : : #endif 147 : : 148 : : #ifndef SIP_RUN 149 : : 150 : : /** 151 : : * Sets a \a handler function to call whenever content is written by the process to stderr. 152 : : */ 153 : : void setStdErrHandler( const std::function< void( const QByteArray & ) > &handler ) { mStderrHandler = handler; } 154 : : #else 155 : : 156 : : /** 157 : : * Sets a \a handler function to call whenever content is written by the process to stderr. 158 : : */ 159 : : void setStdErrHandler( SIP_PYCALLABLE / AllowNone / ); 160 : : % MethodCode 161 : : Py_BEGIN_ALLOW_THREADS 162 : : 163 : : sipCpp->setStdErrHandler( [a0]( const QByteArray &arg ) 164 : : { 165 : : SIP_BLOCK_THREADS 166 : : Py_XDECREF( sipCallMethod( NULL, a0, "D", &arg, sipType_QByteArray, NULL ) ); 167 : : SIP_UNBLOCK_THREADS 168 : : } ); 169 : : 170 : : Py_END_ALLOW_THREADS 171 : : % End 172 : : #endif 173 : : 174 : : /** 175 : : * Runs the process, and blocks until execution finishes. 176 : : * 177 : : * The optional \a feedback argument can be used to specify a feedback object for cancellation/process termination. 178 : : * 179 : : * After execution completes, the process' result code will be returned. 180 : : */ 181 : : int run( QgsFeedback *feedback = nullptr ); 182 : : 183 : : /** 184 : : * After a call to run(), returns the process' exit status. 185 : : */ 186 : : QProcess::ExitStatus exitStatus() const; 187 : : 188 : : /** 189 : : * After a call to run(), returns the process' reported error. 190 : : * 191 : : * Returns QProcess::UnknownError if no error occurred. 192 : : */ 193 : : QProcess::ProcessError processError() const; 194 : : 195 : : private: 196 : : 197 : : QString mProcess; 198 : : QStringList mArguments; 199 : : std::function< void( const QByteArray & ) > mStdoutHandler; 200 : : std::function< void( const QByteArray & ) > mStderrHandler; 201 : : 202 : : QProcess::ExitStatus mExitStatus = QProcess::NormalExit; 203 : : QProcess::ProcessError mProcessError = QProcess::UnknownError; 204 : : }; 205 : : 206 : : #endif // QT_CONFIG(process) 207 : : 208 : : ///@cond PRIVATE 209 : : #ifndef SIP_RUN 210 : : 211 : : class ProcessThread : public QThread 212 : : { 213 : : Q_OBJECT 214 : : 215 : : public: 216 : 0 : ProcessThread( const std::function<void()> &function, QObject *parent = nullptr ) 217 : 0 : : QThread( parent ) 218 : 0 : , mFunction( function ) 219 : 0 : { 220 : 0 : } 221 : : 222 : : void run() override 223 : : { 224 : : mFunction(); 225 : : } 226 : : 227 : : private: 228 : : std::function<void()> mFunction; 229 : : }; 230 : : 231 : : #endif 232 : : ///@endcond 233 : : 234 : : 235 : : #endif