QGIS API Documentation 4.1.0-Master (31622b25bb0)
Loading...
Searching...
No Matches
qgsprocessingfeedback.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingfeedback.cpp
3 -------------------------
4 begin : June 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include <gdal_version.h>
21#include <ogr_api.h>
22#include <proj.h>
23
24#include "qgsgeos.h"
25#include "qgsmessagelog.h"
27
28#include <QString>
29
30#include "moc_qgsprocessingfeedback.cpp"
31
32using namespace Qt::StringLiterals;
33
34#ifdef HAVE_PDAL_QGIS
35#include <pdal/pdal.hpp>
36#endif
37
38#ifdef WITH_SFCGAL
39#include <SFCGAL/capi/sfcgal_c.h>
40#endif
41
42#ifdef WITH_GEOGRAPHICLIB
43#include <GeographicLib/Constants.hpp>
44#endif
45
47 : mLogFeedback( logFeedback )
48{}
49
50void QgsProcessingFeedback::setProgressText( const QString &text )
51{
52 mHtmlLog.append( text.toHtmlEscaped().replace( '\n', "<br>"_L1 ) + u"<br/>"_s );
53 mTextLog.append( text + '\n' );
54
55 emit progressTextChanged( text );
56}
57
58void QgsProcessingFeedback::log( const QString &htmlMessage, const QString &textMessage )
59{
60 constexpr int MESSAGE_COUNT_LIMIT = 10000;
61 // Avoid logging too many messages, which might blow memory.
62 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
63 return;
64 ++mMessageLoggedCount;
65 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
66 {
67 mHtmlLog.append( u"<span style=\"color:red\">%1</span><br/>"_s.arg( tr( "Message log truncated" ) ) );
68 mTextLog.append( tr( "Message log truncated" ) + '\n' );
69 }
70 else
71 {
72 mHtmlLog.append( htmlMessage );
73 mTextLog.append( textMessage );
74 }
75}
76
77void QgsProcessingFeedback::reportError( const QString &error, bool fatalError )
78{
79 if ( mLogFeedback )
80 QgsMessageLog::logMessage( error, tr( "Processing" ), Qgis::MessageLevel::Critical );
81
82 log( u"<span style=\"color:red\">%1</span><br/>"_s.arg( error.toHtmlEscaped() ).replace( '\n', "<br>"_L1 ), error + '\n' );
83
84 emit errorReported( error, fatalError );
85}
86
87void QgsProcessingFeedback::pushWarning( const QString &warning )
88{
89 if ( mLogFeedback )
90 QgsMessageLog::logMessage( warning, tr( "Processing" ), Qgis::MessageLevel::Warning );
91
92 log( u"<span style=\"color:#b85a20;\">%1</span><br/>"_s.arg( warning.toHtmlEscaped() ).replace( '\n', "<br>"_L1 ) + u"<br/>"_s, warning + '\n' );
93
94 emit warningPushed( warning );
95}
96
97void QgsProcessingFeedback::pushInfo( const QString &info )
98{
99 if ( mLogFeedback )
100 QgsMessageLog::logMessage( info, tr( "Processing" ), Qgis::MessageLevel::Info );
101
102 mHtmlLog.append( info.toHtmlEscaped().replace( '\n', "<br>"_L1 ) + u"<br/>"_s );
103 mTextLog.append( info + '\n' );
104
105 emit infoPushed( info );
106}
107
108void QgsProcessingFeedback::pushFormattedMessage( const QString &html, const QString &text )
109{
110 if ( mLogFeedback )
111 QgsMessageLog::logMessage( text, tr( "Processing" ), Qgis::MessageLevel::Info );
112
113 mHtmlLog.append( html + u"<br/>"_s );
114 mTextLog.append( text + '\n' );
115
116 emit formattedMessagePushed( html );
117}
118
119void QgsProcessingFeedback::pushCommandInfo( const QString &info )
120{
121 if ( mLogFeedback )
122 QgsMessageLog::logMessage( info, tr( "Processing" ), Qgis::MessageLevel::Info );
123
124 log( u"<code>%1</code><br/>"_s.arg( info.toHtmlEscaped().replace( '\n', "<br>"_L1 ) ), info + '\n' );
125
126 emit commandInfoPushed( info );
127}
128
129void QgsProcessingFeedback::pushDebugInfo( const QString &info )
130{
131 if ( mLogFeedback )
132 QgsMessageLog::logMessage( info, tr( "Processing" ), Qgis::MessageLevel::Info );
133
134 log( u"<span style=\"color:#777\">%1</span><br/>"_s.arg( info.toHtmlEscaped().replace( '\n', "<br>"_L1 ) ), info + '\n' );
135
136 emit debugInfoPushed( info );
137}
138
139void QgsProcessingFeedback::pushConsoleInfo( const QString &info )
140{
141 if ( mLogFeedback )
142 QgsMessageLog::logMessage( info, tr( "Processing" ), Qgis::MessageLevel::Info );
143
144 log( u"<code style=\"color:#777\">%1</code><br/>"_s.arg( info.toHtmlEscaped().replace( '\n', "<br>"_L1 ) ), info + '\n' );
145
146 emit consoleInfoPushed( info );
147}
148
150{
151 pushDebugInfo( tr( "QGIS version: %1" ).arg( Qgis::version() ) );
152 if ( QString( Qgis::devVersion() ) != "exported"_L1 )
153 {
154 pushDebugInfo( tr( "QGIS code revision: %1" ).arg( Qgis::devVersion() ) );
155 }
156 pushDebugInfo( tr( "Qt version: %1" ).arg( qVersion() ) );
157 pushDebugInfo( tr( "Python version: %1" ).arg( PYTHON_VERSION ) );
158 pushDebugInfo( tr( "GDAL version: %1" ).arg( GDALVersionInfo( "RELEASE_NAME" ) ) );
159 pushDebugInfo( tr( "GEOS version: %1" ).arg( GEOSversion() ) );
160
161 const PJ_INFO info = proj_info();
162 pushDebugInfo( tr( "PROJ version: %1" ).arg( info.release ) );
163
164#ifdef HAVE_PDAL_QGIS
165#if PDAL_VERSION_MAJOR_INT > 1 || ( PDAL_VERSION_MAJOR_INT == 1 && PDAL_VERSION_MINOR_INT >= 7 )
166 pushDebugInfo( tr( "PDAL version: %1" ).arg( QString::fromStdString( pdal::Config::fullVersionString() ) ) );
167#else
168 pushDebugInfo( tr( "PDAL version: %1" ).arg( QString::fromStdString( pdal::GetFullVersionString() ) ) );
169#endif
170#endif
171
172#ifdef WITH_SFCGAL
173 pushDebugInfo( tr( "SFCGAL version: %1" ).arg( sfcgal_version() ) );
174#else
175 pushDebugInfo( tr( "No support for SFCGAL" ) );
176#endif
177
178#ifdef WITH_GEOGRAPHICLIB
179 pushDebugInfo( tr( "GeographicLib version: %1.%2.%3" ).arg( GEOGRAPHICLIB_VERSION_MAJOR ).arg( GEOGRAPHICLIB_VERSION_MINOR ).arg( GEOGRAPHICLIB_VERSION_PATCH ) );
180#else
181 pushDebugInfo( tr( "No support for GeographicLib" ) );
182#endif
183
184 if ( provider && !provider->versionInfo().isEmpty() )
185 {
186 pushDebugInfo( tr( "%1 version: %2" ).arg( provider->name(), provider->versionInfo() ) );
187 }
188}
189
191{
192 if ( results.empty() )
193 return;
194
195 pushInfo( tr( "Results:" ) );
196
197 const QList< const QgsProcessingOutputDefinition * > outputs = algorithm->outputDefinitions();
198 for ( const QgsProcessingOutputDefinition *output : outputs )
199 {
200 const QString outputName = output->name();
201 if ( outputName == "CHILD_RESULTS"_L1 || outputName == "CHILD_INPUTS"_L1 )
202 continue;
203
204 if ( !results.contains( outputName ) )
205 continue;
206
207 bool ok = false;
208 const QString textValue = output->valueAsString( results.value( output->name() ), context, ok );
209 const QString formattedValue = output->valueAsFormattedString( results.value( output->name() ), context, ok );
210 if ( ok )
211 {
212 pushFormattedMessage( u"<code>&nbsp;&nbsp;%1: %2</code>"_s.arg( output->name(), formattedValue ), u" %1: %2"_s.arg( output->name(), textValue ) );
213 }
214 }
215}
216
218{
219 return mHtmlLog;
220}
221
223{
224 return mTextLog;
225}
226
227void QgsProcessingFeedback::reportSourceLoaded( const QString &parameterName, long long featureCount )
228{
229 emit sourceLoaded( parameterName, featureCount );
230}
231
232void QgsProcessingFeedback::featureAddedToSink( const QString &output )
233{
234 long long countAtLastSignal = 0;
235 long long previousCount = 0;
236 auto it = mSinkFeatureCounts.find( output );
237 if ( it == mSinkFeatureCounts.end() )
238 {
239 it = mSinkFeatureCounts.insert( output, SinkStats() );
240 }
241 else
242 {
243 countAtLastSignal = it.value().countAtLastSignal;
244 previousCount = it.value().featureCount;
245 }
246
247 const long long newCount = previousCount + 1;
248 it.value().featureCount = newCount;
249 if ( newCount - countAtLastSignal >= 100 )
250 {
251 emit sinkFeatureCountChanged( output, newCount );
252 it.value().countAtLastSignal = newCount;
253 }
254}
255
257{
258 long long previousCount = 0;
259 auto it = mSinkFeatureCounts.find( output );
260 if ( it == mSinkFeatureCounts.end() )
261 {
262 it = mSinkFeatureCounts.insert( output, SinkStats() );
263 }
264 else
265 {
266 previousCount = it.value().featureCount;
267 }
268
269 emit sinkFeatureCountChanged( output, previousCount );
270 it.value().countAtLastSignal = previousCount;
271}
272
274{
275 mSinkFeatureCounts.clear();
276}
277
279 : mChildSteps( childAlgorithmCount )
280 , mFeedback( feedback )
281{
282 if ( mFeedback )
283 {
284 connect( mFeedback, &QgsFeedback::canceled, this, &QgsFeedback::cancel, Qt::DirectConnection );
285 connect( this, &QgsFeedback::progressChanged, this, &QgsProcessingMultiStepFeedback::updateOverallProgress );
286 }
287
288 // initialize with equal weights
289 const double equalWeight = mChildSteps > 0 ? 1.0 / mChildSteps : 0.0;
290 for ( int i = 0; i < mChildSteps; ++i )
291 {
292 mStepWeights << equalWeight;
293 }
294}
295
297{
298 mCurrentStep = step;
299
300 // calculate the base progress (sum of all previous steps)
301 mCurrentStepBaseProgress = 0.0;
302 for ( int i = 0; i < mCurrentStep && i < mStepWeights.count(); ++i )
303 {
304 mCurrentStepBaseProgress += mStepWeights.at( i ) * 100.0;
305 }
306
307 emit progressChanged( 0 );
308 if ( mFeedback )
309 mFeedback->setProgress( mCurrentStepBaseProgress );
310}
311
312void QgsProcessingMultiStepFeedback::setStepWeights( const QList<double> &weights )
313{
314 if ( weights.size() != mChildSteps )
315 {
316 return;
317 }
318
319 const double totalWeight = std::reduce( weights.begin(), weights.end() );
320
321 mStepWeights.clear();
322 if ( totalWeight > 0.0 )
323 {
324 for ( double w : weights )
325 {
326 mStepWeights << ( w / totalWeight );
327 }
328 }
329 else
330 {
331 // fallback to equal weights if total weight is 0
332 const double equalWeight = mChildSteps > 0 ? 1.0 / mChildSteps : 0.0;
333 for ( int i = 0; i < mChildSteps; ++i )
334 {
335 mStepWeights << equalWeight;
336 }
337 }
338}
339
341{
342 if ( mFeedback )
343 mFeedback->setProgressText( text );
344}
345
346void QgsProcessingMultiStepFeedback::reportError( const QString &error, bool fatalError )
347{
348 if ( mFeedback )
349 mFeedback->reportError( error, fatalError );
350}
351
353{
354 if ( mFeedback )
355 mFeedback->pushWarning( warning );
356}
357
359{
360 if ( mFeedback )
361 mFeedback->pushInfo( info );
362}
363
365{
366 if ( mFeedback )
367 mFeedback->pushCommandInfo( info );
368}
369
371{
372 if ( mFeedback )
373 mFeedback->pushDebugInfo( info );
374}
375
377{
378 if ( mFeedback )
379 mFeedback->pushConsoleInfo( info );
380}
381
382void QgsProcessingMultiStepFeedback::pushFormattedMessage( const QString &html, const QString &text )
383{
384 if ( mFeedback )
385 mFeedback->pushFormattedMessage( html, text );
386}
387
389{
390 if ( mFeedback )
391 return mFeedback->htmlLog();
392 return QString();
393}
394
396{
397 if ( mFeedback )
398 return mFeedback->textLog();
399 return QString();
400}
401
402void QgsProcessingMultiStepFeedback::updateOverallProgress( double progress )
403{
404 if ( !mFeedback )
405 return;
406
407 const double currentStepWeight = mStepWeights.value( mCurrentStep, 0 );
408
409 mFeedback->setProgress( mCurrentStepBaseProgress + progress * currentStepWeight );
410}
static QString version()
Version string.
Definition qgis.cpp:682
@ Warning
Warning message.
Definition qgis.h:162
@ Critical
Critical/error message.
Definition qgis.h:163
@ Info
Information message.
Definition qgis.h:161
static QString devVersion()
The development version.
Definition qgis.cpp:699
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
void canceled()
Internal routines can connect to this signal if they use event loop.
void cancel()
Tells the internal routines that the current operation should be canceled. This should be run by the ...
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
double progress() const
Returns the current progress reported by the feedback object.
Definition qgsfeedback.h:81
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
Abstract base class for processing algorithms.
Contains information about the context in which a processing algorithm is executed.
void featureAddedToSink(const QString &output)
Reports that a feature was added to the the sink associated with the specified algorithm output.
virtual void pushCommandInfo(const QString &info)
Pushes an informational message containing a command from the algorithm.
void warningPushed(const QString &text)
Emitted when an warning is pushed.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
void infoPushed(const QString &text)
Emitted when information text is pushed.
void errorReported(const QString &text, bool fatalError)
Emitted when an error is reported.
void progressTextChanged(const QString &text)
Emitted when the progress text is changed.
void debugInfoPushed(const QString &text)
Emitted when debug information text is pushed.
void sinkFeatureCountChanged(const QString &output, long long featureCount)
Emitted when the count of features pushed to a sink has changed.
void featureSinkFinalized(const QString &output)
Reports that a feature sink has been finalized.
void pushVersionInfo(const QgsProcessingProvider *provider=nullptr)
Pushes a summary of the QGIS (and underlying library) version information to the log.
virtual QString textLog() const
Returns the plain text contents of the log, which contains all messages pushed to the feedback object...
QgsProcessingFeedback(bool logFeedback=true)
Constructor for QgsProcessingFeedback.
void pushFormattedResults(const QgsProcessingAlgorithm *algorithm, QgsProcessingContext &context, const QVariantMap &results)
Pushes a summary of the execution results to the log.
virtual QString htmlLog() const
Returns the HTML formatted contents of the log, which contains all messages pushed to the feedback ob...
void sourceLoaded(const QString &parameterName, long long featureCount)
Emitted when a feature source was retrieved for the specified algorithm input parameter.
virtual void pushDebugInfo(const QString &info)
Pushes an informational message containing debugging helpers from the algorithm.
void reportSourceLoaded(const QString &parameterName, long long featureCount)
Reports that a feature source was retrieved for the specified algorithm input parameter.
void formattedMessagePushed(const QString &html)
Emitted when a formatted html message is pushed.
virtual void pushFormattedMessage(const QString &html, const QString &text)
Pushes a pre-formatted message from the algorithm.
void resetFeatureSinkCounts()
Resets all stored feature sink counts.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
void commandInfoPushed(const QString &text)
Emitted when command information text is pushed.
void consoleInfoPushed(const QString &text)
Emitted when console information text is pushed.
virtual void pushConsoleInfo(const QString &info)
Pushes a console feedback message from the algorithm.
virtual void setProgressText(const QString &text)
Sets a progress report text string.
QgsProcessingMultiStepFeedback(int steps, QgsProcessingFeedback *feedback)
Constructor for QgsProcessingMultiStepFeedback, for a process with the specified number of steps.
void pushDebugInfo(const QString &info) override
Pushes an informational message containing debugging helpers from the algorithm.
void pushFormattedMessage(const QString &html, const QString &text) override
Pushes a pre-formatted message from the algorithm.
void pushConsoleInfo(const QString &info) override
Pushes a console feedback message from the algorithm.
void pushInfo(const QString &info) override
Pushes a general informational message from the algorithm.
void pushWarning(const QString &warning) override
Pushes a warning informational message from the algorithm.
void setProgressText(const QString &text) override
Sets a progress report text string.
void setCurrentStep(int step)
Sets the step which is being executed.
void setStepWeights(const QList< double > &weights)
Sets the relative weights for each step.
void reportError(const QString &error, bool fatalError=false) override
Reports that the algorithm encountered an error while executing.
QString textLog() const override
Returns the plain text contents of the log, which contains all messages pushed to the feedback object...
void pushCommandInfo(const QString &info) override
Pushes an informational message containing a command from the algorithm.
QString htmlLog() const override
Returns the HTML formatted contents of the log, which contains all messages pushed to the feedback ob...
Base class for the definition of processing outputs.
Abstract base class for processing providers.
virtual QString versionInfo() const
Returns a version information string for the provider, or an empty string if this is not applicable (...
virtual QString name() const =0
Returns the provider name, which is used to describe the provider within the GUI.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call