QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
18#include <nlohmann/json.hpp>
19
23#include "qgsapplication.h"
24#include "qgsgui.h"
25#include "qgshelp.h"
26#include "qgsjsonutils.h"
27#include "qgsmessagebar.h"
28#include "qgsnative.h"
29#include "qgspanelwidget.h"
30#include "qgssettings.h"
31#include "qgsstringutils.h"
32#include "qgstaskmanager.h"
33#include "qgsunittypes.h"
34
35#include <QApplication>
36#include <QClipboard>
37#include <QDesktopServices>
38#include <QFileDialog>
39#include <QMenu>
40#include <QMimeData>
41#include <QScrollBar>
42#include <QToolButton>
43
44#include "moc_qgsprocessingalgorithmdialogbase.cpp"
45
47
48QgsProcessingAlgorithmDialogFeedback::QgsProcessingAlgorithmDialogFeedback()
49 : QgsProcessingFeedback( false )
50{}
51
52void QgsProcessingAlgorithmDialogFeedback::setProgressText( const QString &text )
53{
55 emit progressTextChanged( text );
56}
57
58void QgsProcessingAlgorithmDialogFeedback::reportError( const QString &error, bool fatalError )
59{
60 QgsProcessingFeedback::reportError( error, fatalError );
61 emit errorReported( error, fatalError );
62}
63
64void QgsProcessingAlgorithmDialogFeedback::pushWarning( const QString &warning )
65{
67 emit warningPushed( warning );
68}
69
70void QgsProcessingAlgorithmDialogFeedback::pushInfo( const QString &info )
71{
73 emit infoPushed( info );
74}
75
76void QgsProcessingAlgorithmDialogFeedback::pushCommandInfo( const QString &info )
77{
79 emit commandInfoPushed( info );
80}
81
82void QgsProcessingAlgorithmDialogFeedback::pushDebugInfo( const QString &info )
83{
85 emit debugInfoPushed( info );
86}
87
88void QgsProcessingAlgorithmDialogFeedback::pushConsoleInfo( const QString &info )
89{
91 emit consoleInfoPushed( info );
92}
93
94void QgsProcessingAlgorithmDialogFeedback::pushFormattedMessage( const QString &html, const QString &text )
95{
97 emit formattedMessagePushed( html );
98}
99
100//
101// QgsProcessingAlgorithmDialogBase
102//
103
104QgsProcessingAlgorithmDialogBase::QgsProcessingAlgorithmDialogBase( QWidget *parent, Qt::WindowFlags flags, DialogMode mode )
105 : QDialog( parent, flags )
106 , mMode( mode )
107{
108 setupUi( this );
109
110 //don't collapse parameters panel
111 splitter->setCollapsible( 0, false );
112
113 // add collapse button to splitter
114 QSplitterHandle *splitterHandle = splitter->handle( 1 );
115 QVBoxLayout *handleLayout = new QVBoxLayout();
116 handleLayout->setContentsMargins( 0, 0, 0, 0 );
117 mButtonCollapse = new QToolButton( splitterHandle );
118 mButtonCollapse->setAutoRaise( true );
119 mButtonCollapse->setFixedSize( 12, 12 );
120 mButtonCollapse->setCursor( Qt::ArrowCursor );
121 handleLayout->addWidget( mButtonCollapse );
122 handleLayout->addStretch();
123 splitterHandle->setLayout( handleLayout );
124
126
127 txtLog->setOpenLinks( false );
128 connect( txtLog, &QTextBrowser::anchorClicked, this, &QgsProcessingAlgorithmDialogBase::urlClicked );
129
130 const QgsSettings settings;
131 splitter->restoreState( settings.value( QStringLiteral( "/Processing/dialogBaseSplitter" ), QByteArray() ).toByteArray() );
132 mSplitterState = splitter->saveState();
133 splitterChanged( 0, 0 );
134
135 // Rename OK button to Run
136 mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
137 mButtonRun->setText( tr( "Run" ) );
138
139 // Rename Yes button. Yes is used to ensure same position of Run and Change Parameters with respect to Close button.
140 mButtonChangeParameters = mButtonBox->button( QDialogButtonBox::Yes );
141 mButtonChangeParameters->setText( tr( "Change Parameters" ) );
142
143 buttonCancel->setEnabled( false );
144 mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
145
146 switch ( mMode )
147 {
148 case DialogMode::Single:
149 {
150 mAdvancedButton = new QPushButton( tr( "Advanced" ) );
151 mAdvancedMenu = new QMenu( this );
152 mAdvancedButton->setMenu( mAdvancedMenu );
153
154 mContextSettingsAction = new QAction( tr( "Algorithm Settings…" ), mAdvancedMenu );
155 mContextSettingsAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/settings.svg" ) ) );
156 mAdvancedMenu->addAction( mContextSettingsAction );
157
158 connect( mContextSettingsAction, &QAction::triggered, this, [this] {
159 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( mMainWidget ) )
160 {
161 mTabWidget->setCurrentIndex( 0 );
162
163 if ( !mContextOptionsWidget )
164 {
165 mContextOptionsWidget = new QgsProcessingContextOptionsWidget();
166 mContextOptionsWidget->setFromContext( processingContext() );
167 mContextOptionsWidget->setLogLevel( mLogLevel );
168 panel->openPanel( mContextOptionsWidget );
169
170 connect( mContextOptionsWidget, &QgsPanelWidget::widgetChanged, this, [this] {
171 mOverrideDefaultContextSettings = true;
172 mGeometryCheck = mContextOptionsWidget->invalidGeometryCheck();
173 mDistanceUnits = mContextOptionsWidget->distanceUnit();
174 mAreaUnits = mContextOptionsWidget->areaUnit();
175 mTemporaryFolderOverride = mContextOptionsWidget->temporaryFolder();
176 mMaximumThreads = mContextOptionsWidget->maximumThreads();
177 mLogLevel = mContextOptionsWidget->logLevel();
178 } );
179 }
180 }
181 } );
182 mAdvancedMenu->addSeparator();
183
184 QAction *copyAsPythonCommand = new QAction( tr( "Copy as Python Command" ), mAdvancedMenu );
185 copyAsPythonCommand->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconPythonFile.svg" ) ) );
186
187 mAdvancedMenu->addAction( copyAsPythonCommand );
188 connect( copyAsPythonCommand, &QAction::triggered, this, [this] {
189 if ( const QgsProcessingAlgorithm *alg = algorithm() )
190 {
191 QgsProcessingContext *context = processingContext();
192 if ( !context )
193 return;
194
195 const QString command = alg->asPythonCommand( createProcessingParameters(), *context );
196 QMimeData *m = new QMimeData();
197 m->setText( command );
198 QClipboard *cb = QApplication::clipboard();
199
200#ifdef Q_OS_LINUX
201 cb->setMimeData( m, QClipboard::Selection );
202#endif
203 cb->setMimeData( m, QClipboard::Clipboard );
204 }
205 } );
206
207 mCopyAsQgisProcessCommand = new QAction( tr( "Copy as qgis_process Command" ), mAdvancedMenu );
208 mCopyAsQgisProcessCommand->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionTerminal.svg" ) ) );
209 mAdvancedMenu->addAction( mCopyAsQgisProcessCommand );
210
211 connect( mCopyAsQgisProcessCommand, &QAction::triggered, this, [this] {
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 if ( const QgsProcessingAlgorithm *alg = algorithm() )
246 {
247 QgsProcessingContext *context = processingContext();
248 if ( !context )
249 return;
250
251 const QVariantMap properties = alg->asMap( createProcessingParameters(), *context );
252 const QString json = QString::fromStdString( QgsJsonUtils::jsonFromVariant( properties ).dump( 2 ) );
253
254 QMimeData *m = new QMimeData();
255 m->setText( json );
256 QClipboard *cb = QApplication::clipboard();
257
258#ifdef Q_OS_LINUX
259 cb->setMimeData( m, QClipboard::Selection );
260#endif
261 cb->setMimeData( m, QClipboard::Clipboard );
262 }
263 } );
264
265 mPasteJsonAction = new QAction( tr( "Paste Settings" ), mAdvancedMenu );
266 mPasteJsonAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionEditPaste.svg" ) ) );
267
268 mAdvancedMenu->addAction( mPasteJsonAction );
269 connect( mPasteJsonAction, &QAction::triggered, this, [this] {
270 const QString text = QApplication::clipboard()->text();
271 if ( text.isEmpty() )
272 return;
273
274 const QVariantMap parameterValues = QgsJsonUtils::parseJson( text ).toMap().value( QStringLiteral( "inputs" ) ).toMap();
275 if ( parameterValues.isEmpty() )
276 return;
277
278 bool ok = false;
279 QString error;
280 const QVariantMap preparedValues = QgsProcessingUtils::preprocessQgisProcessParameters( parameterValues, ok, error );
281
282 setParameters( preparedValues );
283 } );
284
285 mButtonBox->addButton( mAdvancedButton, QDialogButtonBox::ResetRole );
286 break;
287 }
288
289 case DialogMode::Batch:
290 break;
291 }
292
293 if ( mAdvancedMenu )
294 {
295 connect( mAdvancedMenu, &QMenu::aboutToShow, this, [this] {
296 mCopyAsQgisProcessCommand->setEnabled( algorithm() && !( algorithm()->flags() & Qgis::ProcessingAlgorithmFlag::NotAvailableInStandaloneTool ) );
297 mPasteJsonAction->setEnabled( !QApplication::clipboard()->text().isEmpty() );
298 } );
299 }
300
301 connect( mButtonRun, &QPushButton::clicked, this, &QgsProcessingAlgorithmDialogBase::runAlgorithm );
302 connect( mButtonChangeParameters, &QPushButton::clicked, this, &QgsProcessingAlgorithmDialogBase::showParameters );
303 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QgsProcessingAlgorithmDialogBase::closeClicked );
304 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsProcessingAlgorithmDialogBase::openHelp );
305 connect( mButtonCollapse, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::toggleCollapsed );
306 connect( splitter, &QSplitter::splitterMoved, this, &QgsProcessingAlgorithmDialogBase::splitterChanged );
307
308 connect( mButtonSaveLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::saveLog );
309 connect( mButtonCopyLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::copyLogToClipboard );
310 connect( mButtonClearLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::clearLog );
311
312 connect( mTabWidget, &QTabWidget::currentChanged, this, &QgsProcessingAlgorithmDialogBase::mTabWidget_currentChanged );
313
314 mMessageBar = new QgsMessageBar();
315 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
316 verticalLayout->insertWidget( 0, mMessageBar );
317
318 connect( QgsApplication::taskManager(), &QgsTaskManager::taskTriggered, this, &QgsProcessingAlgorithmDialogBase::taskTriggered );
319}
320
321QgsProcessingAlgorithmDialogBase::~QgsProcessingAlgorithmDialogBase() = default;
322
323void QgsProcessingAlgorithmDialogBase::setParameters( const QVariantMap & )
324{}
325
326void QgsProcessingAlgorithmDialogBase::setAlgorithm( QgsProcessingAlgorithm *algorithm )
327{
328 mAlgorithm.reset( algorithm );
329 QString title;
331 {
332 title = mAlgorithm->group().isEmpty()
333 ? QgsStringUtils::capitalize( mAlgorithm->displayName(), Qgis::Capitalization::TitleCase )
334 : QStringLiteral( "%1 - %2" ).arg( QgsStringUtils::capitalize( mAlgorithm->group(), Qgis::Capitalization::TitleCase ), QgsStringUtils::capitalize( mAlgorithm->displayName(), Qgis::Capitalization::TitleCase ) );
335 }
336 else
337 {
338 title = mAlgorithm->group().isEmpty()
339 ? mAlgorithm->displayName()
340 : QStringLiteral( "%1 - %2" ).arg( mAlgorithm->group(), mAlgorithm->displayName() );
341 }
342
343 setWindowTitle( title );
344
345 const QString algHelp = formatHelp( algorithm );
346 if ( algHelp.isEmpty() )
347 textShortHelp->hide();
348 else
349 {
350 textShortHelp->document()->setDefaultStyleSheet( QStringLiteral( ".summary { margin-left: 10px; margin-right: 10px; }\n"
351 "h2 { color: #555555; padding-bottom: 15px; }\n"
352 "a { text - decoration: none; color: #3498db; font-weight: bold; }\n"
353 "p, ul, li { color: #666666; }\n"
354 "b { color: #333333; }\n"
355 "dl dd { margin - bottom: 5px; }" ) );
356 textShortHelp->setHtml( algHelp );
357 connect( textShortHelp, &QTextBrowser::anchorClicked, this, &QgsProcessingAlgorithmDialogBase::linkClicked );
358 textShortHelp->show();
359 }
360
361 if ( algorithm->helpUrl().isEmpty() && ( !algorithm->provider() || algorithm->provider()->helpId().isEmpty() ) )
362 {
363 mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Help ) );
364 }
365
366 const QString warning = algorithm->provider() ? algorithm->provider()->warningMessage() : QString();
367 if ( !warning.isEmpty() )
368 {
369 mMessageBar->pushMessage( warning, Qgis::MessageLevel::Warning );
370 }
371}
372
373QgsProcessingAlgorithm *QgsProcessingAlgorithmDialogBase::algorithm()
374{
375 return mAlgorithm.get();
376}
377
378void QgsProcessingAlgorithmDialogBase::setMainWidget( QgsPanelWidget *widget )
379{
380 if ( mMainWidget )
381 {
382 mMainWidget->deleteLater();
383 }
384
385 mPanelStack->setMainPanel( widget );
386 widget->setDockMode( true );
387
388 mMainWidget = widget;
389 connect( mMainWidget, &QgsPanelWidget::panelAccepted, this, &QDialog::reject );
390}
391
392QgsPanelWidget *QgsProcessingAlgorithmDialogBase::mainWidget()
393{
394 return mMainWidget;
395}
396
397void QgsProcessingAlgorithmDialogBase::saveLogToFile( const QString &path, const LogFormat format )
398{
399 QFile logFile( path );
400 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
401 {
402 return;
403 }
404 QTextStream fout( &logFile );
405
406 switch ( format )
407 {
408 case FormatPlainText:
409 fout << txtLog->toPlainText();
410 break;
411
412 case FormatHtml:
413 fout << txtLog->toHtml();
414 break;
415 }
416}
417
418QgsProcessingFeedback *QgsProcessingAlgorithmDialogBase::createFeedback()
419{
420 auto feedback = std::make_unique<QgsProcessingAlgorithmDialogFeedback>();
421 connect( feedback.get(), &QgsProcessingFeedback::progressChanged, this, &QgsProcessingAlgorithmDialogBase::setPercentage );
422 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::commandInfoPushed, this, &QgsProcessingAlgorithmDialogBase::pushCommandInfo );
423 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::consoleInfoPushed, this, &QgsProcessingAlgorithmDialogBase::pushConsoleInfo );
424 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::debugInfoPushed, this, &QgsProcessingAlgorithmDialogBase::pushDebugInfo );
425 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::errorReported, this, &QgsProcessingAlgorithmDialogBase::reportError );
426 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::warningPushed, this, &QgsProcessingAlgorithmDialogBase::pushWarning );
427 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::infoPushed, this, &QgsProcessingAlgorithmDialogBase::pushInfo );
428 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::formattedMessagePushed, this, &QgsProcessingAlgorithmDialogBase::pushFormattedMessage );
429 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::progressTextChanged, this, &QgsProcessingAlgorithmDialogBase::setProgressText );
430 connect( buttonCancel, &QPushButton::clicked, feedback.get(), &QgsProcessingFeedback::cancel );
431 return feedback.release();
432}
433
434QDialogButtonBox *QgsProcessingAlgorithmDialogBase::buttonBox()
435{
436 return mButtonBox;
437}
438
439QTabWidget *QgsProcessingAlgorithmDialogBase::tabWidget()
440{
441 return mTabWidget;
442}
443
444void QgsProcessingAlgorithmDialogBase::showLog()
445{
446 mTabWidget->setCurrentIndex( 1 );
447}
448
449void QgsProcessingAlgorithmDialogBase::showParameters()
450{
451 mTabWidget->setCurrentIndex( 0 );
452}
453
454QPushButton *QgsProcessingAlgorithmDialogBase::runButton()
455{
456 return mButtonRun;
457}
458
459QPushButton *QgsProcessingAlgorithmDialogBase::cancelButton()
460{
461 return buttonCancel;
462}
463
464QPushButton *QgsProcessingAlgorithmDialogBase::changeParametersButton()
465{
466 return mButtonChangeParameters;
467}
468
469void QgsProcessingAlgorithmDialogBase::clearProgress()
470{
471 progressBar->setMaximum( 0 );
472}
473
474void QgsProcessingAlgorithmDialogBase::setExecuted( bool executed )
475{
476 mExecuted = executed;
477}
478
479void QgsProcessingAlgorithmDialogBase::setExecutedAnyResult( bool executedAnyResult )
480{
481 mExecutedAnyResult = executedAnyResult;
482}
483
484void QgsProcessingAlgorithmDialogBase::setResults( const QVariantMap &results )
485{
486 mResults = results;
487}
488
489void QgsProcessingAlgorithmDialogBase::finished( bool, const QVariantMap &, QgsProcessingContext &, QgsProcessingFeedback * )
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().replace( "_", "-" ) ) ) );
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 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
669 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
670 sb->setValue( sb->maximum() );
671 } );
672 return dialog;
673}
674
675void QgsProcessingAlgorithmDialogBase::clearLog()
676{
677 txtLog->clear();
678}
679
680void QgsProcessingAlgorithmDialogBase::saveLog()
681{
682 QgsSettings settings;
683 const QString lastUsedDir = settings.value( QStringLiteral( "/Processing/lastUsedLogDirectory" ), QDir::homePath() ).toString();
684
685 QString filter;
686 const QString txtExt = tr( "Text files" ) + QStringLiteral( " (*.txt *.TXT)" );
687 const QString htmlExt = tr( "HTML files" ) + QStringLiteral( " (*.html *.HTML)" );
688
689 const QString path = QFileDialog::getSaveFileName( this, tr( "Save Log to File" ), lastUsedDir, txtExt + ";;" + htmlExt, &filter );
690 // return dialog focus on Mac
691 activateWindow();
692 raise();
693 if ( path.isEmpty() )
694 {
695 return;
696 }
697
698 settings.setValue( QStringLiteral( "/Processing/lastUsedLogDirectory" ), QFileInfo( path ).path() );
699
700 LogFormat format = FormatPlainText;
701 if ( filter == htmlExt )
702 {
703 format = FormatHtml;
704 }
705 saveLogToFile( path, format );
706}
707
708void QgsProcessingAlgorithmDialogBase::copyLogToClipboard()
709{
710 QMimeData *m = new QMimeData();
711 m->setText( txtLog->toPlainText() );
712 m->setHtml( txtLog->toHtml() );
713 QClipboard *cb = QApplication::clipboard();
714
715#ifdef Q_OS_LINUX
716 cb->setMimeData( m, QClipboard::Selection );
717#endif
718 cb->setMimeData( m, QClipboard::Clipboard );
719}
720
721void QgsProcessingAlgorithmDialogBase::closeEvent( QCloseEvent *e )
722{
723 if ( !mHelpCollapsed )
724 {
725 QgsSettings settings;
726 settings.setValue( QStringLiteral( "/Processing/dialogBaseSplitter" ), splitter->saveState() );
727 }
728
729 QDialog::closeEvent( e );
730
731 if ( !mAlgorithmTask && isFinalized() )
732 {
733 // when running a background task, the dialog is kept around and deleted only when the task
734 // completes. But if not running a task, we auto cleanup (later - gotta give callers a chance
735 // to retrieve results and execution status).
736 deleteLater();
737 }
738}
739
740void QgsProcessingAlgorithmDialogBase::runAlgorithm()
741{
742}
743
744void QgsProcessingAlgorithmDialogBase::setPercentage( double percent )
745{
746 // delay setting maximum progress value until we know algorithm reports progress
747 if ( progressBar->maximum() == 0 )
748 progressBar->setMaximum( 100 );
749 progressBar->setValue( percent );
750 processEvents();
751}
752
753void QgsProcessingAlgorithmDialogBase::setProgressText( const QString &text )
754{
755 lblProgress->setText( text );
756 setInfo( text, false );
757 scrollToBottomOfLog();
758 processEvents();
759}
760
761QString QgsProcessingAlgorithmDialogBase::formatHelp( QgsProcessingAlgorithm *algorithm )
762{
763 QString result;
764 const QString text = algorithm->shortHelpString();
765 if ( !text.isEmpty() )
766 {
767 const QStringList paragraphs = text.split( '\n' );
768 QString help;
769 for ( const QString &paragraph : paragraphs )
770 {
771 help += QStringLiteral( "<p>%1</p>" ).arg( paragraph );
772 }
773 result = QStringLiteral( "<h2>%1</h2>%2" ).arg( algorithm->displayName(), help );
774 }
775 else if ( !algorithm->shortDescription().isEmpty() )
776 {
777 result = QStringLiteral( "<h2>%1</h2><p>%2</p>" ).arg( algorithm->displayName(), algorithm->shortDescription() );
778 }
779
780 if ( algorithm->documentationFlags() != Qgis::ProcessingAlgorithmDocumentationFlags() )
781 {
782 QStringList flags;
784 {
785 if ( algorithm->documentationFlags() & flag )
786 {
788 }
789 }
790 result += QStringLiteral( "<ul><li><i>%1</i></li></ul>" ).arg( flags.join( QLatin1String( "</i></li><li><i>" ) ) );
791 }
793 {
794 result += QStringLiteral( "<p><b>%1</b></p>" ).arg( tr( "Warning: This algorithm is a potential security risk if executed with unchecked inputs, and may result in system damage or data leaks." ) );
795 }
797 {
798 result += QStringLiteral( "<p><b>%1</b></p>" ).arg( tr( "Warning: This algorithm has known issues. The results must be carefully validated by the user." ) );
799 }
800
801 return result;
802}
803
804void QgsProcessingAlgorithmDialogBase::processEvents()
805{
806 if ( mAlgorithmTask )
807 {
808 // no need to call this - the algorithm is running in a thread.
809 // in fact, calling it causes a crash on Windows when the algorithm
810 // is running in a background thread... unfortunately we need something
811 // like this for non-threadable algorithms, otherwise there's no chance
812 // for users to hit cancel or see progress updates...
813 return;
814 }
815
816 // So that we get a chance of hitting the Abort button
817#ifdef Q_OS_LINUX
818 // One iteration is actually enough on Windows to get good interactivity
819 // whereas on Linux we must allow for far more iterations.
820 // For safety limit the number of iterations
821 int nIters = 0;
822 while ( ++nIters < 100 )
823#endif
824 {
825 QCoreApplication::processEvents();
826 }
827}
828
829void QgsProcessingAlgorithmDialogBase::scrollToBottomOfLog()
830{
831 QScrollBar *sb = txtLog->verticalScrollBar();
832 sb->setValue( sb->maximum() );
833}
834
835void QgsProcessingAlgorithmDialogBase::resetGui()
836{
837 lblProgress->clear();
838 progressBar->setMaximum( 100 );
839 progressBar->setValue( 0 );
840 mButtonRun->setEnabled( true );
841 mButtonChangeParameters->setEnabled( true );
842 mButtonClose->setEnabled( true );
843 if ( mMainWidget )
844 {
845 mMainWidget->setEnabled( true );
846 }
847 updateRunButtonVisibility();
848 resetAdditionalGui();
849}
850
851void QgsProcessingAlgorithmDialogBase::updateRunButtonVisibility()
852{
853 // Activate run button if current tab is Parameters
854 const bool runButtonVisible = mTabWidget->currentIndex() == 0;
855 mButtonRun->setVisible( runButtonVisible );
856 if ( runButtonVisible )
857 progressBar->resetFormat();
858 mButtonChangeParameters->setVisible( !runButtonVisible && mExecutedAnyResult && mButtonChangeParameters->isEnabled() );
859}
860
861void QgsProcessingAlgorithmDialogBase::resetAdditionalGui()
862{
863}
864
865void QgsProcessingAlgorithmDialogBase::blockControlsWhileRunning()
866{
867 mButtonRun->setEnabled( false );
868 mButtonChangeParameters->setEnabled( false );
869 if ( mMainWidget )
870 {
871 mMainWidget->setEnabled( false );
872 }
873 blockAdditionalControlsWhileRunning();
874}
875
876void QgsProcessingAlgorithmDialogBase::blockAdditionalControlsWhileRunning()
877{
878}
879
880QgsMessageBar *QgsProcessingAlgorithmDialogBase::messageBar()
881{
882 return mMessageBar;
883}
884
885void QgsProcessingAlgorithmDialogBase::hideShortHelp()
886{
887 textShortHelp->setVisible( false );
888}
889
890void QgsProcessingAlgorithmDialogBase::setCurrentTask( QgsProcessingAlgRunnerTask *task )
891{
892 mAlgorithmTask = task;
893 connect( mAlgorithmTask, &QgsProcessingAlgRunnerTask::executed, this, &QgsProcessingAlgorithmDialogBase::algExecuted );
894 QgsApplication::taskManager()->addTask( mAlgorithmTask );
895}
896
897QString QgsProcessingAlgorithmDialogBase::formatStringForLog( const QString &string )
898{
899 QString s = string;
900 s.replace( '\n', QLatin1String( "<br>" ) );
901 return s;
902}
903
904bool QgsProcessingAlgorithmDialogBase::isFinalized()
905{
906 return true;
907}
908
909void QgsProcessingAlgorithmDialogBase::applyContextOverrides( QgsProcessingContext *context )
910{
911 if ( !context )
912 return;
913
914 context->setLogLevel( logLevel() );
915
916 if ( mOverrideDefaultContextSettings )
917 {
918 context->setInvalidGeometryCheck( mGeometryCheck );
919 context->setDistanceUnit( mDistanceUnits );
920 context->setAreaUnit( mAreaUnits );
921 context->setTemporaryFolder( mTemporaryFolderOverride );
922 context->setMaximumThreads( mMaximumThreads );
923 }
924}
925
926void QgsProcessingAlgorithmDialogBase::setInfo( const QString &message, bool isError, bool escapeHtml, bool isWarning )
927{
928 constexpr int MESSAGE_COUNT_LIMIT = 10000;
929 // Avoid logging too many messages, which might blow memory.
930 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
931 return;
932 ++mMessageLoggedCount;
933
934 // note -- we have to wrap the message in a span block, or QTextEdit::append sometimes gets confused
935 // and varies between treating it as a HTML string or a plain text string! (see https://github.com/qgis/QGIS/issues/37934)
936 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
937 txtLog->append( QStringLiteral( "<span style=\"color:red\">%1</span>" ).arg( tr( "Message log truncated" ) ) );
938 else if ( isError || isWarning )
939 txtLog->append( QStringLiteral( "<span style=\"color:%1\">%2</span>" ).arg( isError ? QStringLiteral( "red" ) : QStringLiteral( "#b85a20" ), escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
940 else if ( escapeHtml )
941 txtLog->append( QStringLiteral( "<span>%1</span" ).arg( formatStringForLog( message.toHtmlEscaped() ) ) );
942 else
943 txtLog->append( QStringLiteral( "<span>%1</span>" ).arg( formatStringForLog( message ) ) );
944 scrollToBottomOfLog();
945 processEvents();
946}
947
948void QgsProcessingAlgorithmDialogBase::reject()
949{
950 if ( !mAlgorithmTask && isFinalized() )
951 {
952 setAttribute( Qt::WA_DeleteOnClose );
953 }
954 QDialog::reject();
955}
956
957//
958// QgsProcessingAlgorithmProgressDialog
959//
960
961QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
962 : QDialog( parent )
963{
964 setupUi( this );
965}
966
967QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
968{
969 return mProgressBar;
970}
971
972QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
973{
974 return mButtonBox->button( QDialogButtonBox::Cancel );
975}
976
977QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
978{
979 return mTxtLog;
980}
981
982void QgsProcessingAlgorithmProgressDialog::reject()
983{
984}
985
986
987//
988// QgsProcessingContextOptionsWidget
989//
990
991QgsProcessingContextOptionsWidget::QgsProcessingContextOptionsWidget( QWidget *parent )
992 : QgsPanelWidget( parent )
993{
994 setupUi( this );
995 setPanelTitle( tr( "Algorithm Settings" ) );
996
997 mComboInvalidFeatureFiltering->addItem( tr( "Do not Filter (Better Performance)" ), QVariant::fromValue( Qgis::InvalidGeometryCheck::NoCheck ) );
998 mComboInvalidFeatureFiltering->addItem( tr( "Skip (Ignore) Features with Invalid Geometries" ), QVariant::fromValue( Qgis::InvalidGeometryCheck::SkipInvalid ) );
999 mComboInvalidFeatureFiltering->addItem( tr( "Stop Algorithm Execution When a Geometry is Invalid" ), QVariant::fromValue( Qgis::InvalidGeometryCheck::AbortOnInvalid ) );
1000
1001 mTemporaryFolderWidget->setDialogTitle( tr( "Select Temporary Directory" ) );
1002 mTemporaryFolderWidget->setStorageMode( QgsFileWidget::GetDirectory );
1003 mTemporaryFolderWidget->lineEdit()->setPlaceholderText( tr( "Default" ) );
1004
1005 mLogLevelComboBox->addItem( tr( "Default" ), static_cast<int>( Qgis::ProcessingLogLevel::DefaultLevel ) );
1006 mLogLevelComboBox->addItem( tr( "Verbose" ), static_cast<int>( Qgis::ProcessingLogLevel::Verbose ) );
1007 mLogLevelComboBox->addItem( tr( "Verbose (Model Debugging)" ), static_cast<int>( Qgis::ProcessingLogLevel::ModelDebug ) );
1008
1009 mDistanceUnitsCombo->addItem( tr( "Default" ), QVariant::fromValue( Qgis::DistanceUnit::Unknown ) );
1010 for ( Qgis::DistanceUnit unit :
1011 {
1022 } )
1023 {
1024 QString title;
1026 {
1028 }
1029 else
1030 {
1031 title = QgsUnitTypes::toString( unit );
1032 }
1033
1034 mDistanceUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1035 }
1036
1037 mAreaUnitsCombo->addItem( tr( "Default" ), QVariant::fromValue( Qgis::AreaUnit::Unknown ) );
1038 for ( Qgis::AreaUnit unit :
1039 {
1052 } )
1053 {
1054 QString title;
1056 {
1058 }
1059 else
1060 {
1061 title = QgsUnitTypes::toString( unit );
1062 }
1063
1064 mAreaUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1065 }
1066
1067 mThreadsSpinBox->setRange( 1, QThread::idealThreadCount() );
1068
1069 connect( mLogLevelComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1070 connect( mComboInvalidFeatureFiltering, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1071 connect( mDistanceUnitsCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1072 connect( mAreaUnitsCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1073 connect( mTemporaryFolderWidget, &QgsFileWidget::fileChanged, this, &QgsPanelWidget::widgetChanged );
1074 connect( mThreadsSpinBox, qOverload<int>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
1075}
1076
1077void QgsProcessingContextOptionsWidget::setFromContext( const QgsProcessingContext *context )
1078{
1079 whileBlocking( mComboInvalidFeatureFiltering )->setCurrentIndex( mComboInvalidFeatureFiltering->findData( QVariant::fromValue( context->invalidGeometryCheck() ) ) );
1080 whileBlocking( mDistanceUnitsCombo )->setCurrentIndex( mDistanceUnitsCombo->findData( QVariant::fromValue( context->distanceUnit() ) ) );
1081 whileBlocking( mAreaUnitsCombo )->setCurrentIndex( mAreaUnitsCombo->findData( QVariant::fromValue( context->areaUnit() ) ) );
1082 whileBlocking( mTemporaryFolderWidget )->setFilePath( context->temporaryFolder() );
1083 whileBlocking( mThreadsSpinBox )->setValue( context->maximumThreads() );
1084 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData( static_cast<int>( context->logLevel() ) ) );
1085}
1086
1087Qgis::InvalidGeometryCheck QgsProcessingContextOptionsWidget::invalidGeometryCheck() const
1088{
1089 return mComboInvalidFeatureFiltering->currentData().value<Qgis::InvalidGeometryCheck>();
1090}
1091
1092Qgis::DistanceUnit QgsProcessingContextOptionsWidget::distanceUnit() const
1093{
1094 return mDistanceUnitsCombo->currentData().value<Qgis::DistanceUnit>();
1095}
1096
1097Qgis::AreaUnit QgsProcessingContextOptionsWidget::areaUnit() const
1098{
1099 return mAreaUnitsCombo->currentData().value<Qgis::AreaUnit>();
1100}
1101
1102QString QgsProcessingContextOptionsWidget::temporaryFolder()
1103{
1104 return mTemporaryFolderWidget->filePath();
1105}
1106
1107int QgsProcessingContextOptionsWidget::maximumThreads() const
1108{
1109 return mThreadsSpinBox->value();
1110}
1111
1112void QgsProcessingContextOptionsWidget::setLogLevel( Qgis::ProcessingLogLevel level )
1113{
1114 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData( static_cast<int>( level ) ) );
1115}
1116
1117Qgis::ProcessingLogLevel QgsProcessingContextOptionsWidget::logLevel() const
1118{
1119 return static_cast<Qgis::ProcessingLogLevel>( mLogLevelComboBox->currentData().toInt() );
1120}
1121
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:56
DistanceUnit
Units of distance.
Definition qgis.h:5013
@ Feet
Imperial feet.
Definition qgis.h:5016
@ Centimeters
Centimeters.
Definition qgis.h:5021
@ Millimeters
Millimeters.
Definition qgis.h:5022
@ Miles
Terrestrial miles.
Definition qgis.h:5019
@ Meters
Meters.
Definition qgis.h:5014
@ Unknown
Unknown distance unit.
Definition qgis.h:5063
@ Yards
Imperial yards.
Definition qgis.h:5018
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5020
@ Inches
Inches.
Definition qgis.h:5023
@ NauticalMiles
Nautical miles.
Definition qgis.h:5017
@ Kilometers
Kilometers.
Definition qgis.h:5015
AreaUnit
Units of area.
Definition qgis.h:5090
@ Acres
Acres.
Definition qgis.h:5097
@ SquareFeet
Square feet.
Definition qgis.h:5093
@ SquareCentimeters
Square centimeters.
Definition qgis.h:5100
@ SquareInches
Square inches.
Definition qgis.h:5102
@ SquareNauticalMiles
Square nautical miles.
Definition qgis.h:5098
@ SquareMillimeters
Square millimeters.
Definition qgis.h:5101
@ SquareYards
Square yards.
Definition qgis.h:5094
@ Hectares
Hectares.
Definition qgis.h:5096
@ SquareKilometers
Square kilometers.
Definition qgis.h:5092
@ SquareMeters
Square meters.
Definition qgis.h:5091
@ Unknown
Unknown areal unit.
Definition qgis.h:5103
@ SquareDegrees
Square degrees, for planar geographic CRS area measurements.
Definition qgis.h:5099
@ SquareMiles
Square miles.
Definition qgis.h:5095
@ Warning
Warning message.
Definition qgis.h:158
@ TitleCase
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
Definition qgis.h:3395
ProcessingAlgorithmDocumentationFlag
Flags describing algorithm behavior for documentation purposes.
Definition qgis.h:3618
QFlags< ProcessingAlgorithmDocumentationFlag > ProcessingAlgorithmDocumentationFlags
Flags describing algorithm behavior for documentation purposes.
Definition qgis.h:3630
InvalidGeometryCheck
Methods for handling of features with invalid geometries.
Definition qgis.h:2238
@ NoCheck
No invalid geometry checking.
Definition qgis.h:2239
@ AbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
Definition qgis.h:2241
@ SkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
Definition qgis.h:2240
@ NotAvailableInStandaloneTool
Algorithm should not be available from the standalone "qgis_process" tool. Used to flag algorithms wh...
Definition qgis.h:3595
@ SecurityRisk
The algorithm represents a potential security risk if executed with untrusted inputs.
Definition qgis.h:3597
@ DisplayNameIsLiteral
Algorithm's display name is a static literal string, and should not be translated or automatically fo...
Definition qgis.h:3589
@ KnownIssues
Algorithm has known issues.
Definition qgis.h:3591
ProcessingLogLevel
Logging level for algorithms to use when pushing feedback messages.
Definition qgis.h:3656
@ DefaultLevel
Default logging level.
Definition qgis.h:3657
@ Verbose
Verbose logging.
Definition qgis.h:3658
@ ModelDebug
Model debug level logging. Includes verbose logging and other outputs useful for debugging models.
Definition qgis.h:3659
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 ...
@ GetDirectory
Select a directory.
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:221
@ HigDialogTitleIsTitleCase
Dialog titles should be title case.
Definition qgsgui.h:281
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition qgsgui.cpp:96
static QgsGui::HigFlags higFlags()
Returns the platform's HIG flags.
Definition qgsgui.cpp:250
static QUrl helpUrl(const QString &key)
Returns URI of the help topic for the given key.
Definition qgshelp.cpp:43
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.
Base class for any widget that can be shown as an 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.
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.
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.
static QVariantMap preprocessQgisProcessParameters(const QVariantMap &parameters, bool &ok, QString &error)
Pre-processes a set of parameter values for the qgis_process command.
static QString documentationFlagToString(Qgis::ProcessingAlgorithmDocumentationFlag flag)
Converts a documentation flag to a translated string.
Stores settings for use within QGIS.
Definition qgssettings.h:65
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.
Utility functions for working with strings.
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
const QList< T > qgsEnumList()
Returns a list all enum entries.
Definition qgis.h:6764
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:6511