28 #include <QToolButton>
29 #include <QDesktopServices>
31 #include <QApplication>
33 #include <QFileDialog>
38 QgsProcessingAlgorithmDialogFeedback::QgsProcessingAlgorithmDialogFeedback()
42 void QgsProcessingAlgorithmDialogFeedback::setProgressText(
const QString &text )
45 emit progressTextChanged( text );
48 void QgsProcessingAlgorithmDialogFeedback::reportError(
const QString &error,
bool fatalError )
51 emit errorReported( error, fatalError );
54 void QgsProcessingAlgorithmDialogFeedback::pushInfo(
const QString &info )
57 emit infoPushed( info );
60 void QgsProcessingAlgorithmDialogFeedback::pushCommandInfo(
const QString &info )
63 emit commandInfoPushed( info );
66 void QgsProcessingAlgorithmDialogFeedback::pushDebugInfo(
const QString &info )
69 emit debugInfoPushed( info );
72 void QgsProcessingAlgorithmDialogFeedback::pushConsoleInfo(
const QString &info )
75 emit consoleInfoPushed( info );
82 QgsProcessingAlgorithmDialogBase::QgsProcessingAlgorithmDialogBase( QWidget *parent, Qt::WindowFlags flags )
83 : QDialog( parent, flags )
88 splitter->setCollapsible( 0,
false );
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 );
105 splitter->restoreState( settings.
value( QStringLiteral(
"/Processing/dialogBaseSplitter" ), QByteArray() ).toByteArray() );
106 mSplitterState = splitter->saveState();
107 splitterChanged( 0, 0 );
110 mButtonRun = mButtonBox->button( QDialogButtonBox::Ok );
111 mButtonRun->setText( tr(
"Run" ) );
114 mButtonChangeParameters = mButtonBox->button( QDialogButtonBox::Yes );
115 mButtonChangeParameters->setText( tr(
"Change Parameters" ) );
117 buttonCancel->setEnabled(
false );
118 mButtonClose = mButtonBox->button( QDialogButtonBox::Close );
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 );
127 connect( mButtonSaveLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::saveLog );
128 connect( mButtonCopyLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::copyLogToClipboard );
129 connect( mButtonClearLog, &QToolButton::clicked,
this, &QgsProcessingAlgorithmDialogBase::clearLog );
131 connect( mTabWidget, &QTabWidget::currentChanged,
this, &QgsProcessingAlgorithmDialogBase::mTabWidget_currentChanged );
134 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
135 verticalLayout->insertWidget( 0, mMessageBar );
140 QgsProcessingAlgorithmDialogBase::~QgsProcessingAlgorithmDialogBase() =
default;
152 title = mAlgorithm->displayName();
154 setWindowTitle( title );
156 QString algHelp = formatHelp(
algorithm );
157 if ( algHelp.isEmpty() )
158 textShortHelp->hide();
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 );
173 mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Help ) );
177 if ( !warning.isEmpty() )
185 return mAlgorithm.get();
188 void QgsProcessingAlgorithmDialogBase::setMainWidget(
QgsPanelWidget *widget )
192 mMainWidget->deleteLater();
195 mPanelStack->setMainPanel( widget );
198 mMainWidget = widget;
207 void QgsProcessingAlgorithmDialogBase::saveLogToFile(
const QString &path,
const LogFormat format )
209 QFile logFile( path );
210 if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
214 QTextStream fout( &logFile );
218 case FormatPlainText:
219 fout << txtLog->toPlainText();
223 fout << txtLog->toHtml();
230 auto feedback = qgis::make_unique< QgsProcessingAlgorithmDialogFeedback >();
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 );
239 return feedback.release();
242 QDialogButtonBox *QgsProcessingAlgorithmDialogBase::buttonBox()
247 QTabWidget *QgsProcessingAlgorithmDialogBase::tabWidget()
252 void QgsProcessingAlgorithmDialogBase::showLog()
254 mTabWidget->setCurrentIndex( 1 );
257 void QgsProcessingAlgorithmDialogBase::showParameters()
259 mTabWidget->setCurrentIndex( 0 );
262 QPushButton *QgsProcessingAlgorithmDialogBase::runButton()
267 QPushButton *QgsProcessingAlgorithmDialogBase::cancelButton()
272 QPushButton *QgsProcessingAlgorithmDialogBase::changeParametersButton()
274 return mButtonChangeParameters;
277 void QgsProcessingAlgorithmDialogBase::clearProgress()
279 progressBar->setMaximum( 0 );
282 void QgsProcessingAlgorithmDialogBase::setExecuted(
bool executed )
284 mExecuted = executed;
287 void QgsProcessingAlgorithmDialogBase::setExecutedAnyResult(
bool executedAnyResult )
289 mExecutedAnyResult = executedAnyResult;
292 void QgsProcessingAlgorithmDialogBase::setResults(
const QVariantMap &results )
302 void QgsProcessingAlgorithmDialogBase::openHelp()
304 QUrl algHelp = mAlgorithm->helpUrl();
305 if ( algHelp.isEmpty() )
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() ) ) );
310 if ( !algHelp.isEmpty() )
311 QDesktopServices::openUrl( algHelp );
314 void QgsProcessingAlgorithmDialogBase::toggleCollapsed()
316 if ( mHelpCollapsed )
318 splitter->restoreState( mSplitterState );
319 mButtonCollapse->setArrowType( Qt::RightArrow );
323 mSplitterState = splitter->saveState();
324 splitter->setSizes( QList<int>() << 1 << 0 );
325 mButtonCollapse->setArrowType( Qt::LeftArrow );
327 mHelpCollapsed = !mHelpCollapsed;
330 void QgsProcessingAlgorithmDialogBase::splitterChanged(
int,
int )
332 if ( splitter->sizes().at( 1 ) == 0 )
334 mHelpCollapsed =
true;
335 mButtonCollapse->setArrowType( Qt::LeftArrow );
339 mHelpCollapsed =
false;
340 mButtonCollapse->setArrowType( Qt::RightArrow );
344 void QgsProcessingAlgorithmDialogBase::mTabWidget_currentChanged(
int )
346 updateRunButtonVisibility();
349 void QgsProcessingAlgorithmDialogBase::linkClicked(
const QUrl &url )
351 QDesktopServices::openUrl( url.toString() );
354 void QgsProcessingAlgorithmDialogBase::algExecuted(
bool successful,
const QVariantMap & )
356 mAlgorithmTask =
nullptr;
363 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
377 void QgsProcessingAlgorithmDialogBase::taskTriggered(
QgsTask *task )
379 if ( task == mAlgorithmTask )
383 setWindowState( ( windowState() & ~Qt::WindowMinimized ) | Qt::WindowActive );
389 void QgsProcessingAlgorithmDialogBase::closeClicked()
395 void QgsProcessingAlgorithmDialogBase::reportError(
const QString &error,
bool fatalError )
397 setInfo( error,
true );
404 void QgsProcessingAlgorithmDialogBase::pushInfo(
const QString &info )
410 void QgsProcessingAlgorithmDialogBase::pushCommandInfo(
const QString &command )
412 txtLog->append( QStringLiteral(
"<code>%1<code>" ).arg( formatStringForLog( command.toHtmlEscaped() ) ) );
413 scrollToBottomOfLog();
417 void QgsProcessingAlgorithmDialogBase::pushDebugInfo(
const QString &message )
419 txtLog->append( QStringLiteral(
"<span style=\"color:#777\">%1</span>" ).arg( formatStringForLog( message.toHtmlEscaped() ) ) );
420 scrollToBottomOfLog();
424 void QgsProcessingAlgorithmDialogBase::pushConsoleInfo(
const QString &info )
426 txtLog->append( QStringLiteral(
"<code style=\"color:#777\">%1</code>" ).arg( formatStringForLog( info.toHtmlEscaped() ) ) );
427 scrollToBottomOfLog();
431 QDialog *QgsProcessingAlgorithmDialogBase::createProgressDialog()
433 QgsProcessingAlgorithmProgressDialog *dialog =
new QgsProcessingAlgorithmProgressDialog(
this );
434 dialog->setWindowModality( Qt::ApplicationModal );
435 dialog->setWindowTitle( windowTitle() );
436 dialog->setGeometry( geometry() );
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]()
442 dialog->logTextEdit()->setHtml( txtLog->toHtml() );
443 QScrollBar *sb = dialog->logTextEdit()->verticalScrollBar();
444 sb->setValue( sb->maximum() );
449 void QgsProcessingAlgorithmDialogBase::clearLog()
454 void QgsProcessingAlgorithmDialogBase::saveLog()
457 QString lastUsedDir = settings.
value( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QDir::homePath() ).toString();
460 const QString txtExt = tr(
"Text files" ) + QStringLiteral(
" (*.txt *.TXT)" );
461 const QString htmlExt = tr(
"HTML files" ) + QStringLiteral(
" (*.html *.HTML)" );
463 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save Log to File" ), lastUsedDir, txtExt +
";;" + htmlExt, &filter );
464 if ( path.isEmpty() )
469 settings.
setValue( QStringLiteral(
"/Processing/lastUsedLogDirectory" ), QFileInfo( path ).path() );
471 LogFormat format = FormatPlainText;
472 if ( filter == htmlExt )
476 saveLogToFile( path, format );
479 void QgsProcessingAlgorithmDialogBase::copyLogToClipboard()
481 QMimeData *m =
new QMimeData();
482 m->setText( txtLog->toPlainText() );
483 m->setHtml( txtLog->toHtml() );
484 QClipboard *cb = QApplication::clipboard();
487 cb->setMimeData( m, QClipboard::Selection );
489 cb->setMimeData( m, QClipboard::Clipboard );
492 void QgsProcessingAlgorithmDialogBase::closeEvent( QCloseEvent *e )
494 if ( !mHelpCollapsed )
497 settings.
setValue( QStringLiteral(
"/Processing/dialogBaseSplitter" ), splitter->saveState() );
500 QDialog::closeEvent( e );
502 if ( !mAlgorithmTask )
511 void QgsProcessingAlgorithmDialogBase::runAlgorithm()
516 void QgsProcessingAlgorithmDialogBase::setPercentage(
double percent )
519 if ( progressBar->maximum() == 0 )
520 progressBar->setMaximum( 100 );
521 progressBar->setValue( percent );
525 void QgsProcessingAlgorithmDialogBase::setProgressText(
const QString &text )
527 lblProgress->setText( text );
528 setInfo( text,
false );
529 scrollToBottomOfLog();
536 if ( !text.isEmpty() )
538 QStringList paragraphs = text.split(
'\n' );
540 for (
const QString ¶graph : paragraphs )
542 help += QStringLiteral(
"<p>%1</p>" ).arg( paragraph );
554 void QgsProcessingAlgorithmDialogBase::processEvents()
556 if ( mAlgorithmTask )
572 while ( ++nIters < 100 )
575 QCoreApplication::processEvents();
579 void QgsProcessingAlgorithmDialogBase::scrollToBottomOfLog()
581 QScrollBar *sb = txtLog->verticalScrollBar();
582 sb->setValue( sb->maximum() );
585 void QgsProcessingAlgorithmDialogBase::resetGui()
587 lblProgress->clear();
588 progressBar->setMaximum( 100 );
589 progressBar->setValue( 0 );
590 mButtonRun->setEnabled(
true );
591 mButtonChangeParameters->setEnabled(
true );
592 mButtonClose->setEnabled(
true );
595 mMainWidget->setEnabled(
true );
597 updateRunButtonVisibility();
598 resetAdditionalGui();
601 void QgsProcessingAlgorithmDialogBase::updateRunButtonVisibility()
604 bool runButtonVisible = mTabWidget->currentIndex() == 0;
605 mButtonRun->setVisible( runButtonVisible );
606 mButtonChangeParameters->setVisible( !runButtonVisible && mExecutedAnyResult && mButtonChangeParameters->isEnabled() );
609 void QgsProcessingAlgorithmDialogBase::resetAdditionalGui()
614 void QgsProcessingAlgorithmDialogBase::blockControlsWhileRunning()
616 mButtonRun->setEnabled(
false );
617 mButtonChangeParameters->setEnabled(
false );
620 mMainWidget->setEnabled(
false );
622 blockAdditionalControlsWhileRunning();
625 void QgsProcessingAlgorithmDialogBase::blockAdditionalControlsWhileRunning()
630 QgsMessageBar *QgsProcessingAlgorithmDialogBase::messageBar()
635 void QgsProcessingAlgorithmDialogBase::hideShortHelp()
637 textShortHelp->setVisible(
false );
642 mAlgorithmTask = task;
647 QString QgsProcessingAlgorithmDialogBase::formatStringForLog(
const QString &
string )
650 s.replace(
'\n', QStringLiteral(
"<br>" ) );
654 void QgsProcessingAlgorithmDialogBase::setInfo(
const QString &message,
bool isError,
bool escapeHtml )
657 txtLog->append( QStringLiteral(
"<span style=\"color:red\">%1</span>" ).arg( escapeHtml ? formatStringForLog( message.toHtmlEscaped() ) : formatStringForLog( message ) ) );
658 else if ( escapeHtml )
659 txtLog->append( formatStringForLog( message.toHtmlEscaped() ) );
661 txtLog->append( formatStringForLog( message ) );
662 scrollToBottomOfLog();
666 void QgsProcessingAlgorithmDialogBase::reject()
668 if ( !mAlgorithmTask )
670 setAttribute( Qt::WA_DeleteOnClose );
679 QgsProcessingAlgorithmProgressDialog::QgsProcessingAlgorithmProgressDialog( QWidget *parent )
685 QProgressBar *QgsProcessingAlgorithmProgressDialog::progressBar()
690 QPushButton *QgsProcessingAlgorithmProgressDialog::cancelButton()
692 return mButtonBox->button( QDialogButtonBox::Cancel );
695 QTextEdit *QgsProcessingAlgorithmProgressDialog::logTextEdit()
700 void QgsProcessingAlgorithmProgressDialog::reject()