QGIS API Documentation  3.20.0-Odense (decaadbb31)
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  sink->addFeature( feat, QgsFeatureSink::FastInsert );
152 
153  feedback->setProgress( current++ * step );
154  }
155 
156  QVariantMap outputs;
157  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
158  return outputs;
159 }
160 
161 
162 //
163 // QgsLayerToBookmarksAlgorithm
164 //
165 
166 void QgsLayerToBookmarksAlgorithm::initAlgorithm( const QVariantMap & )
167 {
168  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon ) );
169 
170  std::unique_ptr< QgsProcessingParameterEnum > sourceParam = std::make_unique<QgsProcessingParameterEnum >( QStringLiteral( "DESTINATION" ), QObject::tr( "Bookmark destination" ), QStringList() <<
171  QObject::tr( "Project bookmarks" ) << QObject::tr( "User bookmarks" ), false, 0 );
172  addParameter( sourceParam.release() );
173 
174  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "NAME_EXPRESSION" ), QObject::tr( "Name field" ), QVariant(), QStringLiteral( "INPUT" ) ) );
175  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "GROUP_EXPRESSION" ), QObject::tr( "Group field" ), QVariant(), QStringLiteral( "INPUT" ), true ) );
176 
177  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "COUNT" ), QObject::tr( "Count of bookmarks added" ) ) );
178 }
179 
180 QString QgsLayerToBookmarksAlgorithm::name() const
181 {
182  return QStringLiteral( "layertobookmarks" );
183 }
184 
185 QString QgsLayerToBookmarksAlgorithm::displayName() const
186 {
187  return QObject::tr( "Convert layer to spatial bookmarks" );
188 }
189 
190 QStringList QgsLayerToBookmarksAlgorithm::tags() const
191 {
192  return QObject::tr( "save,extract,store" ).split( ',' );
193 }
194 
195 QString QgsLayerToBookmarksAlgorithm::group() const
196 {
197  return QObject::tr( "Vector general" );
198 }
199 
200 QString QgsLayerToBookmarksAlgorithm::groupId() const
201 {
202  return QStringLiteral( "vectorgeneral" );
203 }
204 
205 QString QgsLayerToBookmarksAlgorithm::shortHelpString() const
206 {
207  return QObject::tr( "This algorithm creates spatial bookmarks corresponding to the extent of features contained in a layer." );
208 }
209 
210 QString QgsLayerToBookmarksAlgorithm::shortDescription() const
211 {
212  return QObject::tr( "Converts feature extents to stored spatial bookmarks." );
213 }
214 
215 QIcon QgsLayerToBookmarksAlgorithm::icon() const
216 {
217  return QgsApplication::getThemeIcon( QStringLiteral( "mActionShowBookmarks.svg" ) );
218 }
219 
220 QString QgsLayerToBookmarksAlgorithm::svgIconPath() const
221 {
222  return QgsApplication::iconPath( QStringLiteral( "mActionShowBookmarks.svg" ) );
223 }
224 
225 QgsLayerToBookmarksAlgorithm *QgsLayerToBookmarksAlgorithm::createInstance() const
226 {
227  return new QgsLayerToBookmarksAlgorithm();
228 }
229 
230 QVariantMap QgsLayerToBookmarksAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
231 {
232  mDest = parameterAsEnum( parameters, QStringLiteral( "DESTINATION" ), context );
233  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
234  if ( !source )
235  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
236 
237 
238  QString nameExpressionString = parameterAsExpression( parameters, QStringLiteral( "NAME_EXPRESSION" ), context );
239  QString groupExpressionString = parameterAsExpression( parameters, QStringLiteral( "GROUP_EXPRESSION" ), context );
240 
241  QgsExpressionContext expressionContext = context.expressionContext();
242  expressionContext.appendScope( source->createExpressionContextScope() );
243 
244  QgsExpression nameExpression = QgsExpression( nameExpressionString );
245  if ( !nameExpression.prepare( &expressionContext ) )
246  throw QgsProcessingException( QObject::tr( "Invalid name expression: %1" ).arg( nameExpression.parserErrorString() ) );
247 
248  QSet< QString > requiredColumns = nameExpression.referencedColumns();
249 
250  std::unique_ptr< QgsExpression > groupExpression;
251  if ( !groupExpressionString.isEmpty() )
252  {
253  groupExpression = std::make_unique< QgsExpression >( groupExpressionString );
254  if ( !groupExpression->prepare( &expressionContext ) )
255  throw QgsProcessingException( QObject::tr( "Invalid group expression: %1" ).arg( groupExpression->parserErrorString() ) );
256  requiredColumns.unite( groupExpression->referencedColumns() );
257  }
258 
259  QgsFeatureRequest req;
260  req.setSubsetOfAttributes( requiredColumns, source->fields() );
261 
262  double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 1;
264  QgsFeature f;
265  int current = 0;
266  while ( fi.nextFeature( f ) )
267  {
268  if ( feedback->isCanceled() )
269  {
270  break;
271  }
272 
273  if ( f.hasGeometry() )
274  {
275  const QgsReferencedRectangle extent( f.geometry().boundingBox(), source->sourceCrs() );
276  expressionContext.setFeature( f );
277  const QString name = nameExpression.evaluate( &expressionContext ).toString();
278  if ( !nameExpression.evalErrorString().isEmpty() )
279  {
280  feedback->reportError( QObject::tr( "Error evaluating name expression: %1" ).arg( nameExpression.evalErrorString() ) );
281  feedback->setProgress( current * step );
282  current++;
283  continue;
284  }
285  QString group;
286  if ( groupExpression )
287  {
288  group = groupExpression->evaluate( &expressionContext ).toString();
289  if ( !groupExpression->evalErrorString().isEmpty() )
290  {
291  feedback->reportError( QObject::tr( "Error evaluating group expression: %1" ).arg( groupExpression->evalErrorString() ) );
292  feedback->setProgress( current * step );
293  current++;
294  continue;
295  }
296  }
297 
298  QgsBookmark b;
299  b.setName( name );
300  b.setGroup( group );
301  b.setExtent( extent );
302  mBookmarks << b;
303  }
304  feedback->setProgress( current * step );
305  current++;
306  }
307 
308  return QVariantMap();
309 }
310 
311 QVariantMap QgsLayerToBookmarksAlgorithm::postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback * )
312 {
313  QgsBookmarkManager *dest = nullptr;
314  switch ( mDest )
315  {
316  case 0:
317  dest = context.project()->bookmarkManager();
318  break;
319 
320  case 1:
322  break;
323  }
324 
325  for ( const QgsBookmark &b : std::as_const( mBookmarks ) )
326  dest->addBookmark( b );
327 
328  QVariantMap res;
329  res.insert( QStringLiteral( "COUNT" ), mBookmarks.size() );
330  return res;
331 }
332 
334 
335 
336 
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:135
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:205
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:145
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:124
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Returns a copy of the geometry which has been densified by adding the specified number of extra nodes...
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
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