QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsprocessingalgorithmdialogbase.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprocessingalgorithmdialogbase.cpp
3  ------------------------------------
4  Date : November 2017
5  Copyright : (C) 2017 Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgssettings.h"
18 #include "qgshelp.h"
19 #include "qgsmessagebar.h"
20 #include "qgsgui.h"
23 #include "qgstaskmanager.h"
25 #include "qgsstringutils.h"
26 #include "qgsapplication.h"
27 #include "qgspanelwidget.h"
28 #include <QToolButton>
29 #include <QDesktopServices>
30 #include <QScrollBar>
31 #include <QApplication>
32 #include <QClipboard>
33 #include <QFileDialog>
34 
35 
37 
38 QgsProcessingAlgorithmDialogFeedback::QgsProcessingAlgorithmDialogFeedback()
39  : QgsProcessingFeedback( false )
40 {}
41 
42 void QgsProcessingAlgorithmDialogFeedback::setProgressText( const QString &text )
43 {
45  emit progressTextChanged( text );
46 }
47 
48 void QgsProcessingAlgorithmDialogFeedback::reportError( const QString &error, bool fatalError )
49 {
50  QgsProcessingFeedback::reportError( error, fatalError );
51  emit errorReported( error, fatalError );
52 }
53 
54 void QgsProcessingAlgorithmDialogFeedback::pushInfo( const QString &info )
55 {
57  emit infoPushed( info );
58 }
59 
60 void QgsProcessingAlgorithmDialogFeedback::pushCommandInfo( const QString &info )
61 {
63  emit commandInfoPushed( info );
64 }
65 
66 void QgsProcessingAlgorithmDialogFeedback::pushDebugInfo( const QString &info )
67 {
69  emit debugInfoPushed( info );
70 }
71 
72 void QgsProcessingAlgorithmDialogFeedback::pushConsoleInfo( const QString &info )
73 {
75  emit consoleInfoPushed( info );
76 }
77 
78 //
79 // QgsProcessingAlgorithmDialogBase
80 //
81 
82 QgsProcessingAlgorithmDialogBase::QgsProcessingAlgorithmDialogBase( QWidget *parent, Qt::WindowFlags flags )
83  : QDialog( parent, flags )
84 {
85  setupUi( this );
86 
87  //don't collapse parameters panel
88  splitter->setCollapsible( 0, false );
89 
90  // add collapse button to splitter
91  QSplitterHandle *splitterHandle = splitter->handle( 1 );
92  QVBoxLayout *handleLayout = new QVBoxLayout();
93  handleLayout->setContentsMargins( 0, 0, 0, 0 );
94  mButtonCollapse = new QToolButton( splitterHandle );
95  mButtonCollapse->setAutoRaise( true );
96  mButtonCollapse->setFixedSize( 12, 12 );
97  mButtonCollapse->setCursor( Qt::ArrowCursor );
98  handleLayout->addWidget( mButtonCollapse );
99  handleLayout->addStretch();
100  splitterHandle->setLayout( handleLayout );
101 
103 
104  QgsSettings settings;
105  splitter->restoreState( settings.value( QStringLiteral( "/Processing/dialogBaseSplitter" ), QByteArray() ).toByteArray() );
106  mSplitterState = splitter->saveState();
107  splitterChanged( 0, 0 );
108 
109  // Rename OK button to Run
110  mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
111  mButtonRun->setText( tr( "Run" ) );
112 
113  // Rename Yes button. Yes is used to ensure same position of Run and Change Parameters with respect to Close button.
114  mButtonChangeParameters = mButtonBox->button( QDialogButtonBox::Yes );
115  mButtonChangeParameters->setText( tr( "Change Parameters" ) );
116 
117  buttonCancel->setEnabled( false );
118  mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
119 
120  connect( mButtonRun, &QPushButton::clicked, this, &QgsProcessingAlgorithmDialogBase::runAlgorithm );
121  connect( mButtonChangeParameters, &QPushButton::clicked, this, &QgsProcessingAlgorithmDialogBase::showParameters );
122  connect( mButtonBox, &QDialogButtonBox::rejected, this, &QgsProcessingAlgorithmDialogBase::closeClicked );
123  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsProcessingAlgorithmDialogBase::openHelp );
124  connect( mButtonCollapse, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::toggleCollapsed );
125  connect( splitter, &QSplitter::splitterMoved, this, &QgsProcessingAlgorithmDialogBase::splitterChanged );
126 
127  connect( mButtonSaveLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::saveLog );
128  connect( mButtonCopyLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::copyLogToClipboard );
129  connect( mButtonClearLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::clearLog );
130 
131  connect( mTabWidget, &QTabWidget::currentChanged, this, &QgsProcessingAlgorithmDialogBase::mTabWidget_currentChanged );
132 
133  mMessageBar = new QgsMessageBar();
134  mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
135  verticalLayout->insertWidget( 0, mMessageBar );
136 
137  connect( QgsApplication::taskManager(), &QgsTaskManager::taskTriggered, this, &QgsProcessingAlgorithmDialogBase::taskTriggered );
138 }
139 
140 QgsProcessingAlgorithmDialogBase::~QgsProcessingAlgorithmDialogBase() = default;
141 
142 void QgsProcessingAlgorithmDialogBase::setAlgorithm( QgsProcessingAlgorithm *algorithm )
143 {
144  mAlgorithm.reset( algorithm );
145  QString title;
147  {
148  title = QgsStringUtils::capitalize( mAlgorithm->displayName(), QgsStringUtils::TitleCase );
149  }
150  else
151  {
152  title = mAlgorithm->displayName();
153  }
154  setWindowTitle( title );
155 
156  QString algHelp = formatHelp( algorithm );
157  if ( algHelp.isEmpty() )
158  textShortHelp->hide();
159  else
160  {
161  textShortHelp->document()->setDefaultStyleSheet( QStringLiteral( ".summary { margin-left: 10px; margin-right: 10px; }\n"
162  "h2 { color: #555555; padding-bottom: 15px; }\n"
163  "a { text - decoration: none; color: #3498db; font-weight: bold; }\n"
164  "p { color: #666666; }\n"
165  "b { color: #333333; }\n"
166  "dl dd { margin - bottom: 5px; }" ) );
167  textShortHelp->setHtml( algHelp );
168  connect( textShortHelp, &QTextBrowser::anchorClicked, this, &QgsProcessingAlgorithmDialogBase::linkClicked );
169  }
170 
171  if ( algorithm->helpUrl().isEmpty() && algorithm->provider()->helpId().isEmpty() )
172  {
173  mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Help ) );
174  }
175 
176  const QString warning = algorithm->provider()->warningMessage();
177  if ( !warning.isEmpty() )
178  {
179  mMessageBar->pushMessage( warning, Qgis::Warning, 0 );
180  }
181 }
182 
184 {
185  return mAlgorithm.get();
186 }
187 
188 void QgsProcessingAlgorithmDialogBase::setMainWidget( QgsPanelWidget *widget )
189 {
190  if ( mMainWidget )
191  {
192  mMainWidget->deleteLater();
193  }
194 
195  mPanelStack->setMainPanel( widget );
196  widget->setDockMode( true );
197 
198  mMainWidget = widget;
199  connect( mMainWidget, &QgsPanelWidget::panelAccepted, this, &QDialog::reject );
200 }
201 
202 QgsPanelWidget *QgsProcessingAlgorithmDialogBase::mainWidget()
203 {
204  return mMainWidget;
205 }
206 
207 void QgsProcessingAlgorithmDialogBase::saveLogToFile( const QString &path, const LogFormat format )
208 {
209  QFile logFile( path );
210  if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
211  {
212  return;
213  }
214  QTextStream fout( &logFile );
215 
216  switch ( format )
217  {
218  case FormatPlainText:
219  fout << txtLog->toPlainText();
220  break;
221 
222  case FormatHtml:
223  fout << txtLog->toHtml();
224  break;
225  }
226 }
227 
228 QgsProcessingFeedback *QgsProcessingAlgorithmDialogBase::createFeedback()
229 {
230  auto feedback = qgis::make_unique< QgsProcessingAlgorithmDialogFeedback >();
231  connect( feedback.get(), &QgsProcessingFeedback::progressChanged, this, &QgsProcessingAlgorithmDialogBase::setPercentage );
232  connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::commandInfoPushed, this, &QgsProcessingAlgorithmDialogBase::pushCommandInfo );
233  connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::consoleInfoPushed, this, &QgsProcessingAlgorithmDialogBase::pushConsoleInfo );
234  connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::debugInfoPushed, this, &QgsProcessingAlgorithmDialogBase::pushDebugInfo );
235  connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::errorReported, this, &QgsProcessingAlgorithmDialogBase::reportError );
236  connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::infoPushed, this, &QgsProcessingAlgorithmDialogBase::pushInfo );
237  connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::progressTextChanged, this, &QgsProcessingAlgorithmDialogBase::setProgressText );
238  connect( buttonCancel, &QPushButton::clicked, feedback.get(), &QgsProcessingFeedback::cancel );
239  return feedback.release();
240 }
241 
242 QDialogButtonBox *QgsProcessingAlgorithmDialogBase::buttonBox()
243 {
244  return mButtonBox;
245 }
246 
247 QTabWidget *QgsProcessingAlgorithmDialogBase::tabWidget()
248 {
249  return mTabWidget;
250 }
251 
252 void QgsProcessingAlgorithmDialogBase::showLog()
253 {
254  mTabWidget->setCurrentIndex( 1 );
255 }
256 
257 void QgsProcessingAlgorithmDialogBase::showParameters()
258 {
259  mTabWidget->setCurrentIndex( 0 );
260 }
261 
262 QPushButton *QgsProcessingAlgorithmDialogBase::runButton()
263 {
264  return mButtonRun;
265 }
266 
267 QPushButton *QgsProcessingAlgorithmDialogBase::cancelButton()
268 {
269  return buttonCancel;
270 }
271 
272 QPushButton *QgsProcessingAlgorithmDialogBase::changeParametersButton()
273 {
274  return mButtonChangeParameters;
275 }
276 
277 void QgsProcessingAlgorithmDialogBase::clearProgress()
278 {
279  progressBar->setMaximum( 0 );
280 }
281 
282 void QgsProcessingAlgorithmDialogBase::setExecuted( bool executed )
283 {
284  mExecuted = executed;
285 }
286 
287 void QgsProcessingAlgorithmDialogBase::setExecutedAnyResult( bool executedAnyResult )
288 {
289  mExecutedAnyResult = executedAnyResult;
290 }
291 
292 void QgsProcessingAlgorithmDialogBase::setResults( const QVariantMap &results )
293 {
294  mResults = results;
295 }
296 
297 void QgsProcessingAlgorithmDialogBase::finished( bool, const QVariantMap &, QgsProcessingContext &, QgsProcessingFeedback * )
298 {
299 
300 }
301 
302 void QgsProcessingAlgorithmDialogBase::openHelp()
303 {
304  QUrl algHelp = mAlgorithm->helpUrl();
305  if ( algHelp.isEmpty() )
306  {
307  algHelp = QgsHelp::helpUrl( QStringLiteral( "processing_algs/%1/%2.html#%3" ).arg( mAlgorithm->provider()->helpId(), mAlgorithm->groupId(), QStringLiteral( "%1%2" ).arg( mAlgorithm->provider()->helpId() ).arg( mAlgorithm->name() ) ) );
308  }
309 
310  if ( !algHelp.isEmpty() )
311  QDesktopServices::openUrl( algHelp );
312 }
313 
314 void QgsProcessingAlgorithmDialogBase::toggleCollapsed()
315 {
316  if ( mHelpCollapsed )
317  {
318  splitter->restoreState( mSplitterState );
319  mButtonCollapse->setArrowType( Qt::RightArrow );
320  }
321  else
322  {
323  mSplitterState = splitter->saveState();
324  splitter->setSizes( QList<int>() << 1 << 0 );
325  mButtonCollapse->setArrowType( Qt::LeftArrow );
326  }
327  mHelpCollapsed = !mHelpCollapsed;
328 }
329 
330 void QgsProcessingAlgorithmDialogBase::splitterChanged( int, int )
331 {
332  if ( splitter->sizes().at( 1 ) == 0 )
333  {
334  mHelpCollapsed = true;
335  mButtonCollapse->setArrowType( Qt::LeftArrow );
336  }
337  else
338  {
339  mHelpCollapsed = false;
340  mButtonCollapse->setArrowType( Qt::RightArrow );
341  }
342 }
343 
344 void QgsProcessingAlgorithmDialogBase::mTabWidget_currentChanged( int )
345 {
346  updateRunButtonVisibility();
347 }
348 
349 void QgsProcessingAlgorithmDialogBase::linkClicked( const QUrl &url )
350 {
351  QDesktopServices::openUrl( url.toString() );
352 }
353 
354 void QgsProcessingAlgorithmDialogBase::algExecuted( bool successful, const QVariantMap & )
355 {
356  mAlgorithmTask = nullptr;
357 
358  if ( !successful )
359  {
360  // show dialog to display errors
361  show();
362  raise();
363  setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
364  activateWindow();
365  showLog();
366  }
367  else
368  {
369  // delete dialog if closed
370  if ( !isVisible() )
371  {
372  deleteLater();
373  }
374  }
375 }
376 
377 void QgsProcessingAlgorithmDialogBase::taskTriggered( QgsTask *task )
378 {
379  if ( task == mAlgorithmTask )
380  {
381  show();
382  raise();
383  setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
384  activateWindow();
385  showLog();
386  }
387 }
388 
389 void QgsProcessingAlgorithmDialogBase::closeClicked()
390 {
391  reject();
392  close();
393 }
394 
395 void QgsProcessingAlgorithmDialogBase::reportError( const QString &error, bool fatalError )
396 {
397  setInfo( error, true );
398  if ( fatalError )
399  resetGui();
400  showLog();
401  processEvents();
402 }
403 
404 void QgsProcessingAlgorithmDialogBase::pushInfo( const QString &info )
405 {
406  setInfo( info );
407  processEvents();
408 }
409 
410 void QgsProcessingAlgorithmDialogBase::pushCommandInfo( const QString &command )
411 {
412  txtLog->append( QStringLiteral( "<code>%1<code>" ).arg( formatStringForLog( command.toHtmlEscaped() ) ) );
413  scrollToBottomOfLog();
414  processEvents();
415 }
416 
417 void QgsProcessingAlgorithmDialogBase::pushDebugInfo( const QString &message )
418 {
419  txtLog->append( QStringLiteral( "<span style=\"color:#777\">%1</span>" ).arg( formatStringForLog( message.toHtmlEscaped() ) ) );
420  scrollToBottomOfLog();
421  processEvents();
422 }
423 
424 void QgsProcessingAlgorithmDialogBase::pushConsoleInfo( const QString &info )
425 {
426  txtLog->append( QStringLiteral( "<code style=\"color:#777\">%1</code>" ).arg( formatStringForLog( info.toHtmlEscaped() ) ) );
427  scrollToBottomOfLog();
428  processEvents();
429 }
430 
431 QDialog *QgsProcessingAlgorithmDialogBase::createProgressDialog()
432 {
433  QgsProcessingAlgorithmProgressDialog *dialog = new QgsProcessingAlgorithmProgressDialog( this );
434  dialog->setWindowModality( Qt::ApplicationModal );
435  dialog->setWindowTitle( windowTitle() );
436  dialog->setGeometry( geometry() ); // match size/position to this dialog
437  connect( progressBar, &QProgressBar::valueChanged, dialog->progressBar(), &QProgressBar::setValue );
438  connect( dialog->cancelButton(), &QPushButton::clicked, buttonCancel, &QPushButton::click );
439  dialog->logTextEdit()->setHtml( txtLog->toHtml() );
440  connect( txtLog, &QTextEdit::textChanged, dialog, [this, dialog]()
441  {
442  dialog->logTextEdit()->setHtml( txtLog->toHtml() );
443  QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
444  sb->setValue( sb->maximum() );
445  } );
446  return dialog;
447 }
448 
449 void QgsProcessingAlgorithmDialogBase::clearLog()
450 {
451  txtLog->clear();
452 }
453 
454 void QgsProcessingAlgorithmDialogBase::saveLog()
455 {
456  QgsSettings settings;
457  QString lastUsedDir = settings.value( QStringLiteral( "/Processing/lastUsedLogDirectory" ), QDir::homePath() ).toString();
458 
459  QString filter;
460  const QString txtExt = tr( "Text files" ) + QStringLiteral( " (*.txt *.TXT)" );
461  const QString htmlExt = tr( "HTML files" ) + QStringLiteral( " (*.html *.HTML)" );
462 
463  QString path = QFileDialog::getSaveFileName( this, tr( "Save Log to File" ), lastUsedDir, txtExt + ";;" + htmlExt, &filter );
464  if ( path.isEmpty() )
465  {
466  return;
467  }
468 
469  settings.setValue( QStringLiteral( "/Processing/lastUsedLogDirectory" ), QFileInfo( path ).path() );
470 
471  LogFormat format = FormatPlainText;
472  if ( filter == htmlExt )
473  {
474  format = FormatHtml;
475  }
476  saveLogToFile( path, format );
477 }
478 
479 void QgsProcessingAlgorithmDialogBase::copyLogToClipboard()
480 {
481  QMimeData *m = new QMimeData();
482  m->setText( txtLog->toPlainText() );
483  m->setHtml( txtLog->toHtml() );
484  QClipboard *cb = QApplication::clipboard();
485 
486 #ifdef Q_OS_LINUX
487  cb->setMimeData( m, QClipboard::Selection );
488 #endif
489  cb->setMimeData( m, QClipboard::Clipboard );
490 }
491 
492 void QgsProcessingAlgorithmDialogBase::closeEvent( QCloseEvent *e )
493 {
494  if ( !mHelpCollapsed )
495  {
496  QgsSettings settings;
497  settings.setValue( QStringLiteral( "/Processing/dialogBaseSplitter" ), splitter->saveState() );
498  }
499 
500  QDialog::closeEvent( e );
501 
502  if ( !mAlgorithmTask )
503  {
504  // when running a background task, the dialog is kept around and deleted only when the task
505  // completes. But if not running a task, we auto cleanup (later - gotta give callers a chance
506  // to retrieve results and execution status).
507  deleteLater();
508  }
509 }
510 
511 void QgsProcessingAlgorithmDialogBase::runAlgorithm()
512 {
513 
514 }
515 
516 void QgsProcessingAlgorithmDialogBase::setPercentage( double percent )
517 {
518  // delay setting maximum progress value until we know algorithm reports progress
519  if ( progressBar->maximum() == 0 )
520  progressBar->setMaximum( 100 );
521  progressBar->setValue( percent );
522  processEvents();
523 }
524 
525 void QgsProcessingAlgorithmDialogBase::setProgressText( const QString &text )
526 {
527  lblProgress->setText( text );
528  setInfo( text, false );
529  scrollToBottomOfLog();
530  processEvents();
531 }
532 
533 QString QgsProcessingAlgorithmDialogBase::formatHelp( QgsProcessingAlgorithm *algorithm )
534 {
535  QString text = algorithm->shortHelpString();
536  if ( !text.isEmpty() )
537  {
538  QStringList paragraphs = text.split( '\n' );
539  QString help;
540  for ( const QString &paragraph : paragraphs )
541  {
542  help += QStringLiteral( "<p>%1</p>" ).arg( paragraph );
543  }
544  return QStringLiteral( "<h2>%1</h2>%2" ).arg( algorithm->displayName(), help );
545  }
546  else if ( !algorithm->shortDescription().isEmpty() )
547  {
548  return QStringLiteral( "<h2>%1</h2><p>%2</p>" ).arg( algorithm->displayName(), algorithm->shortDescription() );
549  }
550  else
551  return QString();
552 }
553 
554 void QgsProcessingAlgorithmDialogBase::processEvents()
555 {
556  if ( mAlgorithmTask )
557  {
558  // no need to call this - the algorithm is running in a thread.
559  // in fact, calling it causes a crash on Windows when the algorithm
560  // is running in a background thread... unfortunately we need something
561  // like this for non-threadable algorithms, otherwise there's no chance
562  // for users to hit cancel or see progress updates...
563  return;
564  }
565 
566  // So that we get a chance of hitting the Abort button
567 #ifdef Q_OS_LINUX
568  // One iteration is actually enough on Windows to get good interactivity
569  // whereas on Linux we must allow for far more iterations.
570  // For safety limit the number of iterations
571  int nIters = 0;
572  while ( ++nIters < 100 )
573 #endif
574  {
575  QCoreApplication::processEvents();
576  }
577 }
578 
579 void QgsProcessingAlgorithmDialogBase::scrollToBottomOfLog()
580 {
581  QScrollBar *sb = txtLog->verticalScrollBar();
582  sb->setValue( sb->maximum() );
583 }
584 
585 void QgsProcessingAlgorithmDialogBase::resetGui()
586 {
587  lblProgress->clear();
588  progressBar->setMaximum( 100 );
589  progressBar->setValue( 0 );
590  mButtonRun->setEnabled( true );
591  mButtonChangeParameters->setEnabled( true );
592  mButtonClose->setEnabled( true );
593  if ( mMainWidget )
594  {
595  mMainWidget->setEnabled( true );
596  }
597  updateRunButtonVisibility();
598  resetAdditionalGui();
599 }
600 
601 void QgsProcessingAlgorithmDialogBase::updateRunButtonVisibility()
602 {
603  // Activate run button if current tab is Parameters
604  bool runButtonVisible = mTabWidget->currentIndex() == 0;
605  mButtonRun->setVisible( runButtonVisible );
606  mButtonChangeParameters->setVisible( !runButtonVisible && mExecutedAnyResult && mButtonChangeParameters->isEnabled() );
607 }
608 
609 void QgsProcessingAlgorithmDialogBase::resetAdditionalGui()
610 {
611 
612 }
613 
614 void QgsProcessingAlgorithmDialogBase::blockControlsWhileRunning()
615 {
616  mButtonRun->setEnabled( false );
617  mButtonChangeParameters->setEnabled( false );
618  if ( mMainWidget )
619  {
620  mMainWidget->setEnabled( false );
621  }
622  blockAdditionalControlsWhileRunning();
623 }
624 
625 void QgsProcessingAlgorithmDialogBase::blockAdditionalControlsWhileRunning()
626 {
627 
628 }
629 
630 QgsMessageBar *QgsProcessingAlgorithmDialogBase::messageBar()
631 {
632  return mMessageBar;
633 }
634 
635 void QgsProcessingAlgorithmDialogBase::hideShortHelp()
636 {
637  textShortHelp->setVisible( false );
638 }
639 
640 void QgsProcessingAlgorithmDialogBase::setCurrentTask( QgsProcessingAlgRunnerTask *task )
641 {
642  mAlgorithmTask = task;
643  connect( mAlgorithmTask, &QgsProcessingAlgRunnerTask::executed, this, &QgsProcessingAlgorithmDialogBase::algExecuted );
644  QgsApplication::taskManager()->addTask( mAlgorithmTask );
645 }
646 
647 QString QgsProcessingAlgorithmDialogBase::formatStringForLog( const QString &string )
648 {
649  QString s = string;
650  s.replace( '\n', QLatin1String( "<br>" ) );
651  return s;
652 }
653 
654 void QgsProcessingAlgorithmDialogBase::setInfo( const QString &message, bool isError, bool escapeHtml )
655 {
656  // note -- we have to wrap the message in a span block, or QTextEdit::append sometimes gets confused
657  // and varies between treating it as a HTML string or a plain text string! (see https://github.com/qgis/QGIS/issues/37934)
658  if ( isError )
659  txtLog->append( QStringLiteral( "<span style=\"color:red\">%1</span>" ).arg( escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
660  else if ( escapeHtml )
661  txtLog->append( QStringLiteral( "<span>%1</span" ).arg( formatStringForLog( message.toHtmlEscaped() ) ) );
662  else
663  txtLog->append( QStringLiteral( "<span>%1</span>" ).arg( formatStringForLog( message ) ) );
664  scrollToBottomOfLog();
665  processEvents();
666 }
667 
668 void QgsProcessingAlgorithmDialogBase::reject()
669 {
670  if ( !mAlgorithmTask )
671  {
672  setAttribute( Qt::WA_DeleteOnClose );
673  }
674  QDialog::reject();
675 }
676 
677 //
678 // QgsProcessingAlgorithmProgressDialog
679 //
680 
681 QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
682  : QDialog( parent )
683 {
684  setupUi( this );
685 }
686 
687 QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
688 {
689  return mProgressBar;
690 }
691 
692 QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
693 {
694  return mButtonBox->button( QDialogButtonBox::Cancel );
695 }
696 
697 QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
698 {
699  return mTxtLog;
700 }
701 
702 void QgsProcessingAlgorithmProgressDialog::reject()
703 {
704 
705 }
706 
707 
708 
QgsProcessingAlgorithm::shortDescription
virtual QString shortDescription() const
Returns an optional translated short description of the algorithm.
Definition: qgsprocessingalgorithm.cpp:58
QgsProcessingAlgRunnerTask
QgsTask task which runs a QgsProcessingAlgorithm in a background task.
Definition: qgsprocessingalgrunnertask.h:36
QgsProcessingFeedback::setProgressText
virtual void setProgressText(const QString &text)
Sets a progress report text string.
Definition: qgsprocessingfeedback.cpp:35
QgsProcessingFeedback::pushCommandInfo
virtual void pushCommandInfo(const QString &info)
Pushes an informational message containing a command from the algorithm.
Definition: qgsprocessingfeedback.cpp:57
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsProcessingAlgorithm::displayName
virtual QString displayName() const =0
Returns the translated algorithm name, which should be used for any user-visible display of the algor...
QgsPanelWidget::setDockMode
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
Definition: qgspanelwidget.cpp:44
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:38
qgstaskmanager.h
algorithm
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
qgsstringutils.h
qgsgui.h
QgsProcessingFeedback::pushInfo
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
Definition: qgsprocessingfeedback.cpp:48
QgsProcessingFeedback::reportError
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
Definition: qgsprocessingfeedback.cpp:39
Qgis::Warning
@ Warning
Definition: qgis.h:91
QgsGui::higFlags
static QgsGui::HigFlags higFlags()
Returns the platform's HIG flags.
Definition: qgsgui.cpp:158
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QgsGui::HigDialogTitleIsTitleCase
@ HigDialogTitleIsTitleCase
Dialog titles should be title case.
Definition: qgsgui.h:184
QgsFeedback::cancel
void cancel()
Tells the internal routines that the current operation should be canceled. This should be run by the ...
Definition: qgsfeedback.h:84
QgsTaskManager::addTask
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Definition: qgstaskmanager.cpp:416
QgsProcessingFeedback::pushConsoleInfo
virtual void pushConsoleInfo(const QString &info)
Pushes a console feedback message from the algorithm.
Definition: qgsprocessingfeedback.cpp:75
qgsapplication.h
QgsGui::enableAutoGeometryRestore
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:139
QgsPanelWidget
Base class for any widget that can be shown as a inline panel.
Definition: qgspanelwidget.h:30
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:44
qgsprocessingalgorithm.h
QgsPanelWidget::panelAccepted
void panelAccepted(QgsPanelWidget *panel)
Emitted when the panel is accepted by the user.
QgsProcessingFeatureBasedAlgorithm::flags
QgsProcessingAlgorithm::Flags flags() const override
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Definition: qgsprocessingalgorithm.cpp:903
QgsProcessingAlgRunnerTask::executed
void executed(bool successful, const QVariantMap &results)
Emitted when the algorithm has finished execution.
QgsApplication::taskManager
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
Definition: qgsapplication.cpp:2133
QgsMessageBar
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
QgsProcessingAlgorithm::shortHelpString
virtual QString shortHelpString() const
Returns a localised short helper string for the algorithm.
Definition: qgsprocessingalgorithm.cpp:63
QgsFeedback::progressChanged
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
qgsmessagebar.h
QgsProcessingProvider::warningMessage
virtual QString warningMessage() const
Returns an optional warning message to show users when running algorithms from this provider.
Definition: qgsprocessingprovider.h:145
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:289
QgsStringUtils::capitalize
static QString capitalize(const QString &string, Capitalization capitalization)
Converts a string by applying capitalization rules to the string.
Definition: qgsstringutils.cpp:25
QgsStringUtils::TitleCase
@ TitleCase
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
Definition: qgsstringutils.h:194
QgsProcessingFeedback::pushDebugInfo
virtual void pushDebugInfo(const QString &info)
Pushes an informational message containing debugging helpers from the algorithm.
Definition: qgsprocessingfeedback.cpp:66
QgsProcessingAlgorithm::helpUrl
virtual QString helpUrl() const
Returns a url pointing to the algorithm's help page.
Definition: qgsprocessingalgorithm.cpp:73
QgsProcessingProvider::helpId
virtual QString helpId() const
Returns the provider help id string, used for creating QgsHelp urls for algorithms belong to this pro...
Definition: qgsprocessingprovider.cpp:49
qgsprocessingalgrunnertask.h
QgsProcessingAlgorithm::FlagDisplayNameIsLiteral
@ FlagDisplayNameIsLiteral
Algorithm's display name is a static literal string, and should not be translated or automatically fo...
Definition: qgsprocessingalgorithm.h:76
QgsProcessingAlgorithm
Abstract base class for processing algorithms.
Definition: qgsprocessingalgorithm.h:52
qgssettings.h
QgsHelp::helpUrl
static QUrl helpUrl(const QString &key)
Returns URI of the help topic for the given key.
Definition: qgshelp.cpp:41
qgsprocessingalgorithmdialogbase.h
QgsTaskManager::taskTriggered
void taskTriggered(QgsTask *task)
Emitted when a task is triggered.
qgspanelwidget.h
QgsProcessingAlgorithm::provider
QgsProcessingProvider * provider() const
Returns the provider to which this algorithm belongs.
Definition: qgsprocessingalgorithm.cpp:128
qgsprocessingprovider.h
qgshelp.h
QgsTask
Abstract base class for long running background tasks.
Definition: qgstaskmanager.h:53