From 2d1579d28acad083d4bc92a031a2f59dd3b9eade Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 15 May 2017 13:09:41 +1000 Subject: [PATCH] Port algorithm help to QgsProcessingAlgorithm --- .../processing/qgsprocessingalgorithm.sip | 26 ++++++++++++++++ .../processing/algs/gdal/GdalAlgorithm.py | 6 ++-- .../processing/algs/grass7/Grass7Algorithm.py | 8 ++--- .../plugins/processing/core/GeoAlgorithm.py | 13 ++------ .../processing/gui/AlgorithmDialogBase.py | 30 +++++++++++-------- .../processing/modeler/ModelerAlgorithm.py | 10 +++---- .../processing/script/ScriptAlgorithm.py | 10 +++---- src/core/processing/qgsnativealgorithms.cpp | 15 ++++++++++ src/core/processing/qgsnativealgorithms.h | 2 ++ .../processing/qgsprocessingalgorithm.cpp | 15 ++++++++++ src/core/processing/qgsprocessingalgorithm.h | 23 ++++++++++++++ 11 files changed, 118 insertions(+), 40 deletions(-) diff --git a/python/core/processing/qgsprocessingalgorithm.sip b/python/core/processing/qgsprocessingalgorithm.sip index 6ed40f98086..12123080b61 100644 --- a/python/core/processing/qgsprocessingalgorithm.sip +++ b/python/core/processing/qgsprocessingalgorithm.sip @@ -76,6 +76,32 @@ class QgsProcessingAlgorithm :rtype: list of str %End + virtual QString shortHelpString() const; +%Docstring + Returns a localised short helper string for the algorithm. This string should provide a basic description + about what the algorithm does and the parameters and outputs associated with it. +.. seealso:: helpString() +.. seealso:: helpUrl() + :rtype: str +%End + + virtual QString helpString() const; +%Docstring + Returns a localised help string for the algorithm. Algorithm subclasses should implement either + helpString() or helpUrl(). +.. seealso:: helpUrl() +.. seealso:: shortHelpString() + :rtype: str +%End + + virtual QString helpUrl() const; +%Docstring + Returns a url pointing to the algorithm's help page. +.. seealso:: helpString() +.. seealso:: shortHelpString() + :rtype: str +%End + virtual QIcon icon() const; %Docstring Returns an icon for the algorithm. diff --git a/python/plugins/processing/algs/gdal/GdalAlgorithm.py b/python/plugins/processing/algs/gdal/GdalAlgorithm.py index 0fb7034b9d4..4372e3929b4 100644 --- a/python/plugins/processing/algs/gdal/GdalAlgorithm.py +++ b/python/plugins/processing/algs/gdal/GdalAlgorithm.py @@ -77,7 +77,7 @@ class GdalAlgorithm(GeoAlgorithm): commands[i] = c GdalUtils.runGdal(commands, feedback) - def shortHelp(self): + def shortHelpString(self): helpPath = GdalUtils.gdalHelpPath() if helpPath == '': return @@ -87,9 +87,9 @@ class GdalAlgorithm(GeoAlgorithm): else: url = helpPath + '{}.html'.format(self.commandName()) - return self._formatHelp('''This algorithm is based on the GDAL {} module. + return '''This algorithm is based on the GDAL {} module. For more info, see the module help - '''.format(self.commandName(), url)) + '''.format(self.commandName(), url) def commandName(self): for output in self.outputs: diff --git a/python/plugins/processing/algs/grass7/Grass7Algorithm.py b/python/plugins/processing/algs/grass7/Grass7Algorithm.py index 0294055725c..c2589b1901c 100644 --- a/python/plugins/processing/algs/grass7/Grass7Algorithm.py +++ b/python/plugins/processing/algs/grass7/Grass7Algorithm.py @@ -112,15 +112,15 @@ class Grass7Algorithm(GeoAlgorithm): def svgIconPath(self): return QgsApplication.iconPath("providerGrass.svg") - def help(self): + def helpUrl(self): helpPath = Grass7Utils.grassHelpPath() if helpPath == '': - return False, None + return None if os.path.exists(helpPath): - return False, QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.grass7Name))).toString() + return QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.grass7Name))).toString() else: - return False, helpPath + '{}.html'.format(self.grass7Name) + return helpPath + '{}.html'.format(self.grass7Name) def getParameterDescriptions(self): descs = {} diff --git a/python/plugins/processing/core/GeoAlgorithm.py b/python/plugins/processing/core/GeoAlgorithm.py index a6ea167ae59..b4a9058f1d5 100755 --- a/python/plugins/processing/core/GeoAlgorithm.py +++ b/python/plugins/processing/core/GeoAlgorithm.py @@ -76,17 +76,8 @@ class GeoAlgorithm(QgsProcessingAlgorithm): # methods to overwrite when creating a custom geoalgorithm - def _formatHelp(self, text): - return "

%s

%s" % (self.displayName(), "".join(["

%s

" % s for s in text.split("\n")])) - - def help(self): - return False, None - - def shortHelp(self): - text = shortHelp.get(self.id(), None) - if text is not None: - text = self._formatHelp(text) - return text + def shortHelpString(self): + return shortHelp.get(self.id(), None) def processAlgorithm(self, context, feedback): """Here goes the algorithm itself. diff --git a/python/plugins/processing/gui/AlgorithmDialogBase.py b/python/plugins/processing/gui/AlgorithmDialogBase.py index 6c0d28b0fd1..695ef9c765f 100644 --- a/python/plugins/processing/gui/AlgorithmDialogBase.py +++ b/python/plugins/processing/gui/AlgorithmDialogBase.py @@ -104,7 +104,7 @@ class AlgorithmDialogBase(BASE, WIDGET): # if desktop.physicalDpiX() > 96: # self.txtHelp.setZoomFactor(desktop.physicalDpiX() / 96) - algHelp = self.alg.shortHelp() + algHelp = self.formatHelp(self.alg) if algHelp is None: self.textShortHelp.setVisible(False) else: @@ -123,18 +123,18 @@ class AlgorithmDialogBase(BASE, WIDGET): self.textShortHelp.anchorClicked.connect(linkClicked) - isText, algHelp = self.alg.help() - if algHelp is not None: - algHelp = algHelp if isText else QUrl(algHelp) + if self.alg.helpString() is not None: try: - if isText: - self.txtHelp.setHtml(algHelp) - else: - html = self.tr('

Downloading algorithm help... Please wait.

') - self.txtHelp.setHtml(html) - rq = QNetworkRequest(algHelp) - self.reply = QgsNetworkAccessManager.instance().get(rq) - self.reply.finished.connect(self.requestFinished) + self.txtHelp.setHtml(self.alg.helpString()) + except Exception: + self.tabWidget.removeTab(2) + elif self.alg.helpUrl() is not None: + try: + html = self.tr('

Downloading algorithm help... Please wait.

') + self.txtHelp.setHtml(html) + rq = QNetworkRequest(QUrl(self.alg.helpUrl())) + self.reply = QgsNetworkAccessManager.instance().get(rq) + self.reply.finished.connect(self.requestFinished) except Exception: self.tabWidget.removeTab(2) else: @@ -143,6 +143,12 @@ class AlgorithmDialogBase(BASE, WIDGET): self.showDebug = ProcessingConfig.getSetting( ProcessingConfig.SHOW_DEBUG_IN_DIALOG) + def formatHelp(self, alg): + text = alg.shortHelpString() + if not text: + return None + return "

%s

%s" % (alg.displayName(), "".join(["

%s

" % s for s in text.split("\n")])) + def requestFinished(self): """Change the webview HTML content""" reply = self.sender() diff --git a/python/plugins/processing/modeler/ModelerAlgorithm.py b/python/plugins/processing/modeler/ModelerAlgorithm.py index aa472caee46..97ea25e616c 100644 --- a/python/plugins/processing/modeler/ModelerAlgorithm.py +++ b/python/plugins/processing/modeler/ModelerAlgorithm.py @@ -539,15 +539,15 @@ class ModelerAlgorithm(GeoAlgorithm): if self.modelerdialog: self.modelerdialog.repaintModel() - def help(self): + def helpString(self): try: - return True, getHtmlFromDescriptionsDict(self, self.helpContent) + return getHtmlFromDescriptionsDict(self, self.helpContent) except: - return False, None + return None - def shortHelp(self): + def shortHelpString(self): if 'ALG_DESC' in self.helpContent: - return self._formatHelp(str(self.helpContent['ALG_DESC'])) + return str(self.helpContent['ALG_DESC']) return None def getParameterDescriptions(self): diff --git a/python/plugins/processing/script/ScriptAlgorithm.py b/python/plugins/processing/script/ScriptAlgorithm.py index 649f82e5706..21dbbed95d8 100644 --- a/python/plugins/processing/script/ScriptAlgorithm.py +++ b/python/plugins/processing/script/ScriptAlgorithm.py @@ -198,16 +198,16 @@ class ScriptAlgorithm(GeoAlgorithm): for out in self.outputs: out.setValue(ns[out.name]) - def help(self): + def helpString(self): if self.descriptionFile is None: return False, None helpfile = self.descriptionFile + '.help' if os.path.exists(helpfile): - return True, getHtmlFromHelpFile(self, helpfile) + return getHtmlFromHelpFile(self, helpfile) else: - return False, None + return None - def shortHelp(self): + def shortHelpString(self): if self.descriptionFile is None: return None helpFile = str(self.descriptionFile) + '.help' @@ -216,7 +216,7 @@ class ScriptAlgorithm(GeoAlgorithm): try: descriptions = json.load(f) if 'ALG_DESC' in descriptions: - return self._formatHelp(str(descriptions['ALG_DESC'])) + return str(descriptions['ALG_DESC']) except: return None return None diff --git a/src/core/processing/qgsnativealgorithms.cpp b/src/core/processing/qgsnativealgorithms.cpp index cf160164a81..2736bf031a8 100644 --- a/src/core/processing/qgsnativealgorithms.cpp +++ b/src/core/processing/qgsnativealgorithms.cpp @@ -70,6 +70,12 @@ QgsCentroidAlgorithm::QgsCentroidAlgorithm() addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT_LAYER" ), QObject::tr( "Centroids" ), QgsProcessingParameterDefinition::TypeVectorPoint ) ); } +QString QgsCentroidAlgorithm::shortHelpString() const +{ + return QObject::tr( "This algorithm creates a new point layer, with points representing the centroid of the geometries in an input layer.\n\n" + "The attributes associated to each point in the output layer are the same ones associated to the original features." ); +} + QVariantMap QgsCentroidAlgorithm::run( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const { QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( parameterAsLayer( parameters, QStringLiteral( "INPUT" ), context ) ); @@ -129,6 +135,15 @@ QgsBufferAlgorithm::QgsBufferAlgorithm() addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT_LAYER" ), QObject::tr( "Buffered" ), QgsProcessingParameterDefinition::TypeVectorPoint ) ); } +QString QgsBufferAlgorithm::shortHelpString() const +{ + return QObject::tr( "This algorithm computes a buffer area for all the features in an input layer, using a fixed or dynamic distance.\n\n" + "The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets.\n\n" + "The end cap style parameter controls how line endings are handled in the buffer.\n\n" + "The join style parameter specifies whether round, mitre or beveled joins should be used when offsetting corners in a line.\n\n" + "The mitre limit parameter is only applicable for mitre join styles, and controls the maximum distance from the offset curve to use when creating a mitred join." ); +} + QVariantMap QgsBufferAlgorithm::run( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const { QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( parameterAsLayer( parameters, QStringLiteral( "INPUT" ), context ) ); diff --git a/src/core/processing/qgsnativealgorithms.h b/src/core/processing/qgsnativealgorithms.h index 411da74e733..c4d469f2e30 100644 --- a/src/core/processing/qgsnativealgorithms.h +++ b/src/core/processing/qgsnativealgorithms.h @@ -57,6 +57,7 @@ class QgsCentroidAlgorithm : public QgsProcessingAlgorithm QString displayName() const override { return QObject::tr( "Centroids" ); } virtual QStringList tags() const override { return QObject::tr( "centroid,center,average,point,middle" ).split( ',' ); } QString group() const override { return QObject::tr( "Vector geometry tools" ); } + QString shortHelpString() const override; virtual QVariantMap run( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override; @@ -77,6 +78,7 @@ class QgsBufferAlgorithm : public QgsProcessingAlgorithm QString displayName() const override { return QObject::tr( "Buffer" ); } virtual QStringList tags() const override { return QObject::tr( "buffer,grow" ).split( ',' ); } QString group() const override { return QObject::tr( "Vector geometry tools" ); } + QString shortHelpString() const override; virtual QVariantMap run( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override; diff --git a/src/core/processing/qgsprocessingalgorithm.cpp b/src/core/processing/qgsprocessingalgorithm.cpp index 52fffc4490a..dd7274404cd 100644 --- a/src/core/processing/qgsprocessingalgorithm.cpp +++ b/src/core/processing/qgsprocessingalgorithm.cpp @@ -36,6 +36,21 @@ QString QgsProcessingAlgorithm::id() const return name(); } +QString QgsProcessingAlgorithm::shortHelpString() const +{ + return QString(); +} + +QString QgsProcessingAlgorithm::helpString() const +{ + return QString(); +} + +QString QgsProcessingAlgorithm::helpUrl() const +{ + return QString(); +} + QIcon QgsProcessingAlgorithm::icon() const { return QgsApplication::getThemeIcon( "/processingAlgorithm.svg" ); diff --git a/src/core/processing/qgsprocessingalgorithm.h b/src/core/processing/qgsprocessingalgorithm.h index 54900935de4..896b3bb7d86 100644 --- a/src/core/processing/qgsprocessingalgorithm.h +++ b/src/core/processing/qgsprocessingalgorithm.h @@ -95,6 +95,29 @@ class CORE_EXPORT QgsProcessingAlgorithm */ virtual QStringList tags() const { return QStringList(); } + /** + * Returns a localised short helper string for the algorithm. This string should provide a basic description + * about what the algorithm does and the parameters and outputs associated with it. + * \see helpString() + * \see helpUrl() + */ + virtual QString shortHelpString() const; + + /** + * Returns a localised help string for the algorithm. Algorithm subclasses should implement either + * helpString() or helpUrl(). + * \see helpUrl() + * \see shortHelpString() + */ + virtual QString helpString() const; + + /** + * Returns a url pointing to the algorithm's help page. + * \see helpString() + * \see shortHelpString() + */ + virtual QString helpUrl() const; + /** * Returns an icon for the algorithm. * \see svgIconPath()