QGIS API Documentation 3.41.0-Master (88383c3d16f)
Loading...
Searching...
No Matches
qgsmimedatautils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmimedatautils.cpp
3 ---------------------
4 begin : November 2011
5 copyright : (C) 2011 by Martin Dobias
6 email : wonder dot sk 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#include <QStringList>
16
17#include "qgsmimedatautils.h"
18
19#include "qgslayertree.h"
20#include "qgslogger.h"
21#include "qgsrasterlayer.h"
22#include "qgsvectorlayer.h"
23#include "qgsmaplayerfactory.h"
24#include "qgsmeshlayer.h"
25
26#include <QRegularExpression>
27
28static const char *QGIS_URILIST_MIMETYPE = "application/x-vnd.qgis.qgis.uri";
29
30QgsMimeDataUtils::Uri::Uri( const QString &encData )
31{
32 QgsDebugMsgLevel( "encData: " + encData, 4 );
33 const QStringList decoded = decode( encData );
34 if ( decoded.size() < 4 )
35 return;
36
37 layerType = decoded[0];
38 providerKey = decoded[1];
39 name = decoded[2];
40 uri = decoded[3];
41
42 if ( layerType == QLatin1String( "raster" ) && decoded.size() >= 6 )
43 {
44 supportedCrs = decode( decoded[4] );
45 supportedFormats = decode( decoded[5] );
46 }
47 else
48 {
49 supportedCrs.clear();
50 supportedFormats.clear();
51 }
52
53 if ( decoded.size() > 6 )
54 layerId = decoded.at( 6 );
55 if ( decoded.size() > 7 )
56 pId = decoded.at( 7 );
57 if ( decoded.size() > 8 )
58 wkbType = QgsWkbTypes::parseType( decoded.at( 8 ) );
59 if ( decoded.size() > 9 )
60 filePath = decoded.at( 9 );
61
62 QgsDebugMsgLevel( QStringLiteral( "type:%1 key:%2 name:%3 uri:%4 supportedCRS:%5 supportedFormats:%6" )
64 supportedCrs.join( ',' ),
65 supportedFormats.join( ',' ) ), 2 );
66}
67
69 : providerKey( layer->providerType() )
70 , name( layer->name() )
71 , uri( layer->dataProvider() ? layer->dataProvider()->dataSourceUri() : layer->source() )
72 , layerId( layer->id() )
73 , pId( QString::number( QCoreApplication::applicationPid() ) )
74{
76 switch ( layer->type() )
77 {
79 {
80 wkbType = qobject_cast< QgsVectorLayer *>( layer )->wkbType();
81 break;
82 }
88 {
89 break;
90 }
91
95 {
96 // plugin layers do not have a standard way of storing their URI...
97 return;
98 }
99 }
100}
101
103{
104 return encode( { layerType,
105 providerKey,
106 name,
107 uri,
108 encode( supportedCrs ),
109 encode( supportedFormats ),
110 layerId,
111 pId,
113 filePath
114 } );
115}
116
117QgsVectorLayer *QgsMimeDataUtils::Uri::vectorLayer( bool &owner, QString &error ) const
118{
119 owner = false;
120 error.clear();
121 if ( layerType != QLatin1String( "vector" ) )
122 {
123 error = QObject::tr( "%1: Not a vector layer." ).arg( name );
124 return nullptr;
125 }
126
127 if ( !layerId.isEmpty() && QgsMimeDataUtils::hasOriginatedFromCurrentAppInstance( *this ) )
128 {
129 if ( QgsVectorLayer *vectorLayer = QgsProject::instance()->mapLayer<QgsVectorLayer *>( layerId ) ) // skip-keyword-check
130 {
131 return vectorLayer;
132 }
133 }
134 if ( providerKey == QLatin1String( "memory" ) )
135 {
136 error = QObject::tr( "Cannot get memory layer." );
137 return nullptr;
138 }
139
140 owner = true;
141 const QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() }; // skip-keyword-check
142 return new QgsVectorLayer( uri, name, providerKey, options );
143}
144
145QgsRasterLayer *QgsMimeDataUtils::Uri::rasterLayer( bool &owner, QString &error ) const
146{
147 owner = false;
148 error.clear();
149 if ( layerType != QLatin1String( "raster" ) )
150 {
151 error = QObject::tr( "%1: Not a raster layer." ).arg( name );
152 return nullptr;
153 }
154
155 if ( !layerId.isEmpty() && QgsMimeDataUtils::hasOriginatedFromCurrentAppInstance( *this ) )
156 {
157 if ( QgsRasterLayer *rasterLayer = QgsProject::instance()->mapLayer<QgsRasterLayer *>( layerId ) ) // skip-keyword-check
158 {
159 return rasterLayer;
160 }
161 }
162
163 owner = true;
164 return new QgsRasterLayer( uri, name, providerKey );
165}
166
167QgsMeshLayer *QgsMimeDataUtils::Uri::meshLayer( bool &owner, QString &error ) const
168{
169 owner = false;
170 error.clear();
171 if ( layerType != QLatin1String( "mesh" ) )
172 {
173 error = QObject::tr( "%1: Not a mesh layer." ).arg( name );
174 return nullptr;
175 }
176
177 if ( !layerId.isEmpty() && QgsMimeDataUtils::hasOriginatedFromCurrentAppInstance( *this ) )
178 {
179 if ( QgsMeshLayer *meshLayer = QgsProject::instance()->mapLayer<QgsMeshLayer *>( layerId ) ) // skip-keyword-check
180 {
181 return meshLayer;
182 }
183 }
184
185 owner = true;
186 return new QgsMeshLayer( uri, name, providerKey );
187}
188
190{
191 if ( !layerId.isEmpty() && QgsMimeDataUtils::hasOriginatedFromCurrentAppInstance( *this ) )
192 {
193 return QgsProject::instance()->mapLayer( layerId ); // skip-keyword-check
194 }
195 return nullptr;
196}
197
198// -----
199
200bool QgsMimeDataUtils::isUriList( const QMimeData *data )
201{
202 return data->hasFormat( QGIS_URILIST_MIMETYPE );
203}
204
206{
207 QMimeData *mimeData = new QMimeData();
208
209 mimeData->setData( QGIS_URILIST_MIMETYPE, uriListToByteArray( layers ) );
210 return mimeData;
211}
212
213
215{
216 QByteArray encodedData = data->data( QGIS_URILIST_MIMETYPE );
217 QDataStream stream( &encodedData, QIODevice::ReadOnly );
218 QString xUri; // extended uri: layer_type:provider_key:uri
219 UriList list;
220 while ( !stream.atEnd() )
221 {
222 stream >> xUri;
223 QgsDebugMsgLevel( xUri, 4 );
224 list.append( Uri( xUri ) );
225 }
226 return list;
227}
228
229
230static void _addLayerTreeNodeToUriList( QgsLayerTreeNode *node, QgsMimeDataUtils::UriList &uris )
231{
232 if ( QgsLayerTree::isGroup( node ) )
233 {
234 const auto constChildren = QgsLayerTree::toGroup( node )->children();
235 for ( QgsLayerTreeNode *child : constChildren )
236 _addLayerTreeNodeToUriList( child, uris );
237 }
238 else if ( QgsLayerTree::isLayer( node ) )
239 {
240 QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
241 QgsMapLayer *layer = nodeLayer->layer();
242 if ( !layer )
243 return;
244
245 if ( layer->type() == Qgis::LayerType::Plugin )
246 return; // plugin layers do not have a standard way of storing their URI...
247
248 uris << QgsMimeDataUtils::Uri( layer );
249 }
250}
251
252QByteArray QgsMimeDataUtils::layerTreeNodesToUriList( const QList<QgsLayerTreeNode *> &nodes )
253{
254 UriList uris;
255 const auto constNodes = nodes;
256 for ( QgsLayerTreeNode *node : constNodes )
257 _addLayerTreeNodeToUriList( node, uris );
258 return uriListToByteArray( uris );
259}
260
262{
263 if ( uri.pId.isEmpty() )
264 return false;
265
266 const qint64 pid = uri.pId.toLongLong();
267 return pid == QCoreApplication::applicationPid();
268}
269
270QString QgsMimeDataUtils::encode( const QStringList &items )
271{
272 QString encoded;
273 // Do not escape colon twice
274 const thread_local QRegularExpression re( QStringLiteral( "(?<!\\\\):" ) );
275 const auto constItems = items;
276 for ( const QString &item : constItems )
277 {
278 QString str = item;
279 str.replace( '\\', QLatin1String( "\\\\" ) );
280 str.replace( re, QStringLiteral( "\\:" ) );
281 encoded += str + ':';
282 }
283 return encoded.left( encoded.length() - 1 );
284}
285
286QStringList QgsMimeDataUtils::decode( const QString &encoded )
287{
288 QStringList items;
289 QString item;
290 bool inEscape = false;
291 const auto constEncoded = encoded;
292 for ( const QChar c : constEncoded )
293 {
294 if ( c == '\\' && inEscape )
295 {
296 item += c;
297 }
298 else if ( c == '\\' )
299 {
300 inEscape = true;
301 }
302 else if ( c == ':' && !inEscape )
303 {
304 items.append( item );
305 item.clear();
306 }
307 else
308 {
309 item += c;
310 inEscape = false;
311 }
312 }
313 items.append( item );
314 return items;
315}
316
317
318QByteArray QgsMimeDataUtils::uriListToByteArray( const QgsMimeDataUtils::UriList &layers )
319{
320 QByteArray encodedData;
321
322 QDataStream stream( &encodedData, QIODevice::WriteOnly );
323 const auto constLayers = layers;
324 for ( const Uri &u : constLayers )
325 {
326 stream << u.data();
327 }
328 return encodedData;
329}
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ Vector
Vector layer.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ Raster
Raster layer.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Layer tree node points to a map layer.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
This class is a base class for nodes in a layer tree.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
static QString typeToString(Qgis::LayerType type)
Converts a map layer type to a string value.
Base class for all map layer types.
Definition qgsmaplayer.h:76
Qgis::LayerType type
Definition qgsmaplayer.h:86
Represents a mesh layer supporting display of data on structured or unstructured meshes.
static QByteArray layerTreeNodesToUriList(const QList< QgsLayerTreeNode * > &nodes)
Returns encoded URI list from a list of layer tree nodes.
static bool isUriList(const QMimeData *data)
QList< QgsMimeDataUtils::Uri > UriList
static QMimeData * encodeUriList(const UriList &layers)
Encodes a URI list to a new QMimeData object.
static UriList decodeUriList(const QMimeData *data)
static bool hasOriginatedFromCurrentAppInstance(const QgsMimeDataUtils::Uri &uri)
Returns true if uri originated from the current QGIS application instance.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
QgsCoordinateTransformContext transformContext
Definition qgsproject.h:113
Represents a raster layer.
Represents a vector layer which manages a vector based data sets.
static Qgis::WkbType parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
static QString displayString(Qgis::WkbType type)
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
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 c
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:41
QgsMeshLayer * meshLayer(bool &owner, QString &error) const
Gets mesh layer from uri if possible, otherwise returns nullptr and error is set.
Qgis::WkbType wkbType
WKB type, if associated with a vector layer, or QgsWkbTypes::Unknown if not yet known.
QString filePath
Path to file, if uri is associated with a file.
QString uri
Identifier of the data source recognized by its providerKey.
QString name
Human readable name to be used e.g. in layer tree.
QgsMapLayer * mapLayer() const
Returns the layer from the active project corresponding to this uri (if possible),...
QString pId
Unique ID associated with application instance.
QgsRasterLayer * rasterLayer(bool &owner, QString &error) const
Gets raster layer from uri if possible, otherwise returns nullptr and error is set.
QString providerKey
For "vector" / "raster" type: provider id.
QgsVectorLayer * vectorLayer(bool &owner, QString &error) const
Gets vector layer from uri if possible, otherwise returns nullptr and error is set.
QString layerId
Layer ID, if uri is associated with a layer from a QgsProject.
QString data() const
Returns encoded representation of the object.
Uri()=default
Constructs invalid URI.
QString layerType
Type of URI.
Setting options for loading vector layers.