26 #include <QToolButton> 27 #include <QDesktopServices> 29 #include <QApplication> 31 #include <QFileDialog> 36 QgsProcessingAlgorithmDialogFeedback::QgsProcessingAlgorithmDialogFeedback()
40 void QgsProcessingAlgorithmDialogFeedback::setProgressText(
const QString &text )
42 emit progressTextChanged( text );
45 void QgsProcessingAlgorithmDialogFeedback::reportError(
const QString &error,
bool fatalError )
47 emit errorReported( error, fatalError );
50 void QgsProcessingAlgorithmDialogFeedback::pushInfo(
const QString &info )
52 emit infoPushed( info );
55 void QgsProcessingAlgorithmDialogFeedback::pushCommandInfo(
const QString &info )
57 emit commandInfoPushed( info );
60 void QgsProcessingAlgorithmDialogFeedback::pushDebugInfo(
const QString &info )
62 emit debugInfoPushed( info );
65 void QgsProcessingAlgorithmDialogFeedback::pushConsoleInfo(
const QString &info )
67 emit consoleInfoPushed( info );
74 QgsProcessingAlgorithmDialogBase::QgsProcessingAlgorithmDialogBase( QWidget *parent, Qt::WindowFlags flags )
75 : QDialog( parent, flags )
80 splitter->setCollapsible( 0,
false );
83 QSplitterHandle *splitterHandle = splitter->handle( 1 );
84 QVBoxLayout *handleLayout =
new QVBoxLayout();
85 handleLayout->setContentsMargins( 0, 0, 0, 0 );
86 mButtonCollapse =
new QToolButton( splitterHandle );
87 mButtonCollapse->setAutoRaise(
true );
88 mButtonCollapse->setFixedSize( 12, 12 );
89 mButtonCollapse->setCursor( Qt::ArrowCursor );
90 handleLayout->addWidget( mButtonCollapse );
91 handleLayout->addStretch();
92 splitterHandle->setLayout( handleLayout );
97 splitter->restoreState( settings.
value( QStringLiteral(
"/Processing/dialogBaseSplitter" ), QByteArray() ).toByteArray() );
98 mSplitterState = splitter->saveState();
99 splitterChanged( 0, 0 );
101 connect( mButtonBox, &QDialogButtonBox::rejected,
this, &QgsProcessingAlgorithmDialogBase::closeClicked );
102 connect( mButtonBox, &QDialogButtonBox::accepted,
this, &QgsProcessingAlgorithmDialogBase::accept );
105 mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
106 mButtonRun->setText( tr(
"Run" ) );
108 buttonCancel->setEnabled(
false );
109 mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
111 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsProcessingAlgorithmDialogBase::openHelp );
112 connect( mButtonCollapse, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::toggleCollapsed );
113 connect( splitter, &QSplitter::splitterMoved,
this, &QgsProcessingAlgorithmDialogBase::splitterChanged );
115 connect( mButtonSaveLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::saveLog );
116 connect( mButtonCopyLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::copyLogToClipboard );
117 connect( mButtonClearLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::clearLog );
120 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
121 verticalLayout->insertWidget( 0, mMessageBar );
134 setWindowTitle( title );
136 QString algHelp = formatHelp( algorithm );
137 if ( algHelp.isEmpty() )
138 textShortHelp->hide();
141 textShortHelp->document()->setDefaultStyleSheet( QStringLiteral(
".summary { margin-left: 10px; margin-right: 10px; }\n" 142 "h2 { color: #555555; padding-bottom: 15px; }\n" 143 "a { text - decoration: none; color: #3498db; font-weight: bold; }\n" 144 "p { color: #666666; }\n" 145 "b { color: #333333; }\n" 146 "dl dd { margin - bottom: 5px; }" ) );
147 textShortHelp->setHtml( algHelp );
148 connect( textShortHelp, &QTextBrowser::anchorClicked,
this, &QgsProcessingAlgorithmDialogBase::linkClicked );
152 mButtonRun->setText( tr(
"Run in Background" ) );
160 void QgsProcessingAlgorithmDialogBase::setMainWidget( QWidget *widget )
164 mMainWidget->deleteLater();
167 mMainWidget = widget;
168 mTabWidget->widget( 0 )->layout()->addWidget( mMainWidget );
171 QWidget *QgsProcessingAlgorithmDialogBase::mainWidget()
176 QVariantMap QgsProcessingAlgorithmDialogBase::getParameterValues()
const 178 return QVariantMap();
181 void QgsProcessingAlgorithmDialogBase::saveLogToFile(
const QString &path,
const LogFormat format )
183 QFile logFile( path );
184 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
188 QTextStream fout( &logFile );
192 case FormatPlainText:
193 fout << txtLog->toPlainText();
197 fout << txtLog->toHtml();
204 auto feedback = qgis::make_unique< QgsProcessingAlgorithmDialogFeedback >();
206 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::commandInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushCommandInfo );
207 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::consoleInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushConsoleInfo );
208 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::debugInfoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushDebugInfo );
209 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::errorReported,
this, &QgsProcessingAlgorithmDialogBase::reportError );
210 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::infoPushed,
this, &QgsProcessingAlgorithmDialogBase::pushInfo );
211 connect( feedback.get(), &QgsProcessingAlgorithmDialogFeedback::progressTextChanged,
this, &QgsProcessingAlgorithmDialogBase::setProgressText );
213 return feedback.release();
216 QDialogButtonBox *QgsProcessingAlgorithmDialogBase::buttonBox()
221 QTabWidget *QgsProcessingAlgorithmDialogBase::tabWidget()
226 void QgsProcessingAlgorithmDialogBase::showLog()
228 mTabWidget->setCurrentIndex( 1 );
231 QPushButton *QgsProcessingAlgorithmDialogBase::runButton()
236 QPushButton *QgsProcessingAlgorithmDialogBase::cancelButton()
241 void QgsProcessingAlgorithmDialogBase::clearProgress()
243 progressBar->setMaximum( 0 );
246 void QgsProcessingAlgorithmDialogBase::setExecuted(
bool executed )
248 mExecuted = executed;
251 void QgsProcessingAlgorithmDialogBase::setResults(
const QVariantMap &results )
261 void QgsProcessingAlgorithmDialogBase::accept()
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><span style=\"color:blue\">%1</darkgray></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 connect( progressBar, &QProgressBar::valueChanged, dialog->progressBar(), &QProgressBar::setValue );
395 connect( dialog->cancelButton(), &QPushButton::clicked, buttonCancel, &QPushButton::click );
396 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
397 connect( txtLog, &QTextEdit::textChanged, dialog, [
this, dialog]()
399 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
400 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
401 sb->setValue( sb->maximum() );
406 void QgsProcessingAlgorithmDialogBase::clearLog()
411 void QgsProcessingAlgorithmDialogBase::saveLog()
414 QString lastUsedDir = settings.
value( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QDir::homePath() ).toString();
417 const QString txtExt = tr(
"Text files" ) + QStringLiteral(
" (*.txt *.TXT)" );
418 const QString htmlExt = tr(
"HTML files" ) + QStringLiteral(
" (*.html *.HTML)" );
420 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save Log to File" ), lastUsedDir, txtExt +
";;" + htmlExt, &filter );
421 if ( path.isEmpty() )
426 settings.
setValue( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QFileInfo( path ).path() );
428 LogFormat format = FormatPlainText;
429 if ( filter == htmlExt )
433 saveLogToFile( path, format );
436 void QgsProcessingAlgorithmDialogBase::copyLogToClipboard()
438 QMimeData *m =
new QMimeData();
439 m->setText( txtLog->toPlainText() );
440 m->setHtml( txtLog->toHtml() );
441 QClipboard *cb = QApplication::clipboard();
444 cb->setMimeData( m, QClipboard::Selection );
446 cb->setMimeData( m, QClipboard::Clipboard );
449 void QgsProcessingAlgorithmDialogBase::closeEvent( QCloseEvent *e )
451 QDialog::closeEvent( e );
453 if ( !mAlgorithmTask )
462 void QgsProcessingAlgorithmDialogBase::setPercentage(
double percent )
465 if ( progressBar->maximum() == 0 )
466 progressBar->setMaximum( 100 );
467 progressBar->setValue( percent );
471 void QgsProcessingAlgorithmDialogBase::setProgressText(
const QString &text )
473 lblProgress->setText( text );
474 setInfo( text,
false );
475 scrollToBottomOfLog();
482 if ( !text.isEmpty() )
484 QStringList paragraphs = text.split(
'\n' );
486 for (
const QString ¶graph : paragraphs )
488 help += QStringLiteral(
"<p>%1</p>" ).arg( paragraph );
490 return QStringLiteral(
"<h2>%1</h2>%2" ).arg( algorithm->
displayName(), help );
500 void QgsProcessingAlgorithmDialogBase::processEvents()
502 if ( mAlgorithmTask )
519 while ( QCoreApplication::hasPendingEvents() && ++nIters < 100 )
522 QCoreApplication::processEvents();
526 void QgsProcessingAlgorithmDialogBase::scrollToBottomOfLog()
528 QScrollBar *sb = txtLog->verticalScrollBar();
529 sb->setValue( sb->maximum() );
532 void QgsProcessingAlgorithmDialogBase::resetGui()
534 lblProgress->clear();
535 progressBar->setMaximum( 100 );
536 progressBar->setValue( 0 );
537 mButtonRun->setEnabled(
true );
538 mButtonClose->setEnabled(
true );
541 QgsMessageBar *QgsProcessingAlgorithmDialogBase::messageBar()
546 void QgsProcessingAlgorithmDialogBase::hideShortHelp()
548 textShortHelp->setVisible(
false );
553 mAlgorithmTask = task;
558 QString QgsProcessingAlgorithmDialogBase::formatStringForLog(
const QString &
string )
561 s.replace(
'\n', QStringLiteral(
"<br>" ) );
565 void QgsProcessingAlgorithmDialogBase::setInfo(
const QString &message,
bool isError,
bool escapeHtml )
568 txtLog->append( QStringLiteral(
"<span style=\"color:red\">%1</span>" ).arg( escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
569 else if ( escapeHtml )
570 txtLog->append( formatStringForLog( message.toHtmlEscaped() ) );
572 txtLog->append( formatStringForLog( message ) );
573 scrollToBottomOfLog();
581 QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
588 QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
593 QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
595 return mButtonBox->button( QDialogButtonBox::Cancel );
598 QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
603 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:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
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...
static QgsGui * instance()
Returns a pointer to the singleton instance.
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.
Algorithm is not thread safe and cannot be run in a background thread, e.g. for algorithms which mani...
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
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.