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