QGIS API Documentation 4.3.0-Master (bf28115e945)
Loading...
Searching...
No Matches
qgsprocessingalgorithmwidgetbase.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"
25#include "qgsgui.h"
26#include "qgshelp.h"
27#include "qgsjsonutils.h"
28#include "qgsmessagebar.h"
29#include "qgsnative.h"
30#include "qgspanelwidget.h"
31#include "qgssettings.h"
32#include "qgsstringutils.h"
33#include "qgstaskmanager.h"
34#include "qgsunittypes.h"
35
36#include <QApplication>
37#include <QClipboard>
38#include <QDesktopServices>
39#include <QFileDialog>
40#include <QMainWindow>
41#include <QMenu>
42#include <QMimeData>
43#include <QScrollBar>
44#include <QString>
45#include <QToolButton>
46
47#include "moc_qgsprocessingalgorithmwidgetbase.cpp"
48
49using namespace Qt::StringLiterals;
50
52
53//
54// QgsProcessingFeedbackGenerator
55//
56
57QgsProcessingFeedbackGenerator::~QgsProcessingFeedbackGenerator()
58{}
59
60//
61// QgsProcessingAlgorithmWidgetBase
62//
63
64QgsProcessingAlgorithmWidgetBase::QgsProcessingAlgorithmWidgetBase(
65 QMainWindow *parentWindow, WidgetMode mode, QgsProcessingAlgorithmWidgetBase::WidgetFlags flags, Qgis::DockableWidgetInitialState initialState
66)
67 : QWidget()
68 , mMode( mode )
69{
70 setupUi( this );
71
72 //don't collapse parameters panel
73 splitter->setCollapsible( 0, false );
74
75 // add collapse button to splitter
76 QSplitterHandle *splitterHandle = splitter->handle( 1 );
77 QVBoxLayout *handleLayout = new QVBoxLayout();
78 handleLayout->setContentsMargins( 0, 0, 0, 0 );
79 mButtonCollapse = new QToolButton( splitterHandle );
80 mButtonCollapse->setAutoRaise( true );
81 mButtonCollapse->setFixedSize( 12, 12 );
82 mButtonCollapse->setCursor( Qt::ArrowCursor );
83 handleLayout->addWidget( mButtonCollapse );
84 handleLayout->addStretch();
85 splitterHandle->setLayout( handleLayout );
86
88
89 txtLog->setOpenLinks( false );
90 connect( txtLog, &QTextBrowser::anchorClicked, this, &QgsProcessingAlgorithmWidgetBase::urlClicked );
91
92 const QgsSettings settings;
93 splitter->restoreState( settings.value( u"/Processing/dialogBaseSplitter"_s, QByteArray() ).toByteArray() );
94 mSplitterState = splitter->saveState();
95 splitterChanged( 0, 0 );
96
97 // Rename OK button to Run
98 mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
99 mButtonRun->setText( tr( "Run" ) );
100
101 // Rename Yes button. Yes is used to ensure same position of Run and Change Parameters with respect to Close button.
102 mButtonChangeParameters = mButtonBox->button( QDialogButtonBox::Yes );
103 mButtonChangeParameters->setText( tr( "Change Parameters" ) );
104
105 connect( buttonCancel, &QPushButton::clicked, this, &QgsProcessingAlgorithmWidgetBase::cancel );
106 buttonCancel->setEnabled( false );
107 mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
108
109 if ( !parentWindow )
110 parentWindow = qobject_cast< QMainWindow * >( QApplication::activeWindow() );
111
112 bool defaultIsDocked = false;
113 QString dockId = u"ProcessingAlgorithm"_s;
114 if ( flags.testFlags( QgsProcessingAlgorithmWidgetBase::WidgetFlag::NoDocking ) )
115 {
117 dockId = u"ProcessingAlgorithmNonDockable"_s;
118 }
119 else if ( initialState == Qgis::DockableWidgetInitialState::ForceDocked )
120 {
121 dockId = u"ProcessingAlgorithmForceDocked"_s;
122 }
123
124 mDockableWidgetHelper
125 = new QgsDockableWidgetHelper( tr( "Processing" ), this, parentWindow, dockId, QStringList(), initialState, defaultIsDocked, Qt::DockWidgetArea::RightDockWidgetArea, QgsDockableWidgetHelper::Option::RaiseTab );
126 connect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed, this, &QgsProcessingAlgorithmWidgetBase::closeClicked );
127
128 switch ( mMode )
129 {
130 case QgsProcessingAlgorithmWidgetBase::WidgetMode::Single:
131 {
132 mAdvancedButton = new QPushButton( tr( "Advanced" ) );
133 mAdvancedMenu = new QMenu( this );
134 mAdvancedButton->setMenu( mAdvancedMenu );
135
136 mContextSettingsAction = new QAction( tr( "Algorithm Settings…" ), mAdvancedMenu );
137 mContextSettingsAction->setIcon( QgsApplication::getThemeIcon( u"/propertyicons/settings.svg"_s ) );
138 mAdvancedMenu->addAction( mContextSettingsAction );
139
140 connect( mContextSettingsAction, &QAction::triggered, this, [this] {
141 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( mMainWidget ) )
142 {
143 mTabWidget->setCurrentIndex( 0 );
144
145 if ( !mContextOptionsWidget )
146 {
147 mContextOptionsWidget = new QgsProcessingContextOptionsWidget();
148 mContextOptionsWidget->setFromContext( processingContext() );
149 mContextOptionsWidget->setLogLevel( mLogLevel );
150 panel->openPanel( mContextOptionsWidget );
151
152 connect( mContextOptionsWidget, &QgsPanelWidget::widgetChanged, this, [this] {
153 mOverrideDefaultContextSettings = true;
154 mGeometryCheck = mContextOptionsWidget->invalidGeometryCheck();
155 mDistanceUnits = mContextOptionsWidget->distanceUnit();
156 mAreaUnits = mContextOptionsWidget->areaUnit();
157 mTemporaryFolderOverride = mContextOptionsWidget->temporaryFolder();
158 mMaximumThreads = mContextOptionsWidget->maximumThreads();
159 mLogLevel = mContextOptionsWidget->logLevel();
160 } );
161 }
162 }
163 } );
164 mAdvancedMenu->addSeparator();
165
166 QAction *copyAsPythonCommand = new QAction( tr( "Copy as Python Command" ), mAdvancedMenu );
167 copyAsPythonCommand->setIcon( QgsApplication::getThemeIcon( u"mIconPythonFile.svg"_s ) );
168
169 mAdvancedMenu->addAction( copyAsPythonCommand );
170 connect( copyAsPythonCommand, &QAction::triggered, this, [this] {
171 if ( const QgsProcessingAlgorithm *alg = algorithm() )
172 {
173 QgsProcessingContext *context = processingContext();
174 if ( !context )
175 return;
176
177 const QString command = alg->asPythonCommand( createProcessingParameters(), *context );
178 QMimeData *m = new QMimeData();
179 m->setText( command );
180 QClipboard *cb = QApplication::clipboard();
181
182 if ( cb->supportsSelection() )
183 {
184 cb->setMimeData( m, QClipboard::Selection );
185 }
186 cb->setMimeData( m, QClipboard::Clipboard );
187 }
188 } );
189
190 mCopyAsQgisProcessCommand = new QAction( tr( "Copy as qgis_process Command" ), mAdvancedMenu );
191 mCopyAsQgisProcessCommand->setIcon( QgsApplication::getThemeIcon( u"mActionTerminal.svg"_s ) );
192 mAdvancedMenu->addAction( mCopyAsQgisProcessCommand );
193
194 connect( mCopyAsQgisProcessCommand, &QAction::triggered, this, [this] {
195 if ( const QgsProcessingAlgorithm *alg = algorithm() )
196 {
197 QgsProcessingContext *context = processingContext();
198 if ( !context )
199 return;
200
201 bool ok = false;
202 const QString command = alg->asQgisProcessCommand( createProcessingParameters(), *context, ok );
203 if ( !ok )
204 {
205 mMessageBar->pushMessage( tr( "Current settings cannot be specified as arguments to qgis_process (Pipe parameters as JSON to qgis_process instead)" ), Qgis::MessageLevel::Warning );
206 }
207 else
208 {
209 QMimeData *m = new QMimeData();
210 m->setText( command );
211 QClipboard *cb = QApplication::clipboard();
212
213 if ( cb->supportsSelection() )
214 {
215 cb->setMimeData( m, QClipboard::Selection );
216 }
217 cb->setMimeData( m, QClipboard::Clipboard );
218 }
219 }
220 } );
221
222 mAdvancedMenu->addSeparator();
223
224 QAction *copyAsJson = new QAction( tr( "Copy as JSON" ), mAdvancedMenu );
225 copyAsJson->setIcon( QgsApplication::getThemeIcon( u"mActionEditCopy.svg"_s ) );
226
227 mAdvancedMenu->addAction( copyAsJson );
228 connect( copyAsJson, &QAction::triggered, this, [this] {
229 if ( const QgsProcessingAlgorithm *alg = algorithm() )
230 {
231 QgsProcessingContext *context = processingContext();
232 if ( !context )
233 return;
234
235 const QVariantMap properties = alg->asMap( createProcessingParameters(), *context );
236 const QString json = QString::fromStdString( QgsJsonUtils::jsonFromVariant( properties ).dump( 2 ) );
237
238 QMimeData *m = new QMimeData();
239 m->setText( json );
240 QClipboard *cb = QApplication::clipboard();
241
242 if ( cb->supportsSelection() )
243 {
244 cb->setMimeData( m, QClipboard::Selection );
245 }
246 cb->setMimeData( m, QClipboard::Clipboard );
247 }
248 } );
249
250 mPasteJsonAction = new QAction( tr( "Paste Settings" ), mAdvancedMenu );
251 mPasteJsonAction->setIcon( QgsApplication::getThemeIcon( u"mActionEditPaste.svg"_s ) );
252
253 mAdvancedMenu->addAction( mPasteJsonAction );
254 connect( mPasteJsonAction, &QAction::triggered, this, [this] {
255 const QString text = QApplication::clipboard()->text();
256 if ( text.isEmpty() )
257 return;
258
259 const QVariantMap parameterValues = QgsJsonUtils::parseJson( text ).toMap().value( u"inputs"_s ).toMap();
260 if ( parameterValues.isEmpty() )
261 return;
262
263 bool ok = false;
264 QString error;
265 const QVariantMap preparedValues = QgsProcessingUtils::preprocessQgisProcessParameters( parameterValues, ok, error );
266
267 setParameters( preparedValues );
268 } );
269
270 mButtonBox->addButton( mAdvancedButton, QDialogButtonBox::ResetRole );
271 break;
272 }
273
274 case QgsProcessingAlgorithmWidgetBase::WidgetMode::Batch:
275 break;
276 }
277
278 if ( mAdvancedMenu )
279 {
280 connect( mAdvancedMenu, &QMenu::aboutToShow, this, [this] {
281 mCopyAsQgisProcessCommand->setEnabled( algorithm() && !( algorithm()->flags() & Qgis::ProcessingAlgorithmFlag::NotAvailableInStandaloneTool ) );
282 mPasteJsonAction->setEnabled( !QApplication::clipboard()->text().isEmpty() );
283 } );
284 }
285
286 connect( mButtonRun, &QPushButton::clicked, this, &QgsProcessingAlgorithmWidgetBase::runAlgorithm );
287 connect( mButtonChangeParameters, &QPushButton::clicked, this, &QgsProcessingAlgorithmWidgetBase::showParameters );
288 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QgsProcessingAlgorithmWidgetBase::closeClicked );
289 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsProcessingAlgorithmWidgetBase::openHelp );
290 connect( mButtonCollapse, &QToolButton::clicked, this, &QgsProcessingAlgorithmWidgetBase::toggleCollapsed );
291 connect( splitter, &QSplitter::splitterMoved, this, &QgsProcessingAlgorithmWidgetBase::splitterChanged );
292
293 connect( mButtonSaveLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmWidgetBase::saveLog );
294 connect( mButtonCopyLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmWidgetBase::copyLogToClipboard );
295 connect( mButtonClearLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmWidgetBase::clearLog );
296
297 connect( mTabWidget, &QTabWidget::currentChanged, this, &QgsProcessingAlgorithmWidgetBase::mTabWidget_currentChanged );
298
299 mMessageBar = new QgsMessageBar();
300 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
301 verticalLayout->insertWidget( 0, mMessageBar );
302
303 connect( QgsApplication::taskManager(), &QgsTaskManager::taskTriggered, this, &QgsProcessingAlgorithmWidgetBase::taskTriggered );
304}
305
306QgsProcessingAlgorithmWidgetBase::~QgsProcessingAlgorithmWidgetBase()
307{
308 delete mDockableWidgetHelper;
309}
310
311void QgsProcessingAlgorithmWidgetBase::setParameters( const QVariantMap & )
312{}
313
314void QgsProcessingAlgorithmWidgetBase::setTitle( const QString &title )
315{
316 mDockableWidgetHelper->setWindowTitle( title );
317}
318
319void QgsProcessingAlgorithmWidgetBase::exec()
320{
321 // when forcing the widget to show as a dialog, we use a distinct setting key
322 // to prevent the setting for freely dockable algorithm widgets from getting
323 // overridden, which would otherwise reset that setting so that the widgets
324 // are ALWAYS opened as dialogs
325 mDockableWidgetHelper->setSettingKeyDockId( u"ProcessingAlgorithmNonDockable"_s );
326 mDockableWidgetHelper->toggleDockMode( false );
327 mDockableWidgetHelper->dialog()->exec();
328}
329
330void QgsProcessingAlgorithmWidgetBase::setAlgorithm( QgsProcessingAlgorithm *algorithm )
331{
332 mAlgorithm.reset( algorithm );
333 QString title;
335 {
336 title = mAlgorithm->group().isEmpty()
337 ? QgsStringUtils::capitalize( mAlgorithm->displayName(), Qgis::Capitalization::TitleCase )
338 : u"%1 - %2"_s.arg( QgsStringUtils::capitalize( mAlgorithm->group(), Qgis::Capitalization::TitleCase ), QgsStringUtils::capitalize( mAlgorithm->displayName(), Qgis::Capitalization::TitleCase ) );
339 }
340 else
341 {
342 title = mAlgorithm->group().isEmpty() ? mAlgorithm->displayName() : u"%1 - %2"_s.arg( mAlgorithm->group(), mAlgorithm->displayName() );
343 }
344 mDockableWidgetHelper->setWindowTitle( title );
345
346 const QString algHelp = formatHelp( algorithm );
347 if ( algHelp.isEmpty() )
348 textShortHelp->hide();
349 else
350 {
351 textShortHelp->document()->setDefaultStyleSheet( QStringLiteral(
352 ".summary { margin-left: 10px; margin-right: 10px; }\n"
353 "h2 { color: #555555; padding-bottom: 15px; }\n"
354 "a { text - decoration: none; color: #3498db; font-weight: bold; }\n"
355 "p, ul, li { color: #666666; }\n"
356 "b { color: #333333; }\n"
357 "dl dd { margin - bottom: 5px; }"
358 ) );
359 textShortHelp->setHtml( algHelp );
360 connect( textShortHelp, &QTextBrowser::anchorClicked, this, &QgsProcessingAlgorithmWidgetBase::linkClicked );
361 textShortHelp->show();
362 }
363
364 if ( algorithm->helpUrl().isEmpty() && ( !algorithm->provider() || algorithm->provider()->helpId().isEmpty() ) )
365 {
366 mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Help ) );
367 }
368
369 const QString warning = algorithm->provider() ? algorithm->provider()->warningMessage() : QString();
370 if ( !warning.isEmpty() )
371 {
372 mMessageBar->pushMessage( warning, Qgis::MessageLevel::Warning );
373 }
374}
375
376QgsProcessingAlgorithm *QgsProcessingAlgorithmWidgetBase::algorithm()
377{
378 return mAlgorithm.get();
379}
380
381void QgsProcessingAlgorithmWidgetBase::setMainWidget( QgsPanelWidget *widget )
382{
383 if ( mMainWidget )
384 {
385 mMainWidget->deleteLater();
386 }
387
388 mPanelStack->setMainPanel( widget );
389 widget->setDockMode( true );
390
391 mMainWidget = widget;
392 connect( mMainWidget, &QgsPanelWidget::panelAccepted, mDockableWidgetHelper, &QgsDockableWidgetHelper::reject );
393}
394
395QgsPanelWidget *QgsProcessingAlgorithmWidgetBase::mainWidget()
396{
397 return mMainWidget;
398}
399
400void QgsProcessingAlgorithmWidgetBase::saveLogToFile( const QString &path, const LogFormat format )
401{
402 QFile logFile( path );
403 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
404 {
405 return;
406 }
407 QTextStream fout( &logFile );
408
409 switch ( format )
410 {
411 case QgsProcessingAlgorithmWidgetBase::LogFormat::FormatPlainText:
412 fout << txtLog->toPlainText();
413 break;
414
415 case QgsProcessingAlgorithmWidgetBase::LogFormat::FormatHtml:
416 fout << txtLog->toHtml();
417 break;
418 }
419}
420
421void QgsProcessingAlgorithmWidgetBase::registerProcessingFeedbackGenerator( QgsProcessingFeedbackGenerator *factory )
422{
423 mFeedbackFactory = factory;
424}
425
426QgsProcessingFeedback *QgsProcessingAlgorithmWidgetBase::createFeedback()
427{
428 std::unique_ptr< QgsProcessingFeedback > feedback;
429 if ( mFeedbackFactory )
430 {
431 feedback.reset( mFeedbackFactory->createFeedback() );
432 }
433 if ( !feedback )
434 {
435 feedback = std::make_unique< QgsProcessingFeedback >();
436 }
437 connect( feedback.get(), &QgsProcessingFeedback::progressChanged, this, &QgsProcessingAlgorithmWidgetBase::setPercentage );
438 connect( feedback.get(), &QgsProcessingFeedback::commandInfoPushed, this, &QgsProcessingAlgorithmWidgetBase::pushCommandInfo );
439 connect( feedback.get(), &QgsProcessingFeedback::consoleInfoPushed, this, &QgsProcessingAlgorithmWidgetBase::pushConsoleInfo );
440 connect( feedback.get(), &QgsProcessingFeedback::debugInfoPushed, this, &QgsProcessingAlgorithmWidgetBase::pushDebugInfo );
441 connect( feedback.get(), &QgsProcessingFeedback::errorReported, this, &QgsProcessingAlgorithmWidgetBase::reportError );
442 connect( feedback.get(), &QgsProcessingFeedback::warningPushed, this, &QgsProcessingAlgorithmWidgetBase::pushWarning );
443 connect( feedback.get(), &QgsProcessingFeedback::infoPushed, this, &QgsProcessingAlgorithmWidgetBase::pushInfo );
444 connect( feedback.get(), &QgsProcessingFeedback::formattedMessagePushed, this, &QgsProcessingAlgorithmWidgetBase::pushFormattedMessage );
445 connect( feedback.get(), &QgsProcessingFeedback::progressTextChanged, this, &QgsProcessingAlgorithmWidgetBase::setProgressText );
446 connect( this, &QgsProcessingAlgorithmWidgetBase::cancelRequested, feedback.get(), &QgsProcessingFeedback::cancel );
447 return feedback.release();
448}
449
450QDialogButtonBox *QgsProcessingAlgorithmWidgetBase::buttonBox()
451{
452 return mButtonBox;
453}
454
455QTabWidget *QgsProcessingAlgorithmWidgetBase::tabWidget()
456{
457 return mTabWidget;
458}
459
460void QgsProcessingAlgorithmWidgetBase::showLog()
461{
462 mTabWidget->setCurrentIndex( 1 );
463}
464
465void QgsProcessingAlgorithmWidgetBase::showParameters()
466{
467 mTabWidget->setCurrentIndex( 0 );
468}
469
470QPushButton *QgsProcessingAlgorithmWidgetBase::runButton()
471{
472 return mButtonRun;
473}
474
475QPushButton *QgsProcessingAlgorithmWidgetBase::cancelButton()
476{
477 return buttonCancel;
478}
479
480QPushButton *QgsProcessingAlgorithmWidgetBase::changeParametersButton()
481{
482 return mButtonChangeParameters;
483}
484
485void QgsProcessingAlgorithmWidgetBase::clearProgress()
486{
487 progressBar->setMaximum( 0 );
488}
489
490void QgsProcessingAlgorithmWidgetBase::setExecuted( bool executed )
491{
492 mExecuted = executed;
493}
494
495void QgsProcessingAlgorithmWidgetBase::setExecutedAnyResult( bool executedAnyResult )
496{
497 mExecutedAnyResult = executedAnyResult;
498}
499
500void QgsProcessingAlgorithmWidgetBase::setResults( const QVariantMap &results )
501{
502 mResults = results;
503}
504
505void QgsProcessingAlgorithmWidgetBase::finished( bool, const QVariantMap &, QgsProcessingContext &, QgsProcessingFeedback * )
506{}
507
508void QgsProcessingAlgorithmWidgetBase::openHelp()
509{
510 QUrl algHelp = mAlgorithm->helpUrl();
511 if ( algHelp.isEmpty() && mAlgorithm->provider() )
512 {
513 algHelp = QgsHelp::helpUrl(
514 u"processing_algs/%1/%2.html#%3"_s.arg( mAlgorithm->provider()->helpId(), mAlgorithm->groupId(), u"%1%2"_s.arg( mAlgorithm->provider()->helpId() ).arg( mAlgorithm->name().replace( "_", "-" ) ) )
515 );
516 }
517
518 if ( !algHelp.isEmpty() )
519 QDesktopServices::openUrl( algHelp );
520}
521
522void QgsProcessingAlgorithmWidgetBase::toggleCollapsed()
523{
524 if ( mHelpCollapsed )
525 {
526 splitter->restoreState( mSplitterState );
527 mButtonCollapse->setArrowType( Qt::RightArrow );
528 }
529 else
530 {
531 mSplitterState = splitter->saveState();
532 splitter->setSizes( QList<int>() << 1 << 0 );
533 mButtonCollapse->setArrowType( Qt::LeftArrow );
534 }
535 mHelpCollapsed = !mHelpCollapsed;
536}
537
538void QgsProcessingAlgorithmWidgetBase::splitterChanged( int, int )
539{
540 if ( splitter->sizes().at( 1 ) == 0 )
541 {
542 mHelpCollapsed = true;
543 mButtonCollapse->setArrowType( Qt::LeftArrow );
544 }
545 else
546 {
547 mHelpCollapsed = false;
548 mButtonCollapse->setArrowType( Qt::RightArrow );
549 }
550}
551
552void QgsProcessingAlgorithmWidgetBase::mTabWidget_currentChanged( int )
553{
554 updateRunButtonVisibility();
555}
556
557void QgsProcessingAlgorithmWidgetBase::linkClicked( const QUrl &url )
558{
559 QDesktopServices::openUrl( url.toString() );
560}
561
562void QgsProcessingAlgorithmWidgetBase::algExecuted( bool successful, const QVariantMap & )
563{
564 mAlgorithmTask = nullptr;
565
566 if ( !successful )
567 {
568 // show widget to display errors
569 showWidget();
570 showLog();
571 }
572 else
573 {
574 if ( isFinalized() && successful )
575 {
576 progressBar->setFormat( tr( "Complete" ) );
577 }
578
579 // delete widget if closed
580 if ( isFinalized() && !isVisible() )
581 {
582 deleteLater();
583 }
584 }
585}
586
587void QgsProcessingAlgorithmWidgetBase::taskTriggered( QgsTask *task )
588{
589 if ( task == mAlgorithmTask )
590 {
591 showWidget();
592 showLog();
593 }
594}
595
596void QgsProcessingAlgorithmWidgetBase::showWidget()
597{
598 mDockableWidgetHelper->setUserVisible( true );
599}
600
601void QgsProcessingAlgorithmWidgetBase::closeClicked()
602{
603 disconnect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed, this, &QgsProcessingAlgorithmWidgetBase::closeClicked );
604
605 if ( isRunning() )
606 {
607 mDockableWidgetHelper->setUserVisible( false );
608 }
609 else
610 {
611 reject();
612 close();
613 }
614}
615
616void QgsProcessingAlgorithmWidgetBase::urlClicked( const QUrl &url )
617{
618 const QFileInfo file( url.toLocalFile() );
619 if ( file.exists() && !file.isDir() )
620 QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
621 else
622 QDesktopServices::openUrl( url );
623}
624
625Qgis::ProcessingLogLevel QgsProcessingAlgorithmWidgetBase::logLevel() const
626{
627 return mLogLevel;
628}
629
630void QgsProcessingAlgorithmWidgetBase::setLogLevel( Qgis::ProcessingLogLevel level )
631{
632 mLogLevel = level;
633}
634
635void QgsProcessingAlgorithmWidgetBase::reportError( const QString &error, bool fatalError )
636{
637 setInfo( error, true );
638 if ( fatalError )
639 resetGui();
640 showLog();
641 processEvents();
642}
643
644void QgsProcessingAlgorithmWidgetBase::pushWarning( const QString &warning )
645{
646 setInfo( warning, false, true, true );
647 processEvents();
648}
649
650void QgsProcessingAlgorithmWidgetBase::pushInfo( const QString &info )
651{
652 setInfo( info );
653 processEvents();
654}
655
656void QgsProcessingAlgorithmWidgetBase::pushFormattedMessage( const QString &html )
657{
658 setInfo( html, false, false );
659 processEvents();
660}
661
662void QgsProcessingAlgorithmWidgetBase::pushCommandInfo( const QString &command )
663{
664 txtLog->append( u"<code>%1<code>"_s.arg( formatStringForLog( command.toHtmlEscaped() ) ) );
665 scrollToBottomOfLog();
666 processEvents();
667}
668
669void QgsProcessingAlgorithmWidgetBase::pushDebugInfo( const QString &message )
670{
671 txtLog->append( u"<span style=\"color:#777\">%1</span>"_s.arg( formatStringForLog( message.toHtmlEscaped() ) ) );
672 scrollToBottomOfLog();
673 processEvents();
674}
675
676void QgsProcessingAlgorithmWidgetBase::pushConsoleInfo( const QString &info )
677{
678 txtLog->append( u"<code style=\"color:#777\">%1</code>"_s.arg( formatStringForLog( info.toHtmlEscaped() ) ) );
679 scrollToBottomOfLog();
680 processEvents();
681}
682
683QDialog *QgsProcessingAlgorithmWidgetBase::createProgressDialog()
684{
685 QgsProcessingAlgorithmProgressDialog *dialog = new QgsProcessingAlgorithmProgressDialog( this );
686 dialog->setWindowModality( Qt::ApplicationModal );
687 dialog->setWindowTitle( windowTitle() );
688 dialog->setGeometry( geometry() ); // match size/position to this dialog
689 connect( progressBar, &QProgressBar::valueChanged, dialog->progressBar(), &QProgressBar::setValue );
690 connect( dialog->cancelButton(), &QPushButton::clicked, this, &QgsProcessingAlgorithmWidgetBase::cancel );
691 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
692 connect( txtLog, &QTextEdit::textChanged, dialog, [this, dialog]() {
693 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
694 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
695 sb->setValue( sb->maximum() );
696 } );
697 return dialog;
698}
699
700void QgsProcessingAlgorithmWidgetBase::clearLog()
701{
702 txtLog->clear();
703}
704
705void QgsProcessingAlgorithmWidgetBase::saveLog()
706{
707 QgsSettings settings;
708 const QString lastUsedDir = settings.value( u"/Processing/lastUsedLogDirectory"_s, QDir::homePath() ).toString();
709
710 QString filter;
711 const QString txtExt = tr( "Text files" ) + u" (*.txt *.TXT)"_s;
712 const QString htmlExt = tr( "HTML files" ) + u" (*.html *.HTML)"_s;
713
714 const QString path = QFileDialog::getSaveFileName( this, tr( "Save Log to File" ), lastUsedDir, txtExt + ";;" + htmlExt, &filter );
715 // return dialog focus on Mac
716 activateWindow();
717 raise();
718 if ( path.isEmpty() )
719 {
720 return;
721 }
722
723 settings.setValue( u"/Processing/lastUsedLogDirectory"_s, QFileInfo( path ).path() );
724
725 LogFormat format = QgsProcessingAlgorithmWidgetBase::LogFormat::FormatPlainText;
726 if ( filter == htmlExt )
727 {
728 format = QgsProcessingAlgorithmWidgetBase::LogFormat::FormatHtml;
729 }
730 saveLogToFile( path, format );
731}
732
733void QgsProcessingAlgorithmWidgetBase::copyLogToClipboard()
734{
735 QMimeData *m = new QMimeData();
736 m->setText( txtLog->toPlainText() );
737 m->setHtml( txtLog->toHtml() );
738 QClipboard *cb = QApplication::clipboard();
739
740 if ( cb->supportsSelection() )
741 {
742 cb->setMimeData( m, QClipboard::Selection );
743 }
744 cb->setMimeData( m, QClipboard::Clipboard );
745}
746
747void QgsProcessingAlgorithmWidgetBase::closeEvent( QCloseEvent *e )
748{
749 if ( !mHelpCollapsed )
750 {
751 QgsSettings settings;
752 settings.setValue( u"/Processing/dialogBaseSplitter"_s, splitter->saveState() );
753 }
754
755 QWidget::closeEvent( e );
756
757 if ( !mAlgorithmTask && isFinalized() )
758 {
759 // when running a background task, the dialog is kept around and deleted only when the task
760 // completes. But if not running a task, we auto cleanup (later - gotta give callers a chance
761 // to retrieve results and execution status).
762 deleteLater();
763 }
764}
765
766void QgsProcessingAlgorithmWidgetBase::runAlgorithm()
767{}
768
769void QgsProcessingAlgorithmWidgetBase::setPercentage( double percent )
770{
771 // delay setting maximum progress value until we know algorithm reports progress
772 if ( progressBar->maximum() == 0 )
773 progressBar->setMaximum( 100 );
774 progressBar->setValue( percent );
775 processEvents();
776}
777
778void QgsProcessingAlgorithmWidgetBase::setProgressText( const QString &text )
779{
780 lblProgress->setText( text );
781 setInfo( text, false );
782 scrollToBottomOfLog();
783 processEvents();
784}
785
786QString QgsProcessingAlgorithmWidgetBase::formatHelp( QgsProcessingAlgorithm *algorithm )
787{
788 QString result;
789 const QString text = algorithm->shortHelpString();
790 if ( !text.isEmpty() )
791 {
792 const QStringList paragraphs = text.split( '\n' );
793 QString help;
794 for ( const QString &paragraph : paragraphs )
795 {
796 help += u"<p>%1</p>"_s.arg( paragraph );
797 }
798 result = u"<h2>%1</h2>%2"_s.arg( algorithm->displayName(), help );
799 }
800 else if ( !algorithm->shortDescription().isEmpty() )
801 {
802 result = u"<h2>%1</h2><p>%2</p>"_s.arg( algorithm->displayName(), algorithm->shortDescription() );
803 }
804
805 if ( algorithm->documentationFlags() != Qgis::ProcessingAlgorithmDocumentationFlags() )
806 {
807 QStringList flags;
809 {
810 if ( algorithm->documentationFlags() & flag )
811 {
813 }
814 }
815 result += u"<ul><li><i>%1</i></li></ul>"_s.arg( flags.join( "</i></li><li><i>"_L1 ) );
816 }
818 {
819 result += u"<p><b>%1</b></p>"_s.arg( tr( "Warning: This algorithm is a potential security risk if executed with unchecked inputs, and may result in system damage or data leaks." ) );
820 }
822 {
823 result += u"<p><b>%1</b></p>"_s.arg( tr( "Warning: This algorithm has known issues. The results must be carefully validated by the user." ) );
824 }
825
826 return result;
827}
828
829void QgsProcessingAlgorithmWidgetBase::processEvents()
830{
831 if ( mAlgorithmTask )
832 {
833 // no need to call this - the algorithm is running in a thread.
834 // in fact, calling it causes a crash on Windows when the algorithm
835 // is running in a background thread... unfortunately we need something
836 // like this for non-threadable algorithms, otherwise there's no chance
837 // for users to hit cancel or see progress updates...
838 return;
839 }
840
841 // So that we get a chance of hitting the Abort button
842#ifdef Q_OS_LINUX
843 // One iteration is actually enough on Windows to get good interactivity
844 // whereas on Linux we must allow for far more iterations.
845 // For safety limit the number of iterations
846 int nIters = 0;
847 while ( ++nIters < 100 )
848#endif
849 {
850 QCoreApplication::processEvents();
851 }
852}
853
854void QgsProcessingAlgorithmWidgetBase::scrollToBottomOfLog()
855{
856 QScrollBar *sb = txtLog->verticalScrollBar();
857 sb->setValue( sb->maximum() );
858}
859
860void QgsProcessingAlgorithmWidgetBase::resetGui()
861{
862 lblProgress->clear();
863 progressBar->setMaximum( 100 );
864 progressBar->setValue( 0 );
865 mButtonRun->setEnabled( true );
866 mButtonChangeParameters->setEnabled( true );
867 mButtonClose->setEnabled( true );
868 if ( mMainWidget )
869 {
870 mMainWidget->setEnabled( true );
871 }
872 updateRunButtonVisibility();
873 resetAdditionalGui();
874}
875
876void QgsProcessingAlgorithmWidgetBase::updateRunButtonVisibility()
877{
878 // Activate run button if current tab is Parameters
879 const bool runButtonVisible = mTabWidget->currentIndex() == 0;
880 mButtonRun->setVisible( runButtonVisible );
881 if ( runButtonVisible )
882 progressBar->resetFormat();
883 mButtonChangeParameters->setVisible( !runButtonVisible && mExecutedAnyResult && mButtonChangeParameters->isEnabled() );
884}
885
886void QgsProcessingAlgorithmWidgetBase::resetAdditionalGui()
887{}
888
889void QgsProcessingAlgorithmWidgetBase::blockControlsWhileRunning()
890{
891 mButtonRun->setEnabled( false );
892 mButtonChangeParameters->setEnabled( false );
893 if ( mMainWidget )
894 {
895 mMainWidget->setEnabled( false );
896 }
897 blockAdditionalControlsWhileRunning();
898}
899
900void QgsProcessingAlgorithmWidgetBase::blockAdditionalControlsWhileRunning()
901{}
902
903QgsMessageBar *QgsProcessingAlgorithmWidgetBase::messageBar()
904{
905 return mMessageBar;
906}
907
908void QgsProcessingAlgorithmWidgetBase::hideShortHelp()
909{
910 textShortHelp->setVisible( false );
911}
912
913void QgsProcessingAlgorithmWidgetBase::setCurrentTask( QgsProcessingAlgRunnerTask *task )
914{
915 mAlgorithmTask = task;
916 connect( mAlgorithmTask, &QgsProcessingAlgRunnerTask::executed, this, &QgsProcessingAlgorithmWidgetBase::algExecuted );
917 QgsApplication::taskManager()->addTask( mAlgorithmTask );
918}
919
920void QgsProcessingAlgorithmWidgetBase::disconnectCurrentTask()
921{
922 if ( mAlgorithmTask )
923 {
924 disconnect( mAlgorithmTask, &QgsProcessingAlgRunnerTask::executed, this, &QgsProcessingAlgorithmWidgetBase::algExecuted );
925 mAlgorithmTask = nullptr;
926 }
927}
928
929QString QgsProcessingAlgorithmWidgetBase::formatStringForLog( const QString &string )
930{
931 QString s = string;
932 s.replace( '\n', "<br>"_L1 );
933 return s;
934}
935
936bool QgsProcessingAlgorithmWidgetBase::isFinalized()
937{
938 return true;
939}
940
941bool QgsProcessingAlgorithmWidgetBase::isRunning()
942{
943 return false;
944}
945
946void QgsProcessingAlgorithmWidgetBase::cancel()
947{
948 emit cancelRequested();
949}
950
951void QgsProcessingAlgorithmWidgetBase::applyContextOverrides( QgsProcessingContext *context )
952{
953 if ( !context )
954 return;
955
956 context->setLogLevel( logLevel() );
957
958 if ( mOverrideDefaultContextSettings )
959 {
960 context->setInvalidGeometryCheck( mGeometryCheck );
961 context->setDistanceUnit( mDistanceUnits );
962 context->setAreaUnit( mAreaUnits );
963 context->setTemporaryFolder( mTemporaryFolderOverride );
964 context->setMaximumThreads( mMaximumThreads );
965 }
966}
967
968void QgsProcessingAlgorithmWidgetBase::setInfo( const QString &message, bool isError, bool escapeHtml, bool isWarning )
969{
970 constexpr int MESSAGE_COUNT_LIMIT = 10000;
971 // Avoid logging too many messages, which might blow memory.
972 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
973 return;
974 ++mMessageLoggedCount;
975
976 // note -- we have to wrap the message in a span block, or QTextEdit::append sometimes gets confused
977 // and varies between treating it as a HTML string or a plain text string! (see https://github.com/qgis/QGIS/issues/37934)
978 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
979 txtLog->append( u"<span style=\"color:red\">%1</span>"_s.arg( tr( "Message log truncated" ) ) );
980 else if ( isError || isWarning )
981 txtLog->append( u"<span style=\"color:%1\">%2</span>"_s.arg( isError ? u"red"_s : u"#b85a20"_s, escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
982 else if ( escapeHtml )
983 txtLog->append( u"<span>%1</span"_s.arg( formatStringForLog( message.toHtmlEscaped() ) ) );
984 else
985 txtLog->append( u"<span>%1</span>"_s.arg( formatStringForLog( message ) ) );
986 scrollToBottomOfLog();
987 processEvents();
988}
989
990void QgsProcessingAlgorithmWidgetBase::reject()
991{
992 if ( !mAlgorithmTask && isFinalized() )
993 {
994 setAttribute( Qt::WA_DeleteOnClose );
995 }
996
997 mDockableWidgetHelper->reject();
998}
999
1000void QgsProcessingAlgorithmWidgetBase::forceClose()
1001{
1002 disconnectCurrentTask();
1003 reject();
1004}
1005
1006//
1007// QgsProcessingAlgorithmProgressDialog
1008//
1009
1010QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
1011 : QDialog( parent )
1012{
1013 setupUi( this );
1014}
1015
1016QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
1017{
1018 return mProgressBar;
1019}
1020
1021QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
1022{
1023 return mButtonBox->button( QDialogButtonBox::Cancel );
1024}
1025
1026QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
1027{
1028 return mTxtLog;
1029}
1030
1031void QgsProcessingAlgorithmProgressDialog::reject()
1032{}
1033
1034
1035//
1036// QgsProcessingContextOptionsWidget
1037//
1038
1039QgsProcessingContextOptionsWidget::QgsProcessingContextOptionsWidget( QWidget *parent )
1040 : QgsPanelWidget( parent )
1041{
1042 setupUi( this );
1043 setPanelTitle( tr( "Algorithm Settings" ) );
1044
1045 mComboInvalidFeatureFiltering->addItem( tr( "Do not Filter (Better Performance)" ), QVariant::fromValue( Qgis::InvalidGeometryCheck::NoCheck ) );
1046 mComboInvalidFeatureFiltering->addItem( tr( "Skip (Ignore) Features with Invalid Geometries" ), QVariant::fromValue( Qgis::InvalidGeometryCheck::SkipInvalid ) );
1047 mComboInvalidFeatureFiltering->addItem( tr( "Stop Algorithm Execution When a Geometry is Invalid" ), QVariant::fromValue( Qgis::InvalidGeometryCheck::AbortOnInvalid ) );
1048
1049 mTemporaryFolderWidget->setDialogTitle( tr( "Select Temporary Directory" ) );
1050 mTemporaryFolderWidget->setStorageMode( QgsFileWidget::GetDirectory );
1051 mTemporaryFolderWidget->lineEdit()->setPlaceholderText( tr( "Default" ) );
1052
1053 mLogLevelComboBox->addItem( tr( "Default" ), static_cast<int>( Qgis::ProcessingLogLevel::DefaultLevel ) );
1054 mLogLevelComboBox->addItem( tr( "Verbose" ), static_cast<int>( Qgis::ProcessingLogLevel::Verbose ) );
1055 mLogLevelComboBox->addItem( tr( "Verbose (Model Debugging)" ), static_cast<int>( Qgis::ProcessingLogLevel::ModelDebug ) );
1056
1057 mDistanceUnitsCombo->addItem( tr( "Default" ), QVariant::fromValue( Qgis::DistanceUnit::Unknown ) );
1058 for ( Qgis::DistanceUnit unit : {
1069 } )
1070 {
1071 QString title;
1073 {
1075 }
1076 else
1077 {
1078 title = QgsUnitTypes::toString( unit );
1079 }
1080
1081 mDistanceUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1082 }
1083
1084 mAreaUnitsCombo->addItem( tr( "Default" ), QVariant::fromValue( Qgis::AreaUnit::Unknown ) );
1085 for ( Qgis::AreaUnit unit : {
1098 } )
1099 {
1100 QString title;
1102 {
1104 }
1105 else
1106 {
1107 title = QgsUnitTypes::toString( unit );
1108 }
1109
1110 mAreaUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1111 }
1112
1113 mThreadsSpinBox->setRange( 1, QThread::idealThreadCount() );
1114
1115 connect( mLogLevelComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1116 connect( mComboInvalidFeatureFiltering, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1117 connect( mDistanceUnitsCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1118 connect( mAreaUnitsCombo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
1119 connect( mTemporaryFolderWidget, &QgsFileWidget::fileChanged, this, &QgsPanelWidget::widgetChanged );
1120 connect( mThreadsSpinBox, qOverload<int>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
1121}
1122
1123void QgsProcessingContextOptionsWidget::setFromContext( const QgsProcessingContext *context )
1124{
1125 whileBlocking( mComboInvalidFeatureFiltering )->setCurrentIndex( mComboInvalidFeatureFiltering->findData( QVariant::fromValue( context->invalidGeometryCheck() ) ) );
1126 whileBlocking( mDistanceUnitsCombo )->setCurrentIndex( mDistanceUnitsCombo->findData( QVariant::fromValue( context->distanceUnit() ) ) );
1127 whileBlocking( mAreaUnitsCombo )->setCurrentIndex( mAreaUnitsCombo->findData( QVariant::fromValue( context->areaUnit() ) ) );
1128 whileBlocking( mTemporaryFolderWidget )->setFilePath( context->temporaryFolder() );
1129 whileBlocking( mThreadsSpinBox )->setValue( context->maximumThreads() );
1130 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData( static_cast<int>( context->logLevel() ) ) );
1131}
1132
1133Qgis::InvalidGeometryCheck QgsProcessingContextOptionsWidget::invalidGeometryCheck() const
1134{
1135 return mComboInvalidFeatureFiltering->currentData().value<Qgis::InvalidGeometryCheck>();
1136}
1137
1138Qgis::DistanceUnit QgsProcessingContextOptionsWidget::distanceUnit() const
1139{
1140 return mDistanceUnitsCombo->currentData().value<Qgis::DistanceUnit>();
1141}
1142
1143Qgis::AreaUnit QgsProcessingContextOptionsWidget::areaUnit() const
1144{
1145 return mAreaUnitsCombo->currentData().value<Qgis::AreaUnit>();
1146}
1147
1148QString QgsProcessingContextOptionsWidget::temporaryFolder()
1149{
1150 return mTemporaryFolderWidget->filePath();
1151}
1152
1153int QgsProcessingContextOptionsWidget::maximumThreads() const
1154{
1155 return mThreadsSpinBox->value();
1156}
1157
1158void QgsProcessingContextOptionsWidget::setLogLevel( Qgis::ProcessingLogLevel level )
1159{
1160 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData( static_cast<int>( level ) ) );
1161}
1162
1163Qgis::ProcessingLogLevel QgsProcessingContextOptionsWidget::logLevel() const
1164{
1165 return static_cast<Qgis::ProcessingLogLevel>( mLogLevelComboBox->currentData().toInt() );
1166}
1167
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
DistanceUnit
Units of distance.
Definition qgis.h:5464
@ Feet
Imperial feet.
Definition qgis.h:5467
@ Centimeters
Centimeters.
Definition qgis.h:5472
@ Millimeters
Millimeters.
Definition qgis.h:5473
@ Miles
Terrestrial miles.
Definition qgis.h:5470
@ Meters
Meters.
Definition qgis.h:5465
@ Unknown
Unknown distance unit.
Definition qgis.h:5514
@ Yards
Imperial yards.
Definition qgis.h:5469
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5471
@ Inches
Inches.
Definition qgis.h:5474
@ NauticalMiles
Nautical miles.
Definition qgis.h:5468
@ Kilometers
Kilometers.
Definition qgis.h:5466
AreaUnit
Units of area.
Definition qgis.h:5541
@ Acres
Acres.
Definition qgis.h:5548
@ SquareFeet
Square feet.
Definition qgis.h:5544
@ SquareCentimeters
Square centimeters.
Definition qgis.h:5551
@ SquareInches
Square inches.
Definition qgis.h:5553
@ SquareNauticalMiles
Square nautical miles.
Definition qgis.h:5549
@ SquareMillimeters
Square millimeters.
Definition qgis.h:5552
@ SquareYards
Square yards.
Definition qgis.h:5545
@ Hectares
Hectares.
Definition qgis.h:5547
@ SquareKilometers
Square kilometers.
Definition qgis.h:5543
@ SquareMeters
Square meters.
Definition qgis.h:5542
@ Unknown
Unknown areal unit.
Definition qgis.h:5554
@ SquareDegrees
Square degrees, for planar geographic CRS area measurements.
Definition qgis.h:5550
@ SquareMiles
Square miles.
Definition qgis.h:5546
@ Warning
Warning message.
Definition qgis.h:162
@ TitleCase
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
Definition qgis.h:3590
ProcessingAlgorithmDocumentationFlag
Flags describing algorithm behavior for documentation purposes.
Definition qgis.h:3814
QFlags< ProcessingAlgorithmDocumentationFlag > ProcessingAlgorithmDocumentationFlags
Flags describing algorithm behavior for documentation purposes.
Definition qgis.h:3826
InvalidGeometryCheck
Methods for handling of features with invalid geometries.
Definition qgis.h:2386
@ NoCheck
No invalid geometry checking.
Definition qgis.h:2387
@ AbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
Definition qgis.h:2389
@ SkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
Definition qgis.h:2388
@ NotAvailableInStandaloneTool
Algorithm should not be available from the standalone "qgis_process" tool. Used to flag algorithms wh...
Definition qgis.h:3791
@ SecurityRisk
The algorithm represents a potential security risk if executed with untrusted inputs.
Definition qgis.h:3793
@ DisplayNameIsLiteral
Algorithm's display name is a static literal string, and should not be translated or automatically fo...
Definition qgis.h:3785
@ KnownIssues
Algorithm has known issues.
Definition qgis.h:3787
DockableWidgetInitialState
Dockable widget initial states.
Definition qgis.h:6907
@ ForceDocked
Force the widget to be docked.
Definition qgis.h:6909
@ ForceDialog
Force the widget to be shown in a dialog.
Definition qgis.h:6910
ProcessingLogLevel
Logging level for algorithms to use when pushing feedback messages.
Definition qgis.h:3852
@ DefaultLevel
Default logging level.
Definition qgis.h:3853
@ Verbose
Verbose logging.
Definition qgis.h:3854
@ ModelDebug
Model debug level logging. Includes verbose logging and other outputs useful for debugging models.
Definition qgis.h:3855
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:224
@ HigDialogTitleIsTitleCase
Dialog titles should be title case.
Definition qgsgui.h:284
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition qgsgui.cpp:99
static QgsGui::HigFlags higFlags()
Returns the platform's HIG flags.
Definition qgsgui.cpp:253
static QUrl helpUrl(const QString &key)
Returns URI of the help topic for the given key.
Definition qgshelp.cpp:46
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.
void warningPushed(const QString &text)
Emitted when an warning is pushed.
void infoPushed(const QString &text)
Emitted when information text is pushed.
void errorReported(const QString &text, bool fatalError)
Emitted when an error is reported.
void progressTextChanged(const QString &text)
Emitted when the progress text is changed.
void debugInfoPushed(const QString &text)
Emitted when debug information text is pushed.
void formattedMessagePushed(const QString &html)
Emitted when a formatted html message is pushed.
void commandInfoPushed(const QString &text)
Emitted when command information text is pushed.
void consoleInfoPushed(const QString &text)
Emitted when console information text is pushed.
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:68
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:7583
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:7275