QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsprocessingalgorithmdialogbase.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingalgorithmdialogbase.cpp
3 ------------------------------------
4 Date : November 2017
5 Copyright : (C) 2017 Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "qgssettings.h"
18#include "qgshelp.h"
19#include "qgsmessagebar.h"
20#include "qgsgui.h"
23#include "qgstaskmanager.h"
25#include "qgsstringutils.h"
26#include "qgsapplication.h"
27#include "qgspanelwidget.h"
28#include "qgsjsonutils.h"
29#include "qgsunittypes.h"
30#include "qgsnative.h"
31#include <QToolButton>
32#include <QDesktopServices>
33#include <QScrollBar>
34#include <QApplication>
35#include <QClipboard>
36#include <QFileDialog>
37#include <QMimeData>
38#include <QMenu>
39#include <nlohmann/json.hpp>
40
41
43
44QgsProcessingAlgorithmDialogFeedback::QgsProcessingAlgorithmDialogFeedback()
45 : QgsProcessingFeedback( false )
46{}
47
48void QgsProcessingAlgorithmDialogFeedback::setProgressText( const QString &text )
49{
51 emit progressTextChanged( text );
52}
53
54void QgsProcessingAlgorithmDialogFeedback::reportError( const QString &error, bool fatalError )
55{
56 QgsProcessingFeedback::reportError( error, fatalError );
57 emit errorReported( error, fatalError );
58}
59
60void QgsProcessingAlgorithmDialogFeedback::pushWarning( const QString &warning )
61{
63 emit warningPushed( warning );
64}
65
66void QgsProcessingAlgorithmDialogFeedback::pushInfo( const QString &info )
67{
69 emit infoPushed( info );
70}
71
72void QgsProcessingAlgorithmDialogFeedback::pushCommandInfo( const QString &info )
73{
75 emit commandInfoPushed( info );
76}
77
78void QgsProcessingAlgorithmDialogFeedback::pushDebugInfo( const QString &info )
79{
81 emit debugInfoPushed( info );
82}
83
84void QgsProcessingAlgorithmDialogFeedback::pushConsoleInfo( const QString &info )
85{
87 emit consoleInfoPushed( info );
88}
89
90void QgsProcessingAlgorithmDialogFeedback::pushFormattedMessage( const QString &html, const QString &text )
91{
93 emit formattedMessagePushed( html );
94}
95
96//
97// QgsProcessingAlgorithmDialogBase
98//
99
100QgsProcessingAlgorithmDialogBase::QgsProcessingAlgorithmDialogBase( QWidget *parent, Qt::WindowFlags flags, DialogMode mode )
101 : QDialog( parent, flags )
102 , mMode( mode )
103{
104 setupUi( this );
105
106 //don't collapse parameters panel
107 splitter->setCollapsible( 0, false );
108
109 // add collapse button to splitter
110 QSplitterHandle *splitterHandle = splitter->handle( 1 );
111 QVBoxLayout *handleLayout = new QVBoxLayout();
112 handleLayout->setContentsMargins( 0, 0, 0, 0 );
113 mButtonCollapse = new QToolButton( splitterHandle );
114 mButtonCollapse->setAutoRaise( true );
115 mButtonCollapse->setFixedSize( 12, 12 );
116 mButtonCollapse->setCursor( Qt::ArrowCursor );
117 handleLayout->addWidget( mButtonCollapse );
118 handleLayout->addStretch();
119 splitterHandle->setLayout( handleLayout );
120
122
123 txtLog->setOpenLinks( false );
124 connect( txtLog, &QTextBrowser::anchorClicked, this, &QgsProcessingAlgorithmDialogBase::urlClicked );
125
126 const QgsSettings settings;
127 splitter->restoreState( settings.value( QStringLiteral( "/Processing/dialogBaseSplitter" ), QByteArray() ).toByteArray() );
128 mSplitterState = splitter->saveState();
129 splitterChanged( 0, 0 );
130
131 // Rename OK button to Run
132 mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
133 mButtonRun->setText( tr( "Run" ) );
134
135 // Rename Yes button. Yes is used to ensure same position of Run and Change Parameters with respect to Close button.
136 mButtonChangeParameters = mButtonBox->button( QDialogButtonBox::Yes );
137 mButtonChangeParameters->setText( tr( "Change Parameters" ) );
138
139 buttonCancel->setEnabled( false );
140 mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
141
142 switch ( mMode )
143 {
144 case DialogMode::Single:
145 {
146 mAdvancedButton = new QPushButton( tr( "Advanced" ) );
147 mAdvancedMenu = new QMenu( this );
148 mAdvancedButton->setMenu( mAdvancedMenu );
149
150 mContextSettingsAction = new QAction( tr( "Algorithm Settingsā€¦" ), mAdvancedMenu );
151 mContextSettingsAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/settings.svg" ) ) );
152 mAdvancedMenu->addAction( mContextSettingsAction );
153
154 connect( mContextSettingsAction, &QAction::triggered, this, [this]
155 {
156 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( mMainWidget ) )
157 {
158 mTabWidget->setCurrentIndex( 0 );
159
160 if ( !mContextOptionsWidget )
161 {
162 mContextOptionsWidget = new QgsProcessingContextOptionsWidget();
163 mContextOptionsWidget->setFromContext( processingContext() );
164 mContextOptionsWidget->setLogLevel( mLogLevel );
165 panel->openPanel( mContextOptionsWidget );
166
167 connect( mContextOptionsWidget, &QgsPanelWidget::widgetChanged, this, [ = ]
168 {
169 mOverrideDefaultContextSettings = true;
170 mGeometryCheck = mContextOptionsWidget->invalidGeometryCheck();
171 mDistanceUnits = mContextOptionsWidget->distanceUnit();
172 mAreaUnits = mContextOptionsWidget->areaUnit();
173 mTemporaryFolderOverride = mContextOptionsWidget->temporaryFolder();
174 mMaximumThreads = mContextOptionsWidget->maximumThreads();
175 mLogLevel = mContextOptionsWidget->logLevel();
176 } );
177 }
178 }
179 } );
180 mAdvancedMenu->addSeparator();
181
182 QAction *copyAsPythonCommand = new QAction( tr( "Copy as Python Command" ), mAdvancedMenu );
183 copyAsPythonCommand->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconPythonFile.svg" ) ) );
184
185 mAdvancedMenu->addAction( copyAsPythonCommand );
186 connect( copyAsPythonCommand, &QAction::triggered, this, [this]
187 {
188 if ( const QgsProcessingAlgorithm *alg = algorithm() )
189 {
190 QgsProcessingContext *context = processingContext();
191 if ( !context )
192 return;
193
194 const QString command = alg->asPythonCommand( createProcessingParameters(), *context );
195 QMimeData *m = new QMimeData();
196 m->setText( command );
197 QClipboard *cb = QApplication::clipboard();
198
199#ifdef Q_OS_LINUX
200 cb->setMimeData( m, QClipboard::Selection );
201#endif
202 cb->setMimeData( m, QClipboard::Clipboard );
203 }
204 } );
205
206 mCopyAsQgisProcessCommand = new QAction( tr( "Copy as qgis_process Command" ), mAdvancedMenu );
207 mCopyAsQgisProcessCommand->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionTerminal.svg" ) ) );
208 mAdvancedMenu->addAction( mCopyAsQgisProcessCommand );
209
210 connect( mCopyAsQgisProcessCommand, &QAction::triggered, this, [this]
211 {
212 if ( const QgsProcessingAlgorithm *alg = algorithm() )
213 {
214 QgsProcessingContext *context = processingContext();
215 if ( !context )
216 return;
217
218 bool ok = false;
219 const QString command = alg->asQgisProcessCommand( createProcessingParameters(), *context, ok );
220 if ( ! ok )
221 {
222 mMessageBar->pushMessage( tr( "Current settings cannot be specified as arguments to qgis_process (Pipe parameters as JSON to qgis_process instead)" ), Qgis::MessageLevel::Warning );
223 }
224 else
225 {
226 QMimeData *m = new QMimeData();
227 m->setText( command );
228 QClipboard *cb = QApplication::clipboard();
229
230#ifdef Q_OS_LINUX
231 cb->setMimeData( m, QClipboard::Selection );
232#endif
233 cb->setMimeData( m, QClipboard::Clipboard );
234 }
235 }
236 } );
237
238 mAdvancedMenu->addSeparator();
239
240 QAction *copyAsJson = new QAction( tr( "Copy as JSON" ), mAdvancedMenu );
241 copyAsJson->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionEditCopy.svg" ) ) );
242
243 mAdvancedMenu->addAction( copyAsJson );
244 connect( copyAsJson, &QAction::triggered, this, [this]
245 {
246 if ( const QgsProcessingAlgorithm *alg = algorithm() )
247 {
248 QgsProcessingContext *context = processingContext();
249 if ( !context )
250 return;
251
252 const QVariantMap properties = alg->asMap( createProcessingParameters(), *context );
253 const QString json = QString::fromStdString( QgsJsonUtils::jsonFromVariant( properties ).dump( 2 ) );
254
255 QMimeData *m = new QMimeData();
256 m->setText( json );
257 QClipboard *cb = QApplication::clipboard();
258
259#ifdef Q_OS_LINUX
260 cb->setMimeData( m, QClipboard::Selection );
261#endif
262 cb->setMimeData( m, QClipboard::Clipboard );
263 }
264 } );
265
266 mPasteJsonAction = new QAction( tr( "Paste Settings" ), mAdvancedMenu );
267 mPasteJsonAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionEditPaste.svg" ) ) );
268
269 mAdvancedMenu->addAction( mPasteJsonAction );
270 connect( mPasteJsonAction, &QAction::triggered, this, [this]
271 {
272 const QString text = QApplication::clipboard()->text();
273 if ( text.isEmpty() )
274 return;
275
276 const QVariantMap parameterValues = QgsJsonUtils::parseJson( text ).toMap().value( QStringLiteral( "inputs" ) ).toMap();
277 if ( parameterValues.isEmpty() )
278 return;
279
280 bool ok = false;
281 QString error;
282 const QVariantMap preparedValues = QgsProcessingUtils::preprocessQgisProcessParameters( parameterValues, ok, error );
283
284 setParameters( preparedValues );
285 } );
286
287 mButtonBox->addButton( mAdvancedButton, QDialogButtonBox::ResetRole );
288 break;
289 }
290
291 case DialogMode::Batch:
292 break;
293 }
294
295 if ( mAdvancedMenu )
296 {
297 connect( mAdvancedMenu, &QMenu::aboutToShow, this, [ = ]
298 {
299 mCopyAsQgisProcessCommand->setEnabled( algorithm()
301 mPasteJsonAction->setEnabled( !QApplication::clipboard()->text().isEmpty() );
302 } );
303 }
304
305 connect( mButtonRun, &QPushButton::clicked, this, &QgsProcessingAlgorithmDialogBase::runAlgorithm );
306 connect( mButtonChangeParameters, &QPushButton::clicked, this, &QgsProcessingAlgorithmDialogBase::showParameters );
307 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QgsProcessingAlgorithmDialogBase::closeClicked );
308 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsProcessingAlgorithmDialogBase::openHelp );
309 connect( mButtonCollapse, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::toggleCollapsed );
310 connect( splitter, &QSplitter::splitterMoved, this, &QgsProcessingAlgorithmDialogBase::splitterChanged );
311
312 connect( mButtonSaveLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::saveLog );
313 connect( mButtonCopyLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::copyLogToClipboard );
314 connect( mButtonClearLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::clearLog );
315
316 connect( mTabWidget, &QTabWidget::currentChanged, this, &QgsProcessingAlgorithmDialogBase::mTabWidget_currentChanged );
317
318 mMessageBar = new QgsMessageBar();
319 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
320 verticalLayout->insertWidget( 0, mMessageBar );
321
322 connect( QgsApplication::taskManager(), &QgsTaskManager::taskTriggered, this, &QgsProcessingAlgorithmDialogBase::taskTriggered );
323}
324
325QgsProcessingAlgorithmDialogBase::~QgsProcessingAlgorithmDialogBase() = default;
326
327void QgsProcessingAlgorithmDialogBase::setParameters( const QVariantMap & )
328{}
329
330void QgsProcessingAlgorithmDialogBase::setAlgorithm( QgsProcessingAlgorithm *algorithm )
331{
332 mAlgorithm.reset( algorithm );
333 QString title;
335 {
336 title = QgsStringUtils::capitalize( mAlgorithm->displayName(), Qgis::Capitalization::TitleCase );
337 }
338 else
339 {
340 title = mAlgorithm->displayName();
341 }
342 setWindowTitle( title );
343
344 const QString algHelp = formatHelp( algorithm );
345 if ( algHelp.isEmpty() )
346 textShortHelp->hide();
347 else
348 {
349 textShortHelp->document()->setDefaultStyleSheet( QStringLiteral( ".summary { margin-left: 10px; margin-right: 10px; }\n"
350 "h2 { color: #555555; padding-bottom: 15px; }\n"
351 "a { text - decoration: none; color: #3498db; font-weight: bold; }\n"
352 "p { color: #666666; }\n"
353 "b { color: #333333; }\n"
354 "dl dd { margin - bottom: 5px; }" ) );
355 textShortHelp->setHtml( algHelp );
356 connect( textShortHelp, &QTextBrowser::anchorClicked, this, &QgsProcessingAlgorithmDialogBase::linkClicked );
357 textShortHelp->show();
358 }
359
360 if ( algorithm->helpUrl().isEmpty() && ( !algorithm->provider() || algorithm->provider()->helpId().isEmpty() ) )
361 {
362 mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Help ) );
363 }
364
365 const QString warning = algorithm->provider() ? algorithm->provider()->warningMessage() : QString();
366 if ( !warning.isEmpty() )
367 {
368 mMessageBar->pushMessage( warning, Qgis::MessageLevel::Warning );
369 }
370}
371
373{
374 return mAlgorithm.get();
375}
376
377void QgsProcessingAlgorithmDialogBase::setMainWidget( QgsPanelWidget *widget )
378{
379 if ( mMainWidget )
380 {
381 mMainWidget->deleteLater();
382 }
383
384 mPanelStack->setMainPanel( widget );
385 widget->setDockMode( true );
386
387 mMainWidget = widget;
388 connect( mMainWidget, &QgsPanelWidget::panelAccepted, this, &QDialog::reject );
389}
390
391QgsPanelWidget *QgsProcessingAlgorithmDialogBase::mainWidget()
392{
393 return mMainWidget;
394}
395
396void QgsProcessingAlgorithmDialogBase::saveLogToFile( const QString &path, const LogFormat format )
397{
398 QFile logFile( path );
399 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
400 {
401 return;
402 }
403 QTextStream fout( &logFile );
404
405 switch ( format )
406 {
407 case FormatPlainText:
408 fout << txtLog->toPlainText();
409 break;
410
411 case FormatHtml:
412 fout << txtLog->toHtml();
413 break;
414 }
415}
416
417QgsProcessingFeedback *QgsProcessingAlgorithmDialogBase::createFeedback()
418{
419 auto feedback = std::make_unique< QgsProcessingAlgorithmDialogFeedback >();
420 connect( feedback.get(), &QgsProcessingFeedback::progressChanged, this, &QgsProcessingAlgorithmDialogBase::setPercentage );
421 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::commandInfoPushed, this, &QgsProcessingAlgorithmDialogBase::pushCommandInfo );
422 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::consoleInfoPushed, this, &QgsProcessingAlgorithmDialogBase::pushConsoleInfo );
423 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::debugInfoPushed, this, &QgsProcessingAlgorithmDialogBase::pushDebugInfo );
424 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::errorReported, this, &QgsProcessingAlgorithmDialogBase::reportError );
425 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::warningPushed, this, &QgsProcessingAlgorithmDialogBase::pushWarning );
426 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::infoPushed, this, &QgsProcessingAlgorithmDialogBase::pushInfo );
427 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::formattedMessagePushed, this, &QgsProcessingAlgorithmDialogBase::pushFormattedMessage );
428 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::progressTextChanged, this, &QgsProcessingAlgorithmDialogBase::setProgressText );
429 connect( buttonCancel, &QPushButton::clicked, feedback.get(), &QgsProcessingFeedback::cancel );
430 return feedback.release();
431}
432
433QDialogButtonBox *QgsProcessingAlgorithmDialogBase::buttonBox()
434{
435 return mButtonBox;
436}
437
438QTabWidget *QgsProcessingAlgorithmDialogBase::tabWidget()
439{
440 return mTabWidget;
441}
442
443void QgsProcessingAlgorithmDialogBase::showLog()
444{
445 mTabWidget->setCurrentIndex( 1 );
446}
447
448void QgsProcessingAlgorithmDialogBase::showParameters()
449{
450 mTabWidget->setCurrentIndex( 0 );
451}
452
453QPushButton *QgsProcessingAlgorithmDialogBase::runButton()
454{
455 return mButtonRun;
456}
457
458QPushButton *QgsProcessingAlgorithmDialogBase::cancelButton()
459{
460 return buttonCancel;
461}
462
463QPushButton *QgsProcessingAlgorithmDialogBase::changeParametersButton()
464{
465 return mButtonChangeParameters;
466}
467
468void QgsProcessingAlgorithmDialogBase::clearProgress()
469{
470 progressBar->setMaximum( 0 );
471}
472
473void QgsProcessingAlgorithmDialogBase::setExecuted( bool executed )
474{
475 mExecuted = executed;
476}
477
478void QgsProcessingAlgorithmDialogBase::setExecutedAnyResult( bool executedAnyResult )
479{
480 mExecutedAnyResult = executedAnyResult;
481}
482
483void QgsProcessingAlgorithmDialogBase::setResults( const QVariantMap &results )
484{
485 mResults = results;
486}
487
488void QgsProcessingAlgorithmDialogBase::finished( bool, const QVariantMap &, QgsProcessingContext &, QgsProcessingFeedback * )
489{
490
491}
492
493void QgsProcessingAlgorithmDialogBase::openHelp()
494{
495 QUrl algHelp = mAlgorithm->helpUrl();
496 if ( algHelp.isEmpty() && mAlgorithm->provider() )
497 {
498 algHelp = QgsHelp::helpUrl( QStringLiteral( "processing_algs/%1/%2.html#%3" ).arg( mAlgorithm->provider()->helpId(), mAlgorithm->groupId(), QStringLiteral( "%1%2" ).arg( mAlgorithm->provider()->helpId() ).arg( mAlgorithm->name() ) ) );
499 }
500
501 if ( !algHelp.isEmpty() )
502 QDesktopServices::openUrl( algHelp );
503}
504
505void QgsProcessingAlgorithmDialogBase::toggleCollapsed()
506{
507 if ( mHelpCollapsed )
508 {
509 splitter->restoreState( mSplitterState );
510 mButtonCollapse->setArrowType( Qt::RightArrow );
511 }
512 else
513 {
514 mSplitterState = splitter->saveState();
515 splitter->setSizes( QList<int>() << 1 << 0 );
516 mButtonCollapse->setArrowType( Qt::LeftArrow );
517 }
518 mHelpCollapsed = !mHelpCollapsed;
519}
520
521void QgsProcessingAlgorithmDialogBase::splitterChanged( int, int )
522{
523 if ( splitter->sizes().at( 1 ) == 0 )
524 {
525 mHelpCollapsed = true;
526 mButtonCollapse->setArrowType( Qt::LeftArrow );
527 }
528 else
529 {
530 mHelpCollapsed = false;
531 mButtonCollapse->setArrowType( Qt::RightArrow );
532 }
533}
534
535void QgsProcessingAlgorithmDialogBase::mTabWidget_currentChanged( int )
536{
537 updateRunButtonVisibility();
538}
539
540void QgsProcessingAlgorithmDialogBase::linkClicked( const QUrl &url )
541{
542 QDesktopServices::openUrl( url.toString() );
543}
544
545void QgsProcessingAlgorithmDialogBase::algExecuted( bool successful, const QVariantMap & )
546{
547 mAlgorithmTask = nullptr;
548
549 if ( !successful )
550 {
551 // show dialog to display errors
552 show();
553 raise();
554 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
555 activateWindow();
556 showLog();
557 }
558 else
559 {
560 if ( isFinalized() && successful )
561 {
562 progressBar->setFormat( tr( "Complete" ) );
563 }
564
565 // delete dialog if closed
566 if ( isFinalized() && !isVisible() )
567 {
568 deleteLater();
569 }
570 }
571}
572
573void QgsProcessingAlgorithmDialogBase::taskTriggered( QgsTask *task )
574{
575 if ( task == mAlgorithmTask )
576 {
577 show();
578 raise();
579 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
580 activateWindow();
581 showLog();
582 }
583}
584
585void QgsProcessingAlgorithmDialogBase::closeClicked()
586{
587 reject();
588 close();
589}
590
591void QgsProcessingAlgorithmDialogBase::urlClicked( const QUrl &url )
592{
593 const QFileInfo file( url.toLocalFile() );
594 if ( file.exists() && !file.isDir() )
595 QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
596 else
597 QDesktopServices::openUrl( url );
598}
599
600Qgis::ProcessingLogLevel QgsProcessingAlgorithmDialogBase::logLevel() const
601{
602 return mLogLevel;
603}
604
605void QgsProcessingAlgorithmDialogBase::setLogLevel( Qgis::ProcessingLogLevel level )
606{
607 mLogLevel = level;
608}
609
610void QgsProcessingAlgorithmDialogBase::reportError( const QString &error, bool fatalError )
611{
612 setInfo( error, true );
613 if ( fatalError )
614 resetGui();
615 showLog();
616 processEvents();
617}
618
619void QgsProcessingAlgorithmDialogBase::pushWarning( const QString &warning )
620{
621 setInfo( warning, false, true, true );
622 processEvents();
623}
624
625void QgsProcessingAlgorithmDialogBase::pushInfo( const QString &info )
626{
627 setInfo( info );
628 processEvents();
629}
630
631void QgsProcessingAlgorithmDialogBase::pushFormattedMessage( const QString &html )
632{
633 setInfo( html, false, false );
634 processEvents();
635}
636
637void QgsProcessingAlgorithmDialogBase::pushCommandInfo( const QString &command )
638{
639 txtLog->append( QStringLiteral( "<code>%1<code>" ).arg( formatStringForLog( command.toHtmlEscaped() ) ) );
640 scrollToBottomOfLog();
641 processEvents();
642}
643
644void QgsProcessingAlgorithmDialogBase::pushDebugInfo( const QString &message )
645{
646 txtLog->append( QStringLiteral( "<span style=\"color:#777\">%1</span>" ).arg( formatStringForLog( message.toHtmlEscaped() ) ) );
647 scrollToBottomOfLog();
648 processEvents();
649}
650
651void QgsProcessingAlgorithmDialogBase::pushConsoleInfo( const QString &info )
652{
653 txtLog->append( QStringLiteral( "<code style=\"color:#777\">%1</code>" ).arg( formatStringForLog( info.toHtmlEscaped() ) ) );
654 scrollToBottomOfLog();
655 processEvents();
656}
657
658QDialog *QgsProcessingAlgorithmDialogBase::createProgressDialog()
659{
660 QgsProcessingAlgorithmProgressDialog *dialog = new QgsProcessingAlgorithmProgressDialog( this );
661 dialog->setWindowModality( Qt::ApplicationModal );
662 dialog->setWindowTitle( windowTitle() );
663 dialog->setGeometry( geometry() ); // match size/position to this dialog
664 connect( progressBar, &QProgressBar::valueChanged, dialog->progressBar(), &QProgressBar::setValue );
665 connect( dialog->cancelButton(), &QPushButton::clicked, buttonCancel, &QPushButton::click );
666 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
667 connect( txtLog, &QTextEdit::textChanged, dialog, [this, dialog]()
668 {
669 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
670 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
671 sb->setValue( sb->maximum() );
672 } );
673 return dialog;
674}
675
676void QgsProcessingAlgorithmDialogBase::clearLog()
677{
678 txtLog->clear();
679}
680
681void QgsProcessingAlgorithmDialogBase::saveLog()
682{
683 QgsSettings settings;
684 const QString lastUsedDir = settings.value( QStringLiteral( "/Processing/lastUsedLogDirectory" ), QDir::homePath() ).toString();
685
686 QString filter;
687 const QString txtExt = tr( "Text files" ) + QStringLiteral( " (*.txt *.TXT)" );
688 const QString htmlExt = tr( "HTML files" ) + QStringLiteral( " (*.html *.HTML)" );
689
690 const QString path = QFileDialog::getSaveFileName( this, tr( "Save Log to File" ), lastUsedDir, txtExt + ";;" + htmlExt, &filter );
691 // return dialog focus on Mac
692 activateWindow();
693 raise();
694 if ( path.isEmpty() )
695 {
696 return;
697 }
698
699 settings.setValue( QStringLiteral( "/Processing/lastUsedLogDirectory" ), QFileInfo( path ).path() );
700
701 LogFormat format = FormatPlainText;
702 if ( filter == htmlExt )
703 {
704 format = FormatHtml;
705 }
706 saveLogToFile( path, format );
707}
708
709void QgsProcessingAlgorithmDialogBase::copyLogToClipboard()
710{
711 QMimeData *m = new QMimeData();
712 m->setText( txtLog->toPlainText() );
713 m->setHtml( txtLog->toHtml() );
714 QClipboard *cb = QApplication::clipboard();
715
716#ifdef Q_OS_LINUX
717 cb->setMimeData( m, QClipboard::Selection );
718#endif
719 cb->setMimeData( m, QClipboard::Clipboard );
720}
721
722void QgsProcessingAlgorithmDialogBase::closeEvent( QCloseEvent *e )
723{
724 if ( !mHelpCollapsed )
725 {
726 QgsSettings settings;
727 settings.setValue( QStringLiteral( "/Processing/dialogBaseSplitter" ), splitter->saveState() );
728 }
729
730 QDialog::closeEvent( e );
731
732 if ( !mAlgorithmTask && isFinalized() )
733 {
734 // when running a background task, the dialog is kept around and deleted only when the task
735 // completes. But if not running a task, we auto cleanup (later - gotta give callers a chance
736 // to retrieve results and execution status).
737 deleteLater();
738 }
739}
740
741void QgsProcessingAlgorithmDialogBase::runAlgorithm()
742{
743
744}
745
746void QgsProcessingAlgorithmDialogBase::setPercentage( double percent )
747{
748 // delay setting maximum progress value until we know algorithm reports progress
749 if ( progressBar->maximum() == 0 )
750 progressBar->setMaximum( 100 );
751 progressBar->setValue( percent );
752 processEvents();
753}
754
755void QgsProcessingAlgorithmDialogBase::setProgressText( const QString &text )
756{
757 lblProgress->setText( text );
758 setInfo( text, false );
759 scrollToBottomOfLog();
760 processEvents();
761}
762
763QString QgsProcessingAlgorithmDialogBase::formatHelp( QgsProcessingAlgorithm *algorithm )
764{
765 const QString text = algorithm->shortHelpString();
766 if ( !text.isEmpty() )
767 {
768 const QStringList paragraphs = text.split( '\n' );
769 QString help;
770 for ( const QString &paragraph : paragraphs )
771 {
772 help += QStringLiteral( "<p>%1</p>" ).arg( paragraph );
773 }
774 return QStringLiteral( "<h2>%1</h2>%2" ).arg( algorithm->displayName(), help );
775 }
776 else if ( !algorithm->shortDescription().isEmpty() )
777 {
778 return QStringLiteral( "<h2>%1</h2><p>%2</p>" ).arg( algorithm->displayName(), algorithm->shortDescription() );
779 }
780 else
781 return QString();
782}
783
784void QgsProcessingAlgorithmDialogBase::processEvents()
785{
786 if ( mAlgorithmTask )
787 {
788 // no need to call this - the algorithm is running in a thread.
789 // in fact, calling it causes a crash on Windows when the algorithm
790 // is running in a background thread... unfortunately we need something
791 // like this for non-threadable algorithms, otherwise there's no chance
792 // for users to hit cancel or see progress updates...
793 return;
794 }
795
796 // So that we get a chance of hitting the Abort button
797#ifdef Q_OS_LINUX
798 // One iteration is actually enough on Windows to get good interactivity
799 // whereas on Linux we must allow for far more iterations.
800 // For safety limit the number of iterations
801 int nIters = 0;
802 while ( ++nIters < 100 )
803#endif
804 {
805 QCoreApplication::processEvents();
806 }
807}
808
809void QgsProcessingAlgorithmDialogBase::scrollToBottomOfLog()
810{
811 QScrollBar *sb = txtLog->verticalScrollBar();
812 sb->setValue( sb->maximum() );
813}
814
815void QgsProcessingAlgorithmDialogBase::resetGui()
816{
817 lblProgress->clear();
818 progressBar->setMaximum( 100 );
819 progressBar->setValue( 0 );
820 mButtonRun->setEnabled( true );
821 mButtonChangeParameters->setEnabled( true );
822 mButtonClose->setEnabled( true );
823 if ( mMainWidget )
824 {
825 mMainWidget->setEnabled( true );
826 }
827 updateRunButtonVisibility();
828 resetAdditionalGui();
829}
830
831void QgsProcessingAlgorithmDialogBase::updateRunButtonVisibility()
832{
833 // Activate run button if current tab is Parameters
834 const bool runButtonVisible = mTabWidget->currentIndex() == 0;
835 mButtonRun->setVisible( runButtonVisible );
836 if ( runButtonVisible )
837 progressBar->resetFormat();
838 mButtonChangeParameters->setVisible( !runButtonVisible && mExecutedAnyResult && mButtonChangeParameters->isEnabled() );
839}
840
841void QgsProcessingAlgorithmDialogBase::resetAdditionalGui()
842{
843
844}
845
846void QgsProcessingAlgorithmDialogBase::blockControlsWhileRunning()
847{
848 mButtonRun->setEnabled( false );
849 mButtonChangeParameters->setEnabled( false );
850 if ( mMainWidget )
851 {
852 mMainWidget->setEnabled( false );
853 }
854 blockAdditionalControlsWhileRunning();
855}
856
857void QgsProcessingAlgorithmDialogBase::blockAdditionalControlsWhileRunning()
858{
859
860}
861
862QgsMessageBar *QgsProcessingAlgorithmDialogBase::messageBar()
863{
864 return mMessageBar;
865}
866
867void QgsProcessingAlgorithmDialogBase::hideShortHelp()
868{
869 textShortHelp->setVisible( false );
870}
871
872void QgsProcessingAlgorithmDialogBase::setCurrentTask( QgsProcessingAlgRunnerTask *task )
873{
874 mAlgorithmTask = task;
875 connect( mAlgorithmTask, &QgsProcessingAlgRunnerTask::executed, this, &QgsProcessingAlgorithmDialogBase::algExecuted );
876 QgsApplication::taskManager()->addTask( mAlgorithmTask );
877}
878
879QString QgsProcessingAlgorithmDialogBase::formatStringForLog( const QString &string )
880{
881 QString s = string;
882 s.replace( '\n', QLatin1String( "<br>" ) );
883 return s;
884}
885
886bool QgsProcessingAlgorithmDialogBase::isFinalized()
887{
888 return true;
889}
890
891void QgsProcessingAlgorithmDialogBase::applyContextOverrides( QgsProcessingContext *context )
892{
893 if ( !context )
894 return;
895
896 context->setLogLevel( logLevel() );
897
898 if ( mOverrideDefaultContextSettings )
899 {
900 context->setInvalidGeometryCheck( mGeometryCheck );
901 context->setDistanceUnit( mDistanceUnits );
902 context->setAreaUnit( mAreaUnits );
903 context->setTemporaryFolder( mTemporaryFolderOverride );
904 context->setMaximumThreads( mMaximumThreads );
905 }
906}
907
908void QgsProcessingAlgorithmDialogBase::setInfo( const QString &message, bool isError, bool escapeHtml, bool isWarning )
909{
910 constexpr int MESSAGE_COUNT_LIMIT = 10000;
911 // Avoid logging too many messages, which might blow memory.
912 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
913 return;
914 ++mMessageLoggedCount;
915
916 // note -- we have to wrap the message in a span block, or QTextEdit::append sometimes gets confused
917 // and varies between treating it as a HTML string or a plain text string! (see https://github.com/qgis/QGIS/issues/37934)
918 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
919 txtLog->append( QStringLiteral( "<span style=\"color:red\">%1</span>" ).arg( tr( "Message log truncated" ) ) );
920 else if ( isError || isWarning )
921 txtLog->append( QStringLiteral( "<span style=\"color:%1\">%2</span>" ).arg( isError ? QStringLiteral( "red" ) : QStringLiteral( "#b85a20" ), escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
922 else if ( escapeHtml )
923 txtLog->append( QStringLiteral( "<span>%1</span" ).arg( formatStringForLog( message.toHtmlEscaped() ) ) );
924 else
925 txtLog->append( QStringLiteral( "<span>%1</span>" ).arg( formatStringForLog( message ) ) );
926 scrollToBottomOfLog();
927 processEvents();
928}
929
930void QgsProcessingAlgorithmDialogBase::reject()
931{
932 if ( !mAlgorithmTask && isFinalized() )
933 {
934 setAttribute( Qt::WA_DeleteOnClose );
935 }
936 QDialog::reject();
937}
938
939//
940// QgsProcessingAlgorithmProgressDialog
941//
942
943QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
944 : QDialog( parent )
945{
946 setupUi( this );
947}
948
949QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
950{
951 return mProgressBar;
952}
953
954QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
955{
956 return mButtonBox->button( QDialogButtonBox::Cancel );
957}
958
959QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
960{
961 return mTxtLog;
962}
963
964void QgsProcessingAlgorithmProgressDialog::reject()
965{
966
967}
968
969
970//
971// QgsProcessingContextOptionsWidget
972//
973
974QgsProcessingContextOptionsWidget::QgsProcessingContextOptionsWidget( QWidget *parent )
975 : QgsPanelWidget( parent )
976{
977 setupUi( this );
978 setPanelTitle( tr( "Algorithm Settings" ) );
979
980 mComboInvalidFeatureFiltering->addItem( tr( "Do not Filter (Better Performance)" ), QVariant::fromValue( Qgis::InvalidGeometryCheck::NoCheck ) );
981 mComboInvalidFeatureFiltering->addItem( tr( "Skip (Ignore) Features with Invalid Geometries" ), QVariant::fromValue( Qgis::InvalidGeometryCheck::SkipInvalid ) );
982 mComboInvalidFeatureFiltering->addItem( tr( "Stop Algorithm Execution When a Geometry is Invalid" ), QVariant::fromValue( Qgis::InvalidGeometryCheck::AbortOnInvalid ) );
983
984 mTemporaryFolderWidget->setDialogTitle( tr( "Select Temporary Directory" ) );
985 mTemporaryFolderWidget->setStorageMode( QgsFileWidget::GetDirectory );
986 mTemporaryFolderWidget->lineEdit()->setPlaceholderText( tr( "Default" ) );
987
988 mLogLevelComboBox->addItem( tr( "Default" ), static_cast< int >( Qgis::ProcessingLogLevel::DefaultLevel ) );
989 mLogLevelComboBox->addItem( tr( "Verbose" ), static_cast< int >( Qgis::ProcessingLogLevel::Verbose ) );
990 mLogLevelComboBox->addItem( tr( "Verbose (Model Debugging)" ), static_cast< int >( Qgis::ProcessingLogLevel::ModelDebug ) );
991
992 mDistanceUnitsCombo->addItem( tr( "Default" ), QVariant::fromValue( Qgis::DistanceUnit::Unknown ) );
993 for ( Qgis::DistanceUnit unit :
994 {
1005 } )
1006 {
1007 QString title;
1009 {
1011 }
1012 else
1013 {
1014 title = QgsUnitTypes::toString( unit );
1015 }
1016
1017 mDistanceUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1018 }
1019
1020 mAreaUnitsCombo->addItem( tr( "Default" ), QVariant::fromValue( Qgis::AreaUnit::Unknown ) );
1021 for ( Qgis::AreaUnit unit :
1022 {
1035 } )
1036 {
1037 QString title;
1039 {
1041 }
1042 else
1043 {
1044 title = QgsUnitTypes::toString( unit );
1045 }
1046
1047 mAreaUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1048 }
1049
1050 mThreadsSpinBox->setRange( 1, QThread::idealThreadCount() );
1051
1052 connect( mLogLevelComboBox, qOverload< int >( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1053 connect( mComboInvalidFeatureFiltering, qOverload< int >( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1054 connect( mDistanceUnitsCombo, qOverload< int >( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1055 connect( mAreaUnitsCombo, qOverload< int >( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1056 connect( mTemporaryFolderWidget, &QgsFileWidget::fileChanged, this, &QgsPanelWidget::widgetChanged );
1057 connect( mThreadsSpinBox, qOverload< int >( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
1058}
1059
1060void QgsProcessingContextOptionsWidget::setFromContext( const QgsProcessingContext *context )
1061{
1062 whileBlocking( mComboInvalidFeatureFiltering )->setCurrentIndex( mComboInvalidFeatureFiltering->findData( QVariant::fromValue( context->invalidGeometryCheck() ) ) );
1063 whileBlocking( mDistanceUnitsCombo )->setCurrentIndex( mDistanceUnitsCombo->findData( QVariant::fromValue( context->distanceUnit() ) ) );
1064 whileBlocking( mAreaUnitsCombo )->setCurrentIndex( mAreaUnitsCombo->findData( QVariant::fromValue( context->areaUnit() ) ) );
1065 whileBlocking( mTemporaryFolderWidget )->setFilePath( context->temporaryFolder() );
1066 whileBlocking( mThreadsSpinBox )->setValue( context->maximumThreads() );
1067 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData( static_cast< int >( context->logLevel() ) ) );
1068}
1069
1070Qgis::InvalidGeometryCheck QgsProcessingContextOptionsWidget::invalidGeometryCheck() const
1071{
1072 return mComboInvalidFeatureFiltering->currentData().value< Qgis::InvalidGeometryCheck >();
1073}
1074
1075Qgis::DistanceUnit QgsProcessingContextOptionsWidget::distanceUnit() const
1076{
1077 return mDistanceUnitsCombo->currentData().value< Qgis::DistanceUnit >();
1078}
1079
1080Qgis::AreaUnit QgsProcessingContextOptionsWidget::areaUnit() const
1081{
1082 return mAreaUnitsCombo->currentData().value< Qgis::AreaUnit >();
1083}
1084
1085QString QgsProcessingContextOptionsWidget::temporaryFolder()
1086{
1087 return mTemporaryFolderWidget->filePath();
1088}
1089
1090int QgsProcessingContextOptionsWidget::maximumThreads() const
1091{
1092 return mThreadsSpinBox->value();
1093}
1094
1095void QgsProcessingContextOptionsWidget::setLogLevel( Qgis::ProcessingLogLevel level )
1096{
1097 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData( static_cast< int >( level ) ) );
1098}
1099
1100Qgis::ProcessingLogLevel QgsProcessingContextOptionsWidget::logLevel() const
1101{
1102 return static_cast< Qgis::ProcessingLogLevel >( mLogLevelComboBox->currentData().toInt() );
1103}
1104
DistanceUnit
Units of distance.
Definition: qgis.h:4124
@ Feet
Imperial feet.
@ Centimeters
Centimeters.
@ Millimeters
Millimeters.
@ Miles
Terrestrial miles.
@ Unknown
Unknown distance unit.
@ Yards
Imperial yards.
@ Degrees
Degrees, for planar geographic CRS distance measurements.
@ Inches
Inches (since QGIS 3.32)
@ NauticalMiles
Nautical miles.
@ Kilometers
Kilometers.
AreaUnit
Units of area.
Definition: qgis.h:4162
@ SquareFeet
Square feet.
@ SquareCentimeters
Square centimeters.
@ SquareInches
Square inches (since QGIS 3.32)
@ SquareNauticalMiles
Square nautical miles.
@ SquareMillimeters
Square millimeters.
@ SquareYards
Square yards.
@ Hectares
Hectares.
@ SquareKilometers
Square kilometers.
@ SquareMeters
Square meters.
@ Unknown
Unknown areal unit.
@ SquareDegrees
Square degrees, for planar geographic CRS area measurements.
@ SquareMiles
Square miles.
@ TitleCase
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
InvalidGeometryCheck
Methods for handling of features with invalid geometries.
Definition: qgis.h:1778
@ NoCheck
No invalid geometry checking.
@ AbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
@ SkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
@ NotAvailableInStandaloneTool
Algorithm should not be available from the standalone "qgis_process" tool. Used to flag algorithms wh...
@ DisplayNameIsLiteral
Algorithm's display name is a static literal string, and should not be translated or automatically fo...
ProcessingLogLevel
Logging level for algorithms to use when pushing feedback messages.
Definition: qgis.h:2960
@ DefaultLevel
Default logging level.
@ Verbose
Verbose logging.
@ ModelDebug
Model debug level logging. Includes verbose logging and other outputs useful for debugging models (si...
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
void cancel()
Tells the internal routines that the current operation should be canceled. This should be run by the ...
Definition: qgsfeedback.h:105
@ GetDirectory
Select a directory.
Definition: qgsfilewidget.h:69
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition: qgsgui.cpp:194
@ HigDialogTitleIsTitleCase
Dialog titles should be title case.
Definition: qgsgui.h:255
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:79
static QgsGui::HigFlags higFlags()
Returns the platform's HIG flags.
Definition: qgsgui.cpp:218
static QUrl helpUrl(const QString &key)
Returns URI of the help topic for the given key.
Definition: qgshelp.cpp:44
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
static json jsonFromVariant(const QVariant &v)
Converts a QVariant v to a json object.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
Base class for any widget that can be shown as a inline panel.
void panelAccepted(QgsPanelWidget *panel)
Emitted when the panel is accepted by the user.
void widgetChanged()
Emitted when the widget state changes.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
QgsTask task which runs a QgsProcessingAlgorithm in a background task.
void executed(bool successful, const QVariantMap &results)
Emitted when the algorithm has finished execution.
Abstract base class for processing algorithms.
virtual QString helpUrl() const
Returns a url pointing to the algorithm's help page.
virtual QString shortHelpString() const
Returns a localised short helper string for the algorithm.
virtual QString shortDescription() const
Returns an optional translated short description of the algorithm.
virtual QString displayName() const =0
Returns the translated algorithm name, which should be used for any user-visible display of the algor...
QgsProcessingProvider * provider() const
Returns the provider to which this algorithm belongs.
Contains information about the context in which a processing algorithm is executed.
Qgis::AreaUnit areaUnit() const
Returns the area unit to use for area calculations.
void setLogLevel(Qgis::ProcessingLogLevel level)
Sets the logging level for algorithms to use when pushing feedback messages to users.
void setMaximumThreads(int threads)
Sets the (optional) number of threads to use when running algorithms.
void setDistanceUnit(Qgis::DistanceUnit unit)
Sets the unit to use for distance calculations.
void setInvalidGeometryCheck(Qgis::InvalidGeometryCheck check)
Sets the behavior used for checking invalid geometries in input layers.
void setAreaUnit(Qgis::AreaUnit areaUnit)
Sets the unit to use for area calculations.
Qgis::DistanceUnit distanceUnit() const
Returns the distance unit to use for distance calculations.
Qgis::ProcessingLogLevel logLevel() const
Returns the logging level for algorithms to use when pushing feedback messages to users.
Qgis::InvalidGeometryCheck invalidGeometryCheck() const
Returns the behavior used for checking invalid geometries in input layers.
void setTemporaryFolder(const QString &folder)
Sets the (optional) temporary folder to use when running algorithms.
QString temporaryFolder() const
Returns the (optional) temporary folder to use when running algorithms.
int maximumThreads() const
Returns the (optional) number of threads to use when running algorithms.
Qgis::ProcessingAlgorithmFlags flags() const override
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Base class for providing feedback from a processing algorithm.
virtual void pushCommandInfo(const QString &info)
Pushes an informational message containing a command from the algorithm.
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.
virtual void pushDebugInfo(const QString &info)
Pushes an informational message containing debugging helpers from the algorithm.
virtual void pushFormattedMessage(const QString &html, const QString &text)
Pushes a pre-formatted message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
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.
virtual QString helpId() const
Returns the provider help id string, used for creating QgsHelp urls for algorithms belong to this pro...
virtual QString warningMessage() const
Returns an optional warning message to show users when running algorithms from this provider.
static QVariantMap preprocessQgisProcessParameters(const QVariantMap &parameters, bool &ok, QString &error)
Pre-processes a set of parameter values for the qgis_process command.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:64
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QString capitalize(const QString &string, Qgis::Capitalization capitalization)
Converts a string by applying capitalization rules to the string.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
void taskTriggered(QgsTask *task)
Emitted when a task is triggered.
Abstract base class for long running background tasks.
static Q_INVOKABLE QString toString(Qgis::DistanceUnit unit)
Returns a translated string representing a distance unit.
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
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:5111