18#include <nlohmann/json.hpp>
39#include <QApplication>
41#include <QDesktopServices>
50#include "moc_qgsprocessingalgorithmwidgetbase.cpp"
52using namespace Qt::StringLiterals;
60QgsProcessingFeedbackGenerator::~QgsProcessingFeedbackGenerator()
67QgsProcessingAlgorithmWidgetBase::QgsProcessingAlgorithmWidgetBase(
75 const QSize defaultDialogSize = size();
78 splitter->setCollapsible( 0,
false );
81 QSplitterHandle *splitterHandle = splitter->handle( 1 );
82 QVBoxLayout *handleLayout =
new QVBoxLayout();
83 handleLayout->setContentsMargins( 0, 0, 0, 0 );
84 mButtonCollapse =
new QToolButton( splitterHandle );
85 mButtonCollapse->setAutoRaise(
true );
86 mButtonCollapse->setFixedSize( 12, 12 );
87 mButtonCollapse->setCursor( Qt::ArrowCursor );
88 handleLayout->addWidget( mButtonCollapse );
89 handleLayout->addStretch();
90 splitterHandle->setLayout( handleLayout );
94 txtLog->setOpenLinks(
false );
95 connect( txtLog, &QTextBrowser::anchorClicked,
this, &QgsProcessingAlgorithmWidgetBase::urlClicked );
98 splitter->restoreState( settings.
value( u
"/Processing/dialogBaseSplitter"_s, QByteArray() ).toByteArray() );
99 mSplitterState = splitter->saveState();
100 splitterChanged( 0, 0 );
103 mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
104 mButtonRun->setText( tr(
"Run" ) );
107 mButtonChangeParameters = mButtonBox->button( QDialogButtonBox::Yes );
108 mButtonChangeParameters->setText( tr(
"Change Parameters" ) );
110 connect( buttonCancel, &QPushButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::cancel );
111 buttonCancel->setEnabled(
false );
112 mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
115 parentWindow = qobject_cast< QMainWindow * >( QApplication::activeWindow() );
117 bool defaultIsDocked =
false;
118 QString dockId = u
"ProcessingAlgorithm"_s;
119 if ( flags.testFlags( QgsProcessingAlgorithmWidgetBase::WidgetFlag::NoDocking ) )
122 dockId = u
"ProcessingAlgorithmNonDockable"_s;
126 dockId = u
"ProcessingAlgorithmForceDocked"_s;
129 mDockableWidgetHelper
130 =
new QgsDockableWidgetHelper( tr(
"Processing" ),
this, parentWindow, dockId, QStringList(), initialState, defaultIsDocked, Qt::DockWidgetArea::RightDockWidgetArea, QgsDockableWidgetHelper::Option::RaiseTab );
131 connect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed,
this, &QgsProcessingAlgorithmWidgetBase::closeClicked );
132 mDockableWidgetHelper->setDefaultDialogSize( defaultDialogSize );
136 case QgsProcessingAlgorithmWidgetBase::WidgetMode::Single:
138 mAdvancedButton =
new QPushButton( tr(
"Advanced" ) );
139 mAdvancedMenu =
new QMenu(
this );
140 mAdvancedButton->setMenu( mAdvancedMenu );
142 mContextSettingsAction =
new QAction( tr(
"Algorithm Settingsā¦" ), mAdvancedMenu );
144 mAdvancedMenu->addAction( mContextSettingsAction );
146 connect( mContextSettingsAction, &QAction::triggered,
this, [
this] {
149 mTabWidget->setCurrentIndex( 0 );
151 if ( !mContextOptionsWidget )
153 mContextOptionsWidget =
new QgsProcessingContextOptionsWidget();
154 mContextOptionsWidget->setFromContext( processingContext() );
155 mContextOptionsWidget->setLogLevel( mLogLevel );
156 panel->openPanel( mContextOptionsWidget );
159 mOverrideDefaultContextSettings =
true;
160 mGeometryCheck = mContextOptionsWidget->invalidGeometryCheck();
161 mDistanceUnits = mContextOptionsWidget->distanceUnit();
162 mAreaUnits = mContextOptionsWidget->areaUnit();
163 mTemporaryFolderOverride = mContextOptionsWidget->temporaryFolder();
164 mMaximumThreads = mContextOptionsWidget->maximumThreads();
165 mLogLevel = mContextOptionsWidget->logLevel();
170 mAdvancedMenu->addSeparator();
172 QAction *copyAsPythonCommand =
new QAction( tr(
"Copy as Python Command" ), mAdvancedMenu );
175 mAdvancedMenu->addAction( copyAsPythonCommand );
176 connect( copyAsPythonCommand, &QAction::triggered,
this, [
this] {
183 const QString command = alg->asPythonCommand( createProcessingParameters(), *context );
184 QMimeData *m =
new QMimeData();
185 m->setText( command );
186 QClipboard *cb = QApplication::clipboard();
188 if ( cb->supportsSelection() )
190 cb->setMimeData( m, QClipboard::Selection );
192 cb->setMimeData( m, QClipboard::Clipboard );
196 mCopyAsQgisProcessCommand =
new QAction( tr(
"Copy as qgis_process Command" ), mAdvancedMenu );
198 mAdvancedMenu->addAction( mCopyAsQgisProcessCommand );
200 connect( mCopyAsQgisProcessCommand, &QAction::triggered,
this, [
this] {
208 const QString command = alg->asQgisProcessCommand( createProcessingParameters(), *context, ok );
211 mMessageBar->pushMessage( tr(
"Current settings cannot be specified as arguments to qgis_process (Pipe parameters as JSON to qgis_process instead)" ),
Qgis::MessageLevel::Warning );
215 QMimeData *m =
new QMimeData();
216 m->setText( command );
217 QClipboard *cb = QApplication::clipboard();
219 if ( cb->supportsSelection() )
221 cb->setMimeData( m, QClipboard::Selection );
223 cb->setMimeData( m, QClipboard::Clipboard );
228 mAdvancedMenu->addSeparator();
230 QAction *copyAsJson =
new QAction( tr(
"Copy as JSON" ), mAdvancedMenu );
233 mAdvancedMenu->addAction( copyAsJson );
234 connect( copyAsJson, &QAction::triggered,
this, [
this] {
241 const QVariantMap properties = alg->asMap( createProcessingParameters(), *context );
244 QMimeData *m =
new QMimeData();
246 QClipboard *cb = QApplication::clipboard();
248 if ( cb->supportsSelection() )
250 cb->setMimeData( m, QClipboard::Selection );
252 cb->setMimeData( m, QClipboard::Clipboard );
256 mPasteJsonAction =
new QAction( tr(
"Paste Settings" ), mAdvancedMenu );
259 mAdvancedMenu->addAction( mPasteJsonAction );
260 connect( mPasteJsonAction, &QAction::triggered,
this, [
this] {
261 const QString text = QApplication::clipboard()->text();
262 if ( text.isEmpty() )
266 if ( parameterValues.isEmpty() )
273 setParameters( preparedValues );
276 mButtonBox->addButton( mAdvancedButton, QDialogButtonBox::ResetRole );
280 case QgsProcessingAlgorithmWidgetBase::WidgetMode::Batch:
286 connect( mAdvancedMenu, &QMenu::aboutToShow,
this, [
this] {
288 mPasteJsonAction->setEnabled( !QApplication::clipboard()->text().isEmpty() );
292 connect( mButtonRun, &QPushButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::runAlgorithm );
293 connect( mButtonChangeParameters, &QPushButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::showParameters );
294 connect( mButtonBox, &QDialogButtonBox::rejected,
this, &QgsProcessingAlgorithmWidgetBase::closeClicked );
295 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsProcessingAlgorithmWidgetBase::openHelp );
296 connect( mButtonCollapse, &QToolButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::toggleCollapsed );
297 connect( splitter, &QSplitter::splitterMoved,
this, &QgsProcessingAlgorithmWidgetBase::splitterChanged );
299 connect( mButtonSaveLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::saveLog );
300 connect( mButtonCopyLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::copyLogToClipboard );
301 connect( mButtonClearLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::clearLog );
303 connect( mTabWidget, &QTabWidget::currentChanged,
this, &QgsProcessingAlgorithmWidgetBase::mTabWidget_currentChanged );
306 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
307 verticalLayout->insertWidget( 0, mMessageBar );
312QgsProcessingAlgorithmWidgetBase::~QgsProcessingAlgorithmWidgetBase()
314 delete mDockableWidgetHelper;
317void QgsProcessingAlgorithmWidgetBase::setParameters(
const QVariantMap & )
320void QgsProcessingAlgorithmWidgetBase::setTitle(
const QString &title )
322 mDockableWidgetHelper->setWindowTitle( title );
325void QgsProcessingAlgorithmWidgetBase::exec()
331 mDockableWidgetHelper->setSettingKeyDockId( u
"ProcessingAlgorithmNonDockable"_s );
332 mDockableWidgetHelper->toggleDockMode(
false );
333 mDockableWidgetHelper->dialog()->exec();
342 title = mAlgorithm->group().isEmpty()
344 : u
"%1 - %2"_s.arg(
QgsStringUtils::capitalize( mAlgorithm->group(),
Qgis::Capitalization::TitleCase ),
QgsStringUtils::capitalize( mAlgorithm->displayName(),
Qgis::Capitalization::TitleCase ) );
348 title = mAlgorithm->group().isEmpty() ? mAlgorithm->displayName() : u
"%1 - %2"_s.arg( mAlgorithm->group(), mAlgorithm->displayName() );
350 mDockableWidgetHelper->setWindowTitle( title );
352 const QString algHelp = formatHelp(
algorithm );
353 if ( algHelp.isEmpty() )
354 textShortHelp->hide();
357 textShortHelp->document()->setDefaultStyleSheet( QStringLiteral(
358 ".summary { margin-left: 10px; margin-right: 10px; }\n"
359 "h2 { color: #555555; padding-bottom: 15px; }\n"
360 "a { text - decoration: none; color: #3498db; font-weight: bold; }\n"
361 "p, ul, li { color: #666666; }\n"
362 "b { color: #333333; }\n"
363 "dl dd { margin - bottom: 5px; }"
365 textShortHelp->setHtml( algHelp );
366 connect( textShortHelp, &QTextBrowser::anchorClicked,
this, &QgsProcessingAlgorithmWidgetBase::linkClicked );
367 textShortHelp->show();
372 mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Help ) );
375 const QString warning =
algorithm->provider() ?
algorithm->provider()->warningMessage() : QString();
376 if ( !warning.isEmpty() )
384 return mAlgorithm.get();
387void QgsProcessingAlgorithmWidgetBase::setMainWidget(
QgsPanelWidget *widget )
391 mMainWidget->deleteLater();
394 mPanelStack->setMainPanel( widget );
397 mMainWidget = widget;
406void QgsProcessingAlgorithmWidgetBase::saveLogToFile(
const QString &path,
const LogFormat format )
408 QFile logFile( path );
409 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
413 QTextStream fout( &logFile );
417 case QgsProcessingAlgorithmWidgetBase::LogFormat::FormatPlainText:
418 fout << txtLog->toPlainText();
421 case QgsProcessingAlgorithmWidgetBase::LogFormat::FormatHtml:
422 fout << txtLog->toHtml();
427void QgsProcessingAlgorithmWidgetBase::registerProcessingFeedbackGenerator( QgsProcessingFeedbackGenerator *factory )
429 mFeedbackFactory = factory;
434 std::unique_ptr< QgsProcessingFeedback > feedback;
435 if ( mFeedbackFactory )
437 feedback.reset( mFeedbackFactory->createFeedback() );
441 feedback = std::make_unique< QgsProcessingFeedback >();
453 return feedback.release();
456QDialogButtonBox *QgsProcessingAlgorithmWidgetBase::buttonBox()
461QTabWidget *QgsProcessingAlgorithmWidgetBase::tabWidget()
466void QgsProcessingAlgorithmWidgetBase::showLog()
468 mTabWidget->setCurrentIndex( 1 );
471void QgsProcessingAlgorithmWidgetBase::showParameters()
473 mTabWidget->setCurrentIndex( 0 );
476QPushButton *QgsProcessingAlgorithmWidgetBase::runButton()
481QPushButton *QgsProcessingAlgorithmWidgetBase::cancelButton()
486QPushButton *QgsProcessingAlgorithmWidgetBase::changeParametersButton()
488 return mButtonChangeParameters;
491void QgsProcessingAlgorithmWidgetBase::clearProgress()
493 progressBar->setMaximum( 0 );
496void QgsProcessingAlgorithmWidgetBase::setExecuted(
bool executed )
498 mExecuted = executed;
501void QgsProcessingAlgorithmWidgetBase::setExecutedAnyResult(
bool executedAnyResult )
503 mExecutedAnyResult = executedAnyResult;
506void QgsProcessingAlgorithmWidgetBase::setResults(
const QVariantMap &results )
514void QgsProcessingAlgorithmWidgetBase::openHelp()
516 QUrl algHelp = mAlgorithm->helpUrl();
517 if ( algHelp.isEmpty() && mAlgorithm->provider() && !mAlgorithm->provider()->helpId().isEmpty() )
520 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(
"_",
"-" ) ) )
524 if ( !algHelp.isEmpty() )
525 QDesktopServices::openUrl( algHelp );
528void QgsProcessingAlgorithmWidgetBase::toggleCollapsed()
530 if ( mHelpCollapsed )
532 splitter->restoreState( mSplitterState );
533 mButtonCollapse->setArrowType( Qt::RightArrow );
537 mSplitterState = splitter->saveState();
538 splitter->setSizes( QList<int>() << 1 << 0 );
539 mButtonCollapse->setArrowType( Qt::LeftArrow );
541 mHelpCollapsed = !mHelpCollapsed;
544void QgsProcessingAlgorithmWidgetBase::splitterChanged(
int,
int )
546 if ( splitter->sizes().at( 1 ) == 0 )
548 mHelpCollapsed =
true;
549 mButtonCollapse->setArrowType( Qt::LeftArrow );
553 mHelpCollapsed =
false;
554 mButtonCollapse->setArrowType( Qt::RightArrow );
558void QgsProcessingAlgorithmWidgetBase::mTabWidget_currentChanged(
int )
560 updateRunButtonVisibility();
563void QgsProcessingAlgorithmWidgetBase::linkClicked(
const QUrl &url )
565 if ( url.toString() ==
"#help"_L1 )
571 QDesktopServices::openUrl( url.toString() );
574void QgsProcessingAlgorithmWidgetBase::algExecuted(
bool successful,
const QVariantMap & )
576 mAlgorithmTask =
nullptr;
586 if ( isFinalized() && successful )
588 progressBar->setFormat( tr(
"Complete" ) );
592 if ( isFinalized() && !isVisible() )
599void QgsProcessingAlgorithmWidgetBase::taskTriggered(
QgsTask *task )
601 if ( task == mAlgorithmTask )
608void QgsProcessingAlgorithmWidgetBase::showWidget()
610 mDockableWidgetHelper->setUserVisible(
true );
613void QgsProcessingAlgorithmWidgetBase::closeClicked()
615 disconnect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed,
this, &QgsProcessingAlgorithmWidgetBase::closeClicked );
619 mDockableWidgetHelper->setUserVisible(
false );
628void QgsProcessingAlgorithmWidgetBase::urlClicked(
const QUrl &url )
630 const QFileInfo file( url.toLocalFile() );
631 if ( file.exists() && !file.isDir() )
633 if ( file.suffix().compare(
"html"_L1, Qt::CaseInsensitive ) == 0 )
635 QDesktopServices::openUrl( url );
643 QDesktopServices::openUrl( url );
656void QgsProcessingAlgorithmWidgetBase::reportError(
const QString &error,
bool fatalError )
658 setInfo( error,
true );
665void QgsProcessingAlgorithmWidgetBase::pushWarning(
const QString &warning )
667 setInfo( warning,
false,
true,
true );
671void QgsProcessingAlgorithmWidgetBase::pushInfo(
const QString &info )
677void QgsProcessingAlgorithmWidgetBase::pushFormattedMessage(
const QString &html )
679 setInfo( html,
false,
false );
683void QgsProcessingAlgorithmWidgetBase::pushCommandInfo(
const QString &command )
685 txtLog->append( u
"<code>%1<code>"_s.arg( formatStringForLog( command.toHtmlEscaped() ) ) );
686 scrollToBottomOfLog();
690void QgsProcessingAlgorithmWidgetBase::pushDebugInfo(
const QString &message )
692 txtLog->append( u
"<span style=\"color:#777\">%1</span>"_s.arg( formatStringForLog( message.toHtmlEscaped() ) ) );
693 scrollToBottomOfLog();
697void QgsProcessingAlgorithmWidgetBase::pushConsoleInfo(
const QString &info )
699 txtLog->append( u
"<code style=\"color:#777\">%1</code>"_s.arg( formatStringForLog( info.toHtmlEscaped() ) ) );
700 scrollToBottomOfLog();
704QDialog *QgsProcessingAlgorithmWidgetBase::createProgressDialog()
706 QgsProcessingAlgorithmProgressDialog *dialog =
new QgsProcessingAlgorithmProgressDialog(
this );
707 dialog->setWindowModality( Qt::ApplicationModal );
708 dialog->setWindowTitle( windowTitle() );
709 dialog->setGeometry( geometry() );
710 connect( progressBar, &QProgressBar::valueChanged, dialog->progressBar(), &QProgressBar::setValue );
711 connect( dialog->cancelButton(), &QPushButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::cancel );
712 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
713 connect( txtLog, &QTextEdit::textChanged, dialog, [
this, dialog]() {
714 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
715 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
716 sb->setValue( sb->maximum() );
721void QgsProcessingAlgorithmWidgetBase::clearLog()
726void QgsProcessingAlgorithmWidgetBase::saveLog()
729 const QString lastUsedDir = settings.
value( u
"/Processing/lastUsedLogDirectory"_s, QDir::homePath() ).toString();
732 const QString txtExt = tr(
"Text files" ) + u
" (*.txt *.TXT)"_s;
733 const QString htmlExt = tr(
"HTML files" ) + u
" (*.html *.HTML)"_s;
735 const QString path = QFileDialog::getSaveFileName(
this, tr(
"Save Log to File" ), lastUsedDir, txtExt +
";;" + htmlExt, &filter );
739 if ( path.isEmpty() )
744 settings.
setValue( u
"/Processing/lastUsedLogDirectory"_s, QFileInfo( path ).path() );
746 LogFormat format = QgsProcessingAlgorithmWidgetBase::LogFormat::FormatPlainText;
747 if ( filter == htmlExt )
749 format = QgsProcessingAlgorithmWidgetBase::LogFormat::FormatHtml;
751 saveLogToFile( path, format );
754void QgsProcessingAlgorithmWidgetBase::copyLogToClipboard()
756 QMimeData *m =
new QMimeData();
757 m->setText( txtLog->toPlainText() );
758 m->setHtml( txtLog->toHtml() );
759 QClipboard *cb = QApplication::clipboard();
761 if ( cb->supportsSelection() )
763 cb->setMimeData( m, QClipboard::Selection );
765 cb->setMimeData( m, QClipboard::Clipboard );
768void QgsProcessingAlgorithmWidgetBase::closeEvent( QCloseEvent *e )
770 if ( !mHelpCollapsed )
773 settings.
setValue( u
"/Processing/dialogBaseSplitter"_s, splitter->saveState() );
776 QWidget::closeEvent( e );
778 if ( !mAlgorithmTask && isFinalized() )
787void QgsProcessingAlgorithmWidgetBase::runAlgorithm()
790void QgsProcessingAlgorithmWidgetBase::setPercentage(
double percent )
793 if ( progressBar->maximum() == 0 )
794 progressBar->setMaximum( 100 );
795 progressBar->setValue( percent );
799void QgsProcessingAlgorithmWidgetBase::setProgressText(
const QString &text )
801 lblProgress->setText( text );
802 setInfo( text,
false );
803 scrollToBottomOfLog();
810 const QString text =
algorithm->shortHelpString();
811 if ( !text.isEmpty() )
813 const QStringList paragraphs = text.split(
'\n' );
815 for (
const QString ¶graph : paragraphs )
817 help += u
"<p>%1</p>"_s.arg( paragraph );
819 result = u
"<h2>%1</h2>%2"_s.arg(
algorithm->displayName(), help );
821 else if ( !
algorithm->shortDescription().isEmpty() )
823 result = u
"<h2>%1</h2><p>%2</p>"_s.arg(
algorithm->displayName(),
algorithm->shortDescription() );
826 const QList< QgsAcademicReference > references =
algorithm->academicReferences();
827 if ( !references.empty() )
829 QStringList referenceStrings;
832 referenceStrings << reference.asHtml();
834 result += u
"<h4>%1</h4>"_s.arg( tr(
"References" ) );
835 result += u
"<ul><li>%1</li></ul>"_s.arg( referenceStrings.join(
"</li><li>"_L1 ) );
843 if (
algorithm->documentationFlags() & flag )
848 result += u
"<ul><li><i>%1</i></li></ul>"_s.arg( flags.join(
"</i></li><li><i>"_L1 ) );
852 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." ) );
856 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." ) );
864 const QString linkHtml = QStringLiteral( R
"(<a href="#help">%1</a>)" ).arg( tr( "Algorithm documentation" ) );
868 const QString implementationSourceUri =
algorithm->implementationSourceUri();
869 if ( !implementationSourceUri.isEmpty() )
871 const QString linkHtml = QStringLiteral( R
"(<a href="%1">%2</a>)" ).arg( implementationSourceUri, tr( "Algorithm source code" ) );
875 const QList< QgsProcessingAlgorithm::ExternalLink > externalLinks =
algorithm->externalLinks();
878 const QString linkHtml = QStringLiteral( R
"(<a href="%1">%2</a>)" ).arg( link.url, link.description );
882 if ( !links.empty() )
884 result += u
"<h4>%1</h4>"_s.arg( tr(
"Links" ) );
885 result += u
"<ul><li>%1</li></ul>"_s.arg( links.join(
"</li><li>"_L1 ) );
891void QgsProcessingAlgorithmWidgetBase::processEvents()
893 if ( mAlgorithmTask )
909 while ( ++nIters < 100 )
912 QCoreApplication::processEvents();
916void QgsProcessingAlgorithmWidgetBase::scrollToBottomOfLog()
918 QScrollBar *sb = txtLog->verticalScrollBar();
919 sb->setValue( sb->maximum() );
922void QgsProcessingAlgorithmWidgetBase::resetGui()
924 lblProgress->clear();
925 progressBar->setMaximum( 100 );
926 progressBar->setValue( 0 );
927 mButtonRun->setEnabled(
true );
928 mButtonChangeParameters->setEnabled(
true );
929 mButtonClose->setEnabled(
true );
932 mMainWidget->setEnabled(
true );
934 updateRunButtonVisibility();
935 resetAdditionalGui();
938void QgsProcessingAlgorithmWidgetBase::updateRunButtonVisibility()
941 const bool runButtonVisible = mTabWidget->currentIndex() == 0;
942 mButtonRun->setVisible( runButtonVisible );
943 if ( runButtonVisible )
944 progressBar->resetFormat();
945 mButtonChangeParameters->setVisible( !runButtonVisible && mExecutedAnyResult && mButtonChangeParameters->isEnabled() );
948void QgsProcessingAlgorithmWidgetBase::resetAdditionalGui()
951void QgsProcessingAlgorithmWidgetBase::blockControlsWhileRunning()
953 mButtonRun->setEnabled(
false );
954 mButtonChangeParameters->setEnabled(
false );
957 mMainWidget->setEnabled(
false );
959 blockAdditionalControlsWhileRunning();
962void QgsProcessingAlgorithmWidgetBase::blockAdditionalControlsWhileRunning()
970void QgsProcessingAlgorithmWidgetBase::hideShortHelp()
972 textShortHelp->setVisible(
false );
977 mAlgorithmTask = task;
982void QgsProcessingAlgorithmWidgetBase::disconnectCurrentTask()
984 if ( mAlgorithmTask )
987 mAlgorithmTask =
nullptr;
991QString QgsProcessingAlgorithmWidgetBase::formatStringForLog(
const QString &
string )
994 s.replace(
'\n',
"<br>"_L1 );
998bool QgsProcessingAlgorithmWidgetBase::isFinalized()
1003bool QgsProcessingAlgorithmWidgetBase::isRunning()
1008void QgsProcessingAlgorithmWidgetBase::cancel()
1010 emit cancelRequested();
1020 if ( mOverrideDefaultContextSettings )
1030void QgsProcessingAlgorithmWidgetBase::setInfo(
const QString &message,
bool isError,
bool escapeHtml,
bool isWarning )
1032 constexpr int MESSAGE_COUNT_LIMIT = 10000;
1034 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
1036 ++mMessageLoggedCount;
1040 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
1041 txtLog->append( u
"<span style=\"color:red\">%1</span>"_s.arg( tr(
"Message log truncated" ) ) );
1042 else if ( isError || isWarning )
1043 txtLog->append( u
"<span style=\"color:%1\">%2</span>"_s.arg( isError ? u
"red"_s : u
"#b85a20"_s, escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
1044 else if ( escapeHtml )
1045 txtLog->append( u
"<span>%1</span"_s.arg( formatStringForLog( message.toHtmlEscaped() ) ) );
1047 txtLog->append( u
"<span>%1</span>"_s.arg( formatStringForLog( message ) ) );
1048 scrollToBottomOfLog();
1052void QgsProcessingAlgorithmWidgetBase::reject()
1054 if ( !mAlgorithmTask && isFinalized() )
1056 setAttribute( Qt::WA_DeleteOnClose );
1059 mDockableWidgetHelper->reject();
1062void QgsProcessingAlgorithmWidgetBase::forceClose()
1064 disconnectCurrentTask();
1072QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
1078QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
1080 return mProgressBar;
1083QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
1085 return mButtonBox->button( QDialogButtonBox::Cancel );
1088QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
1093void QgsProcessingAlgorithmProgressDialog::reject()
1101QgsProcessingContextOptionsWidget::QgsProcessingContextOptionsWidget( QWidget *parent )
1105 setPanelTitle( tr(
"Algorithm Settings" ) );
1111 mTemporaryFolderWidget->setDialogTitle( tr(
"Select Temporary Directory" ) );
1113 mTemporaryFolderWidget->lineEdit()->setPlaceholderText( tr(
"Default" ) );
1143 mDistanceUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1172 mAreaUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1175 mThreadsSpinBox->setRange( 1, QThread::idealThreadCount() );
1177 connect( mLogLevelComboBox, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &
QgsPanelWidget::changed );
1178 connect( mComboInvalidFeatureFiltering, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &
QgsPanelWidget::changed );
1179 connect( mDistanceUnitsCombo, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &
QgsPanelWidget::changed );
1180 connect( mAreaUnitsCombo, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &
QgsPanelWidget::changed );
1187 whileBlocking( mComboInvalidFeatureFiltering )->setCurrentIndex( mComboInvalidFeatureFiltering->findData( QVariant::fromValue( context->
invalidGeometryCheck() ) ) );
1188 whileBlocking( mDistanceUnitsCombo )->setCurrentIndex( mDistanceUnitsCombo->findData( QVariant::fromValue( context->
distanceUnit() ) ) );
1189 whileBlocking( mAreaUnitsCombo )->setCurrentIndex( mAreaUnitsCombo->findData( QVariant::fromValue( context->
areaUnit() ) ) );
1192 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData(
static_cast<int>( context->
logLevel() ) ) );
1205Qgis::AreaUnit QgsProcessingContextOptionsWidget::areaUnit()
const
1210QString QgsProcessingContextOptionsWidget::temporaryFolder()
1212 return mTemporaryFolderWidget->filePath();
1215int QgsProcessingContextOptionsWidget::maximumThreads()
const
1217 return mThreadsSpinBox->value();
1222 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData(
static_cast<int>( level ) ) );
1236 : QgsProcessingAlgorithmWidgetBase( parentWindow, WidgetMode::Single, flags, initialState )
1237 , mInPlace( inPlace )
1241 connect( buttonBox(), &QDialogButtonBox::accepted,
this, [
this] {
1242 for ( QWidget *widget : std::as_const( mWidgetsToResetPalette ) )
1244 widget->setPalette( QPalette() );
1246 mWidgetsToResetPalette.clear();
1250QgsProcessingParametersWidget *QgsProcessingAlgorithmWidget::createParametersPanel(
bool inPlaceMode,
QgsVectorLayer *activeLayer,
QgsMessageBar *messageBar )
1252 auto widget =
new QgsProcessingParametersWidget(
algorithm(), inPlaceMode, activeLayer, messageBar );
1253 widget->registerProcessingContextGenerator(
this );
1254 widget->initWidgets();
1258QgsProcessingParametersWidget *QgsProcessingAlgorithmWidget::parametersWidget()
1260 return qobject_cast< QgsProcessingParametersWidget * >( mainWidget() );
1263void QgsProcessingAlgorithmWidget::flagInvalidParameterValue(
const QString &message, QWidget *widget )
1268 QPalette palette = widget->palette();
1269 palette.setColor( QPalette::ColorRole::Base, QColor( 255, 255, 0 ) );
1270 widget->setPalette( palette );
1271 mWidgetsToResetPalette.append( widget );
1277void QgsProcessingAlgorithmWidget::flagInvalidOutputExtension(
const QString &message, QWidget *widget )
1282 QPalette palette = widget->palette();
1283 palette.setColor( QPalette::ColorRole::Base, QColor( 255, 255, 0 ) );
1284 widget->setPalette( palette );
1285 mWidgetsToResetPalette.append( widget );
1291bool QgsProcessingAlgorithmWidget::handleValidationResults(
const QList<ParameterValidationResult> &results )
1293 bool allValid =
true;
1294 QgsProcessingParametersWidget *widget = parametersWidget();
1295 for (
const ParameterValidationResult &result : results )
1298 QWidget *widget = wrapper ? wrapper->
wrappedWidget() :
nullptr;
1301 switch ( result.result )
1306 flagInvalidOutputExtension( result.message, widget );
1310 flagInvalidParameterValue( parameter ? parameter->
description() : QString(), widget );
1319bool QgsProcessingAlgorithmWidget::inPlace()
const
1324void QgsProcessingAlgorithmWidget::setParameters(
const QVariantMap &values )
1326 if ( QgsProcessingParametersWidget *widget = parametersWidget() )
1328 widget->setParameters( values );
1332QVariantMap QgsProcessingAlgorithmWidget::createProcessingParameters( Flags flags )
1334 QgsProcessingParametersWidget *widget = parametersWidget();
1338 QList<ParameterValidationResult> validationResults;
1339 const QVariantMap parameters = widget->createAndValidateParameters( flags, validationResults );
1341 const bool allValid = handleValidationResults( validationResults );
1343 return allValid ? parameters : QVariantMap();
1355 mFeedback.reset(
const_cast< QgsProcessingAlgorithmWidget *
>(
this )->createFeedback() );
1359 const_cast< QgsProcessingAlgorithmWidget *
>( this )->applyContextOverrides( mContext.get() );
1360 return mContext.get();
Provides global constants and enumerations for use throughout the application.
DistanceUnit
Units of distance.
@ Centimeters
Centimeters.
@ Millimeters
Millimeters.
@ Miles
Terrestrial miles.
@ Unknown
Unknown distance unit.
@ Degrees
Degrees, for planar geographic CRS distance measurements.
@ NauticalMiles
Nautical miles.
@ SquareCentimeters
Square centimeters.
@ SquareInches
Square inches.
@ SquareNauticalMiles
Square nautical miles.
@ SquareMillimeters
Square millimeters.
@ SquareYards
Square yards.
@ SquareKilometers
Square kilometers.
@ SquareMeters
Square meters.
@ Unknown
Unknown areal unit.
@ SquareDegrees
Square degrees, for planar geographic CRS area measurements.
@ SquareMiles
Square miles.
@ Warning
Warning message.
@ TitleCase
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
ProcessingAlgorithmDocumentationFlag
Flags describing algorithm behavior for documentation purposes.
QFlags< ProcessingAlgorithmDocumentationFlag > ProcessingAlgorithmDocumentationFlags
Flags describing algorithm behavior for documentation purposes.
InvalidGeometryCheck
Methods for handling of features with invalid geometries.
@ NoCheck
No invalid geometry checking.
@ AbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
@ SkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
@ NotAvailableInStandaloneTool
Algorithm should not be available from the standalone "qgis_process" tool. Used to flag algorithms wh...
@ SecurityRisk
The algorithm represents a potential security risk if executed with untrusted inputs.
@ DisplayNameIsLiteral
Algorithm's display name is a static literal string, and should not be translated or automatically fo...
@ KnownIssues
Algorithm has known issues.
DockableWidgetInitialState
Dockable widget initial states.
@ ForceDocked
Force the widget to be docked.
@ ForceDialog
Force the widget to be shown in a dialog.
ProcessingLogLevel
Logging level for algorithms to use when pushing feedback messages.
@ DefaultLevel
Default logging level.
@ Verbose
Verbose logging.
@ ModelDebug
Model debug level logging. Includes verbose logging and other outputs useful for debugging models.
Encapsulates an academic reference and formats it according to style guidelines.
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 ...
static QgsProcessingGuiRegistry * processingGuiRegistry()
Returns the global processing gui registry, used for registering the GUI behavior of processing algor...
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...
@ HigDialogTitleIsTitleCase
Dialog titles should be title case.
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
static QgsGui::HigFlags higFlags()
Returns the platform's HIG flags.
static QUrl helpUrl(const QString &key)
Returns URI of the help topic for the given key.
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.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
bool clearWidgets()
Removes all items from the bar.
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.
const QgsProcessingParameterDefinition * parameterDefinition(const QString &name) const
Returns a matching parameter by name.
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 setFeedback(QgsProcessingFeedback *feedback)
Sets an associated feedback object.
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.
Base class for the definition of processing parameters.
QString description() const
Returns the description for the parameter.
@ InvalidValue
Generic result for invalid parameter values.
@ Valid
Parameter value is valid.
@ InvalidOutputExtension
Output parameter extension is invalid.
static QVariantMap preprocessQgisProcessParameters(const QVariantMap ¶meters, 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.
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.
Represents a vector layer which manages a vector based dataset.
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.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Encapsulates details of an external link describing an algorithm's behavior or source.