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 ) );
162 return mAlgorithm.get();
165 void QgsProcessingAlgorithmDialogBase::setMainWidget( QWidget *widget )
169 mMainWidget->deleteLater();
172 mMainWidget = widget;
173 mTabWidget->widget( 0 )->layout()->addWidget( mMainWidget );
176 QWidget *QgsProcessingAlgorithmDialogBase::mainWidget()
181 QVariantMap QgsProcessingAlgorithmDialogBase::getParameterValues()
const 183 return QVariantMap();
186 void QgsProcessingAlgorithmDialogBase::saveLogToFile(
const QString &path,
const LogFormat format )
188 QFile logFile( path );
189 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
193 QTextStream fout( &logFile );
197 case FormatPlainText:
198 fout << txtLog->toPlainText();
202 fout << txtLog->toHtml();
209 auto feedback = qgis::make_unique< QgsProcessingAlgorithmDialogFeedback >();
211 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::commandInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushCommandInfo );
212 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::consoleInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushConsoleInfo );
213 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::debugInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushDebugInfo );
214 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::errorReported,
this, &QgsProcessingAlgorithmDialogBase::reportError );
215 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::infoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushInfo );
216 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::progressTextChanged,
this, &QgsProcessingAlgorithmDialogBase::setProgressText );
218 return feedback.release();
221 QDialogButtonBox *QgsProcessingAlgorithmDialogBase::buttonBox()
226 QTabWidget *QgsProcessingAlgorithmDialogBase::tabWidget()
231 void QgsProcessingAlgorithmDialogBase::showLog()
233 mTabWidget->setCurrentIndex( 1 );
236 QPushButton *QgsProcessingAlgorithmDialogBase::runButton()
241 QPushButton *QgsProcessingAlgorithmDialogBase::cancelButton()
246 void QgsProcessingAlgorithmDialogBase::clearProgress()
248 progressBar->setMaximum( 0 );
251 void QgsProcessingAlgorithmDialogBase::setExecuted(
bool executed )
253 mExecuted = executed;
256 void QgsProcessingAlgorithmDialogBase::setResults(
const QVariantMap &results )
266 void QgsProcessingAlgorithmDialogBase::openHelp()
268 QUrl algHelp = mAlgorithm->helpUrl();
269 if ( algHelp.isEmpty() )
271 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() ) ) );
274 if ( !algHelp.isEmpty() )
275 QDesktopServices::openUrl( algHelp );
278 void QgsProcessingAlgorithmDialogBase::toggleCollapsed()
280 if ( mHelpCollapsed )
282 splitter->restoreState( mSplitterState );
283 mButtonCollapse->setArrowType( Qt::RightArrow );
287 mSplitterState = splitter->saveState();
288 splitter->setSizes( QList<int>() << 1 << 0 );
289 mButtonCollapse->setArrowType( Qt::LeftArrow );
291 mHelpCollapsed = !mHelpCollapsed;
294 void QgsProcessingAlgorithmDialogBase::splitterChanged(
int,
int )
296 if ( splitter->sizes().at( 1 ) == 0 )
298 mHelpCollapsed =
true;
299 mButtonCollapse->setArrowType( Qt::LeftArrow );
303 mHelpCollapsed =
false;
304 mButtonCollapse->setArrowType( Qt::RightArrow );
308 void QgsProcessingAlgorithmDialogBase::linkClicked(
const QUrl &url )
310 QDesktopServices::openUrl( url.toString() );
313 void QgsProcessingAlgorithmDialogBase::algExecuted(
bool successful,
const QVariantMap & )
315 mAlgorithmTask =
nullptr;
322 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
336 void QgsProcessingAlgorithmDialogBase::taskTriggered(
QgsTask *task )
338 if ( task == mAlgorithmTask )
342 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
348 void QgsProcessingAlgorithmDialogBase::closeClicked()
354 void QgsProcessingAlgorithmDialogBase::reportError(
const QString &error,
bool fatalError )
356 setInfo( error,
true );
363 void QgsProcessingAlgorithmDialogBase::pushInfo(
const QString &info )
369 void QgsProcessingAlgorithmDialogBase::pushCommandInfo(
const QString &command )
371 txtLog->append( QStringLiteral(
"<code>%1<code>" ).arg( formatStringForLog( command.toHtmlEscaped() ) ) );
372 scrollToBottomOfLog();
376 void QgsProcessingAlgorithmDialogBase::pushDebugInfo(
const QString &message )
378 txtLog->append( QStringLiteral(
"<span style=\"color:blue\">%1</span>" ).arg( formatStringForLog( message.toHtmlEscaped() ) ) );
379 scrollToBottomOfLog();
383 void QgsProcessingAlgorithmDialogBase::pushConsoleInfo(
const QString &info )
385 txtLog->append( QStringLiteral(
"<code style=\"color:#777\">%1</code>" ).arg( formatStringForLog( info.toHtmlEscaped() ) ) );
386 scrollToBottomOfLog();
390 QDialog *QgsProcessingAlgorithmDialogBase::createProgressDialog()
392 QgsProcessingAlgorithmProgressDialog *dialog =
new QgsProcessingAlgorithmProgressDialog(
this );
393 dialog->setWindowModality( Qt::ApplicationModal );
394 dialog->setWindowTitle( windowTitle() );
395 dialog->setGeometry( geometry() );
396 connect( progressBar, &QProgressBar::valueChanged, dialog->progressBar(), &QProgressBar::setValue );
397 connect( dialog->cancelButton(), &QPushButton::clicked, buttonCancel, &QPushButton::click );
398 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
399 connect( txtLog, &QTextEdit::textChanged, dialog, [
this, dialog]()
401 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
402 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
403 sb->setValue( sb->maximum() );
408 void QgsProcessingAlgorithmDialogBase::clearLog()
413 void QgsProcessingAlgorithmDialogBase::saveLog()
416 QString lastUsedDir = settings.
value( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QDir::homePath() ).toString();
419 const QString txtExt = tr(
"Text files" ) + QStringLiteral(
" (*.txt *.TXT)" );
420 const QString htmlExt = tr(
"HTML files" ) + QStringLiteral(
" (*.html *.HTML)" );
422 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save Log to File" ), lastUsedDir, txtExt +
";;" + htmlExt, &filter );
423 if ( path.isEmpty() )
428 settings.
setValue( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QFileInfo( path ).path() );
430 LogFormat format = FormatPlainText;
431 if ( filter == htmlExt )
435 saveLogToFile( path, format );
438 void QgsProcessingAlgorithmDialogBase::copyLogToClipboard()
440 QMimeData *m =
new QMimeData();
441 m->setText( txtLog->toPlainText() );
442 m->setHtml( txtLog->toHtml() );
443 QClipboard *cb = QApplication::clipboard();
446 cb->setMimeData( m, QClipboard::Selection );
448 cb->setMimeData( m, QClipboard::Clipboard );
451 void QgsProcessingAlgorithmDialogBase::closeEvent( QCloseEvent *e )
453 QDialog::closeEvent( e );
455 if ( !mAlgorithmTask )
464 void QgsProcessingAlgorithmDialogBase::runAlgorithm()
469 void QgsProcessingAlgorithmDialogBase::setPercentage(
double percent )
472 if ( progressBar->maximum() == 0 )
473 progressBar->setMaximum( 100 );
474 progressBar->setValue( percent );
478 void QgsProcessingAlgorithmDialogBase::setProgressText(
const QString &text )
480 lblProgress->setText( text );
481 setInfo( text,
false );
482 scrollToBottomOfLog();
489 if ( !text.isEmpty() )
491 QStringList paragraphs = text.split(
'\n' );
493 for (
const QString ¶graph : paragraphs )
495 help += QStringLiteral(
"<p>%1</p>" ).arg( paragraph );
497 return QStringLiteral(
"<h2>%1</h2>%2" ).arg( algorithm->
displayName(), help );
507 void QgsProcessingAlgorithmDialogBase::processEvents()
509 if ( mAlgorithmTask )
526 while ( QCoreApplication::hasPendingEvents() && ++nIters < 100 )
529 QCoreApplication::processEvents();
533 void QgsProcessingAlgorithmDialogBase::scrollToBottomOfLog()
535 QScrollBar *sb = txtLog->verticalScrollBar();
536 sb->setValue( sb->maximum() );
539 void QgsProcessingAlgorithmDialogBase::resetGui()
541 lblProgress->clear();
542 progressBar->setMaximum( 100 );
543 progressBar->setValue( 0 );
544 mButtonRun->setEnabled(
true );
545 mButtonClose->setEnabled(
true );
548 QgsMessageBar *QgsProcessingAlgorithmDialogBase::messageBar()
553 void QgsProcessingAlgorithmDialogBase::hideShortHelp()
555 textShortHelp->setVisible(
false );
560 mAlgorithmTask = task;
565 QString QgsProcessingAlgorithmDialogBase::formatStringForLog(
const QString &
string )
568 s.replace(
'\n', QStringLiteral(
"<br>" ) );
572 void QgsProcessingAlgorithmDialogBase::setInfo(
const QString &message,
bool isError,
bool escapeHtml )
575 txtLog->append( QStringLiteral(
"<span style=\"color:red\">%1</span>" ).arg( escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
576 else if ( escapeHtml )
577 txtLog->append( formatStringForLog( message.toHtmlEscaped() ) );
579 txtLog->append( formatStringForLog( message ) );
580 scrollToBottomOfLog();
588 QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
594 QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
599 QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
601 return mButtonBox->button( QDialogButtonBox::Cancel );
604 QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
609 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.
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.