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