QGIS API Documentation  3.27.0-Master (11ef3e5184)
qgsprocessinghelpeditorwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprocessinghelpeditorwidget.h
3  ------------------------
4  Date : February 2022
5  Copyright : (C) 2022 Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
18 #include "qgsgui.h"
19 #include <QTreeWidgetItem>
20 #include <QDialogButtonBox>
21 #include <QVBoxLayout>
22 
24 
25 const QString QgsProcessingHelpEditorWidget::ALGORITHM_DESCRIPTION = QStringLiteral( "ALG_DESC" );
26 const QString QgsProcessingHelpEditorWidget::ALGORITHM_CREATOR = QStringLiteral( "ALG_CREATOR" );
27 const QString QgsProcessingHelpEditorWidget::ALGORITHM_HELP_CREATOR = QStringLiteral( "ALG_HELP_CREATOR" );
28 const QString QgsProcessingHelpEditorWidget::ALGORITHM_VERSION = QStringLiteral( "ALG_VERSION" );
29 const QString QgsProcessingHelpEditorWidget::ALGORITHM_SHORT_DESCRIPTION = QStringLiteral( "SHORT_DESCRIPTION" );
30 const QString QgsProcessingHelpEditorWidget::ALGORITHM_HELP_URL = QStringLiteral( "HELP_URL" );
31 const QString QgsProcessingHelpEditorWidget::ALGORITHM_EXAMPLES = QStringLiteral( "EXAMPLES" );
32 
33 
34 class QgsProcessingHelpEditorTreeItem : public QTreeWidgetItem
35 {
36  public:
37 
38  QgsProcessingHelpEditorTreeItem( const QString &name, const QString &description )
39  : QTreeWidgetItem()
40  , name( name )
41  , description( description )
42  {
43  setText( 0, description );
44  }
45 
46  QString name;
47  QString description;
48 
49 };
50 
51 
52 QgsProcessingHelpEditorWidget::QgsProcessingHelpEditorWidget( QWidget *parent )
53  : QWidget( parent )
54  , mCurrentName( ALGORITHM_DESCRIPTION )
55 {
56  setupUi( this );
57 
58  connect( mElementTree, &QTreeWidget::currentItemChanged, this, &QgsProcessingHelpEditorWidget::changeItem );
59  connect( mTextEdit, &QTextEdit::textChanged, this, [ = ]
60  {
61  if ( !mCurrentName.isEmpty() )
62  {
63  if ( mEditStackedWidget->currentWidget() == mPagePlainText )
64  {
65  mHelpContent[ mCurrentName] = mTextEdit->toPlainText();
66  updateHtmlView();
67  }
68  }
69  } );
70 
71  connect( mRichTextEdit, &QgsRichTextEditor::textChanged, this, [ = ]
72  {
73  if ( !mCurrentName.isEmpty() )
74  {
75  if ( mEditStackedWidget->currentWidget() == mPageRichEdit )
76  {
77  mHelpContent[ mCurrentName] = mRichTextEdit->toHtml();
78  updateHtmlView();
79  }
80  }
81  } );
82 }
83 
84 QgsProcessingHelpEditorWidget::~QgsProcessingHelpEditorWidget() = default;
85 
86 void QgsProcessingHelpEditorWidget::setAlgorithm( const QgsProcessingAlgorithm *algorithm )
87 {
88  if ( !algorithm )
89  return;
90 
91  mAlgorithm.reset( algorithm->create() );
92 
93  if ( const QgsProcessingModelAlgorithm *model = dynamic_cast< const QgsProcessingModelAlgorithm *>( mAlgorithm.get() ) )
94  {
95  mHelpContent = model->helpContent();
96  }
97 
98  mEditStackedWidget->setCurrentWidget( mPageRichEdit );
99  if ( mHelpContent.contains( ALGORITHM_DESCRIPTION ) )
100  {
101  mRichTextEdit->setText( mHelpContent.value( ALGORITHM_DESCRIPTION ).toString() );
102  }
103 
104  mElementTree->addTopLevelItem( new QgsProcessingHelpEditorTreeItem( ALGORITHM_DESCRIPTION, tr( "Algorithm description" ) ) );
105  mElementTree->addTopLevelItem( new QgsProcessingHelpEditorTreeItem( ALGORITHM_SHORT_DESCRIPTION, tr( "Short description" ) ) );
106 
107  QgsProcessingHelpEditorTreeItem *parametersItem = new QgsProcessingHelpEditorTreeItem( QString(), tr( "Input parameters" ) );
108  mElementTree->addTopLevelItem( parametersItem );
109 
110  const QList< const QgsProcessingParameterDefinition * > definitions = mAlgorithm->parameterDefinitions();
111  for ( const QgsProcessingParameterDefinition *definition : definitions )
112  {
113  if ( definition->flags() & QgsProcessingParameterDefinition::FlagHidden || definition->isDestination() )
114  continue;
115 
116  parametersItem->addChild( new QgsProcessingHelpEditorTreeItem( definition->name(), definition->description() ) );
117  }
118 
119  QgsProcessingHelpEditorTreeItem *outputsItem = new QgsProcessingHelpEditorTreeItem( QString(), tr( "Outputs" ) );
120  mElementTree->addTopLevelItem( outputsItem );
121  const QList< const QgsProcessingOutputDefinition * > outputs = mAlgorithm->outputDefinitions();
122  for ( const QgsProcessingOutputDefinition *output : outputs )
123  {
124  outputsItem->addChild( new QgsProcessingHelpEditorTreeItem( output->name(), output->description() ) );
125  }
126 
127  mElementTree->addTopLevelItem( new QgsProcessingHelpEditorTreeItem( ALGORITHM_EXAMPLES, tr( "Examples" ) ) );
128 
129  mElementTree->addTopLevelItem( new QgsProcessingHelpEditorTreeItem( ALGORITHM_CREATOR, tr( "Algorithm author" ) ) );
130  mElementTree->addTopLevelItem( new QgsProcessingHelpEditorTreeItem( ALGORITHM_HELP_CREATOR, tr( "Help author" ) ) );
131  mElementTree->addTopLevelItem( new QgsProcessingHelpEditorTreeItem( ALGORITHM_VERSION, tr( "Algorithm version" ) ) );
132  mElementTree->addTopLevelItem( new QgsProcessingHelpEditorTreeItem( ALGORITHM_HELP_URL, tr( "Documentation help URL (for help button)" ) ) );
133 
134  updateHtmlView();
135 }
136 
137 QVariantMap QgsProcessingHelpEditorWidget::helpContent()
138 {
139  storeCurrentValue();
140  return mHelpContent;
141 }
142 
143 void QgsProcessingHelpEditorWidget::updateHtmlView()
144 {
145  mTextPreview->setHtml( formattedHelp() );
146 }
147 
148 void QgsProcessingHelpEditorWidget::changeItem( QTreeWidgetItem *, QTreeWidgetItem * )
149 {
150  if ( QgsProcessingHelpEditorTreeItem *item = dynamic_cast< QgsProcessingHelpEditorTreeItem *>( mElementTree->currentItem() ) )
151  {
152  storeCurrentValue();
153 
154  const QString name = item->name;
155  if ( !name.isEmpty() )
156  {
157  mTextEdit->setEnabled( true );
158  mRichTextEdit->setEnabled( true );
159 
160  updateHtmlView();
161  mCurrentName = name;
162 
163  const bool useRichTextEdit = name == ALGORITHM_EXAMPLES || name == ALGORITHM_DESCRIPTION;
164  if ( useRichTextEdit )
165  {
166  mEditStackedWidget->setCurrentWidget( mPageRichEdit );
167  if ( mHelpContent.contains( name ) )
168  mRichTextEdit->setText( mHelpContent.value( name ).toString() );
169  else
170  mRichTextEdit->setText( QString() );
171  }
172  else
173  {
174  mEditStackedWidget->setCurrentWidget( mPagePlainText );
175  if ( mHelpContent.contains( name ) )
176  mTextEdit->setText( mHelpContent.value( name ).toString() );
177  else
178  mTextEdit->clear();
179  }
180  }
181  else
182  {
183  mCurrentName.clear();
184  mTextEdit->clear();
185  mRichTextEdit->setText( QString() );
186  mTextEdit->setEnabled( false );
187  mRichTextEdit->setEnabled( false );
188  mEditStackedWidget->setCurrentWidget( mPagePlainText );
189  updateHtmlView();
190  }
191  }
192 }
193 
194 QString QgsProcessingHelpEditorWidget::formattedHelp() const
195 {
196  if ( !mAlgorithm )
197  return QString();
198 
199  return QgsProcessingUtils::formatHelpMapAsHtml( mHelpContent, mAlgorithm.get() );
200 }
201 
202 void QgsProcessingHelpEditorWidget::storeCurrentValue()
203 {
204  if ( !mCurrentName.isEmpty() )
205  {
206  if ( mEditStackedWidget->currentWidget() == mPagePlainText )
207  mHelpContent[ mCurrentName] = mTextEdit->toPlainText();
208  else
209  mHelpContent[ mCurrentName] = mRichTextEdit->toHtml();
210  }
211 }
212 
213 QgsProcessingHelpEditorDialog::QgsProcessingHelpEditorDialog( QWidget *parent, Qt::WindowFlags flags )
214  : QDialog( parent, flags )
215 {
216  setObjectName( QStringLiteral( "QgsProcessingHelpEditorDialog" ) );
217 
218  QVBoxLayout *vLayout = new QVBoxLayout();
219  mWidget = new QgsProcessingHelpEditorWidget();
220  vLayout->addWidget( mWidget, 1 );
221 
222  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
223  connect( buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
224  connect( buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
225  vLayout->addWidget( buttonBox );
226  setLayout( vLayout );
227 
229 }
230 
231 void QgsProcessingHelpEditorDialog::setAlgorithm( const QgsProcessingAlgorithm *algorithm )
232 {
233  mWidget->setAlgorithm( algorithm );
234 }
235 
236 QVariantMap QgsProcessingHelpEditorDialog::helpContent()
237 {
238  return mWidget->helpContent();
239 }
240 
241 
243 
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...
Definition: qgsgui.cpp:178
Abstract base class for processing algorithms.
QgsProcessingAlgorithm * create(const QVariantMap &configuration=QVariantMap()) const SIP_THROW(QgsProcessingException)
Creates a copy of the algorithm, ready for execution.
Base class for the definition of processing outputs.
Base class for the definition of processing parameters.
@ FlagHidden
Parameter is hidden and should not be shown to users.
static QString formatHelpMapAsHtml(const QVariantMap &map, const QgsProcessingAlgorithm *algorithm)
Returns a HTML formatted version of the help text encoded in a variant map for a specified algorithm.
void textChanged()
Emitted when the text contents are changed.
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