QGIS API Documentation  3.23.0-Master (4fd2f04bd0)
qgsbookmarkalgorithms.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsbookmarkalgorithms.cpp
3  ---------------------
4  begin : September 2019
5  copyright : (C) 2019 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsbookmarkalgorithms.h"
19 #include "qgsapplication.h"
20 
22 
23 //
24 // QgsBookmarksToLayerAlgorithm
25 //
26 
27 void QgsBookmarksToLayerAlgorithm::initAlgorithm( const QVariantMap & )
28 {
29  std::unique_ptr< QgsProcessingParameterEnum > sourceParam = std::make_unique<QgsProcessingParameterEnum >( QStringLiteral( "SOURCE" ), QObject::tr( "Bookmark source" ), QStringList() <<
30  QObject::tr( "Project bookmarks" ) << QObject::tr( "User bookmarks" ), true, QVariantList() << 0 << 1 );
31  QVariantMap wrapperMetadata;
32  wrapperMetadata.insert( QStringLiteral( "useCheckBoxes" ), true );
33  QVariantMap metadata;
34  metadata.insert( QStringLiteral( "widget_wrapper" ), wrapperMetadata );
35  sourceParam->setMetadata( metadata );
36  addParameter( sourceParam.release() );
37  addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS" ), QObject::tr( "Output CRS" ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) ) );
38  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Output" ), QgsProcessing::TypeVectorPolygon ) );
39 }
40 
41 QString QgsBookmarksToLayerAlgorithm::name() const
42 {
43  return QStringLiteral( "bookmarkstolayer" );
44 }
45 
46 QString QgsBookmarksToLayerAlgorithm::displayName() const
47 {
48  return QObject::tr( "Convert spatial bookmarks to layer" );
49 }
50 
51 QStringList QgsBookmarksToLayerAlgorithm::tags() const
52 {
53  return QObject::tr( "save,extract" ).split( ',' );
54 }
55 
56 QString QgsBookmarksToLayerAlgorithm::group() const
57 {
58  return QObject::tr( "Vector general" );
59 }
60 
61 QString QgsBookmarksToLayerAlgorithm::groupId() const
62 {
63  return QStringLiteral( "vectorgeneral" );
64 }
65 
66 QString QgsBookmarksToLayerAlgorithm::shortHelpString() const
67 {
68  return QObject::tr( "This algorithm creates a new layer containing polygon features for stored spatial bookmarks.\n\n"
69  "The export can be filtered to only bookmarks belonging to the current project, to all user bookmarks, or a combination of both." );
70 }
71 
72 QString QgsBookmarksToLayerAlgorithm::shortDescription() const
73 {
74  return QObject::tr( "Converts stored spatial bookmarks to a polygon layer." );
75 }
76 
77 QIcon QgsBookmarksToLayerAlgorithm::icon() const
78 {
79  return QgsApplication::getThemeIcon( QStringLiteral( "mActionShowBookmarks.svg" ) );
80 }
81 
82 QString QgsBookmarksToLayerAlgorithm::svgIconPath() const
83 {
84  return QgsApplication::iconPath( QStringLiteral( "mActionShowBookmarks.svg" ) );
85 }
86 
87 QgsBookmarksToLayerAlgorithm *QgsBookmarksToLayerAlgorithm::createInstance() const
88 {
89  return new QgsBookmarksToLayerAlgorithm();
90 }
91 
92 bool QgsBookmarksToLayerAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
93 {
94  QList< int > sources = parameterAsEnums( parameters, QStringLiteral( "SOURCE" ), context );
95  if ( sources.contains( 0 ) )
96  {
97  if ( !context.project() )
98  throw QgsProcessingException( QObject::tr( "No project is available for bookmark extraction" ) );
99  mBookmarks.append( context.project()->bookmarkManager()->bookmarks() );
100  }
101  if ( sources.contains( 1 ) )
102  mBookmarks.append( QgsApplication::bookmarkManager()->bookmarks() );
103 
104  return true;
105 }
106 
107 QVariantMap QgsBookmarksToLayerAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
108 {
109  const QgsCoordinateReferenceSystem crs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
110  QgsFields fields;
111  fields.append( QgsField( QStringLiteral( "name" ), QVariant::String ) );
112  fields.append( QgsField( QStringLiteral( "group" ), QVariant::String ) );
113  QString dest;
114  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::Polygon, crs ) );
115  if ( !sink )
116  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
117 
118  int count = mBookmarks.count();
119  int current = 0;
120  double step = count > 0 ? 100.0 / count : 1;
121 
122  for ( const QgsBookmark &b : std::as_const( mBookmarks ) )
123  {
124  if ( feedback->isCanceled() )
125  {
126  break;
127  }
128 
129  QgsFeature feat;
130  feat.setAttributes( QgsAttributes() << b.name() << b.group() );
131 
132  QgsGeometry geom = QgsGeometry::fromRect( b.extent() );
133  if ( b.extent().crs() != crs )
134  {
135  QgsCoordinateTransform xform( b.extent().crs(), crs, context.transformContext() );
136  geom = geom.densifyByCount( 20 );
137  try
138  {
139  geom.transform( xform );
140  }
141  catch ( QgsCsException & )
142  {
143  feedback->reportError( QObject::tr( "Could not reproject bookmark %1 to destination CRS" ).arg( b.name() ) );
144  feedback->setProgress( current++ * step );
145  continue;
146  }
147  }
148 
149  feat.setGeometry( geom );
150 
151  if ( !sink->addFeature( feat, QgsFeatureSink::FastInsert ) )
152  throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
153 
154  feedback->setProgress( current++ * step );
155  }
156 
157  QVariantMap outputs;
158  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
159  return outputs;
160 }
161 
162 
163 //
164 // QgsLayerToBookmarksAlgorithm
165 //
166 
167 void QgsLayerToBookmarksAlgorithm::initAlgorithm( const QVariantMap & )
168 {
169  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon ) );
170 
171  std::unique_ptr< QgsProcessingParameterEnum > sourceParam = std::make_unique<QgsProcessingParameterEnum >( QStringLiteral( "DESTINATION" ), QObject::tr( "Bookmark destination" ), QStringList() <<
172  QObject::tr( "Project bookmarks" ) << QObject::tr( "User bookmarks" ), false, 0 );
173  addParameter( sourceParam.release() );
174 
175  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "NAME_EXPRESSION" ), QObject::tr( "Name field" ), QVariant(), QStringLiteral( "INPUT" ) ) );
176  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "GROUP_EXPRESSION" ), QObject::tr( "Group field" ), QVariant(), QStringLiteral( "INPUT" ), true ) );
177 
178  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "COUNT" ), QObject::tr( "Count of bookmarks added" ) ) );
179 }
180 
181 QString QgsLayerToBookmarksAlgorithm::name() const
182 {
183  return QStringLiteral( "layertobookmarks" );
184 }
185 
186 QString QgsLayerToBookmarksAlgorithm::displayName() const
187 {
188  return QObject::tr( "Convert layer to spatial bookmarks" );
189 }
190 
191 QStringList QgsLayerToBookmarksAlgorithm::tags() const
192 {
193  return QObject::tr( "save,extract,store" ).split( ',' );
194 }
195 
196 QString QgsLayerToBookmarksAlgorithm::group() const
197 {
198  return QObject::tr( "Vector general" );
199 }
200 
201 QString QgsLayerToBookmarksAlgorithm::groupId() const
202 {
203  return QStringLiteral( "vectorgeneral" );
204 }
205 
206 QString QgsLayerToBookmarksAlgorithm::shortHelpString() const
207 {
208  return QObject::tr( "This algorithm creates spatial bookmarks corresponding to the extent of features contained in a layer." );
209 }
210 
211 QString QgsLayerToBookmarksAlgorithm::shortDescription() const
212 {
213  return QObject::tr( "Converts feature extents to stored spatial bookmarks." );
214 }
215 
216 QIcon QgsLayerToBookmarksAlgorithm::icon() const
217 {
218  return QgsApplication::getThemeIcon( QStringLiteral( "mActionShowBookmarks.svg" ) );
219 }
220 
221 QString QgsLayerToBookmarksAlgorithm::svgIconPath() const
222 {
223  return QgsApplication::iconPath( QStringLiteral( "mActionShowBookmarks.svg" ) );
224 }
225 
226 QgsLayerToBookmarksAlgorithm *QgsLayerToBookmarksAlgorithm::createInstance() const
227 {
228  return new QgsLayerToBookmarksAlgorithm();
229 }
230 
231 QVariantMap QgsLayerToBookmarksAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
232 {
233  mDest = parameterAsEnum( parameters, QStringLiteral( "DESTINATION" ), context );
234  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
235  if ( !source )
236  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
237 
238 
239  QString nameExpressionString = parameterAsExpression( parameters, QStringLiteral( "NAME_EXPRESSION" ), context );
240  QString groupExpressionString = parameterAsExpression( parameters, QStringLiteral( "GROUP_EXPRESSION" ), context );
241 
242  QgsExpressionContext expressionContext = context.expressionContext();
243  expressionContext.appendScope( source->createExpressionContextScope() );
244 
245  QgsExpression nameExpression = QgsExpression( nameExpressionString );
246  if ( !nameExpression.prepare( &expressionContext ) )
247  throw QgsProcessingException( QObject::tr( "Invalid name expression: %1" ).arg( nameExpression.parserErrorString() ) );
248 
249  QSet< QString > requiredColumns = nameExpression.referencedColumns();
250 
251  std::unique_ptr< QgsExpression > groupExpression;
252  if ( !groupExpressionString.isEmpty() )
253  {
254  groupExpression = std::make_unique< QgsExpression >( groupExpressionString );
255  if ( !groupExpression->prepare( &expressionContext ) )
256  throw QgsProcessingException( QObject::tr( "Invalid group expression: %1" ).arg( groupExpression->parserErrorString() ) );
257  requiredColumns.unite( groupExpression->referencedColumns() );
258  }
259 
260  QgsFeatureRequest req;
261  req.setSubsetOfAttributes( requiredColumns, source->fields() );
262 
263  double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 1;
265  QgsFeature f;
266  int current = 0;
267  while ( fi.nextFeature( f ) )
268  {
269  if ( feedback->isCanceled() )
270  {
271  break;
272  }
273 
274  if ( f.hasGeometry() )
275  {
276  const QgsReferencedRectangle extent( f.geometry().boundingBox(), source->sourceCrs() );
277  expressionContext.setFeature( f );
278  const QString name = nameExpression.evaluate( &expressionContext ).toString();
279  if ( !nameExpression.evalErrorString().isEmpty() )
280  {
281  feedback->reportError( QObject::tr( "Error evaluating name expression: %1" ).arg( nameExpression.evalErrorString() ) );
282  feedback->setProgress( current * step );
283  current++;
284  continue;
285  }
286  QString group;
287  if ( groupExpression )
288  {
289  group = groupExpression->evaluate( &expressionContext ).toString();
290  if ( !groupExpression->evalErrorString().isEmpty() )
291  {
292  feedback->reportError( QObject::tr( "Error evaluating group expression: %1" ).arg( groupExpression->evalErrorString() ) );
293  feedback->setProgress( current * step );
294  current++;
295  continue;
296  }
297  }
298 
299  QgsBookmark b;
300  b.setName( name );
301  b.setGroup( group );
302  b.setExtent( extent );
303  mBookmarks << b;
304  }
305  feedback->setProgress( current * step );
306  current++;
307  }
308 
309  return QVariantMap();
310 }
311 
312 QVariantMap QgsLayerToBookmarksAlgorithm::postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback * )
313 {
314  QgsBookmarkManager *dest = nullptr;
315  switch ( mDest )
316  {
317  case 0:
318  dest = context.project()->bookmarkManager();
319  break;
320 
321  case 1:
323  break;
324  }
325 
326  for ( const QgsBookmark &b : std::as_const( mBookmarks ) )
327  dest->addBookmark( b );
328 
329  QVariantMap res;
330  res.insert( QStringLiteral( "COUNT" ), mBookmarks.size() );
331  return res;
332 }
333 
335 
336 
337 
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsBookmarkManager * bookmarkManager()
Returns the application's bookmark manager, used for storing installation-wide bookmarks.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
A vector of attributes.
Definition: qgsattributes.h:58
Manages storage of a set of bookmarks.
QString addBookmark(const QgsBookmark &bookmark, bool *ok=nullptr)
Adds a bookmark to the manager.
QList< QgsBookmark > bookmarks() const
Returns a list of all bookmarks contained in the manager.
Represents a spatial bookmark, with a name, CRS and extent.
void setGroup(const QString &group)
Sets the bookmark's group, which is a user-visible string identifying the bookmark's category.
void setExtent(const QgsReferencedRectangle &extent)
Sets the bookmark's spatial extent.
void setName(const QString &name)
Sets the bookmark's name, which is a user-visible string identifying the bookmark.
This class represents a coordinate reference system (CRS).
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QString evalErrorString() const
Returns evaluation error.
QString parserErrorString() const
Returns parser error.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
QVariant evaluate()
Evaluate the feature and return the result.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:153
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:223
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:163
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Returns a copy of the geometry which has been densified by adding the specified number of extra nodes...
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QgsExpressionContext & expressionContext()
Returns the expression context.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Base class for providing feedback from a processing algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A numeric output for processing algorithms.
A coordinate reference system parameter for processing algorithms.
An expression parameter for processing algorithms.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:50
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:51
const QgsBookmarkManager * bookmarkManager() const
Returns the project's bookmark manager, which manages bookmarks within the project.
A QgsRectangle with associated coordinate reference system.
const QgsCoordinateReferenceSystem & crs