18#include <nlohmann/json.hpp>
39#include <QApplication>
41#include <QDesktopServices>
50#include "moc_qgsprocessingalgorithmwidgetbase.cpp"
52using namespace Qt::StringLiterals;
60QgsProcessingFeedbackGenerator::~QgsProcessingFeedbackGenerator()
67QgsProcessingAlgorithmWidgetBase::QgsProcessingAlgorithmWidgetBase(
76 splitter->setCollapsible( 0,
false );
79 QSplitterHandle *splitterHandle = splitter->handle( 1 );
80 QVBoxLayout *handleLayout =
new QVBoxLayout();
81 handleLayout->setContentsMargins( 0, 0, 0, 0 );
82 mButtonCollapse =
new QToolButton( splitterHandle );
83 mButtonCollapse->setAutoRaise(
true );
84 mButtonCollapse->setFixedSize( 12, 12 );
85 mButtonCollapse->setCursor( Qt::ArrowCursor );
86 handleLayout->addWidget( mButtonCollapse );
87 handleLayout->addStretch();
88 splitterHandle->setLayout( handleLayout );
92 txtLog->setOpenLinks(
false );
93 connect( txtLog, &QTextBrowser::anchorClicked,
this, &QgsProcessingAlgorithmWidgetBase::urlClicked );
96 splitter->restoreState( settings.
value( u
"/Processing/dialogBaseSplitter"_s, QByteArray() ).toByteArray() );
97 mSplitterState = splitter->saveState();
98 splitterChanged( 0, 0 );
101 mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
102 mButtonRun->setText( tr(
"Run" ) );
105 mButtonChangeParameters = mButtonBox->button( QDialogButtonBox::Yes );
106 mButtonChangeParameters->setText( tr(
"Change Parameters" ) );
108 connect( buttonCancel, &QPushButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::cancel );
109 buttonCancel->setEnabled(
false );
110 mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
113 parentWindow = qobject_cast< QMainWindow * >( QApplication::activeWindow() );
115 bool defaultIsDocked =
false;
116 QString dockId = u
"ProcessingAlgorithm"_s;
117 if ( flags.testFlags( QgsProcessingAlgorithmWidgetBase::WidgetFlag::NoDocking ) )
120 dockId = u
"ProcessingAlgorithmNonDockable"_s;
124 dockId = u
"ProcessingAlgorithmForceDocked"_s;
127 mDockableWidgetHelper
128 =
new QgsDockableWidgetHelper( tr(
"Processing" ),
this, parentWindow, dockId, QStringList(), initialState, defaultIsDocked, Qt::DockWidgetArea::RightDockWidgetArea, QgsDockableWidgetHelper::Option::RaiseTab );
129 connect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed,
this, &QgsProcessingAlgorithmWidgetBase::closeClicked );
133 case QgsProcessingAlgorithmWidgetBase::WidgetMode::Single:
135 mAdvancedButton =
new QPushButton( tr(
"Advanced" ) );
136 mAdvancedMenu =
new QMenu(
this );
137 mAdvancedButton->setMenu( mAdvancedMenu );
139 mContextSettingsAction =
new QAction( tr(
"Algorithm Settingsā¦" ), mAdvancedMenu );
141 mAdvancedMenu->addAction( mContextSettingsAction );
143 connect( mContextSettingsAction, &QAction::triggered,
this, [
this] {
146 mTabWidget->setCurrentIndex( 0 );
148 if ( !mContextOptionsWidget )
150 mContextOptionsWidget =
new QgsProcessingContextOptionsWidget();
151 mContextOptionsWidget->setFromContext( processingContext() );
152 mContextOptionsWidget->setLogLevel( mLogLevel );
153 panel->openPanel( mContextOptionsWidget );
156 mOverrideDefaultContextSettings =
true;
157 mGeometryCheck = mContextOptionsWidget->invalidGeometryCheck();
158 mDistanceUnits = mContextOptionsWidget->distanceUnit();
159 mAreaUnits = mContextOptionsWidget->areaUnit();
160 mTemporaryFolderOverride = mContextOptionsWidget->temporaryFolder();
161 mMaximumThreads = mContextOptionsWidget->maximumThreads();
162 mLogLevel = mContextOptionsWidget->logLevel();
167 mAdvancedMenu->addSeparator();
169 QAction *copyAsPythonCommand =
new QAction( tr(
"Copy as Python Command" ), mAdvancedMenu );
172 mAdvancedMenu->addAction( copyAsPythonCommand );
173 connect( copyAsPythonCommand, &QAction::triggered,
this, [
this] {
180 const QString command = alg->asPythonCommand( createProcessingParameters(), *context );
181 QMimeData *m =
new QMimeData();
182 m->setText( command );
183 QClipboard *cb = QApplication::clipboard();
185 if ( cb->supportsSelection() )
187 cb->setMimeData( m, QClipboard::Selection );
189 cb->setMimeData( m, QClipboard::Clipboard );
193 mCopyAsQgisProcessCommand =
new QAction( tr(
"Copy as qgis_process Command" ), mAdvancedMenu );
195 mAdvancedMenu->addAction( mCopyAsQgisProcessCommand );
197 connect( mCopyAsQgisProcessCommand, &QAction::triggered,
this, [
this] {
205 const QString command = alg->asQgisProcessCommand( createProcessingParameters(), *context, ok );
208 mMessageBar->pushMessage( tr(
"Current settings cannot be specified as arguments to qgis_process (Pipe parameters as JSON to qgis_process instead)" ),
Qgis::MessageLevel::Warning );
212 QMimeData *m =
new QMimeData();
213 m->setText( command );
214 QClipboard *cb = QApplication::clipboard();
216 if ( cb->supportsSelection() )
218 cb->setMimeData( m, QClipboard::Selection );
220 cb->setMimeData( m, QClipboard::Clipboard );
225 mAdvancedMenu->addSeparator();
227 QAction *copyAsJson =
new QAction( tr(
"Copy as JSON" ), mAdvancedMenu );
230 mAdvancedMenu->addAction( copyAsJson );
231 connect( copyAsJson, &QAction::triggered,
this, [
this] {
238 const QVariantMap properties = alg->asMap( createProcessingParameters(), *context );
241 QMimeData *m =
new QMimeData();
243 QClipboard *cb = QApplication::clipboard();
245 if ( cb->supportsSelection() )
247 cb->setMimeData( m, QClipboard::Selection );
249 cb->setMimeData( m, QClipboard::Clipboard );
253 mPasteJsonAction =
new QAction( tr(
"Paste Settings" ), mAdvancedMenu );
256 mAdvancedMenu->addAction( mPasteJsonAction );
257 connect( mPasteJsonAction, &QAction::triggered,
this, [
this] {
258 const QString text = QApplication::clipboard()->text();
259 if ( text.isEmpty() )
263 if ( parameterValues.isEmpty() )
270 setParameters( preparedValues );
273 mButtonBox->addButton( mAdvancedButton, QDialogButtonBox::ResetRole );
277 case QgsProcessingAlgorithmWidgetBase::WidgetMode::Batch:
283 connect( mAdvancedMenu, &QMenu::aboutToShow,
this, [
this] {
285 mPasteJsonAction->setEnabled( !QApplication::clipboard()->text().isEmpty() );
289 connect( mButtonRun, &QPushButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::runAlgorithm );
290 connect( mButtonChangeParameters, &QPushButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::showParameters );
291 connect( mButtonBox, &QDialogButtonBox::rejected,
this, &QgsProcessingAlgorithmWidgetBase::closeClicked );
292 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsProcessingAlgorithmWidgetBase::openHelp );
293 connect( mButtonCollapse, &QToolButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::toggleCollapsed );
294 connect( splitter, &QSplitter::splitterMoved,
this, &QgsProcessingAlgorithmWidgetBase::splitterChanged );
296 connect( mButtonSaveLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::saveLog );
297 connect( mButtonCopyLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::copyLogToClipboard );
298 connect( mButtonClearLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::clearLog );
300 connect( mTabWidget, &QTabWidget::currentChanged,
this, &QgsProcessingAlgorithmWidgetBase::mTabWidget_currentChanged );
303 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
304 verticalLayout->insertWidget( 0, mMessageBar );
309QgsProcessingAlgorithmWidgetBase::~QgsProcessingAlgorithmWidgetBase()
311 delete mDockableWidgetHelper;
314void QgsProcessingAlgorithmWidgetBase::setParameters(
const QVariantMap & )
317void QgsProcessingAlgorithmWidgetBase::setTitle(
const QString &title )
319 mDockableWidgetHelper->setWindowTitle( title );
322void QgsProcessingAlgorithmWidgetBase::exec()
328 mDockableWidgetHelper->setSettingKeyDockId( u
"ProcessingAlgorithmNonDockable"_s );
329 mDockableWidgetHelper->toggleDockMode(
false );
330 mDockableWidgetHelper->dialog()->exec();
339 title = mAlgorithm->group().isEmpty()
341 : u
"%1 - %2"_s.arg(
QgsStringUtils::capitalize( mAlgorithm->group(),
Qgis::Capitalization::TitleCase ),
QgsStringUtils::capitalize( mAlgorithm->displayName(),
Qgis::Capitalization::TitleCase ) );
345 title = mAlgorithm->group().isEmpty() ? mAlgorithm->displayName() : u
"%1 - %2"_s.arg( mAlgorithm->group(), mAlgorithm->displayName() );
347 mDockableWidgetHelper->setWindowTitle( title );
349 const QString algHelp = formatHelp(
algorithm );
350 if ( algHelp.isEmpty() )
351 textShortHelp->hide();
354 textShortHelp->document()->setDefaultStyleSheet( QStringLiteral(
355 ".summary { margin-left: 10px; margin-right: 10px; }\n"
356 "h2 { color: #555555; padding-bottom: 15px; }\n"
357 "a { text - decoration: none; color: #3498db; font-weight: bold; }\n"
358 "p, ul, li { color: #666666; }\n"
359 "b { color: #333333; }\n"
360 "dl dd { margin - bottom: 5px; }"
362 textShortHelp->setHtml( algHelp );
363 connect( textShortHelp, &QTextBrowser::anchorClicked,
this, &QgsProcessingAlgorithmWidgetBase::linkClicked );
364 textShortHelp->show();
369 mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Help ) );
372 const QString warning =
algorithm->provider() ?
algorithm->provider()->warningMessage() : QString();
373 if ( !warning.isEmpty() )
381 return mAlgorithm.get();
384void QgsProcessingAlgorithmWidgetBase::setMainWidget(
QgsPanelWidget *widget )
388 mMainWidget->deleteLater();
391 mPanelStack->setMainPanel( widget );
394 mMainWidget = widget;
403void QgsProcessingAlgorithmWidgetBase::saveLogToFile(
const QString &path,
const LogFormat format )
405 QFile logFile( path );
406 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
410 QTextStream fout( &logFile );
414 case QgsProcessingAlgorithmWidgetBase::LogFormat::FormatPlainText:
415 fout << txtLog->toPlainText();
418 case QgsProcessingAlgorithmWidgetBase::LogFormat::FormatHtml:
419 fout << txtLog->toHtml();
424void QgsProcessingAlgorithmWidgetBase::registerProcessingFeedbackGenerator( QgsProcessingFeedbackGenerator *factory )
426 mFeedbackFactory = factory;
431 std::unique_ptr< QgsProcessingFeedback > feedback;
432 if ( mFeedbackFactory )
434 feedback.reset( mFeedbackFactory->createFeedback() );
438 feedback = std::make_unique< QgsProcessingFeedback >();
450 return feedback.release();
453QDialogButtonBox *QgsProcessingAlgorithmWidgetBase::buttonBox()
458QTabWidget *QgsProcessingAlgorithmWidgetBase::tabWidget()
463void QgsProcessingAlgorithmWidgetBase::showLog()
465 mTabWidget->setCurrentIndex( 1 );
468void QgsProcessingAlgorithmWidgetBase::showParameters()
470 mTabWidget->setCurrentIndex( 0 );
473QPushButton *QgsProcessingAlgorithmWidgetBase::runButton()
478QPushButton *QgsProcessingAlgorithmWidgetBase::cancelButton()
483QPushButton *QgsProcessingAlgorithmWidgetBase::changeParametersButton()
485 return mButtonChangeParameters;
488void QgsProcessingAlgorithmWidgetBase::clearProgress()
490 progressBar->setMaximum( 0 );
493void QgsProcessingAlgorithmWidgetBase::setExecuted(
bool executed )
495 mExecuted = executed;
498void QgsProcessingAlgorithmWidgetBase::setExecutedAnyResult(
bool executedAnyResult )
500 mExecutedAnyResult = executedAnyResult;
503void QgsProcessingAlgorithmWidgetBase::setResults(
const QVariantMap &results )
511void QgsProcessingAlgorithmWidgetBase::openHelp()
513 QUrl algHelp = mAlgorithm->helpUrl();
514 if ( algHelp.isEmpty() && mAlgorithm->provider() && !mAlgorithm->provider()->helpId().isEmpty() )
517 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(
"_",
"-" ) ) )
521 if ( !algHelp.isEmpty() )
522 QDesktopServices::openUrl( algHelp );
525void QgsProcessingAlgorithmWidgetBase::toggleCollapsed()
527 if ( mHelpCollapsed )
529 splitter->restoreState( mSplitterState );
530 mButtonCollapse->setArrowType( Qt::RightArrow );
534 mSplitterState = splitter->saveState();
535 splitter->setSizes( QList<int>() << 1 << 0 );
536 mButtonCollapse->setArrowType( Qt::LeftArrow );
538 mHelpCollapsed = !mHelpCollapsed;
541void QgsProcessingAlgorithmWidgetBase::splitterChanged(
int,
int )
543 if ( splitter->sizes().at( 1 ) == 0 )
545 mHelpCollapsed =
true;
546 mButtonCollapse->setArrowType( Qt::LeftArrow );
550 mHelpCollapsed =
false;
551 mButtonCollapse->setArrowType( Qt::RightArrow );
555void QgsProcessingAlgorithmWidgetBase::mTabWidget_currentChanged(
int )
557 updateRunButtonVisibility();
560void QgsProcessingAlgorithmWidgetBase::linkClicked(
const QUrl &url )
562 if ( url.toString() ==
"#help"_L1 )
568 QDesktopServices::openUrl( url.toString() );
571void QgsProcessingAlgorithmWidgetBase::algExecuted(
bool successful,
const QVariantMap & )
573 mAlgorithmTask =
nullptr;
583 if ( isFinalized() && successful )
585 progressBar->setFormat( tr(
"Complete" ) );
589 if ( isFinalized() && !isVisible() )
596void QgsProcessingAlgorithmWidgetBase::taskTriggered(
QgsTask *task )
598 if ( task == mAlgorithmTask )
605void QgsProcessingAlgorithmWidgetBase::showWidget()
607 mDockableWidgetHelper->setUserVisible(
true );
610void QgsProcessingAlgorithmWidgetBase::closeClicked()
612 disconnect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed,
this, &QgsProcessingAlgorithmWidgetBase::closeClicked );
616 mDockableWidgetHelper->setUserVisible(
false );
625void QgsProcessingAlgorithmWidgetBase::urlClicked(
const QUrl &url )
627 const QFileInfo file( url.toLocalFile() );
628 if ( file.exists() && !file.isDir() )
630 if ( file.suffix().compare(
"html"_L1, Qt::CaseInsensitive ) == 0 )
632 QDesktopServices::openUrl( url );
640 QDesktopServices::openUrl( url );
653void QgsProcessingAlgorithmWidgetBase::reportError(
const QString &error,
bool fatalError )
655 setInfo( error,
true );
662void QgsProcessingAlgorithmWidgetBase::pushWarning(
const QString &warning )
664 setInfo( warning,
false,
true,
true );
668void QgsProcessingAlgorithmWidgetBase::pushInfo(
const QString &info )
674void QgsProcessingAlgorithmWidgetBase::pushFormattedMessage(
const QString &html )
676 setInfo( html,
false,
false );
680void QgsProcessingAlgorithmWidgetBase::pushCommandInfo(
const QString &command )
682 txtLog->append( u
"<code>%1<code>"_s.arg( formatStringForLog( command.toHtmlEscaped() ) ) );
683 scrollToBottomOfLog();
687void QgsProcessingAlgorithmWidgetBase::pushDebugInfo(
const QString &message )
689 txtLog->append( u
"<span style=\"color:#777\">%1</span>"_s.arg( formatStringForLog( message.toHtmlEscaped() ) ) );
690 scrollToBottomOfLog();
694void QgsProcessingAlgorithmWidgetBase::pushConsoleInfo(
const QString &info )
696 txtLog->append( u
"<code style=\"color:#777\">%1</code>"_s.arg( formatStringForLog( info.toHtmlEscaped() ) ) );
697 scrollToBottomOfLog();
701QDialog *QgsProcessingAlgorithmWidgetBase::createProgressDialog()
703 QgsProcessingAlgorithmProgressDialog *dialog =
new QgsProcessingAlgorithmProgressDialog(
this );
704 dialog->setWindowModality( Qt::ApplicationModal );
705 dialog->setWindowTitle( windowTitle() );
706 dialog->setGeometry( geometry() );
707 connect( progressBar, &QProgressBar::valueChanged, dialog->progressBar(), &QProgressBar::setValue );
708 connect( dialog->cancelButton(), &QPushButton::clicked,
this, &QgsProcessingAlgorithmWidgetBase::cancel );
709 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
710 connect( txtLog, &QTextEdit::textChanged, dialog, [
this, dialog]() {
711 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
712 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
713 sb->setValue( sb->maximum() );
718void QgsProcessingAlgorithmWidgetBase::clearLog()
723void QgsProcessingAlgorithmWidgetBase::saveLog()
726 const QString lastUsedDir = settings.
value( u
"/Processing/lastUsedLogDirectory"_s, QDir::homePath() ).toString();
729 const QString txtExt = tr(
"Text files" ) + u
" (*.txt *.TXT)"_s;
730 const QString htmlExt = tr(
"HTML files" ) + u
" (*.html *.HTML)"_s;
732 const QString path = QFileDialog::getSaveFileName(
this, tr(
"Save Log to File" ), lastUsedDir, txtExt +
";;" + htmlExt, &filter );
736 if ( path.isEmpty() )
741 settings.
setValue( u
"/Processing/lastUsedLogDirectory"_s, QFileInfo( path ).path() );
743 LogFormat format = QgsProcessingAlgorithmWidgetBase::LogFormat::FormatPlainText;
744 if ( filter == htmlExt )
746 format = QgsProcessingAlgorithmWidgetBase::LogFormat::FormatHtml;
748 saveLogToFile( path, format );
751void QgsProcessingAlgorithmWidgetBase::copyLogToClipboard()
753 QMimeData *m =
new QMimeData();
754 m->setText( txtLog->toPlainText() );
755 m->setHtml( txtLog->toHtml() );
756 QClipboard *cb = QApplication::clipboard();
758 if ( cb->supportsSelection() )
760 cb->setMimeData( m, QClipboard::Selection );
762 cb->setMimeData( m, QClipboard::Clipboard );
765void QgsProcessingAlgorithmWidgetBase::closeEvent( QCloseEvent *e )
767 if ( !mHelpCollapsed )
770 settings.
setValue( u
"/Processing/dialogBaseSplitter"_s, splitter->saveState() );
773 QWidget::closeEvent( e );
775 if ( !mAlgorithmTask && isFinalized() )
784void QgsProcessingAlgorithmWidgetBase::runAlgorithm()
787void QgsProcessingAlgorithmWidgetBase::setPercentage(
double percent )
790 if ( progressBar->maximum() == 0 )
791 progressBar->setMaximum( 100 );
792 progressBar->setValue( percent );
796void QgsProcessingAlgorithmWidgetBase::setProgressText(
const QString &text )
798 lblProgress->setText( text );
799 setInfo( text,
false );
800 scrollToBottomOfLog();
807 const QString text =
algorithm->shortHelpString();
808 if ( !text.isEmpty() )
810 const QStringList paragraphs = text.split(
'\n' );
812 for (
const QString ¶graph : paragraphs )
814 help += u
"<p>%1</p>"_s.arg( paragraph );
816 result = u
"<h2>%1</h2>%2"_s.arg(
algorithm->displayName(), help );
818 else if ( !
algorithm->shortDescription().isEmpty() )
820 result = u
"<h2>%1</h2><p>%2</p>"_s.arg(
algorithm->displayName(),
algorithm->shortDescription() );
823 const QList< QgsAcademicReference > references =
algorithm->academicReferences();
824 if ( !references.empty() )
826 QStringList referenceStrings;
829 referenceStrings << reference.asHtml();
831 result += u
"<h4>%1</h4>"_s.arg( tr(
"References" ) );
832 result += u
"<ul><li>%1</li></ul>"_s.arg( referenceStrings.join(
"</li><li>"_L1 ) );
840 if (
algorithm->documentationFlags() & flag )
845 result += u
"<ul><li><i>%1</i></li></ul>"_s.arg( flags.join(
"</i></li><li><i>"_L1 ) );
849 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." ) );
853 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." ) );
861 const QString linkHtml = QStringLiteral( R
"(<a href="#help">%1</a>)" ).arg( tr( "Algorithm documentation" ) );
865 const QString implementationSourceUri =
algorithm->implementationSourceUri();
866 if ( !implementationSourceUri.isEmpty() )
868 const QString linkHtml = QStringLiteral( R
"(<a href="%1">%2</a>)" ).arg( implementationSourceUri, tr( "Algorithm source code" ) );
872 const QList< QgsProcessingAlgorithm::ExternalLink > externalLinks =
algorithm->externalLinks();
875 const QString linkHtml = QStringLiteral( R
"(<a href="%1">%2</a>)" ).arg( link.url, link.description );
879 if ( !links.empty() )
881 result += u
"<h4>%1</h4>"_s.arg( tr(
"Links" ) );
882 result += u
"<ul><li>%1</li></ul>"_s.arg( links.join(
"</li><li>"_L1 ) );
888void QgsProcessingAlgorithmWidgetBase::processEvents()
890 if ( mAlgorithmTask )
906 while ( ++nIters < 100 )
909 QCoreApplication::processEvents();
913void QgsProcessingAlgorithmWidgetBase::scrollToBottomOfLog()
915 QScrollBar *sb = txtLog->verticalScrollBar();
916 sb->setValue( sb->maximum() );
919void QgsProcessingAlgorithmWidgetBase::resetGui()
921 lblProgress->clear();
922 progressBar->setMaximum( 100 );
923 progressBar->setValue( 0 );
924 mButtonRun->setEnabled(
true );
925 mButtonChangeParameters->setEnabled(
true );
926 mButtonClose->setEnabled(
true );
929 mMainWidget->setEnabled(
true );
931 updateRunButtonVisibility();
932 resetAdditionalGui();
935void QgsProcessingAlgorithmWidgetBase::updateRunButtonVisibility()
938 const bool runButtonVisible = mTabWidget->currentIndex() == 0;
939 mButtonRun->setVisible( runButtonVisible );
940 if ( runButtonVisible )
941 progressBar->resetFormat();
942 mButtonChangeParameters->setVisible( !runButtonVisible && mExecutedAnyResult && mButtonChangeParameters->isEnabled() );
945void QgsProcessingAlgorithmWidgetBase::resetAdditionalGui()
948void QgsProcessingAlgorithmWidgetBase::blockControlsWhileRunning()
950 mButtonRun->setEnabled(
false );
951 mButtonChangeParameters->setEnabled(
false );
954 mMainWidget->setEnabled(
false );
956 blockAdditionalControlsWhileRunning();
959void QgsProcessingAlgorithmWidgetBase::blockAdditionalControlsWhileRunning()
967void QgsProcessingAlgorithmWidgetBase::hideShortHelp()
969 textShortHelp->setVisible(
false );
974 mAlgorithmTask = task;
979void QgsProcessingAlgorithmWidgetBase::disconnectCurrentTask()
981 if ( mAlgorithmTask )
984 mAlgorithmTask =
nullptr;
988QString QgsProcessingAlgorithmWidgetBase::formatStringForLog(
const QString &
string )
991 s.replace(
'\n',
"<br>"_L1 );
995bool QgsProcessingAlgorithmWidgetBase::isFinalized()
1000bool QgsProcessingAlgorithmWidgetBase::isRunning()
1005void QgsProcessingAlgorithmWidgetBase::cancel()
1007 emit cancelRequested();
1017 if ( mOverrideDefaultContextSettings )
1027void QgsProcessingAlgorithmWidgetBase::setInfo(
const QString &message,
bool isError,
bool escapeHtml,
bool isWarning )
1029 constexpr int MESSAGE_COUNT_LIMIT = 10000;
1031 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
1033 ++mMessageLoggedCount;
1037 if ( mMessageLoggedCount == MESSAGE_COUNT_LIMIT )
1038 txtLog->append( u
"<span style=\"color:red\">%1</span>"_s.arg( tr(
"Message log truncated" ) ) );
1039 else if ( isError || isWarning )
1040 txtLog->append( u
"<span style=\"color:%1\">%2</span>"_s.arg( isError ? u
"red"_s : u
"#b85a20"_s, escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
1041 else if ( escapeHtml )
1042 txtLog->append( u
"<span>%1</span"_s.arg( formatStringForLog( message.toHtmlEscaped() ) ) );
1044 txtLog->append( u
"<span>%1</span>"_s.arg( formatStringForLog( message ) ) );
1045 scrollToBottomOfLog();
1049void QgsProcessingAlgorithmWidgetBase::reject()
1051 if ( !mAlgorithmTask && isFinalized() )
1053 setAttribute( Qt::WA_DeleteOnClose );
1056 mDockableWidgetHelper->reject();
1059void QgsProcessingAlgorithmWidgetBase::forceClose()
1061 disconnectCurrentTask();
1069QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
1075QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
1077 return mProgressBar;
1080QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
1082 return mButtonBox->button( QDialogButtonBox::Cancel );
1085QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
1090void QgsProcessingAlgorithmProgressDialog::reject()
1098QgsProcessingContextOptionsWidget::QgsProcessingContextOptionsWidget( QWidget *parent )
1102 setPanelTitle( tr(
"Algorithm Settings" ) );
1108 mTemporaryFolderWidget->setDialogTitle( tr(
"Select Temporary Directory" ) );
1110 mTemporaryFolderWidget->lineEdit()->setPlaceholderText( tr(
"Default" ) );
1140 mDistanceUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1169 mAreaUnitsCombo->addItem( title, QVariant::fromValue( unit ) );
1172 mThreadsSpinBox->setRange( 1, QThread::idealThreadCount() );
1174 connect( mLogLevelComboBox, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &
QgsPanelWidget::changed );
1175 connect( mComboInvalidFeatureFiltering, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &
QgsPanelWidget::changed );
1176 connect( mDistanceUnitsCombo, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &
QgsPanelWidget::changed );
1177 connect( mAreaUnitsCombo, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &
QgsPanelWidget::changed );
1184 whileBlocking( mComboInvalidFeatureFiltering )->setCurrentIndex( mComboInvalidFeatureFiltering->findData( QVariant::fromValue( context->
invalidGeometryCheck() ) ) );
1185 whileBlocking( mDistanceUnitsCombo )->setCurrentIndex( mDistanceUnitsCombo->findData( QVariant::fromValue( context->
distanceUnit() ) ) );
1186 whileBlocking( mAreaUnitsCombo )->setCurrentIndex( mAreaUnitsCombo->findData( QVariant::fromValue( context->
areaUnit() ) ) );
1189 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData(
static_cast<int>( context->
logLevel() ) ) );
1202Qgis::AreaUnit QgsProcessingContextOptionsWidget::areaUnit()
const
1207QString QgsProcessingContextOptionsWidget::temporaryFolder()
1209 return mTemporaryFolderWidget->filePath();
1212int QgsProcessingContextOptionsWidget::maximumThreads()
const
1214 return mThreadsSpinBox->value();
1219 whileBlocking( mLogLevelComboBox )->setCurrentIndex( mLogLevelComboBox->findData(
static_cast<int>( level ) ) );
1233 : QgsProcessingAlgorithmWidgetBase( parentWindow, WidgetMode::Single, flags, initialState )
1234 , mInPlace( inPlace )
1238 connect( buttonBox(), &QDialogButtonBox::accepted,
this, [
this] {
1239 for ( QWidget *widget : std::as_const( mWidgetsToResetPalette ) )
1241 widget->setPalette( QPalette() );
1243 mWidgetsToResetPalette.clear();
1247QgsProcessingParametersWidget *QgsProcessingAlgorithmWidget::createParametersPanel(
bool inPlaceMode,
QgsVectorLayer *activeLayer,
QgsMessageBar *messageBar )
1249 auto widget =
new QgsProcessingParametersWidget(
algorithm(), inPlaceMode, activeLayer, messageBar );
1250 widget->registerProcessingContextGenerator(
this );
1251 widget->initWidgets();
1255QgsProcessingParametersWidget *QgsProcessingAlgorithmWidget::parametersWidget()
1257 return qobject_cast< QgsProcessingParametersWidget * >( mainWidget() );
1260void QgsProcessingAlgorithmWidget::flagInvalidParameterValue(
const QString &message, QWidget *widget )
1265 QPalette palette = widget->palette();
1266 palette.setColor( QPalette::ColorRole::Base, QColor( 255, 255, 0 ) );
1267 widget->setPalette( palette );
1268 mWidgetsToResetPalette.append( widget );
1274void QgsProcessingAlgorithmWidget::flagInvalidOutputExtension(
const QString &message, QWidget *widget )
1279 QPalette palette = widget->palette();
1280 palette.setColor( QPalette::ColorRole::Base, QColor( 255, 255, 0 ) );
1281 widget->setPalette( palette );
1282 mWidgetsToResetPalette.append( widget );
1288bool QgsProcessingAlgorithmWidget::handleValidationResults(
const QList<ParameterValidationResult> &results )
1290 bool allValid =
true;
1291 QgsProcessingParametersWidget *widget = parametersWidget();
1292 for (
const ParameterValidationResult &result : results )
1295 QWidget *widget = wrapper ? wrapper->
wrappedWidget() :
nullptr;
1298 switch ( result.result )
1303 flagInvalidOutputExtension( result.message, widget );
1307 flagInvalidParameterValue( parameter ? parameter->
description() : QString(), widget );
1316bool QgsProcessingAlgorithmWidget::inPlace()
const
1321void QgsProcessingAlgorithmWidget::setParameters(
const QVariantMap &values )
1323 if ( QgsProcessingParametersWidget *widget = parametersWidget() )
1325 widget->setParameters( values );
1329QVariantMap QgsProcessingAlgorithmWidget::createProcessingParameters( Flags flags )
1331 QgsProcessingParametersWidget *widget = parametersWidget();
1335 QList<ParameterValidationResult> validationResults;
1336 const QVariantMap parameters = widget->createAndValidateParameters( flags, validationResults );
1338 const bool allValid = handleValidationResults( validationResults );
1340 return allValid ? parameters : QVariantMap();
1352 mFeedback.reset(
const_cast< QgsProcessingAlgorithmWidget *
>(
this )->createFeedback() );
1356 const_cast< QgsProcessingAlgorithmWidget *
>( this )->applyContextOverrides( mContext.get() );
1357 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.