26 #include <QToolButton> 27 #include <QDesktopServices> 29 #include <QApplication> 31 #include <QFileDialog> 36 void QgsProcessingAlgorithmDialogFeedback::setProgressText(
const QString &text )
38 emit progressTextChanged( text );
41 void QgsProcessingAlgorithmDialogFeedback::reportError(
const QString &error,
bool fatalError )
43 emit errorReported( error, fatalError );
46 void QgsProcessingAlgorithmDialogFeedback::pushInfo(
const QString &info )
48 emit infoPushed( info );
51 void QgsProcessingAlgorithmDialogFeedback::pushCommandInfo(
const QString &info )
53 emit commandInfoPushed( info );
56 void QgsProcessingAlgorithmDialogFeedback::pushDebugInfo(
const QString &info )
58 emit debugInfoPushed( info );
61 void QgsProcessingAlgorithmDialogFeedback::pushConsoleInfo(
const QString &info )
63 emit consoleInfoPushed( info );
70 QgsProcessingAlgorithmDialogBase::QgsProcessingAlgorithmDialogBase( QWidget *parent, Qt::WindowFlags flags )
71 : QDialog( parent, flags )
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 );
93 splitter->restoreState( settings.
value( QStringLiteral(
"/Processing/dialogBaseSplitter" ), QByteArray() ).toByteArray() );
94 mSplitterState = splitter->saveState();
95 splitterChanged( 0, 0 );
97 connect( mButtonBox, &QDialogButtonBox::rejected,
this, &QgsProcessingAlgorithmDialogBase::closeClicked );
98 connect( mButtonBox, &QDialogButtonBox::accepted,
this, &QgsProcessingAlgorithmDialogBase::runAlgorithm );
101 mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
102 mButtonRun->setText( tr(
"Run" ) );
104 buttonCancel->setEnabled(
false );
105 mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
107 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsProcessingAlgorithmDialogBase::openHelp );
108 connect( mButtonCollapse, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::toggleCollapsed );
109 connect( splitter, &QSplitter::splitterMoved,
this, &QgsProcessingAlgorithmDialogBase::splitterChanged );
111 connect( mButtonSaveLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::saveLog );
112 connect( mButtonCopyLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::copyLogToClipboard );
113 connect( mButtonClearLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::clearLog );
116 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
117 verticalLayout->insertWidget( 0, mMessageBar );
122 QgsProcessingAlgorithmDialogBase::~QgsProcessingAlgorithmDialogBase() =
default;
126 mAlgorithm.reset( algorithm );
134 title = mAlgorithm->displayName();
136 setWindowTitle( title );
138 QString algHelp = formatHelp( algorithm );
139 if ( algHelp.isEmpty() )
140 textShortHelp->hide();
143 textShortHelp->document()->setDefaultStyleSheet( QStringLiteral(
".summary { margin-left: 10px; margin-right: 10px; }\n" 144 "h2 { color: #555555; padding-bottom: 15px; }\n" 145 "a { text - decoration: none; color: #3498db; font-weight: bold; }\n" 146 "p { color: #666666; }\n" 147 "b { color: #333333; }\n" 148 "dl dd { margin - bottom: 5px; }" ) );
149 textShortHelp->setHtml( algHelp );
150 connect( textShortHelp, &QTextBrowser::anchorClicked,
this, &QgsProcessingAlgorithmDialogBase::linkClicked );
155 mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Help ) );
161 return mAlgorithm.get();
164 void QgsProcessingAlgorithmDialogBase::setMainWidget( QWidget *widget )
168 mMainWidget->deleteLater();
171 mMainWidget = widget;
172 mTabWidget->widget( 0 )->layout()->addWidget( mMainWidget );
175 QWidget *QgsProcessingAlgorithmDialogBase::mainWidget()
180 QVariantMap QgsProcessingAlgorithmDialogBase::getParameterValues()
const 182 return QVariantMap();
185 void QgsProcessingAlgorithmDialogBase::saveLogToFile(
const QString &path,
const LogFormat format )
187 QFile logFile( path );
188 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
192 QTextStream fout( &logFile );
196 case FormatPlainText:
197 fout << txtLog->toPlainText();
201 fout << txtLog->toHtml();
208 auto feedback = qgis::make_unique< QgsProcessingAlgorithmDialogFeedback >();
210 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::commandInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushCommandInfo );
211 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::consoleInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushConsoleInfo );
212 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::debugInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushDebugInfo );
213 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::errorReported,
this, &QgsProcessingAlgorithmDialogBase::reportError );
214 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::infoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushInfo );
215 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::progressTextChanged,
this, &QgsProcessingAlgorithmDialogBase::setProgressText );
217 return feedback.release();
220 QDialogButtonBox *QgsProcessingAlgorithmDialogBase::buttonBox()
225 QTabWidget *QgsProcessingAlgorithmDialogBase::tabWidget()
230 void QgsProcessingAlgorithmDialogBase::showLog()
232 mTabWidget->setCurrentIndex( 1 );
235 QPushButton *QgsProcessingAlgorithmDialogBase::runButton()
240 QPushButton *QgsProcessingAlgorithmDialogBase::cancelButton()
245 void QgsProcessingAlgorithmDialogBase::clearProgress()
247 progressBar->setMaximum( 0 );
250 void QgsProcessingAlgorithmDialogBase::setExecuted(
bool executed )
252 mExecuted = executed;
255 void QgsProcessingAlgorithmDialogBase::setResults(
const QVariantMap &results )
265 void QgsProcessingAlgorithmDialogBase::openHelp()
267 QUrl algHelp = mAlgorithm->helpUrl();
268 if ( algHelp.isEmpty() )
270 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() ) ) );
273 if ( !algHelp.isEmpty() )
274 QDesktopServices::openUrl( algHelp );
277 void QgsProcessingAlgorithmDialogBase::toggleCollapsed()
279 if ( mHelpCollapsed )
281 splitter->restoreState( mSplitterState );
282 mButtonCollapse->setArrowType( Qt::RightArrow );
286 mSplitterState = splitter->saveState();
287 splitter->setSizes( QList<int>() << 1 << 0 );
288 mButtonCollapse->setArrowType( Qt::LeftArrow );
290 mHelpCollapsed = !mHelpCollapsed;
293 void QgsProcessingAlgorithmDialogBase::splitterChanged(
int,
int )
295 if ( splitter->sizes().at( 1 ) == 0 )
297 mHelpCollapsed =
true;
298 mButtonCollapse->setArrowType( Qt::LeftArrow );
302 mHelpCollapsed =
false;
303 mButtonCollapse->setArrowType( Qt::RightArrow );
307 void QgsProcessingAlgorithmDialogBase::linkClicked(
const QUrl &url )
309 QDesktopServices::openUrl( url.toString() );
312 void QgsProcessingAlgorithmDialogBase::algExecuted(
bool successful,
const QVariantMap & )
314 mAlgorithmTask =
nullptr;
321 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
335 void QgsProcessingAlgorithmDialogBase::taskTriggered(
QgsTask *task )
337 if ( task == mAlgorithmTask )
341 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
347 void QgsProcessingAlgorithmDialogBase::closeClicked()
353 void QgsProcessingAlgorithmDialogBase::reportError(
const QString &error,
bool fatalError )
355 setInfo( error,
true );
362 void QgsProcessingAlgorithmDialogBase::pushInfo(
const QString &info )
368 void QgsProcessingAlgorithmDialogBase::pushCommandInfo(
const QString &command )
370 txtLog->append( QStringLiteral(
"<code>%1<code>" ).arg( formatStringForLog( command.toHtmlEscaped() ) ) );
371 scrollToBottomOfLog();
375 void QgsProcessingAlgorithmDialogBase::pushDebugInfo(
const QString &message )
377 txtLog->append( QStringLiteral(
"<span style=\"color:blue\">%1</span>" ).arg( formatStringForLog( message.toHtmlEscaped() ) ) );
378 scrollToBottomOfLog();
382 void QgsProcessingAlgorithmDialogBase::pushConsoleInfo(
const QString &info )
384 txtLog->append( QStringLiteral(
"<code style=\"color:#777\">%1</code>" ).arg( formatStringForLog( info.toHtmlEscaped() ) ) );
385 scrollToBottomOfLog();
389 QDialog *QgsProcessingAlgorithmDialogBase::createProgressDialog()
391 QgsProcessingAlgorithmProgressDialog *dialog =
new QgsProcessingAlgorithmProgressDialog(
this );
392 dialog->setWindowModality( Qt::ApplicationModal );
393 dialog->setWindowTitle( windowTitle() );
394 dialog->setGeometry( geometry() );
395 connect( progressBar, &QProgressBar::valueChanged, dialog->progressBar(), &QProgressBar::setValue );
396 connect( dialog->cancelButton(), &QPushButton::clicked, buttonCancel, &QPushButton::click );
397 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
398 connect( txtLog, &QTextEdit::textChanged, dialog, [
this, dialog]()
400 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
401 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
402 sb->setValue( sb->maximum() );
407 void QgsProcessingAlgorithmDialogBase::clearLog()
412 void QgsProcessingAlgorithmDialogBase::saveLog()
415 QString lastUsedDir = settings.
value( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QDir::homePath() ).toString();
418 const QString txtExt = tr(
"Text files" ) + QStringLiteral(
" (*.txt *.TXT)" );
419 const QString htmlExt = tr(
"HTML files" ) + QStringLiteral(
" (*.html *.HTML)" );
421 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save Log to File" ), lastUsedDir, txtExt +
";;" + htmlExt, &filter );
422 if ( path.isEmpty() )
427 settings.
setValue( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QFileInfo( path ).path() );
429 LogFormat format = FormatPlainText;
430 if ( filter == htmlExt )
434 saveLogToFile( path, format );
437 void QgsProcessingAlgorithmDialogBase::copyLogToClipboard()
439 QMimeData *m =
new QMimeData();
440 m->setText( txtLog->toPlainText() );
441 m->setHtml( txtLog->toHtml() );
442 QClipboard *cb = QApplication::clipboard();
445 cb->setMimeData( m, QClipboard::Selection );
447 cb->setMimeData( m, QClipboard::Clipboard );
450 void QgsProcessingAlgorithmDialogBase::closeEvent( QCloseEvent *e )
452 QDialog::closeEvent( e );
454 if ( !mAlgorithmTask )
463 void QgsProcessingAlgorithmDialogBase::runAlgorithm()
468 void QgsProcessingAlgorithmDialogBase::setPercentage(
double percent )
471 if ( progressBar->maximum() == 0 )
472 progressBar->setMaximum( 100 );
473 progressBar->setValue( percent );
477 void QgsProcessingAlgorithmDialogBase::setProgressText(
const QString &text )
479 lblProgress->setText( text );
480 setInfo( text,
false );
481 scrollToBottomOfLog();
488 if ( !text.isEmpty() )
490 QStringList paragraphs = text.split(
'\n' );
492 for (
const QString ¶graph : paragraphs )
494 help += QStringLiteral(
"<p>%1</p>" ).arg( paragraph );
496 return QStringLiteral(
"<h2>%1</h2>%2" ).arg( algorithm->
displayName(), help );
506 void QgsProcessingAlgorithmDialogBase::processEvents()
508 if ( mAlgorithmTask )
525 while ( QCoreApplication::hasPendingEvents() && ++nIters < 100 )
528 QCoreApplication::processEvents();
532 void QgsProcessingAlgorithmDialogBase::scrollToBottomOfLog()
534 QScrollBar *sb = txtLog->verticalScrollBar();
535 sb->setValue( sb->maximum() );
538 void QgsProcessingAlgorithmDialogBase::resetGui()
540 lblProgress->clear();
541 progressBar->setMaximum( 100 );
542 progressBar->setValue( 0 );
543 mButtonRun->setEnabled(
true );
544 mButtonClose->setEnabled(
true );
547 QgsMessageBar *QgsProcessingAlgorithmDialogBase::messageBar()
552 void QgsProcessingAlgorithmDialogBase::hideShortHelp()
554 textShortHelp->setVisible(
false );
559 mAlgorithmTask = task;
564 QString QgsProcessingAlgorithmDialogBase::formatStringForLog(
const QString &
string )
567 s.replace(
'\n', QStringLiteral(
"<br>" ) );
571 void QgsProcessingAlgorithmDialogBase::setInfo(
const QString &message,
bool isError,
bool escapeHtml )
574 txtLog->append( QStringLiteral(
"<span style=\"color:red\">%1</span>" ).arg( escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
575 else if ( escapeHtml )
576 txtLog->append( formatStringForLog( message.toHtmlEscaped() ) );
578 txtLog->append( formatStringForLog( message ) );
579 scrollToBottomOfLog();
587 QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
593 QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
598 QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
600 return mButtonBox->button( QDialogButtonBox::Cancel );
603 QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
608 void QgsProcessingAlgorithmProgressDialog::reject()
Base class for providing feedback from a processing algorithm.
void taskTriggered(QgsTask *task)
Emitted when a task is triggered.
void cancel()
Tells the internal routines that the current operation should be canceled. This should be run by the ...
This class is a composition of two QSettings instances:
Dialog titles should be title case.
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
Algorithm's display name is a static literal string, and should not be translated or automatically fo...
A bar for displaying non-blocking messages to the user.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Abstract base class for processing algorithms.
virtual QString helpId() const
Returns the provider help id string, used for creating QgsHelp urls for algorithms belong to this pro...
static QUrl helpUrl(const QString &key)
Returns URI of the help topic for the given key.
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.
static QString capitalize(const QString &string, 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.
Abstract base class for long running background tasks.
QgsProcessingProvider * provider() const
Returns the provider to which this algorithm belongs.
virtual Flags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users...
static QgsGui::HigFlags higFlags()
Returns the platform's HIG flags.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
virtual QString shortDescription() const
Returns an optional translated short description of the 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
virtual QString displayName() const =0
Returns the translated algorithm name, which should be used for any user-visible display of the algor...
virtual QString helpUrl() const
Returns a url pointing to the algorithm's help page.
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...
QgsTask task which runs a QgsProcessingAlgorithm in a background task.
Contains information about the context in which a processing algorithm is executed.
void executed(bool successful, const QVariantMap &results)
Emitted when the algorithm has finished execution.
virtual QString shortHelpString() const
Returns a localised short helper string for the algorithm.