27 #include <QToolButton> 28 #include <QDesktopServices> 30 #include <QApplication> 32 #include <QFileDialog> 37 void QgsProcessingAlgorithmDialogFeedback::setProgressText(
const QString &text )
39 emit progressTextChanged( text );
42 void QgsProcessingAlgorithmDialogFeedback::reportError(
const QString &error,
bool fatalError )
44 emit errorReported( error, fatalError );
47 void QgsProcessingAlgorithmDialogFeedback::pushInfo(
const QString &info )
49 emit infoPushed( info );
52 void QgsProcessingAlgorithmDialogFeedback::pushCommandInfo(
const QString &info )
54 emit commandInfoPushed( info );
57 void QgsProcessingAlgorithmDialogFeedback::pushDebugInfo(
const QString &info )
59 emit debugInfoPushed( info );
62 void QgsProcessingAlgorithmDialogFeedback::pushConsoleInfo(
const QString &info )
64 emit consoleInfoPushed( info );
71 QgsProcessingAlgorithmDialogBase::QgsProcessingAlgorithmDialogBase( QWidget *parent, Qt::WindowFlags flags )
72 : QDialog( parent, flags )
77 splitter->setCollapsible( 0,
false );
80 QSplitterHandle *splitterHandle = splitter->handle( 1 );
81 QVBoxLayout *handleLayout =
new QVBoxLayout();
82 handleLayout->setContentsMargins( 0, 0, 0, 0 );
83 mButtonCollapse =
new QToolButton( splitterHandle );
84 mButtonCollapse->setAutoRaise(
true );
85 mButtonCollapse->setFixedSize( 12, 12 );
86 mButtonCollapse->setCursor( Qt::ArrowCursor );
87 handleLayout->addWidget( mButtonCollapse );
88 handleLayout->addStretch();
89 splitterHandle->setLayout( handleLayout );
94 splitter->restoreState( settings.
value( QStringLiteral(
"/Processing/dialogBaseSplitter" ), QByteArray() ).toByteArray() );
95 mSplitterState = splitter->saveState();
96 splitterChanged( 0, 0 );
98 connect( mButtonBox, &QDialogButtonBox::rejected,
this, &QgsProcessingAlgorithmDialogBase::closeClicked );
99 connect( mButtonBox, &QDialogButtonBox::accepted,
this, &QgsProcessingAlgorithmDialogBase::runAlgorithm );
102 mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
103 mButtonRun->setText( tr(
"Run" ) );
105 buttonCancel->setEnabled(
false );
106 mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
108 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsProcessingAlgorithmDialogBase::openHelp );
109 connect( mButtonCollapse, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::toggleCollapsed );
110 connect( splitter, &QSplitter::splitterMoved,
this, &QgsProcessingAlgorithmDialogBase::splitterChanged );
112 connect( mButtonSaveLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::saveLog );
113 connect( mButtonCopyLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::copyLogToClipboard );
114 connect( mButtonClearLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::clearLog );
117 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
118 verticalLayout->insertWidget( 0, mMessageBar );
123 QgsProcessingAlgorithmDialogBase::~QgsProcessingAlgorithmDialogBase() =
default;
127 mAlgorithm.reset( algorithm );
135 title = mAlgorithm->displayName();
137 setWindowTitle( title );
139 QString algHelp = formatHelp( algorithm );
140 if ( algHelp.isEmpty() )
141 textShortHelp->hide();
144 textShortHelp->document()->setDefaultStyleSheet( QStringLiteral(
".summary { margin-left: 10px; margin-right: 10px; }\n" 145 "h2 { color: #555555; padding-bottom: 15px; }\n" 146 "a { text - decoration: none; color: #3498db; font-weight: bold; }\n" 147 "p { color: #666666; }\n" 148 "b { color: #333333; }\n" 149 "dl dd { margin - bottom: 5px; }" ) );
150 textShortHelp->setHtml( algHelp );
151 connect( textShortHelp, &QTextBrowser::anchorClicked,
this, &QgsProcessingAlgorithmDialogBase::linkClicked );
156 mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Help ) );
160 if ( !warning.isEmpty() )
168 return mAlgorithm.get();
171 void QgsProcessingAlgorithmDialogBase::setMainWidget( QWidget *widget )
175 mMainWidget->deleteLater();
178 mMainWidget = widget;
179 mTabWidget->widget( 0 )->layout()->addWidget( mMainWidget );
182 QWidget *QgsProcessingAlgorithmDialogBase::mainWidget()
187 QVariantMap QgsProcessingAlgorithmDialogBase::getParameterValues()
const 189 return QVariantMap();
192 void QgsProcessingAlgorithmDialogBase::saveLogToFile(
const QString &path,
const LogFormat format )
194 QFile logFile( path );
195 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
199 QTextStream fout( &logFile );
203 case FormatPlainText:
204 fout << txtLog->toPlainText();
208 fout << txtLog->toHtml();
215 auto feedback = qgis::make_unique< QgsProcessingAlgorithmDialogFeedback >();
217 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::commandInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushCommandInfo );
218 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::consoleInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushConsoleInfo );
219 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::debugInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushDebugInfo );
220 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::errorReported,
this, &QgsProcessingAlgorithmDialogBase::reportError );
221 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::infoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushInfo );
222 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::progressTextChanged,
this, &QgsProcessingAlgorithmDialogBase::setProgressText );
224 return feedback.release();
227 QDialogButtonBox *QgsProcessingAlgorithmDialogBase::buttonBox()
232 QTabWidget *QgsProcessingAlgorithmDialogBase::tabWidget()
237 void QgsProcessingAlgorithmDialogBase::showLog()
239 mTabWidget->setCurrentIndex( 1 );
242 QPushButton *QgsProcessingAlgorithmDialogBase::runButton()
247 QPushButton *QgsProcessingAlgorithmDialogBase::cancelButton()
252 void QgsProcessingAlgorithmDialogBase::clearProgress()
254 progressBar->setMaximum( 0 );
257 void QgsProcessingAlgorithmDialogBase::setExecuted(
bool executed )
259 mExecuted = executed;
262 void QgsProcessingAlgorithmDialogBase::setResults(
const QVariantMap &results )
272 void QgsProcessingAlgorithmDialogBase::openHelp()
274 QUrl algHelp = mAlgorithm->helpUrl();
275 if ( algHelp.isEmpty() )
277 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() ) ) );
280 if ( !algHelp.isEmpty() )
281 QDesktopServices::openUrl( algHelp );
284 void QgsProcessingAlgorithmDialogBase::toggleCollapsed()
286 if ( mHelpCollapsed )
288 splitter->restoreState( mSplitterState );
289 mButtonCollapse->setArrowType( Qt::RightArrow );
293 mSplitterState = splitter->saveState();
294 splitter->setSizes( QList<int>() << 1 << 0 );
295 mButtonCollapse->setArrowType( Qt::LeftArrow );
297 mHelpCollapsed = !mHelpCollapsed;
300 void QgsProcessingAlgorithmDialogBase::splitterChanged(
int,
int )
302 if ( splitter->sizes().at( 1 ) == 0 )
304 mHelpCollapsed =
true;
305 mButtonCollapse->setArrowType( Qt::LeftArrow );
309 mHelpCollapsed =
false;
310 mButtonCollapse->setArrowType( Qt::RightArrow );
314 void QgsProcessingAlgorithmDialogBase::linkClicked(
const QUrl &url )
316 QDesktopServices::openUrl( url.toString() );
319 void QgsProcessingAlgorithmDialogBase::algExecuted(
bool successful,
const QVariantMap & )
321 mAlgorithmTask =
nullptr;
328 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
342 void QgsProcessingAlgorithmDialogBase::taskTriggered(
QgsTask *task )
344 if ( task == mAlgorithmTask )
348 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
354 void QgsProcessingAlgorithmDialogBase::closeClicked()
360 void QgsProcessingAlgorithmDialogBase::reportError(
const QString &error,
bool fatalError )
362 setInfo( error,
true );
369 void QgsProcessingAlgorithmDialogBase::pushInfo(
const QString &info )
375 void QgsProcessingAlgorithmDialogBase::pushCommandInfo(
const QString &command )
377 txtLog->append( QStringLiteral(
"<code>%1<code>" ).arg( formatStringForLog( command.toHtmlEscaped() ) ) );
378 scrollToBottomOfLog();
382 void QgsProcessingAlgorithmDialogBase::pushDebugInfo(
const QString &message )
384 txtLog->append( QStringLiteral(
"<span style=\"color:#777\">%1</span>" ).arg( formatStringForLog( message.toHtmlEscaped() ) ) );
385 scrollToBottomOfLog();
389 void QgsProcessingAlgorithmDialogBase::pushConsoleInfo(
const QString &info )
391 txtLog->append( QStringLiteral(
"<code style=\"color:#777\">%1</code>" ).arg( formatStringForLog( info.toHtmlEscaped() ) ) );
392 scrollToBottomOfLog();
396 QDialog *QgsProcessingAlgorithmDialogBase::createProgressDialog()
398 QgsProcessingAlgorithmProgressDialog *dialog =
new QgsProcessingAlgorithmProgressDialog(
this );
399 dialog->setWindowModality( Qt::ApplicationModal );
400 dialog->setWindowTitle( windowTitle() );
401 dialog->setGeometry( geometry() );
402 connect( progressBar, &QProgressBar::valueChanged, dialog->progressBar(), &QProgressBar::setValue );
403 connect( dialog->cancelButton(), &QPushButton::clicked, buttonCancel, &QPushButton::click );
404 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
405 connect( txtLog, &QTextEdit::textChanged, dialog, [
this, dialog]()
407 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
408 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
409 sb->setValue( sb->maximum() );
414 void QgsProcessingAlgorithmDialogBase::clearLog()
419 void QgsProcessingAlgorithmDialogBase::saveLog()
422 QString lastUsedDir = settings.
value( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QDir::homePath() ).toString();
425 const QString txtExt = tr(
"Text files" ) + QStringLiteral(
" (*.txt *.TXT)" );
426 const QString htmlExt = tr(
"HTML files" ) + QStringLiteral(
" (*.html *.HTML)" );
428 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save Log to File" ), lastUsedDir, txtExt +
";;" + htmlExt, &filter );
429 if ( path.isEmpty() )
434 settings.
setValue( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QFileInfo( path ).path() );
436 LogFormat format = FormatPlainText;
437 if ( filter == htmlExt )
441 saveLogToFile( path, format );
444 void QgsProcessingAlgorithmDialogBase::copyLogToClipboard()
446 QMimeData *m =
new QMimeData();
447 m->setText( txtLog->toPlainText() );
448 m->setHtml( txtLog->toHtml() );
449 QClipboard *cb = QApplication::clipboard();
452 cb->setMimeData( m, QClipboard::Selection );
454 cb->setMimeData( m, QClipboard::Clipboard );
457 void QgsProcessingAlgorithmDialogBase::closeEvent( QCloseEvent *e )
459 if ( !mHelpCollapsed )
462 settings.
setValue( QStringLiteral(
"/Processing/dialogBaseSplitter" ), splitter->saveState() );
465 QDialog::closeEvent( e );
467 if ( !mAlgorithmTask )
476 void QgsProcessingAlgorithmDialogBase::runAlgorithm()
481 void QgsProcessingAlgorithmDialogBase::setPercentage(
double percent )
484 if ( progressBar->maximum() == 0 )
485 progressBar->setMaximum( 100 );
486 progressBar->setValue( percent );
490 void QgsProcessingAlgorithmDialogBase::setProgressText(
const QString &text )
492 lblProgress->setText( text );
493 setInfo( text,
false );
494 scrollToBottomOfLog();
501 if ( !text.isEmpty() )
503 QStringList paragraphs = text.split(
'\n' );
505 for (
const QString ¶graph : paragraphs )
507 help += QStringLiteral(
"<p>%1</p>" ).arg( paragraph );
509 return QStringLiteral(
"<h2>%1</h2>%2" ).arg( algorithm->
displayName(), help );
519 void QgsProcessingAlgorithmDialogBase::processEvents()
521 if ( mAlgorithmTask )
537 while ( ++nIters < 100 )
540 QCoreApplication::processEvents();
544 void QgsProcessingAlgorithmDialogBase::scrollToBottomOfLog()
546 QScrollBar *sb = txtLog->verticalScrollBar();
547 sb->setValue( sb->maximum() );
550 void QgsProcessingAlgorithmDialogBase::resetGui()
552 lblProgress->clear();
553 progressBar->setMaximum( 100 );
554 progressBar->setValue( 0 );
555 mButtonRun->setEnabled(
true );
556 mButtonClose->setEnabled(
true );
559 QgsMessageBar *QgsProcessingAlgorithmDialogBase::messageBar()
564 void QgsProcessingAlgorithmDialogBase::hideShortHelp()
566 textShortHelp->setVisible(
false );
571 mAlgorithmTask = task;
576 QString QgsProcessingAlgorithmDialogBase::formatStringForLog(
const QString &
string )
579 s.replace(
'\n', QStringLiteral(
"<br>" ) );
583 void QgsProcessingAlgorithmDialogBase::setInfo(
const QString &message,
bool isError,
bool escapeHtml )
586 txtLog->append( QStringLiteral(
"<span style=\"color:red\">%1</span>" ).arg( escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
587 else if ( escapeHtml )
588 txtLog->append( formatStringForLog( message.toHtmlEscaped() ) );
590 txtLog->append( formatStringForLog( message ) );
591 scrollToBottomOfLog();
599 QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
605 QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
610 QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
612 return mButtonBox->button( QDialogButtonBox::Cancel );
615 QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
620 void QgsProcessingAlgorithmProgressDialog::reject()
virtual QString helpUrl() const
Returns a url pointing to the algorithm's help page.
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.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QgsProcessingProvider * provider() const
Returns the provider to which this algorithm belongs.
virtual QString helpId() const
Returns the provider help id string, used for creating QgsHelp urls for algorithms belong to this pro...
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.
virtual Flags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users...
virtual QString shortHelpString() const
Returns a localised short helper string for the algorithm.
Abstract base class for processing algorithms.
virtual QString warningMessage() const
Returns an optional warning message to show users when running algorithms from this provider...
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.
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
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 displayName() const =0
Returns the translated algorithm name, which should be used for any user-visible display of the algor...
virtual QString shortDescription() const
Returns an optional translated short description of the algorithm.
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.